fix(lastleg): enforce delivery and return workflows
This commit is contained in:
+2
-2
@@ -68,8 +68,8 @@ public class CustomerVisitController {
|
||||
@PreAuthorize("hasAuthority('" + OverseasPermissions.DELIVERY_STATUS + "')")
|
||||
public ApiResponse<CustomerVisitResponses.Completed> completeDelivery(
|
||||
@AuthenticationPrincipal AuthenticatedUser user, @RequestParam(required = false) String customerId,
|
||||
@PathVariable String deliveryNo) {
|
||||
return ApiResponse.success(service.completeDelivery(requiredScope(user, customerId), operator(user), deliveryNo));
|
||||
@PathVariable String deliveryNo, @Valid @RequestBody CustomerVisitRequests.DeliveryStatus request) {
|
||||
return ApiResponse.success(service.completeDelivery(requiredScope(user, customerId), operator(user), deliveryNo, request));
|
||||
}
|
||||
|
||||
@PutMapping("/delivery-orders/{deliveryNo}/status")
|
||||
|
||||
+1
@@ -31,5 +31,6 @@ public final class CustomerVisitRequests {
|
||||
@NotNull @Min(0) Long sizeBytes) { }
|
||||
|
||||
public record DeliveryStatus(@NotBlank @Size(max = 32) String status,
|
||||
@NotNull @Min(0) Long expectedVersion,
|
||||
@Size(max = 500) String remark) { }
|
||||
}
|
||||
|
||||
+19
-14
@@ -15,10 +15,8 @@ import com.baiyue.lastleg.delivery.mapper.DeliveryOrderMapper;
|
||||
import com.baiyue.lastleg.delivery.model.DeliveryStatusPolicy;
|
||||
import com.baiyue.lastleg.entity.LastlegInboundOrder;
|
||||
import com.baiyue.lastleg.entity.LastlegOrder;
|
||||
import com.baiyue.lastleg.entity.LastlegOrderStatusHistory;
|
||||
import com.baiyue.lastleg.mapper.LastlegInboundOrderMapper;
|
||||
import com.baiyue.lastleg.mapper.LastlegOrderMapper;
|
||||
import com.baiyue.lastleg.mapper.LastlegOrderStatusHistoryMapper;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
@@ -52,7 +50,6 @@ public class CustomerVisitService {
|
||||
@Resource private DeliveryOperationMapper deliveryOperations;
|
||||
@Resource private LastlegOrderMapper lastMileOrders;
|
||||
@Resource private LastlegInboundOrderMapper inboundOrders;
|
||||
@Resource private LastlegOrderStatusHistoryMapper histories;
|
||||
@Resource private CustomerVisitFileGateway files;
|
||||
@Resource private ObjectMapper objectMapper;
|
||||
|
||||
@@ -80,29 +77,31 @@ public class CustomerVisitService {
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public CustomerVisitResponses.Completed completeDelivery(String customerId, String operatorId, String deliveryNo) {
|
||||
DeliveryOrder delivery = deliveryOrders.findByNo(customerId, deliveryNo);
|
||||
public CustomerVisitResponses.Completed completeDelivery(String customerId, String operatorId, String deliveryNo,
|
||||
CustomerVisitRequests.DeliveryStatus request) {
|
||||
if (!"DELIVERED".equals(trim(request.status()).toUpperCase(Locale.ROOT))) {
|
||||
throw badRequest("派送完成接口只接受 DELIVERED 状态");
|
||||
}
|
||||
DeliveryOrder delivery = deliveryOrders.lockByNo(customerId, deliveryNo);
|
||||
if (delivery == null) throw notFound("派送单不存在");
|
||||
boolean replayed = "DELIVERED".equals(delivery.getStatus());
|
||||
if (!replayed) requireDeliveryTransition(delivery.getStatus(), "DELIVERED");
|
||||
if (!replayed) {
|
||||
requireVersion(delivery, request.expectedVersion());
|
||||
requireDeliveryTransition(delivery.getStatus(), "DELIVERED");
|
||||
}
|
||||
LocalDateTime now = replayed && delivery.getSignedAt() != null ? delivery.getSignedAt() : LocalDateTime.now();
|
||||
if (!replayed) {
|
||||
delivery.setStatus("DELIVERED");
|
||||
delivery.setSignedAt(now);
|
||||
delivery.setUpdatedAt(now);
|
||||
delivery.setVersion(version(delivery) + 1);
|
||||
deliveryOrders.updateById(delivery);
|
||||
for (LastlegOrder order : lastMileOrders.selectList(new LambdaQueryWrapper<LastlegOrder>()
|
||||
.eq(LastlegOrder::getCustomerId, customerId)
|
||||
.eq(LastlegOrder::getDeliveryOrderNo, deliveryNo))) {
|
||||
String from = order.getCurrentStatus();
|
||||
order.setCurrentStatus("DELIVERED");
|
||||
order.setSubOrderStatus("DELIVERY:DELIVERED");
|
||||
order.setUpdatedAt(now);
|
||||
lastMileOrders.updateById(order);
|
||||
LastlegOrderStatusHistory history = new LastlegOrderStatusHistory();
|
||||
history.setCustomerId(customerId); history.setOrderId(order.getId()); history.setFromStatus(from);
|
||||
history.setToStatus("DELIVERED"); history.setEventId("DELIVERY_COMPLETED:" + deliveryNo);
|
||||
history.setRemark("派送完成"); history.setCreatedAt(now); histories.insert(history);
|
||||
}
|
||||
recordOperation(delivery, operatorId, "COMPLETE_DELIVERY", "派送完成并生成客户回访记录", now);
|
||||
}
|
||||
@@ -118,20 +117,22 @@ public class CustomerVisitService {
|
||||
if (!DeliveryStatusPolicy.isEditableTarget(target)) {
|
||||
throw badRequest("不支持的派送状态");
|
||||
}
|
||||
if ("DELIVERED".equals(target)) return completeDelivery(customerId, operatorId, deliveryNo);
|
||||
DeliveryOrder delivery = deliveryOrders.findByNo(customerId, deliveryNo);
|
||||
if ("DELIVERED".equals(target)) return completeDelivery(customerId, operatorId, deliveryNo, request);
|
||||
DeliveryOrder delivery = deliveryOrders.lockByNo(customerId, deliveryNo);
|
||||
if (delivery == null) throw notFound("派送单不存在");
|
||||
if (target.equals(delivery.getStatus())) {
|
||||
CustomerVisit existing = visits.findByDelivery(customerId, delivery.getId());
|
||||
return new CustomerVisitResponses.Completed(existing == null ? null : existing.getId(), deliveryNo,
|
||||
delivery.getStatus(), existing == null ? null : existing.getStatus(), true);
|
||||
}
|
||||
requireVersion(delivery, request.expectedVersion());
|
||||
requireDeliveryTransition(delivery.getStatus(), target);
|
||||
String from = delivery.getStatus();
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
delivery.setStatus(target);
|
||||
if ("DELIVERING".equals(target) && delivery.getDispatchedAt() == null) delivery.setDispatchedAt(now);
|
||||
delivery.setUpdatedAt(now);
|
||||
delivery.setVersion(version(delivery) + 1);
|
||||
deliveryOrders.updateById(delivery);
|
||||
String result = "派送状态由 " + from + " 修改为 " + target;
|
||||
if (StringUtils.hasText(request.remark())) result += ",备注:" + trim(request.remark());
|
||||
@@ -313,6 +314,10 @@ public class CustomerVisitService {
|
||||
throw conflict("派送状态不允许由 " + from + " 变更为 " + target);
|
||||
}
|
||||
}
|
||||
private static void requireVersion(DeliveryOrder delivery, long expectedVersion) {
|
||||
if (version(delivery) != expectedVersion) throw conflict("派送单版本已变化,请刷新后重试");
|
||||
}
|
||||
private static long version(DeliveryOrder delivery) { return Objects.requireNonNullElse(delivery.getVersion(), 0L); }
|
||||
private static ResponseStatusException badRequest(String message) { return new ResponseStatusException(HttpStatus.BAD_REQUEST, message); }
|
||||
private static ResponseStatusException notFound(String message) { return new ResponseStatusException(HttpStatus.NOT_FOUND, message); }
|
||||
private static ResponseStatusException conflict(String message) { return new ResponseStatusException(HttpStatus.CONFLICT, message); }
|
||||
|
||||
Reference in New Issue
Block a user