This commit is contained in:
2026-10-19 17:59:34 +08:00
parent dcfba1053c
commit ce189f062f
14 changed files with 305 additions and 6 deletions
@@ -0,0 +1,66 @@
package com.baiyue.lastleg.discard.repository;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baiyue.lastleg.discard.entity.CargoDiscardApplication;
import com.baiyue.lastleg.discard.entity.CargoDiscardItem;
import com.baiyue.lastleg.inventory.entity.InventoryLedger;
import com.baiyue.lastleg.inventory.entity.InventoryPosition;
import com.baiyue.lastleg.inventory.mapper.InventoryBalanceMapper;
import com.baiyue.lastleg.inventory.mapper.InventoryLedgerMapper;
import com.baiyue.lastleg.returnreceipt.mapper.ReturnInventoryBalanceMapper;
import com.baiyue.lastleg.returnreceipt.mapper.ReturnInventoryCartonMapper;
import jakarta.annotation.Resource;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Repository;
import org.springframework.web.server.ResponseStatusException;
import java.time.LocalDateTime;
/** 废弃实物扣减对应的退货余额和普通库存总账。 */
@Repository
public class CargoDiscardStockLedgerRepository {
@Resource private ReturnInventoryBalanceMapper returnBalances;
@Resource private ReturnInventoryCartonMapper returnCartons;
@Resource private InventoryBalanceMapper balances;
@Resource private InventoryLedgerMapper ledgers;
/** 箱内 SKU 扣减时同步扣汇总,只有该 SKU 在箱内耗尽才减一箱。 */
public void deductReturn(String customerId, CargoDiscardApplication application, CargoDiscardItem item,
long before, long quantity) {
var carton = returnCartons.lockId(item.getReturnCartonId());
if (carton == null || !customerId.equals(carton.getCustomerId())
|| !application.getOverseasWarehouseId().equals(carton.getOverseasWarehouseId())
|| !"DISCARD_PENDING".equals(carton.getStatus())) {
throw new ResponseStatusException(HttpStatus.CONFLICT, "退货废弃箱归属或状态已变化");
}
long boxes = before == quantity && !"PARCEL".equals(carton.getSourceUnitType()) ? 1 : 0;
var balance = returnBalances.lockSku(customerId, carton.getOverseasWarehouseId(), item.getSkuCode());
if (balance == null || returnBalances.deductConversion(customerId, carton.getOverseasWarehouseId(),
item.getSkuCode(), quantity, boxes) != 1) {
throw new ResponseStatusException(HttpStatus.CONFLICT, "退货库存汇总数量不足,不能完成废弃");
}
}
/** 一件代发已扣实物仓位后,按同事务余额快照追加库存总账。 */
public void recordDropship(String customerId, CargoDiscardApplication application, CargoDiscardItem item,
InventoryPosition position, long quantity, String operator, LocalDateTime at) {
var balance = balances.selectById(position.getBalanceId());
if (balance == null || !customerId.equals(balance.getCustomerId())) {
throw new ResponseStatusException(HttpStatus.CONFLICT, "废弃库存余额不存在");
}
var fact = new InventoryLedger();
fact.setId(IdWorker.getId()); fact.setCustomerId(customerId); fact.setCustomerName(balance.getCustomerName());
fact.setBalanceId(balance.getId()); fact.setPositionId(position.getId());
fact.setOverseasWarehouseId(balance.getOverseasWarehouseId()); fact.setDestinationWarehouseCode(balance.getDestinationWarehouseCode());
fact.setInboundOrderId(balance.getInboundOrderId()); fact.setInboundCode(balance.getInboundCode());
fact.setInboundOrderNo(balance.getInboundOrderNo()); fact.setPalletId(position.getPalletId());
fact.setPalletNo(position.getPalletNo()); fact.setBatchNo(position.getBatchNo());
fact.setWarehouseLocationCode(position.getWarehouseLocationCode()); fact.setSkuCode(item.getSkuCode());
fact.setBusinessType("DISCARD"); fact.setBusinessOrderId(application.getId()); fact.setBusinessOrderNo(application.getDiscardNo());
fact.setIdempotencyKey("CARGO_DISCARD:" + application.getId() + ":" + item.getId() + ":STOCK");
fact.setStatusFrom("AVAILABLE"); fact.setStatusTo("DISCARDED");
fact.setBeforePackages(balance.getAvailablePackages() + quantity); fact.setDeltaPackages(-quantity);
fact.setAfterPackages(balance.getAvailablePackages()); fact.setOperatorId(operator);
fact.setRemark("货物废弃"); fact.setOccurredAt(at); fact.setCreatedAt(at);
if (ledgers.insert(fact) != 1) throw new IllegalStateException("废弃库存流水写入失败");
}
}
@@ -33,6 +33,7 @@ import java.util.Map;
/** Final inventory mutation for a warehouse-approved cargo discard. */
@Service
public class CargoDiscardInventoryAdjustmentService {
@Resource private com.baiyue.lastleg.discard.repository.CargoDiscardStockLedgerRepository stockLedger;
@Resource private CargoDiscardInventoryMapper inventory;
@Resource private CargoDiscardStockService stockService;
@Resource private DropshipCartonLedgerMapper cartonLedgers;
@@ -44,6 +45,7 @@ public class CargoDiscardInventoryAdjustmentService {
@Resource private ReturnInventoryCartonMapper returnCartons;
@Resource private ReturnInventoryCartonItemMapper returnCartonItems;
/** 实物废弃、来源库存扣减与流水在同一事务内完成。 */
@Transactional(propagation = Propagation.MANDATORY)
public AdjustmentResult discardPalletItem(String customerId, CargoDiscardApplication application,
CargoDiscardItem item, List<CargoDiscardCarton> links,
@@ -53,7 +55,7 @@ public class CargoDiscardInventoryAdjustmentService {
stockService.discard(customerId, operatorId, application, item, actualPackages);
return new AdjustmentResult(item.getDiscardPackages(), actualPackages, 0);
}
if (isReturnItem(item)) return discardReturnItem(customerId, item, actualPackages);
if (isReturnItem(item)) return discardReturnItem(customerId, application, item, actualPackages);
if (actualPackages < 0 || actualPackages > links.size()) throw conflict("实际废弃数量超出该托盘申请数量");
DropshipSkuInventory sku = inventory.lockSkuInventory(customerId, item.getSkuInventoryId());
if (sku == null) throw conflict("托盘 SKU 库存不存在: " + item.getSkuCode());
@@ -97,10 +99,12 @@ public class CargoDiscardInventoryAdjustmentService {
}
long after = value(inventory.skuPackages(customerId, sku.getId()));
if (after != before - actualPackages) throw conflict("托盘 SKU 库存扣减不守恒");
stockLedger.recordDropship(customerId, application, item, position, actualPackages, operatorId, occurredAt);
return new AdjustmentResult(before, actualPackages, after);
}
private AdjustmentResult discardReturnItem(String customerId, CargoDiscardItem item, int actualPackages) {
/** 退货箱按件扣减,同时同步库存余额;完成事实由明细的 PDA 完成快照提供。 */
private AdjustmentResult discardReturnItem(String customerId, CargoDiscardApplication application, CargoDiscardItem item, int actualPackages) {
if (actualPackages < 0 || actualPackages > item.getDiscardPackages()) {
throw conflict("实际废弃数量超出退货库存申请数量");
}
@@ -110,6 +114,7 @@ public class CargoDiscardInventoryAdjustmentService {
if (before < actualPackages || (actualPackages > 0 && returnCartonItems.deduct(sku.getId(), actualPackages) != 1)) {
throw conflict("退货库存数量不足");
}
if (actualPackages > 0) stockLedger.deductReturn(customerId, application, item, before, actualPackages);
return new AdjustmentResult(before, actualPackages, before - actualPackages);
}