feat: gate overseas receiving and harden phase4 workflows
This commit is contained in:
+1
@@ -68,5 +68,6 @@ public final class LocalLooseboardRequests {
|
||||
public record ChangeStatus(
|
||||
@NotNull @Min(0) Long version,
|
||||
@NotBlank @Size(max = 32) String status,
|
||||
@NotBlank @Size(max = 255) String idempotencyKey,
|
||||
@Size(max = 1000) String remark) { }
|
||||
}
|
||||
|
||||
+1
-1
@@ -17,7 +17,7 @@ public final class LocalLooseboardResponses {
|
||||
|
||||
public record History(
|
||||
String operationType, String fromStatus, String toStatus, String operatorId,
|
||||
String changeDetail, String remark, LocalDateTime createdAt) { }
|
||||
String idempotencyKey, String changeDetail, String remark, LocalDateTime createdAt) { }
|
||||
|
||||
public record Detail(
|
||||
Summary summary, String originAddress, String destinationAddress, String remark,
|
||||
|
||||
+1
@@ -17,6 +17,7 @@ public class LocalLooseboardHistory {
|
||||
private String fromStatus;
|
||||
private String toStatus;
|
||||
private String operatorId;
|
||||
private String idempotencyKey;
|
||||
private String changeDetail;
|
||||
private String remark;
|
||||
private LocalDateTime createdAt;
|
||||
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
package com.baiyue.lastleg.looseboard.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Data
|
||||
@TableName("ll_local_looseboard_operation")
|
||||
public class LocalLooseboardOperation {
|
||||
@TableId(type = IdType.INPUT) private Long id;
|
||||
private Long orderId;
|
||||
private String customerId;
|
||||
private String operationType;
|
||||
private String idempotencyKey;
|
||||
private String requestHash;
|
||||
private Long resultVersion;
|
||||
private String createdBy;
|
||||
private LocalDateTime createdAt;
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
package com.baiyue.lastleg.looseboard.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.baiyue.lastleg.looseboard.entity.LocalLooseboardOperation;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
|
||||
@Mapper
|
||||
public interface LocalLooseboardOperationMapper extends BaseMapper<LocalLooseboardOperation> {
|
||||
@Select("SELECT * FROM ll_local_looseboard_operation WHERE customer_id=#{customerId} AND order_id=#{orderId} AND idempotency_key=#{key} LIMIT 1")
|
||||
LocalLooseboardOperation findKey(@Param("customerId") String customerId,
|
||||
@Param("orderId") Long orderId,
|
||||
@Param("key") String key);
|
||||
}
|
||||
+26
-5
@@ -12,8 +12,10 @@ import com.baiyue.lastleg.looseboard.dto.LocalLooseboardRequests;
|
||||
import com.baiyue.lastleg.looseboard.dto.LocalLooseboardResponses;
|
||||
import com.baiyue.lastleg.looseboard.entity.LocalLooseboardHistory;
|
||||
import com.baiyue.lastleg.looseboard.entity.LocalLooseboardOrder;
|
||||
import com.baiyue.lastleg.looseboard.entity.LocalLooseboardOperation;
|
||||
import com.baiyue.lastleg.looseboard.mapper.LocalLooseboardHistoryMapper;
|
||||
import com.baiyue.lastleg.looseboard.mapper.LocalLooseboardOrderMapper;
|
||||
import com.baiyue.lastleg.looseboard.mapper.LocalLooseboardOperationMapper;
|
||||
import com.baiyue.lastleg.service.LastlegOrderNoGenerator;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
@@ -51,6 +53,7 @@ public class LocalLooseboardService {
|
||||
|
||||
@Resource private LocalLooseboardOrderMapper orders;
|
||||
@Resource private LocalLooseboardHistoryMapper histories;
|
||||
@Resource private LocalLooseboardOperationMapper operations;
|
||||
@Resource private LastlegOrderMapper lastlegOrders;
|
||||
@Resource private LastlegOrderStatusHistoryMapper lastlegHistories;
|
||||
@Resource private LastlegOrderNoGenerator lastlegOrderNoGenerator;
|
||||
@@ -88,7 +91,8 @@ public class LocalLooseboardService {
|
||||
if (concurrent != null) return replay(customerId, concurrent, requestHash);
|
||||
throw exception;
|
||||
}
|
||||
history(order, "CREATE", null, PENDING_ACCEPTANCE, operatorId, null, request.remark(), now);
|
||||
history(order, "CREATE", null, PENDING_ACCEPTANCE, operatorId,
|
||||
key, null, request.remark(), now);
|
||||
lastlegHistory(customerId, lastlegOrder.getId(), null, lastlegOrder.getCurrentStatus(),
|
||||
"Local looseboard order submitted", now);
|
||||
return detail(customerId, order.getOrderNo());
|
||||
@@ -139,7 +143,7 @@ public class LocalLooseboardService {
|
||||
touch(order, now);
|
||||
orders.updateById(order);
|
||||
history(order, "UPDATE", order.getStatus(), order.getStatus(), operatorId,
|
||||
changeDetail(before, after), null, now);
|
||||
null, changeDetail(before, after), null, now);
|
||||
return response(order);
|
||||
}
|
||||
|
||||
@@ -147,6 +151,15 @@ public class LocalLooseboardService {
|
||||
public LocalLooseboardResponses.Detail changeStatus(String customerId, String orderNo, String operatorId,
|
||||
LocalLooseboardRequests.ChangeStatus request) {
|
||||
LocalLooseboardOrder order = lock(customerId, orderNo);
|
||||
String key = request.idempotencyKey().trim();
|
||||
String requestHash = hash(request);
|
||||
LocalLooseboardOperation existing = operations.findKey(customerId, order.getId(), key);
|
||||
if (existing != null) {
|
||||
if (!"STATUS".equals(existing.getOperationType()) || !requestHash.equals(existing.getRequestHash())) {
|
||||
throw conflict("Idempotency key was reused with a different looseboard status payload");
|
||||
}
|
||||
return response(order);
|
||||
}
|
||||
if (!request.version().equals(value(order.getVersion()))) throw conflict("Order was changed; refresh and retry");
|
||||
String next = norm(request.status());
|
||||
if (!STATUSES.contains(next)) throw badRequest("Unsupported looseboard order status");
|
||||
@@ -160,7 +173,13 @@ public class LocalLooseboardService {
|
||||
touch(order, now);
|
||||
orders.updateById(order);
|
||||
syncLastlegOrder(order, next, now);
|
||||
history(order, "STATUS", from, next, operatorId, null, request.remark(), now);
|
||||
LocalLooseboardOperation operation = new LocalLooseboardOperation();
|
||||
operation.setId(IdWorker.getId()); operation.setOrderId(order.getId());
|
||||
operation.setCustomerId(customerId); operation.setOperationType("STATUS");
|
||||
operation.setIdempotencyKey(key); operation.setRequestHash(requestHash);
|
||||
operation.setResultVersion(order.getVersion()); operation.setCreatedBy(operatorId);
|
||||
operation.setCreatedAt(now); operations.insert(operation);
|
||||
history(order, "STATUS", from, next, operatorId, key, null, request.remark(), now);
|
||||
return response(order);
|
||||
}
|
||||
|
||||
@@ -204,7 +223,8 @@ public class LocalLooseboardService {
|
||||
order.getDestinationAddress(), order.getRemark(), order.getCreatedBy(),
|
||||
histories.listOrder(order.getCustomerId(), order.getId()).stream()
|
||||
.map(value -> new LocalLooseboardResponses.History(value.getOperationType(), value.getFromStatus(),
|
||||
value.getToStatus(), value.getOperatorId(), value.getChangeDetail(), value.getRemark(),
|
||||
value.getToStatus(), value.getOperatorId(), value.getIdempotencyKey(),
|
||||
value.getChangeDetail(), value.getRemark(),
|
||||
value.getCreatedAt())).toList());
|
||||
}
|
||||
|
||||
@@ -218,7 +238,7 @@ public class LocalLooseboardService {
|
||||
}
|
||||
|
||||
private void history(LocalLooseboardOrder order, String type, String from, String to, String operator,
|
||||
String changeDetail, String remark, LocalDateTime now) {
|
||||
String idempotencyKey, String changeDetail, String remark, LocalDateTime now) {
|
||||
LocalLooseboardHistory history = new LocalLooseboardHistory();
|
||||
history.setId(IdWorker.getId());
|
||||
history.setOrderId(order.getId());
|
||||
@@ -227,6 +247,7 @@ public class LocalLooseboardService {
|
||||
history.setFromStatus(from);
|
||||
history.setToStatus(to);
|
||||
history.setOperatorId(operator);
|
||||
history.setIdempotencyKey(trim(idempotencyKey));
|
||||
history.setChangeDetail(changeDetail);
|
||||
history.setRemark(trim(remark));
|
||||
history.setCreatedAt(now);
|
||||
|
||||
Reference in New Issue
Block a user