Merge branch 'dev-lyhfive' of http://git.buggoglobal.com/java-project/baiyue-firstleg into dev
This commit is contained in:
-2
@@ -13,7 +13,6 @@ import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
@@ -27,7 +26,6 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
|
||||
@RestController
|
||||
@ConditionalOnProperty(name = "lastleg.future-outbound-api.enabled", havingValue = "true")
|
||||
@RequestMapping("/api/platform/v1/last-leg/dispatches")
|
||||
@Tag(name = "Tail-leg vehicle dispatch")
|
||||
public class DispatchController {
|
||||
|
||||
-2
@@ -7,14 +7,12 @@ import com.baiyue.lastleg.dispatch.pda.dto.DispatchPdaResponses;
|
||||
import com.baiyue.lastleg.dispatch.pda.service.DispatchPdaWorkflowService;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
|
||||
@RestController
|
||||
@ConditionalOnProperty(name = "lastleg.future-outbound-api.enabled", havingValue = "true")
|
||||
@RequestMapping("/api/pda/v1/last-leg/dispatches/{dispatchNo}")
|
||||
public class DispatchPdaController {
|
||||
public static final String OPERATE_PERMISSION = "lastleg:pda:operate";
|
||||
|
||||
+2
-1
@@ -7,7 +7,8 @@ public final class DispatchPdaResponses {
|
||||
public record Task(Long id, String taskNo, String dispatchNo, String vehiclePlate, String warehouseId, String status,
|
||||
List<Item> items) {}
|
||||
public record Item(Long dispatchItemId, String palletNo, String destinationWarehouseCode,
|
||||
String destinationWarehouseName, String fbaWarehouseCode, int scheduledPackages,
|
||||
String destinationWarehouseName, String fbaWarehouseCode, String warehouseRouteLabel,
|
||||
int scheduledPackages,
|
||||
long pickedPackages, List<Position> positions) {}
|
||||
public record Position(Long id, Long balanceId, long availablePackages, long allocatedPackages,
|
||||
long pickedPackages) {}
|
||||
|
||||
+22
-9
@@ -119,6 +119,11 @@ public class DispatchPdaWorkflowService {
|
||||
inventory.pick(customerId, operatorId, new InventoryCommandRequests.Move(request.positionId(),
|
||||
request.packages(), order.getDispatchNo(), order.getDispatchNo(), null,
|
||||
keyBase + ":PICK", request.remark()));
|
||||
// A successful PDA scan is the inventory deduction point. Departure only
|
||||
// changes outbound/dispatch facts and must not deduct the same quantity again.
|
||||
inventory.ship(customerId, operatorId, new InventoryCommandRequests.Move(request.positionId(),
|
||||
request.packages(), order.getDispatchNo(), order.getDispatchNo(), null,
|
||||
keyBase + ":SHIP", request.remark()));
|
||||
DispatchPdaPick pick = new DispatchPdaPick();
|
||||
pick.setId(IdWorker.getId()); pick.setCustomerId(customerId); pick.setTaskId(task.getId());
|
||||
pick.setDispatchItemId(itemId); pick.setInventoryPositionId(request.positionId()); pick.setPackages(request.packages());
|
||||
@@ -149,6 +154,14 @@ public class DispatchPdaWorkflowService {
|
||||
if (replay != null) return read(replay, DispatchPdaResponses.PickingCompleted.class).withReplay();
|
||||
requireVehicle(order);
|
||||
DispatchPdaTask task = tasks.lockByDispatch(customerId, order.getId());
|
||||
if (task != null && "COMPLETED".equals(task.getStatus())) {
|
||||
List<DispatchItem> completedItems = items.findByDispatchOrder(customerId, order.getId());
|
||||
long planned = completedItems.stream().map(DispatchItem::getPackageCount).filter(Objects::nonNull)
|
||||
.mapToLong(Integer::longValue).sum();
|
||||
long picked = picks.listTask(customerId, task.getId()).stream().mapToLong(p -> n(p.getPackages())).sum();
|
||||
return new DispatchPdaResponses.PickingCompleted(order.getDispatchNo(), order.getStatus(), planned,
|
||||
picked, Math.max(0, planned - picked), picked < planned, true);
|
||||
}
|
||||
if (task == null || !("PDA_PENDING".equals(task.getStatus()) || "PICKING".equals(task.getStatus()))) {
|
||||
throw conflict("Dispatch PDA task is not available for completion");
|
||||
}
|
||||
@@ -197,14 +210,7 @@ public class DispatchPdaWorkflowService {
|
||||
}
|
||||
List<DispatchPdaPick> dispatchPicks = picks.listTask(customerId, task.getId());
|
||||
if (dispatchPicks.isEmpty()) throw conflict("Dispatch has no PDA picks to ship");
|
||||
long shipped = 0;
|
||||
for (DispatchPdaPick pick : dispatchPicks) {
|
||||
String key = "DISPATCH:" + order.getDispatchNo() + ":PICK:" + pick.getId() + ":SHIP";
|
||||
inventory.ship(customerId, operatorId, new InventoryCommandRequests.Move(
|
||||
pick.getInventoryPositionId(), n(pick.getPackages()),
|
||||
outbound.getOutboundNo(), outbound.getOutboundNo(), null, key, request.remark()));
|
||||
shipped += n(pick.getPackages());
|
||||
}
|
||||
long shipped = dispatchPicks.stream().mapToLong(p -> n(p.getPackages())).sum();
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
pickAttribution.depart(customerId, outbound.getOutboundNo(), order.getDispatchNo(), dispatchPicks, now);
|
||||
outbound.setStatus("OUTBOUNDED");
|
||||
@@ -227,7 +233,8 @@ public class DispatchPdaWorkflowService {
|
||||
List<InventoryPosition> palletPositions = item.getWarehousePalletId() == null ? List.of()
|
||||
: positions.listPallet(customerId, item.getWarehousePalletId());
|
||||
values.add(new DispatchPdaResponses.Item(item.getId(), item.getPalletNo(), item.getDestinationWarehouseCode(),
|
||||
item.getDestinationWarehouseName(), item.getFbaWarehouseCode(), item.getPackageCount(),
|
||||
item.getDestinationWarehouseName(), item.getFbaWarehouseCode(),
|
||||
warehouseRouteLabel(item.getFbaWarehouseCode(), item.getDestinationWarehouseCode()), item.getPackageCount(),
|
||||
picks.totalItem(customerId, task.getId(), item.getId()), palletPositions.stream().map(p ->
|
||||
new DispatchPdaResponses.Position(p.getId(), p.getBalanceId(), n(p.getAvailablePackages()),
|
||||
n(p.getAllocatedPackages()), n(p.getPickedPackages()))).toList()));
|
||||
@@ -270,6 +277,12 @@ public class DispatchPdaWorkflowService {
|
||||
private String json(Object value) { try { return objectMapper.writeValueAsString(value); } catch (Exception e) { throw new IllegalStateException(e); } }
|
||||
private static long n(Long value) { return value == null ? 0 : value; }
|
||||
private static long n(Integer value) { return value == null ? 0 : value; }
|
||||
static String warehouseRouteLabel(String originalFbaWarehouseCode, String destinationWarehouseCode) {
|
||||
String original = trim(originalFbaWarehouseCode);
|
||||
String destination = trim(destinationWarehouseCode);
|
||||
return original != null && destination != null && !original.equalsIgnoreCase(destination)
|
||||
? original + " -> " + destination : null;
|
||||
}
|
||||
private static String trim(String value) { return value == null || value.trim().isEmpty() ? null : value.trim(); }
|
||||
private static String required(String value, String message) { String result = trim(value); if (result == null) throw new ResponseStatusException(HttpStatus.BAD_REQUEST, message); return result; }
|
||||
private static ResponseStatusException conflict(String message) { return new ResponseStatusException(HttpStatus.CONFLICT, message); }
|
||||
|
||||
+1
@@ -84,6 +84,7 @@ public class DispatchPickOrderAttributionService {
|
||||
long shipped = value(before.getShippedPackageCount()) + entry.getValue();
|
||||
String to = shipped == value(before.getPackageCount()) ? "COMPLETED" : "PARTIALLY_SHIPPED";
|
||||
LastlegOrderStatusHistory row = new LastlegOrderStatusHistory();
|
||||
row.setCustomerId(customerId);
|
||||
row.setOrderId(entry.getKey());
|
||||
row.setFromStatus(before.getCurrentStatus());
|
||||
row.setToStatus(to);
|
||||
|
||||
+3
-1
@@ -31,6 +31,7 @@ import org.springframework.web.server.ResponseStatusException;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import com.baiyue.lastleg.service.LastlegOrderNoGenerator;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
@@ -48,6 +49,7 @@ public class DispatchService {
|
||||
@Resource private DispatchDraftMapper drafts;
|
||||
@Resource private DispatchDraftContainerMapper draftContainers;
|
||||
@Resource private DispatchCandidateMapper candidates;
|
||||
@Resource private LastlegOrderNoGenerator orderNoGenerator;
|
||||
|
||||
public String resolveCustomerScopeForPlans(List<Long> planIds) {
|
||||
return requireSingleCustomerScope(candidates.findCustomerScopesByPlanIds(normalizeIds(planIds, "Plan IDs")),
|
||||
@@ -239,7 +241,7 @@ public class DispatchService {
|
||||
DispatchOrder dispatch = new DispatchOrder();
|
||||
dispatch.setId(IdWorker.getId());
|
||||
dispatch.setCustomerId(customerId);
|
||||
dispatch.setDispatchNo("PC" + now.format(DateTimeFormatter.BASIC_ISO_DATE) + dispatch.getId());
|
||||
dispatch.setDispatchNo(orderNoGenerator.next("DISPATCH", selected.get(0).overseasWarehouseId(), dispatch.getId()));
|
||||
dispatch.setOverseasWarehouseId(selected.get(0).overseasWarehouseId());
|
||||
dispatch.setOverseasWarehouseName(selected.get(0).overseasWarehouseName());
|
||||
dispatch.setRoute(StringUtils.hasText(request.route()) ? request.route().trim() : route(selected));
|
||||
|
||||
Reference in New Issue
Block a user