This commit is contained in:
2026-08-26 15:51:46 +08:00
parent 93e1540e3f
commit 5c6c0ef5ca
3 changed files with 40 additions and 14 deletions
@@ -18,8 +18,8 @@ public final class DeliveryRequests {
@NotBlank @Size(max = 32) String deliveryMethod,
@Size(max = 128) String waybillNo,
@Size(max = 255) String carrierName,
@Size(max = 64) String pickupMethod,
@Size(max = 64) String loadingType,
@NotBlank @Size(max = 64) String pickupMethod,
@NotBlank @Size(max = 64) String loadingType,
@Size(max = 64) String vehicleType,
@Size(max = 64) String vehicleSize,
@Size(max = 128) String driverName,
@@ -28,12 +28,7 @@ public final class DeliveryRequests {
@Size(max = 128) String appointmentAccount,
@Size(max = 128) String sellerName,
@Size(max = 1000) String remark,
@Valid @Size(max = 20) List<FeeItem> fees) {
public Transfer(String idempotencyKey, String remark) {
this(idempotencyKey, LocalDateTime.now(), "SELF_DELIVERY", null, null, null, null,
null, null, null, null, null, null, null, remark, List.of());
}
}
@NotNull @Valid @Size(min = 1, max = 20) List<FeeItem> fees) {}
public record FeeItem(@NotBlank @Size(max = 64) String feeType,
@NotBlank @Size(max = 8) String currency,
@@ -100,6 +100,7 @@ public class DeliveryTransferService {
throw conflict("All dispatch pallets must be received before transfer to delivery");
}
if (!StringUtils.hasText(dispatch.getOverseasWarehouseId())) throw conflict("Dispatch warehouse is required");
validateTransferFees(request);
LocalDateTime now = LocalDateTime.now();
OutboundOrder outbound = new OutboundOrder();
@@ -168,6 +169,29 @@ public class DeliveryTransferService {
return result(outbound, delivery, false);
}
private void validateTransferFees(DeliveryRequests.Transfer request) {
List<DeliveryRequests.FeeItem> inputs = request.fees() == null ? List.of() : request.fees();
if (inputs.isEmpty()) throw conflict("Delivery fee is required");
Set<String> allowed = Set.of("DELIVERY_FEE", "LOADING_FEE", "APPOINTMENT_FEE");
Set<String> seen = new HashSet<>();
for (DeliveryRequests.FeeItem input : inputs) {
String feeType = input.feeType().trim().toUpperCase(Locale.ROOT);
if (!allowed.contains(feeType)) throw conflict("Unsupported delivery fee type: " + feeType);
if (!seen.add(feeType)) throw conflict("Duplicate delivery fee type: " + feeType);
if (!"USD".equalsIgnoreCase(input.currency().trim())) throw conflict("Delivery fees must use USD");
if (input.amount().signum() < 0) throw conflict("Delivery fee amount cannot be negative");
}
if (!seen.contains("DELIVERY_FEE")) throw conflict("Delivery fee is required");
if (Set.of("FLOOR", "MIXED").contains(request.loadingType().trim().toUpperCase(Locale.ROOT))
&& !seen.contains("LOADING_FEE")) {
throw conflict("Loading fee is required for floor or mixed loading");
}
if ("BUY_APPOINTMENT".equalsIgnoreCase(trim(request.appointmentAccount()))) {
if (!StringUtils.hasText(request.sellerName())) throw conflict("Seller name is required when buying an appointment");
if (!seen.contains("APPOINTMENT_FEE")) throw conflict("Appointment fee is required when buying an appointment");
}
}
@Transactional
public DeliveryResponses.PdaTask createOneClick(String customerId, String operatorId, DeliveryRequests.OneClickOutbound request) {
OutboundOrder existing = outboundOrders.findByIdempotency(customerId, request.idempotencyKey().trim());