feat(fleet): integrate costs quotes operations and in-transit handovers
This commit is contained in:
+61
@@ -174,6 +174,67 @@ public class DispatchFleetAdapter implements FleetDispatchGateway {
|
||||
return new FleetCompletionModels.DispatchCompletion(dispatchNo, dispatch.getOverseasWarehouseId(), outcomes, reason);
|
||||
}
|
||||
// Existing delivery commands persist LocalDateTime.now(); convert in that server zone, never the browser zone.
|
||||
@Override
|
||||
public com.baiyue.lastleg.fleet.exception.FleetTransitEvidence transitEvidence(String dispatchNo, boolean lock) {
|
||||
var dispatch = lock ? orders.lockGlobalByDispatchNo(dispatchNo) : orders.findGlobalByDispatchNo(dispatchNo);
|
||||
if (dispatch == null) throw new ResponseStatusException(HttpStatus.NOT_FOUND, "排车单不存在");
|
||||
var outbound = lock ? outbounds.lockByDispatch(dispatch.getCustomerId(), dispatch.getId())
|
||||
: outbounds.findByDispatch(dispatch.getCustomerId(), dispatch.getId());
|
||||
if (!"DEPARTED".equals(dispatch.getStatus()) || outbound == null || !"OUTBOUNDED".equals(outbound.getStatus())
|
||||
|| dispatch.getShippedPackageCount() == null || dispatch.getShippedPackageCount() <= 0
|
||||
|| !Objects.equals(dispatch.getShippedPackageCount(), outbound.getPackageCount()))
|
||||
throw conflict("交接必须具有已完成出库的真实发运依据");
|
||||
var rows = lock ? deliveries.lockByOutbound(dispatch.getCustomerId(), outbound.getId())
|
||||
: deliveries.findByOutbound(dispatch.getCustomerId(), outbound.getId());
|
||||
var facts = new java.util.ArrayList<com.baiyue.lastleg.fleet.exception.FleetTransitEvidence.Delivery>();
|
||||
long packages = 0;
|
||||
for (var row : rows) {
|
||||
if (!Objects.equals(row.getCustomerId(), dispatch.getCustomerId())
|
||||
|| !Objects.equals(row.getDispatchOrderId(), dispatch.getId())
|
||||
|| !Objects.equals(row.getOutboundOrderId(), outbound.getId())
|
||||
|| !Objects.equals(row.getOverseasWarehouseId(), dispatch.getOverseasWarehouseId())
|
||||
|| row.getPackageCount() == null || row.getPackageCount() <= 0 || row.getVersion() == null
|
||||
|| row.getStatus() == null || !java.util.Set.of("WAIT_DELIVERY", "DELIVERED", "RETURN_PENDING", "RETURNED").contains(row.getStatus()))
|
||||
throw conflict("派送货物归属或执行状态与原始发运不一致");
|
||||
Instant terminal = originallySigned(row) ? instant(row.getSignedAt()) : "RETURNED".equals(row.getStatus())
|
||||
? instant(deliveryOperations.returnedAt(dispatch.getCustomerId(), row.getId())) : null;
|
||||
if (("DELIVERED".equals(row.getStatus()) || "RETURNED".equals(row.getStatus())) && terminal == null)
|
||||
throw conflict("派送终态缺少真实签收或退回完成证据");
|
||||
String key = destination(row.getDestinationType(), row.getDestinationWarehouseCode(), null,
|
||||
row.getDeliveryAddress(), row.getPostalCode());
|
||||
if (key == null) throw conflict("派送单缺少真实卸货目的地");
|
||||
var cargo = new com.baiyue.lastleg.fleet.exception.FleetHandoverPolicy.Delivery(dispatch.getCustomerId(),
|
||||
dispatchNo, row.getDeliveryNo(), key, row.getPackageCount(), terminal);
|
||||
facts.add(new com.baiyue.lastleg.fleet.exception.FleetTransitEvidence.Delivery(cargo, row.getStatus(), row.getVersion(),
|
||||
new com.baiyue.lastleg.fleet.exception.FleetTransitEvidence.Transport(row.getVehiclePlate(), row.getDriverName(), row.getDriverPhone())));
|
||||
packages = Math.addExact(packages, row.getPackageCount());
|
||||
}
|
||||
if (facts.isEmpty() || packages != dispatch.getShippedPackageCount())
|
||||
throw conflict("派送明细未核平本次实发货物");
|
||||
return new com.baiyue.lastleg.fleet.exception.FleetTransitEvidence(dispatchNo, dispatch.getCustomerId(),
|
||||
dispatch.getOverseasWarehouseId(), dispatch.getShippedPackageCount(), java.util.List.copyOf(facts));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handover(com.baiyue.lastleg.fleet.exception.FleetTransitEvidence evidence, Assignment assignment) {
|
||||
var current = transitEvidence(evidence.dispatchNo(), true);
|
||||
if (!current.equals(evidence)) throw conflict("交接货物已变化,请重新核对");
|
||||
for (var fact : evidence.deliveries()) {
|
||||
if (fact.cargo().terminalAt() != null) continue;
|
||||
var row = deliveries.lockByNo(evidence.customerId(), fact.cargo().deliveryNo());
|
||||
if (row == null || !Objects.equals(row.getVersion(), fact.recordVersion()) || row.getSignedAt() != null)
|
||||
throw conflict("派送货物已变化,请重新核对交接");
|
||||
if (deliveries.update(null, new LambdaUpdateWrapper<DeliveryOrder>()
|
||||
.eq(DeliveryOrder::getId, row.getId()).eq(DeliveryOrder::getCustomerId, evidence.customerId())
|
||||
.eq(DeliveryOrder::getVersion, fact.recordVersion()).eq(DeliveryOrder::getStatus, fact.status())
|
||||
.isNull(DeliveryOrder::getSignedAt)
|
||||
.set(DeliveryOrder::getVehiclePlate, assignment.vehiclePlate()).set(DeliveryOrder::getDriverName, assignment.driverName())
|
||||
.set(DeliveryOrder::getDriverPhone, assignment.driverPhone()).set(DeliveryOrder::getVersion, fact.recordVersion() + 1)
|
||||
.set(DeliveryOrder::getUpdatedAt, LocalDateTime.now())) != 1)
|
||||
throw conflict("派送交接保存失败,请刷新核对");
|
||||
}
|
||||
}
|
||||
|
||||
private static Instant instant(LocalDateTime value) { return value == null ? null : value.atZone(ZoneId.systemDefault()).toInstant(); }
|
||||
private static boolean originallySigned(DeliveryOrder order) {
|
||||
return order.getSignedAt() != null && java.util.Set.of("DELIVERED", "RETURN_PENDING", "RETURNED").contains(order.getStatus());
|
||||
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
package com.baiyue.lastleg.dispatch.fleet;
|
||||
|
||||
import com.baiyue.common.core.api.ApiResponse;
|
||||
import com.baiyue.common.security.AuthenticatedUser;
|
||||
import com.baiyue.lastleg.pda.security.PdaWarehouseIdentity;
|
||||
import com.baiyue.lastleg.fleet.exception.FleetHandoverPdaQuery;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/pda/v1/last-leg/dispatches")
|
||||
@PreAuthorize("hasAuthority('lastleg:pda:operate') and hasAuthority('ROLE_OVERSEAS_WAREHOUSE_PDA_OPERATOR')")
|
||||
public class PdaFleetHandoverController {
|
||||
private final FleetHandoverPdaQuery service;
|
||||
public PdaFleetHandoverController(FleetHandoverPdaQuery service) { this.service = service; }
|
||||
@GetMapping("/{dispatchNo}/handover-status")
|
||||
public ApiResponse<FleetHandoverPdaQuery.Status> status(@AuthenticationPrincipal AuthenticatedUser user, @PathVariable String dispatchNo) {
|
||||
var identity = PdaWarehouseIdentity.require(user);
|
||||
return ApiResponse.success(service.status(identity.overseasWarehouseId(), dispatchNo));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user