feat: close overseas wallet and pallet cost flow
This commit is contained in:
@@ -11,6 +11,8 @@ import jakarta.validation.constraints.Size;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.math.BigDecimal;
|
||||
import jakarta.validation.constraints.DecimalMin;
|
||||
|
||||
public final class RelabelRequests {
|
||||
private RelabelRequests() {}
|
||||
@@ -21,6 +23,7 @@ public final class RelabelRequests {
|
||||
@NotNull LocalDateTime labelDeadline,
|
||||
@NotBlank @Size(max = 128) String contactName,
|
||||
@NotBlank @Size(max = 64) String contactPhone,
|
||||
@NotNull @DecimalMin(value = "0.01") BigDecimal chargeAmount,
|
||||
@Size(max = 1000) String remark,
|
||||
@NotBlank @Size(max = 255) String idempotencyKey,
|
||||
@NotEmpty @Size(max = 500) List<@Valid Item> items
|
||||
|
||||
@@ -2,6 +2,7 @@ package com.baiyue.lastleg.relabel.dto;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
public final class RelabelResponses {
|
||||
private RelabelResponses() {}
|
||||
@@ -10,6 +11,8 @@ public final class RelabelResponses {
|
||||
String customerOrderNo, String overseasWarehouseId, LocalDateTime labelDeadline,
|
||||
String contactName, String contactPhone, String status, int itemCount,
|
||||
int totalPackageCount, int notifiedPackageCount, String skuCodes,
|
||||
BigDecimal chargeAmount, String chargeCurrency, String walletStatus,
|
||||
String walletErrorMessage,
|
||||
LocalDateTime createdAt) {}
|
||||
public record Item(Long id, String skuCode, String productImageFileId, String productImageFileName,
|
||||
String productImageUrl, String productNameZh, int totalPackageCount,
|
||||
|
||||
+7
@@ -6,6 +6,7 @@ import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@Data
|
||||
@TableName("ll_relabel_application")
|
||||
@@ -24,6 +25,12 @@ public class RelabelApplication {
|
||||
private Integer itemCount;
|
||||
private Integer totalPackageCount;
|
||||
private Integer notifiedPackageCount;
|
||||
private BigDecimal chargeAmount;
|
||||
private String chargeCurrency;
|
||||
private String walletStatus;
|
||||
private String walletErrorCode;
|
||||
private String walletErrorMessage;
|
||||
private String walletCommandEventId;
|
||||
private String idempotencyKey;
|
||||
private String requestHash;
|
||||
private String createdBy;
|
||||
|
||||
+50
-2
@@ -17,6 +17,9 @@ import com.baiyue.lastleg.relabel.mapper.RelabelApplicationMapper;
|
||||
import com.baiyue.lastleg.relabel.mapper.RelabelItemMapper;
|
||||
import com.baiyue.lastleg.relabel.mapper.RelabelStatusHistoryMapper;
|
||||
import com.baiyue.lastleg.service.LastlegOrderNoGenerator;
|
||||
import com.baiyue.lastleg.wallet.WalletCommandOutboxService;
|
||||
import com.baiyue.lastleg.wallet.WalletResultHandler;
|
||||
import com.baiyue.common.event.WalletCommandCompletedV1;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.http.HttpStatus;
|
||||
@@ -36,7 +39,7 @@ import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
public class RelabelApplicationService {
|
||||
public class RelabelApplicationService implements WalletResultHandler {
|
||||
public static final String PENDING_PROCESSING = "PENDING_PROCESSING";
|
||||
private static final Set<String> STATUSES = Set.of(PENDING_PROCESSING, "PROCESSING", "COMPLETED", "REJECTED", "CANCELLED");
|
||||
|
||||
@@ -47,6 +50,7 @@ public class RelabelApplicationService {
|
||||
@Resource private LastlegOrderStatusHistoryMapper orderHistories;
|
||||
@Resource private LastlegOrderNoGenerator orderNoGenerator;
|
||||
@Resource private ObjectMapper objectMapper;
|
||||
@Resource private WalletCommandOutboxService walletCommands;
|
||||
|
||||
@Transactional
|
||||
public RelabelResponses.Detail create(String customerId, String operatorId, RelabelRequests.Create request) {
|
||||
@@ -109,6 +113,9 @@ public class RelabelApplicationService {
|
||||
application.setItemCount(request.items().size());
|
||||
application.setTotalPackageCount(total);
|
||||
application.setNotifiedPackageCount(notified);
|
||||
application.setChargeAmount(request.chargeAmount());
|
||||
application.setChargeCurrency("CNY");
|
||||
application.setWalletStatus("FREEZE_PENDING");
|
||||
application.setIdempotencyKey(request.idempotencyKey().trim());
|
||||
application.setRequestHash(requestHash);
|
||||
application.setCreatedBy(trim(operatorId));
|
||||
@@ -116,6 +123,11 @@ public class RelabelApplicationService {
|
||||
application.setUpdatedAt(now);
|
||||
applications.insert(application);
|
||||
|
||||
String walletEventId = walletCommands.publish("FREEZE", Long.parseLong(customerId), "RELABEL_ORDER",
|
||||
relabelNo, request.chargeAmount(), "换标订单费用冻结", 1L);
|
||||
application.setWalletCommandEventId(walletEventId);
|
||||
applications.updateById(application);
|
||||
|
||||
for (RelabelRequests.Item source : request.items()) insertItem(customerId, applicationId, source, now);
|
||||
insertHistory(customerId, applicationId, null, PENDING_PROCESSING, operatorId, "Relabel application submitted", now);
|
||||
insertOrderHistory(customerId, order.getId(), null, order.getCurrentStatus(),
|
||||
@@ -172,11 +184,23 @@ public class RelabelApplicationService {
|
||||
if (!STATUSES.contains(next)) throw badRequest("Unsupported relabel status");
|
||||
if (next.equals(application.getStatus())) return detail(customerId, relabelNo);
|
||||
validateTransition(application.getStatus(), next);
|
||||
if ("PROCESSING".equals(next) && !"FROZEN".equals(application.getWalletStatus())) {
|
||||
throw conflict("Relabel funds must be frozen before processing");
|
||||
}
|
||||
String before = application.getStatus();
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
application.setStatus(next);
|
||||
application.setUpdatedAt(now);
|
||||
applications.updateById(application);
|
||||
if ("COMPLETED".equals(next)) {
|
||||
walletCommands.publish("SETTLE", Long.parseLong(customerId), "RELABEL_ORDER", relabelNo, null,
|
||||
"换标完成,结算费用", 2L);
|
||||
application.setWalletStatus("SETTLE_PENDING"); applications.updateById(application);
|
||||
} else if (Set.of("REJECTED", "CANCELLED").contains(next) && "FROZEN".equals(application.getWalletStatus())) {
|
||||
walletCommands.publish("RELEASE", Long.parseLong(customerId), "RELABEL_ORDER", relabelNo, null,
|
||||
"换标取消,释放冻结", 2L);
|
||||
application.setWalletStatus("RELEASE_PENDING"); applications.updateById(application);
|
||||
}
|
||||
LastlegOrder order = orders.selectById(application.getLastlegOrderId());
|
||||
if (order == null || !customerId.equals(order.getCustomerId())) throw conflict("Linked tail-leg order is missing");
|
||||
String orderBefore = order.getCurrentStatus();
|
||||
@@ -221,7 +245,31 @@ public class RelabelApplicationService {
|
||||
value.getLabelDeadline(), value.getContactName(), value.getContactPhone(), value.getStatus(),
|
||||
Objects.requireNonNullElse(value.getItemCount(), detailItems.size()),
|
||||
Objects.requireNonNullElse(value.getTotalPackageCount(), 0),
|
||||
Objects.requireNonNullElse(value.getNotifiedPackageCount(), 0), skuCodes, value.getCreatedAt());
|
||||
Objects.requireNonNullElse(value.getNotifiedPackageCount(), 0), skuCodes,
|
||||
value.getChargeAmount(), value.getChargeCurrency(), value.getWalletStatus(), value.getWalletErrorMessage(),
|
||||
value.getCreatedAt());
|
||||
}
|
||||
|
||||
@Override public boolean supports(String businessType) { return "RELABEL_ORDER".equals(businessType); }
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void handle(WalletCommandCompletedV1 result) {
|
||||
RelabelApplication value = applications.findNo(String.valueOf(result.customerId()), result.businessNo());
|
||||
if (value == null) throw notFound("Relabel application not found for wallet result");
|
||||
if ("SUCCEEDED".equals(result.result())) {
|
||||
value.setWalletStatus(switch (result.operation()) { case "FREEZE" -> "FROZEN"; case "SETTLE" -> "SETTLED"; case "RELEASE" -> "RELEASED"; default -> result.holdStatus(); });
|
||||
value.setWalletErrorCode(null); value.setWalletErrorMessage(null);
|
||||
if ("FREEZE".equals(result.operation()) && Set.of("REJECTED", "CANCELLED").contains(value.getStatus())) {
|
||||
walletCommands.publish("RELEASE", result.customerId(), "RELABEL_ORDER", value.getRelabelNo(), null,
|
||||
"换标已取消,冻结成功后立即释放", 2L);
|
||||
value.setWalletStatus("RELEASE_PENDING");
|
||||
}
|
||||
} else {
|
||||
value.setWalletStatus(result.operation() + "_FAILED"); value.setWalletErrorCode(result.errorCode());
|
||||
value.setWalletErrorMessage(result.errorMessage());
|
||||
}
|
||||
value.setUpdatedAt(LocalDateTime.now()); applications.updateById(value);
|
||||
}
|
||||
|
||||
private RelabelResponses.Item item(RelabelItem value) {
|
||||
|
||||
Reference in New Issue
Block a user