fix: 保存前重校验出库库存

This commit is contained in:
zhouz
2026-07-22 16:02:43 +08:00
parent a65f96dab6
commit 4e276c5b05
12 changed files with 179 additions and 5 deletions

View File

@@ -58,6 +58,11 @@ class IostorinvDtlMapperTest {
assertTrue(expanded.stream().allMatch(item -> "STOR-001".equals(item.getStorId())));
assertEquals(2, expanded.stream().map(AvailableInventoryRespVO::getPcsn).distinct().count());
assertTrue(expanded.stream().allMatch(item -> item.getAvailableQty().signum() > 0));
assertEquals(0, new java.math.BigDecimal("5").compareTo(expanded.get(1).getAvailableQty()));
List<AvailableInventoryRespVO> locked = mapper.selectAvailableInventoryByVehicleCodesForUpdate(
"STOR-001", List.of("BOX-001"));
assertEquals(List.of(1L, 2L), locked.stream().map(AvailableInventoryRespVO::getGroupId).toList());
AvailableInventoryPageReqVO warehousePageReqVO = new AvailableInventoryPageReqVO();
warehousePageReqVO.setStorId("STOR-001");

View File

@@ -156,6 +156,57 @@ class IostorInvServiceLocalSpringTest {
assertEquals(0, jdbcTemplate.queryForObject("SELECT COUNT(*) FROM wms_iostorinvdtl", Integer.class));
}
@Test
void shouldRejectMissingChildOfSameBoxBeforeGeneratingCode() {
jdbcTemplate.update("INSERT INTO wms_group_plate VALUES (104,'BOX-01','可用','MID-01','MAT-01','PCSN-EXTRA',1,0,'KG','千克',NULL,NULL,NULL,FALSE)");
assertInventoryRejected(buildRequest());
}
@Test
void shouldRejectCrossWarehouseGroup() {
IostorInvCreateReqVO request = buildRequest();
IostorInvCreateReqVO.Detail detail = request.getDetails().get(0);
detail.setGroupId(103L);
detail.setVehicleCode("BOX-X");
detail.setPcsn("PCSN-X");
detail.setPlanQty(new BigDecimal("5"));
assertInventoryRejected(request);
}
@Test
void shouldRejectQuantityAboveAvailable() {
IostorInvCreateReqVO request = buildRequest();
request.getDetails().get(1).setPlanQty(new BigDecimal("7.251"));
assertInventoryRejected(request);
}
@Test
void shouldRejectDuplicateGroup() {
IostorInvCreateReqVO request = buildRequest();
request.getDetails().get(1).setGroupId(101L);
request.getDetails().get(1).setVehicleCode("BOX-01");
assertInventoryRejected(request);
}
@Test
void shouldRejectInventoryChangedToUnavailable() {
jdbcTemplate.update("UPDATE wms_group_plate SET status = '不可用' WHERE group_id = 101");
assertInventoryRejected(buildRequest());
}
@Test
void shouldRejectInventoryChangedToFullyFrozen() {
jdbcTemplate.update("UPDATE wms_group_plate SET frozen_qty = qty WHERE group_id = 101");
assertInventoryRejected(buildRequest());
}
private void assertInventoryRejected(IostorInvCreateReqVO request) {
ServiceException ex = assertThrows(ServiceException.class, () -> iostorInvService.createOutbound(request));
assertEquals("出库库存已变化,请刷新后重新选择完整箱库存", ex.getMessage());
assertEquals(0, jdbcTemplate.queryForObject("SELECT COUNT(*) FROM wms_iostorinv", Integer.class));
assertEquals(0, jdbcTemplate.queryForObject("SELECT COUNT(*) FROM wms_iostorinvdtl", Integer.class));
}
private IostorInvCreateReqVO buildRequest() {
IostorInvCreateReqVO request = new IostorInvCreateReqVO();
request.setBillType("销售出库");
@@ -179,6 +230,8 @@ class IostorInvServiceLocalSpringTest {
detail.setSourceBillType("ORDER");
detail.setSourceBilldtlId("SRC-DTL-" + suffix);
detail.setRemark(remark);
detail.setGroupId(Long.valueOf("1" + suffix));
detail.setVehicleCode("BOX-" + suffix);
return detail;
}
@@ -205,6 +258,8 @@ class IostorInvServiceLocalSpringTest {
SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
MybatisSqlSessionFactoryBean factory = new MybatisSqlSessionFactoryBean();
factory.setDataSource(dataSource);
factory.setMapperLocations(new org.springframework.core.io.ClassPathResource(
"mapper/iostorinvdtl/IostorinvDtlMapper.xml"));
MybatisConfiguration configuration = new MybatisConfiguration();
configuration.setMapUnderscoreToCamelCase(true);
factory.setConfiguration(configuration);

View File

@@ -55,3 +55,5 @@ VALUES (1, 'BOX-001', '可用', '1001', 'MAT-001', 'PCSN-001', 10, 2, 'UNIT-1',
(4, 'BOX-003', '可用', '1001', 'MAT-001', 'PCSN-004', 10, 10, 'UNIT-1', '', 'EXT-4', 'TYPE-1', 'DTL-4', FALSE),
(5, 'BOX-004', '可用', '1001', 'MAT-001', 'PCSN-005', 10, 0, 'UNIT-1', '', 'EXT-5', 'TYPE-1', 'DTL-5', TRUE),
(6, 'BOX-005', '可用', '1001', 'MAT-001', 'PCSN-006', 10, 0, 'UNIT-1', '', 'EXT-6', 'TYPE-1', 'DTL-6', FALSE);
UPDATE wms_group_plate SET frozen_qty = NULL WHERE group_id = 2;

View File

@@ -1,5 +1,8 @@
DROP TABLE IF EXISTS wms_iostorinvdtl;
DROP TABLE IF EXISTS wms_iostorinv;
DROP TABLE IF EXISTS wms_group_plate;
DROP TABLE IF EXISTS wms_structattr;
DROP TABLE IF EXISTS base_materialbase;
CREATE TABLE wms_iostorinv (
iostorinv_id VARCHAR(64) PRIMARY KEY,
bill_code VARCHAR(64), io_type VARCHAR(32), bill_type VARCHAR(64), biz_date TIMESTAMP,
@@ -22,3 +25,13 @@ CREATE TABLE wms_iostorinvdtl (
material_id VARCHAR(64), create_time TIMESTAMP, update_time TIMESTAMP,
creator VARCHAR(64), updater VARCHAR(64), deleted BOOLEAN DEFAULT FALSE
);
CREATE TABLE base_materialbase (material_id VARCHAR(64) PRIMARY KEY, material_name VARCHAR(64), deleted BOOLEAN NOT NULL);
CREATE TABLE wms_structattr (struct_id VARCHAR(64) PRIMARY KEY, storagevehicle_code VARCHAR(64), stor_id VARCHAR(64), stor_code VARCHAR(64), stor_name VARCHAR(64), deleted BOOLEAN NOT NULL);
CREATE TABLE wms_group_plate (group_id BIGINT PRIMARY KEY, vehicle_code VARCHAR(64), status VARCHAR(16), material_id VARCHAR(64), material_code VARCHAR(64), pcsn VARCHAR(64), qty DECIMAL(18,3), frozen_qty DECIMAL(18,3), qty_unit_id VARCHAR(64), qty_unit_name VARCHAR(64), ext_code VARCHAR(64), ext_type VARCHAR(64), ext_dtl_code VARCHAR(64), deleted BOOLEAN NOT NULL);
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),
(103,'BOX-X','可用','MID-01','MAT-01','PCSN-X',5.000,0,'KG','千克',NULL,NULL,NULL,FALSE);