fix: 显式生成出库单聚合主键

This commit is contained in:
zhouz
2026-07-22 14:55:49 +08:00
parent e562715dd8
commit 3ab5af0eb5
3 changed files with 38 additions and 21 deletions

View File

@@ -1,6 +1,7 @@
package cn.code.nl.module.wms.service.iostorinv;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.IdUtil;
import cn.code.nl.framework.common.pojo.CommonResult;
import cn.code.nl.module.base.api.codegen.CodeGenApi;
import cn.code.nl.module.base.api.codegen.dto.CodeGenerateReqDTO;
@@ -65,6 +66,7 @@ public class IostorInvServiceImpl implements IostorInvService {
.map(IostorInvCreateReqVO.Detail::getPlanQty)
.reduce(BigDecimal.ZERO, BigDecimal::add);
IostorInvDO iostorInv = new IostorInvDO();
iostorInv.setIostorinvId(IdUtil.fastSimpleUUID());
iostorInv.setBillCode(codeResult.getData());
iostorInv.setIoType("OUT");
iostorInv.setBillType(reqVO.getBillType());
@@ -79,6 +81,7 @@ public class IostorInvServiceImpl implements IostorInvService {
for (int index = 0; index < reqVO.getDetails().size(); index++) {
IostorInvCreateReqVO.Detail detail = reqVO.getDetails().get(index);
IostorinvDtlDO detailDO = new IostorinvDtlDO();
detailDO.setIostorinvdtlId(IdUtil.fastSimpleUUID());
detailDO.setIostorinvId(iostorInv.getIostorinvId());
detailDO.setSeqNo(index + 1);
detailDO.setMaterialCode(detail.getMaterialCode());

View File

@@ -5,8 +5,6 @@ import cn.code.nl.framework.common.pojo.CommonResult;
import cn.code.nl.module.base.api.codegen.CodeGenApi;
import cn.code.nl.module.base.api.codegen.dto.CodeGenerateReqDTO;
import cn.code.nl.module.wms.controller.admin.iostorinv.vo.IostorInvCreateReqVO;
import com.baomidou.mybatisplus.core.config.GlobalConfig;
import com.baomidou.mybatisplus.extension.incrementer.H2KeyGenerator;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import jakarta.annotation.Resource;
import org.apache.ibatis.session.SqlSessionFactory;
@@ -31,7 +29,9 @@ import java.time.LocalDateTime;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
@SpringJUnitConfig
@@ -56,10 +56,13 @@ class IostorInvServiceLocalSpringTest {
String id = iostorInvService.createOutbound(buildRequest());
assertNotNull(id);
assertFalse(id.isBlank());
jdbcTemplate.queryForObject("SELECT * FROM wms_iostorinv WHERE iostorinv_id = ?", (rs, rowNum) -> {
assertEquals("OUT-TEST-0001", rs.getString("bill_code"));
assertEquals("OUT", rs.getString("io_type"));
assertEquals("销售出库", rs.getString("bill_type"));
assertEquals(LocalDateTime.of(2026, 7, 22, 0, 0),
rs.getTimestamp("biz_date").toLocalDateTime());
assertEquals("STOR-01", rs.getString("stor_id"));
assertEquals("生成", rs.getString("bill_status"));
assertEquals("主表备注", rs.getString("remark"));
@@ -70,19 +73,27 @@ class IostorInvServiceLocalSpringTest {
List<DetailRow> details = jdbcTemplate.query(
"SELECT * FROM wms_iostorinvdtl WHERE iostorinv_id = ? ORDER BY seq_no",
(rs, rowNum) -> new DetailRow(rs.getInt("seq_no"), rs.getString("material_code"),
(rs, rowNum) -> new DetailRow(rs.getString("iostorinvdtl_id"), rs.getString("iostorinv_id"),
rs.getInt("seq_no"), rs.getString("material_code"),
rs.getString("material_id"), rs.getString("pcsn"), rs.getBigDecimal("plan_qty"),
rs.getBigDecimal("assign_qty"), rs.getBigDecimal("unassign_qty"),
rs.getString("qty_unit_id"), rs.getString("qty_unit_name"),
rs.getString("source_bill_code"), rs.getString("source_bill_type"),
rs.getString("source_billdtl_id"), rs.getString("remark")), id);
assertEquals(List.of(
new DetailRow(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", "明细一"),
new DetailRow(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);
assertEquals(2, details.size());
assertNotNull(details.get(0).detailId());
assertNotNull(details.get(1).detailId());
assertFalse(details.get(0).detailId().isBlank());
assertFalse(details.get(1).detailId().isBlank());
assertNotEquals(details.get(0).detailId(), details.get(1).detailId());
assertEquals(id, details.get(0).headerId());
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));
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));
}
@Test
@@ -97,6 +108,17 @@ class IostorInvServiceLocalSpringTest {
assertEquals(0, jdbcTemplate.queryForObject("SELECT COUNT(*) FROM wms_iostorinvdtl", Integer.class));
}
@Test
void shouldRollbackHeaderAndFirstDetailWhenSecondDetailInsertFails() {
IostorInvCreateReqVO request = buildRequest();
request.getDetails().get(1).setSourceBillCode(null);
assertThrows(RuntimeException.class, () -> iostorInvService.createOutbound(request));
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("销售出库");
@@ -123,7 +145,8 @@ class IostorInvServiceLocalSpringTest {
return detail;
}
private record DetailRow(Integer seqNo, String materialCode, String materialId, String pcsn,
private record DetailRow(String detailId, String headerId, Integer seqNo, String materialCode,
String materialId, String pcsn,
BigDecimal planQty, BigDecimal assignQty, BigDecimal unassignQty,
String qtyUnitId, String qtyUnitName, String sourceBillCode,
String sourceBillType, String sourceBilldtlId, String remark) {
@@ -144,9 +167,6 @@ class IostorInvServiceLocalSpringTest {
SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
MybatisSqlSessionFactoryBean factory = new MybatisSqlSessionFactoryBean();
factory.setDataSource(dataSource);
GlobalConfig.DbConfig dbConfig = new GlobalConfig.DbConfig();
dbConfig.setKeyGenerators(List.of(new H2KeyGenerator()));
factory.setGlobalConfig(new GlobalConfig().setDbConfig(dbConfig));
org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();
configuration.setMapUnderscoreToCamelCase(true);
factory.setConfiguration(configuration);

View File

@@ -1,11 +1,5 @@
DROP TABLE IF EXISTS wms_iostorinvdtl;
DROP TABLE IF EXISTS wms_iostorinv;
DROP SEQUENCE IF EXISTS wms_iostorinvdtl_seq;
DROP SEQUENCE IF EXISTS wms_iostorinv_seq;
CREATE SEQUENCE wms_iostorinv_seq START WITH 1;
CREATE SEQUENCE wms_iostorinvdtl_seq START WITH 1;
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,7 +16,7 @@ CREATE TABLE wms_iostorinvdtl (
iostorinvdtl_id VARCHAR(64) PRIMARY KEY, iostorinv_id VARCHAR(64), seq_no INT,
pcsn VARCHAR(128), bill_status VARCHAR(32), qty_unit_id VARCHAR(64), qty_unit_name VARCHAR(64),
plan_qty DECIMAL(18, 3), real_qty DECIMAL(18, 3), source_billdtl_id VARCHAR(64),
source_bill_type VARCHAR(64), source_bill_code VARCHAR(64), source_bill_table VARCHAR(128),
source_bill_type VARCHAR(64), source_bill_code VARCHAR(64) NOT NULL, source_bill_table VARCHAR(128),
remark VARCHAR(255), assign_qty DECIMAL(18, 3), unassign_qty DECIMAL(18, 3),
material_code VARCHAR(64), source_load_port VARCHAR(64), callback_strategy VARCHAR(255),
material_id VARCHAR(64), create_time TIMESTAMP, update_time TIMESTAMP,