fix(inventory): resolve returns from immutable shipment SKU facts
This commit is contained in:
+4
@@ -0,0 +1,4 @@
|
||||
package com.baiyue.lastleg.inventory.command.dto;
|
||||
|
||||
/** SKU and shipped quantity derived only from the selected immutable outbound shipment facts. */
|
||||
public record ShipmentSource(String skuCode, long shippedPackages) { }
|
||||
+7
-5
@@ -1,6 +1,7 @@
|
||||
package com.baiyue.lastleg.inventory.command.mapper;
|
||||
|
||||
import com.baiyue.lastleg.inventory.entity.InventoryBalance;
|
||||
import com.baiyue.lastleg.inventory.command.dto.ShipmentSource;
|
||||
import com.baiyue.lastleg.inventory.entity.InventoryPosition;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Delete;
|
||||
@@ -47,11 +48,11 @@ public interface InventoryCommandMapper {
|
||||
"AND NOT EXISTS (SELECT 1 FROM ll_inventory_position p WHERE p.balance_id=ll_inventory_balance.id)")
|
||||
int deleteEmptyBalance(@Param("customerId") String customerId, @Param("balanceId") Long balanceId);
|
||||
|
||||
@Select("SELECT COALESCE(-SUM(l.delta_packages),0) FROM ll_inventory_ledger l " +
|
||||
@Select("SELECT l.sku_code AS skuCode, -SUM(l.delta_packages) AS shippedPackages FROM ll_inventory_ledger l " +
|
||||
"JOIN ll_outbound_order o ON o.customer_id=l.customer_id AND o.outbound_no=#{outboundNo} " +
|
||||
"AND o.overseas_warehouse_id=l.overseas_warehouse_id AND o.status='OUTBOUNDED' " +
|
||||
"WHERE l.customer_id=#{customerId} AND l.position_id=#{positionId} " +
|
||||
"AND l.sku_code=#{skuCode} AND l.business_type='SHIP' AND l.delta_packages<0 " +
|
||||
"AND l.business_type='SHIP' AND l.delta_packages<0 " +
|
||||
"AND ((o.outbound_type='DISPATCH_DELIVERY' AND l.business_order_no=o.dispatch_no " +
|
||||
"AND l.outbound_order_no=o.dispatch_no AND EXISTS (" +
|
||||
"SELECT 1 FROM ll_dispatch_pda_task t JOIN ll_dispatch_pda_pick p " +
|
||||
@@ -62,9 +63,10 @@ public interface InventoryCommandMapper {
|
||||
"WHERE t.customer_id=o.customer_id AND t.dispatch_order_id=o.dispatch_order_id " +
|
||||
"AND t.warehouse_id=o.overseas_warehouse_id AND p.inventory_position_id=l.position_id " +
|
||||
"AND p.packages=-l.delta_packages AND l.idempotency_key=CONCAT(op.idempotency_key,':',op.id))) " +
|
||||
"OR (o.outbound_type<>'DISPATCH_DELIVERY' AND l.outbound_order_no=o.outbound_no))")
|
||||
long shippedPackages(@Param("customerId") String customerId, @Param("positionId") Long positionId,
|
||||
@Param("outboundNo") String outboundNo, @Param("skuCode") String skuCode);
|
||||
"OR (o.outbound_type<>'DISPATCH_DELIVERY' AND l.outbound_order_no=o.outbound_no)) " +
|
||||
"GROUP BY l.sku_code")
|
||||
List<ShipmentSource> shipmentSources(@Param("customerId") String customerId, @Param("positionId") Long positionId,
|
||||
@Param("outboundNo") String outboundNo);
|
||||
|
||||
|
||||
@Select("SELECT COALESCE(SUM(delta_packages),0) FROM ll_inventory_ledger " +
|
||||
|
||||
+20
-5
@@ -294,7 +294,7 @@ public class InventoryCommandService {
|
||||
|| source.maxReturnPackages() <= 0) {
|
||||
throw badRequest("A valid returned inventory source is required");
|
||||
}
|
||||
String sourceSku = sku(source.skuCode());
|
||||
String sourceSku = trim(source.skuCode());
|
||||
ReturnedInventoryRestoreRequest.SourceItem normalized = new ReturnedInventoryRestoreRequest.SourceItem(
|
||||
source.outboundPalletItemId(), source.inventoryPositionId(), sourceSku, source.maxReturnPackages());
|
||||
if (sources.putIfAbsent(source.outboundPalletItemId(), normalized) != null) {
|
||||
@@ -351,6 +351,7 @@ public class InventoryCommandService {
|
||||
}
|
||||
|
||||
Map<Long, Locked> lockedSources = new LinkedHashMap<>();
|
||||
Map<Long, ReturnedInventoryRestoreRequest.SourceItem> resolvedSources = new LinkedHashMap<>();
|
||||
Map<Long, Long> balanceBefore = new LinkedHashMap<>();
|
||||
for (ReturnedInventoryRestoreRequest.SourceItem source : sources.values()) {
|
||||
Locked locked = locked(customerId, source.inventoryPositionId());
|
||||
@@ -361,22 +362,36 @@ public class InventoryCommandService {
|
||||
if (!warehouseId.equals(trim(balance.getOverseasWarehouseId()))) {
|
||||
throw conflict("Returned inventory source warehouse does not match");
|
||||
}
|
||||
long shipped = commands.shippedPackages(customerId, source.inventoryPositionId(), outboundNo,
|
||||
source.skuCode());
|
||||
long restored = commands.restoredPackages(customerId, returnSourceIdentity(source), source.skuCode());
|
||||
var shipmentSources = commands.shipmentSources(customerId, source.inventoryPositionId(), outboundNo);
|
||||
if (shipmentSources == null || shipmentSources.isEmpty()) {
|
||||
throw conflict("Immutable outbound shipment source was not found");
|
||||
}
|
||||
var matchingSources = source.skuCode() == null ? shipmentSources : shipmentSources.stream()
|
||||
.filter(shipment -> source.skuCode().equals(shipment.skuCode())).toList();
|
||||
if (matchingSources.size() != 1) {
|
||||
throw conflict(source.skuCode() == null ? "Immutable outbound shipment SKU source is ambiguous"
|
||||
: "Declared return SKU does not match an immutable shipment source");
|
||||
}
|
||||
var shipment = matchingSources.get(0);
|
||||
String actualSku = required(shipment.skuCode(), "Immutable outbound shipment SKU is missing");
|
||||
var resolved = new ReturnedInventoryRestoreRequest.SourceItem(source.outboundPalletItemId(),
|
||||
source.inventoryPositionId(), actualSku, source.maxReturnPackages());
|
||||
long shipped = shipment.shippedPackages();
|
||||
long restored = commands.restoredPackages(customerId, returnSourceIdentity(resolved), actualSku);
|
||||
long requested = requestedBySource.get(source.outboundPalletItemId());
|
||||
if (shipped <= 0) throw conflict("Immutable outbound shipment source was not found");
|
||||
if (restored + requested > shipped) {
|
||||
throw conflict("Returned packages exceed the remaining shipped packages");
|
||||
}
|
||||
lockedSources.put(source.outboundPalletItemId(), locked);
|
||||
resolvedSources.put(source.outboundPalletItemId(), resolved);
|
||||
balanceBefore.putIfAbsent(balance.getId(), value(balance.getAvailablePackages()));
|
||||
}
|
||||
|
||||
long restoredPackages = 0;
|
||||
List<Long> ledgerIds = new java.util.ArrayList<>();
|
||||
for (ReturnedInventoryRestoreRequest.Receipt receipt : request.receipts()) {
|
||||
ReturnedInventoryRestoreRequest.SourceItem source = sources.get(receipt.outboundPalletItemId());
|
||||
ReturnedInventoryRestoreRequest.SourceItem source = resolvedSources.get(receipt.outboundPalletItemId());
|
||||
Locked sourceLocked = lockedSources.get(receipt.outboundPalletItemId());
|
||||
InventoryBalance balance = sourceLocked.balance();
|
||||
WarehouseResourceGateway.WarehousePalletReference pallet = warehouseGateway.resolvePallet(
|
||||
|
||||
Reference in New Issue
Block a user