fix: 使用锁定库存快照保存出库明细
This commit is contained in:
@@ -54,7 +54,7 @@ public class IostorInvServiceImpl implements IostorInvService {
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public String createOutbound(IostorInvCreateReqVO reqVO) {
|
||||
validateAndLockInventory(reqVO);
|
||||
Map<Long, AvailableInventoryRespVO> inventorySnapshot = validateAndLockInventory(reqVO);
|
||||
|
||||
String ruleCode = "IO_CODE";
|
||||
CodeGenerateReqDTO codeGenerateReqDTO = new CodeGenerateReqDTO();
|
||||
@@ -95,24 +95,25 @@ public class IostorInvServiceImpl implements IostorInvService {
|
||||
detailDO.setIostorinvdtlId(IdUtil.fastSimpleUUID());
|
||||
detailDO.setIostorinvId(iostorInv.getIostorinvId());
|
||||
detailDO.setSeqNo(index + 1);
|
||||
detailDO.setMaterialCode(detail.getMaterialCode());
|
||||
detailDO.setMaterialId(detail.getMaterialId());
|
||||
detailDO.setPcsn(detail.getPcsn());
|
||||
AvailableInventoryRespVO inventory = inventorySnapshot.get(detail.getGroupId());
|
||||
detailDO.setMaterialCode(inventory == null ? detail.getMaterialCode() : inventory.getMaterialCode());
|
||||
detailDO.setMaterialId(inventory == null ? detail.getMaterialId() : inventory.getMaterialId());
|
||||
detailDO.setPcsn(inventory == null ? detail.getPcsn() : inventory.getPcsn());
|
||||
detailDO.setPlanQty(detail.getPlanQty());
|
||||
detailDO.setUnassignQty(detail.getPlanQty());
|
||||
detailDO.setAssignQty(BigDecimal.ZERO);
|
||||
detailDO.setQtyUnitId(detail.getQtyUnitId());
|
||||
detailDO.setQtyUnitName(detail.getQtyUnitName());
|
||||
detailDO.setSourceBillCode(detail.getSourceBillCode());
|
||||
detailDO.setSourceBillType(detail.getSourceBillType());
|
||||
detailDO.setSourceBilldtlId(detail.getSourceBilldtlId());
|
||||
detailDO.setQtyUnitId(inventory == null ? detail.getQtyUnitId() : inventory.getQtyUnitId());
|
||||
detailDO.setQtyUnitName(inventory == null ? detail.getQtyUnitName() : inventory.getQtyUnitName());
|
||||
detailDO.setSourceBillCode(inventory == null ? detail.getSourceBillCode() : inventory.getExtCode());
|
||||
detailDO.setSourceBillType(inventory == null ? detail.getSourceBillType() : inventory.getExtType());
|
||||
detailDO.setSourceBilldtlId(inventory == null ? detail.getSourceBilldtlId() : inventory.getExtDtlCode());
|
||||
detailDO.setRemark(detail.getRemark());
|
||||
iostorinvDtlMapper.insert(detailDO);
|
||||
}
|
||||
return iostorInv.getIostorinvId();
|
||||
}
|
||||
|
||||
private void validateAndLockInventory(IostorInvCreateReqVO reqVO) {
|
||||
private Map<Long, AvailableInventoryRespVO> validateAndLockInventory(IostorInvCreateReqVO reqVO) {
|
||||
List<IostorInvCreateReqVO.Detail> inventoryDetails = new ArrayList<>();
|
||||
Set<Long> requestedGroupIds = new HashSet<>();
|
||||
Set<String> vehicleCodes = new LinkedHashSet<>();
|
||||
@@ -132,7 +133,7 @@ public class IostorInvServiceImpl implements IostorInvService {
|
||||
vehicleCodes.add(detail.getVehicleCode());
|
||||
}
|
||||
if (inventoryDetails.isEmpty()) {
|
||||
return;
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
List<AvailableInventoryRespVO> lockedRows =
|
||||
@@ -158,6 +159,7 @@ public class IostorInvServiceImpl implements IostorInvService {
|
||||
}
|
||||
}
|
||||
// 建单仅验证库存快照;库存占用和冻结数量由后续分配流程处理。
|
||||
return lockedByGroupId;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -63,7 +63,7 @@ class IostorInvServiceLocalSpringTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldCreateOutboundHeaderAndDetailsInOneTransaction() {
|
||||
void shouldCreateOutboundUsingLockedInventoryIdentityInsteadOfClientUnitAndSource() {
|
||||
String id = iostorInvService.createOutbound(buildRequest());
|
||||
|
||||
assertNotNull(id);
|
||||
@@ -101,10 +101,10 @@ class IostorInvServiceLocalSpringTest {
|
||||
assertEquals(id, details.get(1).headerId());
|
||||
assertEquals(new DetailRow(details.get(0).detailId(), id, 1, "MAT-01", "MID-01", "PCSN-01",
|
||||
new BigDecimal("12.500"), BigDecimal.ZERO.setScale(3), new BigDecimal("12.500"),
|
||||
"KG", "千克", "SRC-01", "ORDER", "SRC-DTL-01", "明细一"), details.get(0));
|
||||
"DB-KG", "数据库千克", "DB-SRC-01", "DB-TYPE", "DB-DTL-01", "明细一"), details.get(0));
|
||||
assertEquals(new DetailRow(details.get(1).detailId(), id, 2, "MAT-02", "MID-02", "PCSN-02",
|
||||
new BigDecimal("7.250"), BigDecimal.ZERO.setScale(3), new BigDecimal("7.250"),
|
||||
"KG", "千克", "SRC-02", "ORDER", "SRC-DTL-02", "明细二"), details.get(1));
|
||||
"DB-KG", "数据库千克", "DB-SRC-02", "DB-TYPE", "DB-DTL-02", "明细二"), details.get(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -200,6 +200,14 @@ class IostorInvServiceLocalSpringTest {
|
||||
assertInventoryRejected(buildRequest());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldRejectInventoryChangedToPartiallyFrozenBelowRequestedQuantity() {
|
||||
jdbcTemplate.update("UPDATE wms_group_plate SET qty = 10, frozen_qty = 6 WHERE group_id = 101");
|
||||
IostorInvCreateReqVO request = buildRequest();
|
||||
request.getDetails().get(0).setPlanQty(new BigDecimal("5"));
|
||||
assertInventoryRejected(request);
|
||||
}
|
||||
|
||||
private void assertInventoryRejected(IostorInvCreateReqVO request) {
|
||||
ServiceException ex = assertThrows(ServiceException.class, () -> iostorInvService.createOutbound(request));
|
||||
assertEquals("出库库存已变化,请刷新后重新选择完整箱库存", ex.getMessage());
|
||||
|
||||
@@ -32,6 +32,6 @@ CREATE TABLE wms_group_plate (group_id BIGINT PRIMARY KEY, vehicle_code VARCHAR(
|
||||
INSERT INTO base_materialbase VALUES ('MID-01','物料一',FALSE), ('MID-02','物料二',FALSE);
|
||||
INSERT INTO wms_structattr VALUES ('S1','BOX-01','STOR-01','S01','一号仓',FALSE), ('S2','BOX-02','STOR-01','S01','一号仓',FALSE), ('S3','BOX-X','STOR-02','S02','二号仓',FALSE);
|
||||
INSERT INTO wms_group_plate VALUES
|
||||
(101,'BOX-01','可用','MID-01','MAT-01','PCSN-01',12.500,NULL,'KG','千克',NULL,NULL,NULL,FALSE),
|
||||
(102,'BOX-02','可用','MID-02','MAT-02','PCSN-02',8.000,0.750,'KG','千克',NULL,NULL,NULL,FALSE),
|
||||
(101,'BOX-01','可用','MID-01','MAT-01','PCSN-01',12.500,NULL,'DB-KG','数据库千克','DB-SRC-01','DB-TYPE','DB-DTL-01',FALSE),
|
||||
(102,'BOX-02','可用','MID-02','MAT-02','PCSN-02',8.000,0.750,'DB-KG','数据库千克','DB-SRC-02','DB-TYPE','DB-DTL-02',FALSE),
|
||||
(103,'BOX-X','可用','MID-01','MAT-01','PCSN-X',5.000,0,'KG','千克',NULL,NULL,NULL,FALSE);
|
||||
|
||||
Reference in New Issue
Block a user