格式修改
This commit is contained in:
@@ -0,0 +1,15 @@
|
||||
package com.baiyue.firstleg.config;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import java.time.Clock;
|
||||
|
||||
@Configuration
|
||||
public class TimeConfiguration {
|
||||
|
||||
@Bean
|
||||
public Clock systemClock() {
|
||||
return Clock.systemDefaultZone();
|
||||
}
|
||||
}
|
||||
+11
-6
@@ -1,5 +1,8 @@
|
||||
package com.baiyue.firstleg.controller;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.annotation.PostConstruct;
|
||||
|
||||
import com.baiyue.common.core.api.ApiResponse;
|
||||
import com.baiyue.common.core.api.ResultCode;
|
||||
import com.baiyue.common.core.exception.BizException;
|
||||
@@ -23,13 +26,15 @@ import java.security.MessageDigest;
|
||||
@RestController
|
||||
@RequestMapping("/internal/firstleg/v1/inbounds")
|
||||
public class InternalInboundOrderController {
|
||||
private final InboundOrderCreationService service;
|
||||
private final byte[] expectedToken;
|
||||
@Resource
|
||||
private InboundOrderCreationService service;
|
||||
@Value("${baiyue.security.internal-service-token}")
|
||||
private String internalToken;
|
||||
private byte[] expectedToken;
|
||||
|
||||
public InternalInboundOrderController(InboundOrderCreationService service,
|
||||
@Value("${baiyue.security.internal-service-token}") String token) {
|
||||
this.service = service;
|
||||
this.expectedToken = token.getBytes(StandardCharsets.UTF_8);
|
||||
@PostConstruct
|
||||
void initializeToken() {
|
||||
expectedToken = internalToken.getBytes(StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
@PostMapping("/order-approved")
|
||||
|
||||
+4
-5
@@ -1,5 +1,7 @@
|
||||
package com.baiyue.firstleg.controller;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
|
||||
import com.baiyue.common.core.api.ApiResponse;
|
||||
import com.baiyue.common.core.api.ResultCode;
|
||||
import com.baiyue.common.core.exception.BizException;
|
||||
@@ -22,11 +24,8 @@ import org.springframework.http.ResponseEntity;
|
||||
@RestController
|
||||
@RequestMapping("/api/merchant/v1/first-leg/orders")
|
||||
public class MerchantInboundBillingController {
|
||||
private final MerchantInboundBillingService service;
|
||||
|
||||
public MerchantInboundBillingController(MerchantInboundBillingService service) {
|
||||
this.service = service;
|
||||
}
|
||||
@Resource
|
||||
private MerchantInboundBillingService service;
|
||||
|
||||
@GetMapping("/{orderId}/inbound-billing")
|
||||
@PreAuthorize("hasAuthority('merchant:order:view')")
|
||||
|
||||
+4
-5
@@ -1,5 +1,7 @@
|
||||
package com.baiyue.firstleg.controller;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
|
||||
import com.baiyue.common.core.api.ApiResponse;
|
||||
import com.baiyue.firstleg.dto.OpenApiMeasurementDtos.EventResponse;
|
||||
import com.baiyue.firstleg.security.MeasurementRequestHeaders;
|
||||
@@ -32,11 +34,8 @@ import org.springframework.web.multipart.MultipartFile;
|
||||
@SecurityRequirement(name = "measurementNonce")
|
||||
@SecurityRequirement(name = "measurementSignature")
|
||||
public class OpenApiInboundMeasurementController {
|
||||
private final InboundMeasurementOpenApiService service;
|
||||
|
||||
public OpenApiInboundMeasurementController(InboundMeasurementOpenApiService service) {
|
||||
this.service = service;
|
||||
}
|
||||
@Resource
|
||||
private InboundMeasurementOpenApiService service;
|
||||
|
||||
@Operation(summary = "提交一条第三方箱规测量结果和图片",
|
||||
description = "multipart 包含 data 原始JSON和 image 图片;签名 body 为 data原文、换行、图片SHA-256,外层仍按 METHOD、PATH、时间戳、Nonce、Idempotency-Key、body SHA-256 六行签名")
|
||||
|
||||
+4
-3
@@ -1,5 +1,7 @@
|
||||
package com.baiyue.firstleg.controller;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
|
||||
import com.baiyue.common.audit.BusinessAudit;
|
||||
import com.baiyue.common.core.api.ApiResponse;
|
||||
import com.baiyue.common.core.api.ResultCode;
|
||||
@@ -32,9 +34,8 @@ import java.util.List;
|
||||
@RestController
|
||||
@RequestMapping("/api/platform/v1/fba-pricing")
|
||||
public class PlatformFbaMasterDataController {
|
||||
private final FbaMasterDataService service;
|
||||
|
||||
public PlatformFbaMasterDataController(FbaMasterDataService service) { this.service = service; }
|
||||
@Resource
|
||||
private FbaMasterDataService service;
|
||||
|
||||
@GetMapping("/customer-rules")
|
||||
@PreAuthorize("hasAuthority('firstleg:fba-pricing:rule:view')")
|
||||
|
||||
+4
-3
@@ -1,5 +1,7 @@
|
||||
package com.baiyue.firstleg.controller;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
|
||||
import com.baiyue.common.audit.BusinessAudit;
|
||||
import com.baiyue.common.core.api.ApiResponse;
|
||||
import com.baiyue.common.security.AuthenticatedUser;
|
||||
@@ -28,9 +30,8 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
@RestController
|
||||
@RequestMapping("/api/platform/v1/inbounds/{inboundId}/fees")
|
||||
public class PlatformFbaPricingController {
|
||||
private final FbaPricingService service;
|
||||
|
||||
public PlatformFbaPricingController(FbaPricingService service) { this.service = service; }
|
||||
@Resource
|
||||
private FbaPricingService service;
|
||||
|
||||
@PostMapping("/calculate")
|
||||
@PreAuthorize("hasAuthority('firstleg:fba-pricing:calculate')")
|
||||
|
||||
+4
-8
@@ -1,5 +1,7 @@
|
||||
package com.baiyue.firstleg.controller;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
|
||||
import com.baiyue.common.audit.BusinessAudit;
|
||||
import com.baiyue.common.core.api.ApiResponse;
|
||||
import com.baiyue.common.core.api.ResultCode;
|
||||
@@ -28,14 +30,8 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
@RestController
|
||||
@RequestMapping("/api/platform/v1/first-leg/inbounds/{inboundId}")
|
||||
public class PlatformInboundMeasurementController {
|
||||
private final InboundMeasurementService service;
|
||||
private final MeasurementSubmissionService submission;
|
||||
|
||||
public PlatformInboundMeasurementController(InboundMeasurementService service,
|
||||
MeasurementSubmissionService submission) {
|
||||
this.service = service;
|
||||
this.submission = submission;
|
||||
}
|
||||
@Resource private InboundMeasurementService service;
|
||||
@Resource private MeasurementSubmissionService submission;
|
||||
|
||||
@Operation(summary = "查询入库测量详情", description = "返回原单、实测箱规、审核快照和 OCR 重量结果。")
|
||||
@GetMapping("/measurement")
|
||||
|
||||
+4
-8
@@ -1,5 +1,7 @@
|
||||
package com.baiyue.firstleg.controller;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
|
||||
import com.baiyue.common.audit.BusinessAudit;
|
||||
import com.baiyue.common.core.api.ApiResponse;
|
||||
import com.baiyue.common.core.api.PageResult;
|
||||
@@ -34,14 +36,8 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
@RestController
|
||||
@RequestMapping("/api/platform/v1/inbounds")
|
||||
public class PlatformInboundMeasurementReviewController {
|
||||
private final MeasurementReviewService service;
|
||||
private final AutomaticInboundCompletionService automaticCompletion;
|
||||
|
||||
public PlatformInboundMeasurementReviewController(MeasurementReviewService service,
|
||||
AutomaticInboundCompletionService automaticCompletion) {
|
||||
this.service = service;
|
||||
this.automaticCompletion = automaticCompletion;
|
||||
}
|
||||
@Resource private MeasurementReviewService service;
|
||||
@Resource private AutomaticInboundCompletionService automaticCompletion;
|
||||
|
||||
@BusinessAudit(event = "INBOUND_MEASURE_APPROVE", resourceType = "INBOUND",
|
||||
resourceId = "#inboundId", description = "测量审核通过")
|
||||
|
||||
+3
-5
@@ -1,5 +1,7 @@
|
||||
package com.baiyue.firstleg.controller;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
|
||||
import com.baiyue.common.core.api.ApiResponse;
|
||||
import com.baiyue.common.core.api.PageResult;
|
||||
import com.baiyue.common.core.api.ResultCode;
|
||||
@@ -29,11 +31,7 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
@RestController
|
||||
@RequestMapping("/api/platform/inbounds")
|
||||
public class PlatformInboundOrderController {
|
||||
private final InboundOrderQueryService service;
|
||||
|
||||
public PlatformInboundOrderController(InboundOrderQueryService service) {
|
||||
this.service = service;
|
||||
}
|
||||
@Resource private InboundOrderQueryService service;
|
||||
|
||||
@Operation(summary = "分页查询入库单",
|
||||
description = "默认分页查询全部企业入库单;可按目标租户和二期状态页签筛选入库单快照。")
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.baiyue.firstleg.repository;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import com.baiyue.firstleg.entity.CarrierFbaRateEntity;
|
||||
@@ -24,27 +26,20 @@ import java.util.List;
|
||||
/** FBA 计费仓储;平台基础资料列表可跨企业读取,其他业务操作强制带租户条件。 */
|
||||
@Repository
|
||||
public class FbaPricingRepository {
|
||||
private final CustomerChargeRuleMapper rules;
|
||||
private final CarrierFbaRateMapper rates;
|
||||
private final InboundPricingMapper inbounds;
|
||||
private final InboundFeeMapper fees;
|
||||
private final InboundFeeItemMapper items;
|
||||
private final InboundPricingIdempotencyMapper idempotencies;
|
||||
private final InboundOutboxMapper outbox;
|
||||
|
||||
public FbaPricingRepository(CustomerChargeRuleMapper rules, CarrierFbaRateMapper rates,
|
||||
InboundPricingMapper inbounds, InboundFeeMapper fees,
|
||||
InboundFeeItemMapper items,
|
||||
InboundPricingIdempotencyMapper idempotencies,
|
||||
InboundOutboxMapper outbox) {
|
||||
this.rules = rules;
|
||||
this.rates = rates;
|
||||
this.inbounds = inbounds;
|
||||
this.fees = fees;
|
||||
this.items = items;
|
||||
this.idempotencies = idempotencies;
|
||||
this.outbox = outbox;
|
||||
}
|
||||
@Resource
|
||||
private CustomerChargeRuleMapper rules;
|
||||
@Resource
|
||||
private CarrierFbaRateMapper rates;
|
||||
@Resource
|
||||
private InboundPricingMapper inbounds;
|
||||
@Resource
|
||||
private InboundFeeMapper fees;
|
||||
@Resource
|
||||
private InboundFeeItemMapper items;
|
||||
@Resource
|
||||
private InboundPricingIdempotencyMapper idempotencies;
|
||||
@Resource
|
||||
private InboundOutboxMapper outbox;
|
||||
|
||||
public void insertRule(CustomerChargeRuleEntity rule) { rules.insert(rule); }
|
||||
public void insertRate(CarrierFbaRateEntity rate) { rates.insert(rate); }
|
||||
|
||||
+4
-7
@@ -1,5 +1,7 @@
|
||||
package com.baiyue.firstleg.repository;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
|
||||
import com.baiyue.common.core.api.PageResult;
|
||||
import com.baiyue.firstleg.dto.FulfillmentTaskQuery;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
@@ -16,13 +18,8 @@ import org.springframework.util.StringUtils;
|
||||
*/
|
||||
@Repository
|
||||
public class FulfillmentTaskRepository {
|
||||
private final FulfillmentTaskMapper tasks;
|
||||
private final AssignmentHistoryMapper histories;
|
||||
|
||||
public FulfillmentTaskRepository(FulfillmentTaskMapper tasks, AssignmentHistoryMapper histories) {
|
||||
this.tasks = tasks;
|
||||
this.histories = histories;
|
||||
}
|
||||
@Resource private FulfillmentTaskMapper tasks;
|
||||
@Resource private AssignmentHistoryMapper histories;
|
||||
|
||||
public FulfillmentTaskEntity findOwned(long tenantId, long taskId) {
|
||||
return tasks.selectOne(new LambdaQueryWrapper<FulfillmentTaskEntity>()
|
||||
|
||||
+8
-11
@@ -1,5 +1,7 @@
|
||||
package com.baiyue.firstleg.repository;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baiyue.firstleg.entity.InboundMeasurementEntity;
|
||||
import com.baiyue.firstleg.entity.InboundMeasurementItemEntity;
|
||||
@@ -12,17 +14,12 @@ import org.springframework.stereotype.Repository;
|
||||
/** 第三方测量开放接口仓储,仅允许读取主单并写测量、明细和幂等记录。 */
|
||||
@Repository
|
||||
public class InboundMeasurementOpenApiRepository {
|
||||
private final InboundOrderLookupMapper inboundOrders;
|
||||
private final InboundMeasurementMapper measurements;
|
||||
private final InboundMeasurementItemMapper items;
|
||||
|
||||
public InboundMeasurementOpenApiRepository(InboundOrderLookupMapper inboundOrders,
|
||||
InboundMeasurementMapper measurements,
|
||||
InboundMeasurementItemMapper items) {
|
||||
this.inboundOrders = inboundOrders;
|
||||
this.measurements = measurements;
|
||||
this.items = items;
|
||||
}
|
||||
@Resource
|
||||
private InboundOrderLookupMapper inboundOrders;
|
||||
@Resource
|
||||
private InboundMeasurementMapper measurements;
|
||||
@Resource
|
||||
private InboundMeasurementItemMapper items;
|
||||
|
||||
public InboundOrderLookupEntity findInbound(long tenantId, String inboundCode) {
|
||||
return inboundOrders.selectOne(new LambdaQueryWrapper<InboundOrderLookupEntity>()
|
||||
|
||||
+14
-20
@@ -1,5 +1,7 @@
|
||||
package com.baiyue.firstleg.repository;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baiyue.firstleg.entity.InboundMeasurementEntity;
|
||||
import com.baiyue.firstleg.entity.InboundMeasurementItemEntity;
|
||||
@@ -20,26 +22,18 @@ import java.util.List;
|
||||
/** 入库测量仓储,所有读取都同时带租户和入库单边界。 */
|
||||
@Repository
|
||||
public class InboundMeasurementRepository {
|
||||
private final InboundOrderMapper inboundOrders;
|
||||
private final InboundMeasurementMapper measurements;
|
||||
private final InboundMeasurementItemMapper items;
|
||||
private final InboundWeightResultMapper weights;
|
||||
private final InboundWeightRevisionMapper revisions;
|
||||
private final MeasureReviewRecordMapper reviews;
|
||||
|
||||
public InboundMeasurementRepository(InboundOrderMapper inboundOrders,
|
||||
InboundMeasurementMapper measurements,
|
||||
InboundMeasurementItemMapper items,
|
||||
InboundWeightResultMapper weights,
|
||||
InboundWeightRevisionMapper revisions,
|
||||
MeasureReviewRecordMapper reviews) {
|
||||
this.inboundOrders = inboundOrders;
|
||||
this.measurements = measurements;
|
||||
this.items = items;
|
||||
this.weights = weights;
|
||||
this.revisions = revisions;
|
||||
this.reviews = reviews;
|
||||
}
|
||||
@Resource
|
||||
private InboundOrderMapper inboundOrders;
|
||||
@Resource
|
||||
private InboundMeasurementMapper measurements;
|
||||
@Resource
|
||||
private InboundMeasurementItemMapper items;
|
||||
@Resource
|
||||
private InboundWeightResultMapper weights;
|
||||
@Resource
|
||||
private InboundWeightRevisionMapper revisions;
|
||||
@Resource
|
||||
private MeasureReviewRecordMapper reviews;
|
||||
|
||||
public InboundOrderEntity findInbound(long tenantId, long inboundId) {
|
||||
return inboundOrders.selectOne(new LambdaQueryWrapper<InboundOrderEntity>()
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.baiyue.firstleg.repository;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baiyue.common.core.api.PageResult;
|
||||
@@ -29,27 +31,18 @@ import java.util.stream.Collectors;
|
||||
/** 入库单只读仓储;平台分页可跨企业查询,详情继续强制租户隔离。 */
|
||||
@Repository
|
||||
public class InboundOrderRepository {
|
||||
private final InboundOrderMapper orders;
|
||||
private final InboundTransportSnapshotMapper transports;
|
||||
private final InboundPalletAllocationMapper pallets;
|
||||
private final InboundFileMapper files;
|
||||
private final InboundInternalNoteMapper notes;
|
||||
private final InboundStatusHistoryMapper histories;
|
||||
|
||||
public InboundOrderRepository(
|
||||
InboundOrderMapper orders,
|
||||
InboundTransportSnapshotMapper transports,
|
||||
InboundPalletAllocationMapper pallets,
|
||||
InboundFileMapper files,
|
||||
InboundInternalNoteMapper notes,
|
||||
InboundStatusHistoryMapper histories) {
|
||||
this.orders = orders;
|
||||
this.transports = transports;
|
||||
this.pallets = pallets;
|
||||
this.files = files;
|
||||
this.notes = notes;
|
||||
this.histories = histories;
|
||||
}
|
||||
@Resource
|
||||
private InboundOrderMapper orders;
|
||||
@Resource
|
||||
private InboundTransportSnapshotMapper transports;
|
||||
@Resource
|
||||
private InboundPalletAllocationMapper pallets;
|
||||
@Resource
|
||||
private InboundFileMapper files;
|
||||
@Resource
|
||||
private InboundInternalNoteMapper notes;
|
||||
@Resource
|
||||
private InboundStatusHistoryMapper histories;
|
||||
|
||||
public PageResult<InboundOrderSummary> page(Long tenantId, InboundOrderQuery query) {
|
||||
LambdaQueryWrapper<InboundOrderEntity> wrapper = new LambdaQueryWrapper<InboundOrderEntity>()
|
||||
|
||||
+3
-5
@@ -1,5 +1,7 @@
|
||||
package com.baiyue.firstleg.repository;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baiyue.firstleg.client.WarehousePalletLocationClient.BatchResult;
|
||||
import com.baiyue.firstleg.entity.InboundPalletAllocationEntity;
|
||||
@@ -15,11 +17,7 @@ import java.util.stream.Collectors;
|
||||
|
||||
@Repository
|
||||
public class InboundPalletAllocationRepository {
|
||||
private final InboundPalletAllocationMapper mapper;
|
||||
|
||||
public InboundPalletAllocationRepository(InboundPalletAllocationMapper mapper) {
|
||||
this.mapper = mapper;
|
||||
}
|
||||
@Resource private InboundPalletAllocationMapper mapper;
|
||||
|
||||
@Transactional
|
||||
public void replace(long tenantId, long inboundId, long warehouseId, long warehouseResourceTenantId,
|
||||
|
||||
+18
-26
@@ -1,5 +1,7 @@
|
||||
package com.baiyue.firstleg.repository;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baiyue.common.core.api.PageResult;
|
||||
@@ -23,32 +25,22 @@ import org.springframework.stereotype.Repository;
|
||||
/** 入库审核和完成编排仓储;所有业务查询强制携带租户。 */
|
||||
@Repository
|
||||
public class InboundWorkflowRepository {
|
||||
private final InboundOrderMapper orders;
|
||||
private final InboundMeasurementMapper measurements;
|
||||
private final MeasureReviewRecordMapper reviews;
|
||||
private final InboundStatusHistoryMapper histories;
|
||||
private final InboundIdempotencyMapper idempotencies;
|
||||
private final InboundFeeMapper fees;
|
||||
private final InboundOutboxMapper outboxes;
|
||||
private final InboundAllocationQueryMapper allocations;
|
||||
|
||||
public InboundWorkflowRepository(InboundOrderMapper orders,
|
||||
InboundMeasurementMapper measurements,
|
||||
MeasureReviewRecordMapper reviews,
|
||||
InboundStatusHistoryMapper histories,
|
||||
InboundIdempotencyMapper idempotencies,
|
||||
InboundFeeMapper fees,
|
||||
InboundOutboxMapper outboxes,
|
||||
InboundAllocationQueryMapper allocations) {
|
||||
this.orders = orders;
|
||||
this.measurements = measurements;
|
||||
this.reviews = reviews;
|
||||
this.histories = histories;
|
||||
this.idempotencies = idempotencies;
|
||||
this.fees = fees;
|
||||
this.outboxes = outboxes;
|
||||
this.allocations = allocations;
|
||||
}
|
||||
@Resource
|
||||
private InboundOrderMapper orders;
|
||||
@Resource
|
||||
private InboundMeasurementMapper measurements;
|
||||
@Resource
|
||||
private MeasureReviewRecordMapper reviews;
|
||||
@Resource
|
||||
private InboundStatusHistoryMapper histories;
|
||||
@Resource
|
||||
private InboundIdempotencyMapper idempotencies;
|
||||
@Resource
|
||||
private InboundFeeMapper fees;
|
||||
@Resource
|
||||
private InboundOutboxMapper outboxes;
|
||||
@Resource
|
||||
private InboundAllocationQueryMapper allocations;
|
||||
|
||||
public InboundOrderEntity findOwned(long tenantId, long inboundId) {
|
||||
return orders.selectOne(new LambdaQueryWrapper<InboundOrderEntity>()
|
||||
|
||||
+8
-18
@@ -1,9 +1,10 @@
|
||||
package com.baiyue.firstleg.security;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
|
||||
import com.baiyue.common.core.api.ResultCode;
|
||||
import com.baiyue.common.core.exception.BizException;
|
||||
import com.baiyue.firstleg.config.MeasurementOpenApiProperties;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
@@ -21,23 +22,12 @@ import java.util.Map;
|
||||
@Component
|
||||
public class MeasurementRequestAuthenticator {
|
||||
private static final String HMAC_ALGORITHM = "HmacSHA256";
|
||||
private final MeasurementOpenApiProperties properties;
|
||||
private final NonceReplayGuard nonceReplayGuard;
|
||||
private final Clock clock;
|
||||
|
||||
@Autowired
|
||||
public MeasurementRequestAuthenticator(MeasurementOpenApiProperties properties,
|
||||
NonceReplayGuard nonceReplayGuard) {
|
||||
this(properties, nonceReplayGuard, Clock.systemUTC());
|
||||
}
|
||||
|
||||
MeasurementRequestAuthenticator(MeasurementOpenApiProperties properties,
|
||||
NonceReplayGuard nonceReplayGuard,
|
||||
Clock clock) {
|
||||
this.properties = properties;
|
||||
this.nonceReplayGuard = nonceReplayGuard;
|
||||
this.clock = clock;
|
||||
}
|
||||
@Resource
|
||||
private MeasurementOpenApiProperties properties;
|
||||
@Resource
|
||||
private NonceReplayGuard nonceReplayGuard;
|
||||
@Resource
|
||||
private Clock clock;
|
||||
|
||||
public AuthenticatedMeasurementApp authenticate(String method, String path,
|
||||
MeasurementRequestHeaders headers,
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.baiyue.firstleg.security;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@@ -9,11 +11,8 @@ import java.time.Duration;
|
||||
@Component
|
||||
public class RedisNonceReplayGuard implements NonceReplayGuard {
|
||||
private static final String KEY_PREFIX = "baiyue:firstleg:measurement-openapi:nonce:";
|
||||
private final StringRedisTemplate redisTemplate;
|
||||
|
||||
public RedisNonceReplayGuard(StringRedisTemplate redisTemplate) {
|
||||
this.redisTemplate = redisTemplate;
|
||||
}
|
||||
@Resource
|
||||
private StringRedisTemplate redisTemplate;
|
||||
|
||||
@Override
|
||||
public boolean claim(String appKey, String nonce, Duration ttl) {
|
||||
|
||||
+8
-11
@@ -1,5 +1,7 @@
|
||||
package com.baiyue.firstleg.service;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
|
||||
import com.baiyue.common.core.api.ResultCode;
|
||||
import com.baiyue.common.core.exception.BizException;
|
||||
import com.baiyue.firstleg.dto.FbaPricingDtos.FeeSnapshotResponse;
|
||||
@@ -9,17 +11,12 @@ import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class AutomaticInboundCompletionService {
|
||||
private final FbaPricingService pricing;
|
||||
private final InboundWorkflowRepository workflow;
|
||||
private final InboundCompletionOrchestrator completion;
|
||||
|
||||
public AutomaticInboundCompletionService(FbaPricingService pricing,
|
||||
InboundWorkflowRepository workflow,
|
||||
InboundCompletionOrchestrator completion) {
|
||||
this.pricing = pricing;
|
||||
this.workflow = workflow;
|
||||
this.completion = completion;
|
||||
}
|
||||
@Resource
|
||||
private FbaPricingService pricing;
|
||||
@Resource
|
||||
private InboundWorkflowRepository workflow;
|
||||
@Resource
|
||||
private InboundCompletionOrchestrator completion;
|
||||
|
||||
public FeeSnapshotResponse completeApproved(long tenantId, long inboundId, long operatorId,
|
||||
String operatorName, long measurementId,
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.baiyue.firstleg.service;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
|
||||
import com.baiyue.common.core.api.ResultCode;
|
||||
import com.baiyue.common.core.exception.BizException;
|
||||
import com.baiyue.firstleg.dto.FbaPricingDtos.CarrierRateVersionRequest;
|
||||
@@ -17,9 +19,8 @@ import java.util.Objects;
|
||||
/** 客户规则和船司价格版本管理。版本内容创建后不可原地修改。 */
|
||||
@Service
|
||||
public class FbaMasterDataService {
|
||||
private final FbaPricingRepository repository;
|
||||
|
||||
public FbaMasterDataService(FbaPricingRepository repository) { this.repository = repository; }
|
||||
@Resource
|
||||
private FbaPricingRepository repository;
|
||||
|
||||
@Transactional
|
||||
public CustomerChargeRuleEntity createRuleVersion(long tenantId, long operatorId,
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.baiyue.firstleg.service;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
|
||||
import com.baiyue.common.core.api.ResultCode;
|
||||
import com.baiyue.common.core.exception.BizException;
|
||||
import com.baiyue.firstleg.dto.FbaPricingDtos.FeeSnapshotResponse;
|
||||
@@ -12,7 +14,6 @@ import com.baiyue.firstleg.entity.InboundOutboxEntity;
|
||||
import com.baiyue.firstleg.entity.InboundPricingEntity;
|
||||
import com.baiyue.firstleg.entity.InboundPricingIdempotencyEntity;
|
||||
import com.baiyue.firstleg.repository.FbaPricingRepository;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.StringUtils;
|
||||
@@ -32,18 +33,10 @@ import java.util.List;
|
||||
@Service
|
||||
public class FbaPricingService {
|
||||
private static final int MONEY_SCALE = 2;
|
||||
private final FbaPricingRepository repository;
|
||||
private final Clock clock;
|
||||
|
||||
@Autowired
|
||||
public FbaPricingService(FbaPricingRepository repository) {
|
||||
this(repository, Clock.systemDefaultZone());
|
||||
}
|
||||
|
||||
FbaPricingService(FbaPricingRepository repository, Clock clock) {
|
||||
this.repository = repository;
|
||||
this.clock = clock;
|
||||
}
|
||||
@Resource
|
||||
private FbaPricingRepository repository;
|
||||
@Resource
|
||||
private Clock clock;
|
||||
|
||||
@Transactional
|
||||
public FeeSnapshotResponse calculate(long tenantId, long operatorId, long inboundId,
|
||||
|
||||
+6
-8
@@ -1,5 +1,7 @@
|
||||
package com.baiyue.firstleg.service;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
|
||||
import com.baiyue.common.core.api.ResultCode;
|
||||
import com.baiyue.common.core.exception.BizException;
|
||||
import com.baiyue.firstleg.entity.InboundFeeEntity;
|
||||
@@ -21,14 +23,10 @@ import java.time.LocalDateTime;
|
||||
*/
|
||||
@Service
|
||||
public class InboundCompletionOrchestrator {
|
||||
private final InboundWorkflowRepository repository;
|
||||
private final InboundIdempotencyService idempotency;
|
||||
|
||||
public InboundCompletionOrchestrator(InboundWorkflowRepository repository,
|
||||
InboundIdempotencyService idempotency) {
|
||||
this.repository = repository;
|
||||
this.idempotency = idempotency;
|
||||
}
|
||||
@Resource
|
||||
private InboundWorkflowRepository repository;
|
||||
@Resource
|
||||
private InboundIdempotencyService idempotency;
|
||||
|
||||
/**
|
||||
* 任务5对接方法一:锁定发送动作。允许前置状态仅为 FEE_CONFIRMING + CONFIRMED。
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.baiyue.firstleg.service;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
|
||||
import com.baiyue.common.core.api.ResultCode;
|
||||
import com.baiyue.common.core.exception.BizException;
|
||||
import com.baiyue.firstleg.entity.InboundIdempotencyEntity;
|
||||
@@ -17,11 +19,8 @@ import java.util.HexFormat;
|
||||
/** 入库写操作的统一持久化幂等边界。 */
|
||||
@Service
|
||||
public class InboundIdempotencyService {
|
||||
private final InboundWorkflowRepository repository;
|
||||
|
||||
public InboundIdempotencyService(InboundWorkflowRepository repository) {
|
||||
this.repository = repository;
|
||||
}
|
||||
@Resource
|
||||
private InboundWorkflowRepository repository;
|
||||
|
||||
public Context begin(long tenantId, long operatorId, long inboundId,
|
||||
String operation, String idempotencyKey, String canonicalRequest) {
|
||||
|
||||
+20
-30
@@ -1,5 +1,7 @@
|
||||
package com.baiyue.firstleg.service;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
|
||||
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
|
||||
import com.baiyue.common.core.api.ApiResponse;
|
||||
import com.baiyue.common.core.api.ResultCode;
|
||||
@@ -50,36 +52,24 @@ public class InboundMeasurementOpenApiService {
|
||||
private static final BigDecimal VOLUME_WEIGHT_FACTOR = new BigDecimal("167");
|
||||
private static final String CALCULATION_RULE_VERSION = "V1_CBM_CEILING_4_GIRTH_L2WH";
|
||||
|
||||
private final InboundMeasurementOpenApiRepository repository;
|
||||
private final MeasurementRequestAuthenticator authenticator;
|
||||
private final ThirdPartyCallLogService callLogService;
|
||||
private final OrderCargoClient orderCargoClient;
|
||||
private final MeasurementImageClient imageClient;
|
||||
private final String internalToken;
|
||||
private final ObjectMapper objectMapper;
|
||||
private final Validator validator;
|
||||
private final TransactionTemplate transactionTemplate;
|
||||
|
||||
public InboundMeasurementOpenApiService(
|
||||
InboundMeasurementOpenApiRepository repository,
|
||||
MeasurementRequestAuthenticator authenticator,
|
||||
ThirdPartyCallLogService callLogService,
|
||||
OrderCargoClient orderCargoClient,
|
||||
MeasurementImageClient imageClient,
|
||||
@Value("${baiyue.security.internal-service-token}") String internalToken,
|
||||
ObjectMapper objectMapper,
|
||||
Validator validator,
|
||||
TransactionTemplate transactionTemplate) {
|
||||
this.repository = repository;
|
||||
this.authenticator = authenticator;
|
||||
this.callLogService = callLogService;
|
||||
this.orderCargoClient = orderCargoClient;
|
||||
this.imageClient = imageClient;
|
||||
this.internalToken = internalToken;
|
||||
this.objectMapper = objectMapper;
|
||||
this.validator = validator;
|
||||
this.transactionTemplate = transactionTemplate;
|
||||
}
|
||||
@Resource
|
||||
private InboundMeasurementOpenApiRepository repository;
|
||||
@Resource
|
||||
private MeasurementRequestAuthenticator authenticator;
|
||||
@Resource
|
||||
private ThirdPartyCallLogService callLogService;
|
||||
@Resource
|
||||
private OrderCargoClient orderCargoClient;
|
||||
@Resource
|
||||
private MeasurementImageClient imageClient;
|
||||
@Value("${baiyue.security.internal-service-token}")
|
||||
private String internalToken;
|
||||
@Resource
|
||||
private ObjectMapper objectMapper;
|
||||
@Resource
|
||||
private Validator validator;
|
||||
@Resource
|
||||
private TransactionTemplate transactionTemplate;
|
||||
|
||||
public EventResponse receive(MeasurementRequestHeaders headers, String rawData, MultipartFile image) {
|
||||
requireImage(image);
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.baiyue.firstleg.service;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
|
||||
import com.baiyue.common.core.api.ResultCode;
|
||||
import com.baiyue.common.core.exception.BizException;
|
||||
import com.baiyue.firstleg.dto.InboundMeasurementRequests;
|
||||
@@ -36,14 +38,10 @@ public class InboundMeasurementService {
|
||||
Set.of("WAIT_MEASURE", "MEASURING", "MEASURE_REJECTED");
|
||||
private static final BigDecimal LB_TO_KG = new BigDecimal("0.45359237");
|
||||
|
||||
private final InboundMeasurementRepository repository;
|
||||
private final MeasurementBatchService batchService;
|
||||
|
||||
public InboundMeasurementService(InboundMeasurementRepository repository,
|
||||
MeasurementBatchService batchService) {
|
||||
this.repository = repository;
|
||||
this.batchService = batchService;
|
||||
}
|
||||
@Resource
|
||||
private InboundMeasurementRepository repository;
|
||||
@Resource
|
||||
private MeasurementBatchService batchService;
|
||||
|
||||
public InboundMeasurementResponses.Detail detail(long tenantId, long inboundId) {
|
||||
InboundOrderEntity inbound = requireInbound(tenantId, inboundId);
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.baiyue.firstleg.service;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
|
||||
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
|
||||
import com.baiyue.firstleg.dto.OrderApprovedInboundCommand;
|
||||
import com.baiyue.firstleg.dto.InboundOrderReference;
|
||||
@@ -16,13 +18,10 @@ import java.util.List;
|
||||
/** 将已审核的订单快照幂等转换为待测量入库单。 */
|
||||
@Service
|
||||
public class InboundOrderCreationService {
|
||||
private final InboundOrderMapper orders;
|
||||
private final InboundStatusHistoryMapper histories;
|
||||
|
||||
public InboundOrderCreationService(InboundOrderMapper orders, InboundStatusHistoryMapper histories) {
|
||||
this.orders = orders;
|
||||
this.histories = histories;
|
||||
}
|
||||
@Resource
|
||||
private InboundOrderMapper orders;
|
||||
@Resource
|
||||
private InboundStatusHistoryMapper histories;
|
||||
|
||||
@Transactional
|
||||
public long createFromApprovedOrder(OrderApprovedInboundCommand command) {
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.baiyue.firstleg.service;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
|
||||
import com.baiyue.common.core.api.PageResult;
|
||||
import com.baiyue.common.core.api.ResultCode;
|
||||
import com.baiyue.common.core.exception.BizException;
|
||||
@@ -15,11 +17,8 @@ import org.springframework.util.StringUtils;
|
||||
/** 入库单列表和详情只读应用服务,不执行任何状态推进。 */
|
||||
@Service
|
||||
public class InboundOrderQueryService {
|
||||
private final InboundOrderRepository repository;
|
||||
|
||||
public InboundOrderQueryService(InboundOrderRepository repository) {
|
||||
this.repository = repository;
|
||||
}
|
||||
@Resource
|
||||
private InboundOrderRepository repository;
|
||||
|
||||
public PageResult<InboundOrderSummary> page(Long tenantId, InboundOrderQuery query) {
|
||||
validateQuery(query);
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.baiyue.firstleg.service;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
|
||||
import com.baiyue.common.core.api.ResultCode;
|
||||
import com.baiyue.common.core.exception.BizException;
|
||||
import com.baiyue.firstleg.dto.MeasurementBatchCommand;
|
||||
@@ -31,11 +33,8 @@ public class MeasurementBatchService {
|
||||
static final BigDecimal VOLUME_WEIGHT_FACTOR = new BigDecimal("167");
|
||||
static final String CALCULATION_RULE_VERSION = "V1_CBM_CEILING_4_GIRTH_L2WH";
|
||||
|
||||
private final InboundMeasurementRepository repository;
|
||||
|
||||
public MeasurementBatchService(InboundMeasurementRepository repository) {
|
||||
this.repository = repository;
|
||||
}
|
||||
@Resource
|
||||
private InboundMeasurementRepository repository;
|
||||
|
||||
@Transactional
|
||||
public InboundMeasurementEntity saveBatch(MeasurementBatchCommand command) {
|
||||
|
||||
+12
-16
@@ -1,5 +1,7 @@
|
||||
package com.baiyue.firstleg.service;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
|
||||
import com.baiyue.common.core.api.ApiResponse;
|
||||
import com.baiyue.common.core.api.ResultCode;
|
||||
import com.baiyue.common.core.exception.BizException;
|
||||
@@ -18,22 +20,16 @@ import java.time.LocalDateTime;
|
||||
@Service
|
||||
public class MeasurementLocationOccupationService {
|
||||
private static final String SOURCE_SERVICE = "firstleg-service";
|
||||
private final WarehousePalletLocationClient warehouse;
|
||||
private final InboundPalletAllocationRepository allocations;
|
||||
private final InboundWorkflowRepository workflow;
|
||||
private final InboundProperties properties;
|
||||
private final String internalToken;
|
||||
|
||||
public MeasurementLocationOccupationService(WarehousePalletLocationClient warehouse,
|
||||
InboundPalletAllocationRepository allocations, InboundWorkflowRepository workflow,
|
||||
InboundProperties properties,
|
||||
@Value("${baiyue.security.internal-service-token}") String internalToken) {
|
||||
this.warehouse = warehouse;
|
||||
this.allocations = allocations;
|
||||
this.workflow = workflow;
|
||||
this.properties = properties;
|
||||
this.internalToken = internalToken;
|
||||
}
|
||||
@Resource
|
||||
private WarehousePalletLocationClient warehouse;
|
||||
@Resource
|
||||
private InboundPalletAllocationRepository allocations;
|
||||
@Resource
|
||||
private InboundWorkflowRepository workflow;
|
||||
@Resource
|
||||
private InboundProperties properties;
|
||||
@Value("${baiyue.security.internal-service-token}")
|
||||
private String internalToken;
|
||||
|
||||
public void occupy(long tenantId, long inboundId, long operatorId, long measurementId,
|
||||
int measurementVersion) {
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.baiyue.firstleg.service;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
|
||||
import com.baiyue.common.core.api.PageResult;
|
||||
import com.baiyue.common.core.api.ResultCode;
|
||||
import com.baiyue.common.core.exception.BizException;
|
||||
@@ -22,17 +24,12 @@ import java.time.LocalDateTime;
|
||||
*/
|
||||
@Service
|
||||
public class MeasurementReviewService {
|
||||
private final InboundWorkflowRepository repository;
|
||||
private final InboundIdempotencyService idempotency;
|
||||
private final InboundProperties properties;
|
||||
|
||||
public MeasurementReviewService(InboundWorkflowRepository repository,
|
||||
InboundIdempotencyService idempotency,
|
||||
InboundProperties properties) {
|
||||
this.repository = repository;
|
||||
this.idempotency = idempotency;
|
||||
this.properties = properties;
|
||||
}
|
||||
@Resource
|
||||
private InboundWorkflowRepository repository;
|
||||
@Resource
|
||||
private InboundIdempotencyService idempotency;
|
||||
@Resource
|
||||
private InboundProperties properties;
|
||||
|
||||
@Transactional
|
||||
public void approve(long tenantId, long operatorId, String operatorName, long inboundId,
|
||||
|
||||
+6
-8
@@ -1,5 +1,7 @@
|
||||
package com.baiyue.firstleg.service;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
|
||||
import com.baiyue.firstleg.dto.InboundMeasurementRequests;
|
||||
import com.baiyue.firstleg.dto.InboundMeasurementResponses;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -7,14 +9,10 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@Service
|
||||
public class MeasurementSubmissionService {
|
||||
private final InboundMeasurementService measurements;
|
||||
private final MeasurementLocationOccupationService locations;
|
||||
|
||||
public MeasurementSubmissionService(InboundMeasurementService measurements,
|
||||
MeasurementLocationOccupationService locations) {
|
||||
this.measurements = measurements;
|
||||
this.locations = locations;
|
||||
}
|
||||
@Resource
|
||||
private InboundMeasurementService measurements;
|
||||
@Resource
|
||||
private MeasurementLocationOccupationService locations;
|
||||
|
||||
@Transactional
|
||||
public InboundMeasurementResponses.MeasurementSubmitted submit(
|
||||
|
||||
+13
-17
@@ -1,5 +1,8 @@
|
||||
package com.baiyue.firstleg.service;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
|
||||
import com.baiyue.common.core.api.ResultCode;
|
||||
import com.baiyue.common.core.exception.BizException;
|
||||
import com.baiyue.firstleg.dto.MerchantInboundBillingResponse;
|
||||
@@ -15,23 +18,16 @@ import java.util.List;
|
||||
|
||||
@Service
|
||||
public class MerchantInboundBillingService {
|
||||
private final InboundOrderRepository orders;
|
||||
private final FbaPricingService pricing;
|
||||
private final InboundMeasurementService measurements;
|
||||
private final MeasurementImageClient imageClient;
|
||||
private final String internalToken;
|
||||
|
||||
public MerchantInboundBillingService(InboundOrderRepository orders, FbaPricingService pricing,
|
||||
InboundMeasurementService measurements,
|
||||
MeasurementImageClient imageClient,
|
||||
@org.springframework.beans.factory.annotation.Value(
|
||||
"${baiyue.security.internal-service-token}") String internalToken) {
|
||||
this.orders = orders;
|
||||
this.pricing = pricing;
|
||||
this.measurements = measurements;
|
||||
this.imageClient = imageClient;
|
||||
this.internalToken = internalToken;
|
||||
}
|
||||
@Resource
|
||||
private InboundOrderRepository orders;
|
||||
@Resource
|
||||
private FbaPricingService pricing;
|
||||
@Resource
|
||||
private InboundMeasurementService measurements;
|
||||
@Resource
|
||||
private MeasurementImageClient imageClient;
|
||||
@Value("${baiyue.security.internal-service-token}")
|
||||
private String internalToken;
|
||||
|
||||
public MerchantInboundBillingResponse find(long tenantId, long orderId) {
|
||||
InboundOrderEntity inbound = orders.findByOrderId(tenantId, orderId);
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.baiyue.firstleg.service;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
|
||||
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baiyue.firstleg.config.MeasurementOpenApiProperties;
|
||||
@@ -17,14 +19,10 @@ import java.time.LocalDateTime;
|
||||
/** 将每次第三方 API 调用独立留档,业务事务回滚也不会丢失失败记录。 */
|
||||
@Service
|
||||
public class ThirdPartyCallLogService {
|
||||
private final ThirdPartyCallLogMapper mapper;
|
||||
private final MeasurementOpenApiProperties properties;
|
||||
|
||||
public ThirdPartyCallLogService(ThirdPartyCallLogMapper mapper,
|
||||
MeasurementOpenApiProperties properties) {
|
||||
this.mapper = mapper;
|
||||
this.properties = properties;
|
||||
}
|
||||
@Resource
|
||||
private ThirdPartyCallLogMapper mapper;
|
||||
@Resource
|
||||
private MeasurementOpenApiProperties properties;
|
||||
|
||||
@Transactional(propagation = Propagation.REQUIRES_NEW)
|
||||
public long start(String method, String path, MeasurementRequestHeaders headers, String rawBody) {
|
||||
|
||||
Reference in New Issue
Block a user