From 80183a18a625eba8512430f6bfdfb41aaf17c479 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Fri, 10 Apr 2026 11:17:53 +0800 Subject: [PATCH] ✨ feat(qc): 增加到货通知单状态校验及文件 URL 格式验证 --- yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/indicatorresult/MesQcIndicatorResultServiceImpl.java | 21 +++++++++++++++++++-- yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/arrivalnotice/MesWmArrivalNoticeService.java | 9 +++++++++ yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/arrivalnotice/MesWmArrivalNoticeServiceImpl.java | 17 +++++++++++++++++ yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/itemreceipt/MesWmItemReceiptServiceImpl.java | 6 +----- yudao-module-mes/src/test/java/cn/iocoder/yudao/module/mes/service/qc/indicatorresult/MesQcIndicatorResultServiceImplTest.java | 288 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-mes/src/test/resources/sql/clean.sql | 1 + yudao-module-mes/src/test/resources/sql/create_tables.sql | 20 ++++++++++++++++++++ 7 files changed, 355 insertions(+), 7 deletions(-) create mode 100644 yudao-module-mes/src/test/java/cn/iocoder/yudao/module/mes/service/qc/indicatorresult/MesQcIndicatorResultServiceImplTest.java diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/indicatorresult/MesQcIndicatorResultServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/indicatorresult/MesQcIndicatorResultServiceImpl.java index c9ce52f..c6b162f 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/indicatorresult/MesQcIndicatorResultServiceImpl.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/indicatorresult/MesQcIndicatorResultServiceImpl.java @@ -29,6 +29,7 @@ import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import java.math.BigDecimal; +import java.net.URI; import java.util.*; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; @@ -181,7 +182,7 @@ public class MesQcIndicatorResultServiceImpl implements MesQcIndicatorResultServ * 按检测项的 resultType 校验明细值格式 * *

FLOAT → 必须可解析为 BigDecimal;INTEGER → 必须可解析为整数; - * TEXT / DICT / FILE → 放行 + * DICT → 必须属于字典值域;FILE → 必须为 http/https URL;TEXT → 放行 */ private void validateDetailValues(List items, Map indicatorMap) { @@ -219,7 +220,23 @@ public class MesQcIndicatorResultServiceImpl implements MesQcIndicatorResultServ dictDataApi.validateDictDataList(dictType, Collections.singleton(item.getValue())); } } - // FILE / TEXT 不做格式校验 + if (Objects.equals(resultType, MesQcResultValueTypeEnum.FILE.getType()) + && !isHttpUrl(item.getValue())) { + throw exception(QC_RESULT_VALUE_FORMAT_INVALID, + "检测项[" + indicator.getName() + "]要求文件 URL,实际值=" + item.getValue()); + } + // TEXT 不做格式校验 + } + } + + private boolean isHttpUrl(String value) { + try { + URI uri = URI.create(value); + String scheme = uri.getScheme(); + return StrUtil.isNotBlank(uri.getHost()) + && ("http".equalsIgnoreCase(scheme) || "https".equalsIgnoreCase(scheme)); + } catch (IllegalArgumentException e) { + return false; } } diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/arrivalnotice/MesWmArrivalNoticeService.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/arrivalnotice/MesWmArrivalNoticeService.java index 64ac10e..aaea87d 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/arrivalnotice/MesWmArrivalNoticeService.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/arrivalnotice/MesWmArrivalNoticeService.java @@ -117,6 +117,15 @@ public interface MesWmArrivalNoticeService { void validateArrivalNoticeAndLineExists(Long noticeId, Long lineId); /** + * 校验到货通知单已就绪可被采购入库引用 + *

校验状态为待入库 + 所有需检行都已完成 IQC

+ * + * @param id 到货通知单编号 + * @return 到货通知单 + */ + MesWmArrivalNoticeDO validateArrivalNoticeReadyForReceipt(Long id); + + /** * 查询指定供应商的到货通知单数量 * * @param vendorId 供应商编号 diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/arrivalnotice/MesWmArrivalNoticeServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/arrivalnotice/MesWmArrivalNoticeServiceImpl.java index 78ae354..3b5a79e 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/arrivalnotice/MesWmArrivalNoticeServiceImpl.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/arrivalnotice/MesWmArrivalNoticeServiceImpl.java @@ -210,6 +210,23 @@ public class MesWmArrivalNoticeServiceImpl implements MesWmArrivalNoticeService return notice; } + @Override + public MesWmArrivalNoticeDO validateArrivalNoticeReadyForReceipt(Long id) { + // 1. 校验到货通知单存在且状态为待入库 + MesWmArrivalNoticeDO notice = validateArrivalNoticeExists(id); + if (ObjUtil.notEqual(MesWmArrivalNoticeStatusEnum.PENDING_RECEIPT.getStatus(), notice.getStatus())) { + throw exception(WM_ARRIVAL_NOTICE_STATUS_NOT_PENDING_RECEIPT); + } + // 2. 行级防御校验:确保所有需检行都已完成 IQC + List lines = arrivalNoticeLineService.getArrivalNoticeLineListByNoticeId(id); + boolean hasUnchecked = CollectionUtils.anyMatch(lines, + line -> Boolean.TRUE.equals(line.getIqcCheckFlag()) && line.getIqcId() == null); + if (hasUnchecked) { + throw exception(WM_ARRIVAL_NOTICE_IQC_PENDING); + } + return notice; + } + private void validateCodeUnique(Long id, String code) { MesWmArrivalNoticeDO notice = arrivalNoticeMapper.selectByCode(code); if (notice == null) { diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/itemreceipt/MesWmItemReceiptServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/itemreceipt/MesWmItemReceiptServiceImpl.java index aaf2b47..0875cbd 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/itemreceipt/MesWmItemReceiptServiceImpl.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/itemreceipt/MesWmItemReceiptServiceImpl.java @@ -14,7 +14,6 @@ import cn.iocoder.yudao.module.mes.dal.dataobject.wm.itemreceipt.MesWmItemReceip import cn.iocoder.yudao.module.mes.dal.dataobject.wm.itemreceipt.MesWmItemReceiptLineDO; import cn.iocoder.yudao.module.mes.dal.mysql.wm.itemreceipt.MesWmItemReceiptMapper; import cn.iocoder.yudao.module.mes.enums.MesBizTypeConstants; -import cn.iocoder.yudao.module.mes.enums.wm.MesWmArrivalNoticeStatusEnum; import cn.iocoder.yudao.module.mes.enums.wm.MesWmItemReceiptStatusEnum; import cn.iocoder.yudao.module.mes.enums.wm.MesWmTransactionTypeEnum; import cn.iocoder.yudao.module.mes.service.md.vendor.MesMdVendorService; @@ -92,10 +91,7 @@ public class MesWmItemReceiptServiceImpl implements MesWmItemReceiptService { vendorService.validateVendorExistsAndEnable(reqVO.getVendorId()); // 校验到货通知单存在 if (reqVO.getNoticeId() != null) { - MesWmArrivalNoticeDO notice = arrivalNoticeService.validateArrivalNoticeExists(reqVO.getNoticeId()); - if (ObjUtil.notEqual(notice.getStatus(), MesWmArrivalNoticeStatusEnum.PENDING_RECEIPT.getStatus())) { - throw exception(WM_ARRIVAL_NOTICE_STATUS_NOT_PENDING_RECEIPT); - } + MesWmArrivalNoticeDO notice = arrivalNoticeService.validateArrivalNoticeReadyForReceipt(reqVO.getNoticeId()); if (ObjUtil.notEqual(notice.getVendorId(), reqVO.getVendorId())) { throw exception(WM_ARRIVAL_NOTICE_VENDOR_MISMATCH); } diff --git a/yudao-module-mes/src/test/java/cn/iocoder/yudao/module/mes/service/qc/indicatorresult/MesQcIndicatorResultServiceImplTest.java b/yudao-module-mes/src/test/java/cn/iocoder/yudao/module/mes/service/qc/indicatorresult/MesQcIndicatorResultServiceImplTest.java new file mode 100644 index 0000000..ac34a74 --- /dev/null +++ b/yudao-module-mes/src/test/java/cn/iocoder/yudao/module/mes/service/qc/indicatorresult/MesQcIndicatorResultServiceImplTest.java @@ -0,0 +1,288 @@ +package cn.iocoder.yudao.module.mes.service.qc.indicatorresult; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; +import cn.iocoder.yudao.module.mes.controller.admin.qc.indicatorresult.vo.MesQcIndicatorResultPageReqVO; +import cn.iocoder.yudao.module.mes.controller.admin.qc.indicatorresult.vo.MesQcIndicatorResultSaveReqVO; +import cn.iocoder.yudao.module.mes.dal.dataobject.qc.indicator.MesQcIndicatorDO; +import cn.iocoder.yudao.module.mes.dal.dataobject.qc.indicatorresult.MesQcIndicatorResultDO; +import cn.iocoder.yudao.module.mes.dal.dataobject.qc.iqc.MesQcIqcDO; +import cn.iocoder.yudao.module.mes.dal.mysql.qc.indicatorresult.MesQcIndicatorResultMapper; +import cn.iocoder.yudao.module.mes.enums.qc.MesQcResultValueTypeEnum; +import cn.iocoder.yudao.module.mes.enums.qc.MesQcTypeEnum; +import cn.iocoder.yudao.module.mes.service.qc.indicator.MesQcIndicatorService; +import cn.iocoder.yudao.module.mes.service.qc.ipqc.MesQcIpqcService; +import cn.iocoder.yudao.module.mes.service.qc.iqc.MesQcIqcService; +import cn.iocoder.yudao.module.mes.service.qc.oqc.MesQcOqcService; +import cn.iocoder.yudao.module.mes.service.qc.rqc.MesQcRqcService; +import cn.iocoder.yudao.module.system.api.dict.DictDataApi; +import org.junit.jupiter.api.Test; +import org.springframework.context.annotation.Import; +import org.springframework.test.context.bean.override.mockito.MockitoBean; + +import jakarta.annotation.Resource; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; +import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; + +/** + * {@link MesQcIndicatorResultServiceImpl} 的单元测试 + * + * @author 芋道源码 + */ +@Import(MesQcIndicatorResultServiceImpl.class) +public class MesQcIndicatorResultServiceImplTest extends BaseDbUnitTest { + + @Resource + private MesQcIndicatorResultServiceImpl indicatorResultService; + + @Resource + private MesQcIndicatorResultMapper resultMapper; + + @MockitoBean + private MesQcIndicatorResultDetailService resultDetailService; + @MockitoBean + private MesQcIndicatorService indicatorService; + @MockitoBean + private MesQcIqcService iqcService; + @MockitoBean + private MesQcIpqcService ipqcService; + @MockitoBean + private MesQcOqcService oqcService; + @MockitoBean + private MesQcRqcService rqcService; + @MockitoBean + private DictDataApi dictDataApi; + + @Test + public void testCreateIndicatorResult_success() { + // 准备参数 + MesQcIndicatorResultSaveReqVO reqVO = buildReqVO("plain text value", MesQcResultValueTypeEnum.TEXT.getType()); + // mock 方法 + mockIqcAndIndicator(reqVO, MesQcResultValueTypeEnum.TEXT.getType()); + + // 调用 + Long resultId = indicatorResultService.createIndicatorResult(reqVO); + + // 断言 + assertNotNull(resultId); + MesQcIndicatorResultDO dbResult = resultMapper.selectById(resultId); + assertNotNull(dbResult); + assertEquals(reqVO.getCode(), dbResult.getCode()); + assertEquals(reqVO.getQcId(), dbResult.getQcId()); + assertEquals(reqVO.getQcType(), dbResult.getQcType()); + assertEquals(100L, dbResult.getItemId()); // 从 mock IQC 获取 + verify(resultDetailService).createDetailList(anyList()); + } + + @Test + public void testCreateIndicatorResult_fileValueInvalid() { + // 准备参数 + MesQcIndicatorResultSaveReqVO reqVO = buildReqVO("not-a-url", MesQcResultValueTypeEnum.FILE.getType()); + // mock 方法 + mockIqcAndIndicator(reqVO, MesQcResultValueTypeEnum.FILE.getType()); + + // 调用,并断言异常 + assertServiceException(() -> indicatorResultService.createIndicatorResult(reqVO), + QC_RESULT_VALUE_FORMAT_INVALID, "检测项[检测项A]要求文件 URL,实际值=not-a-url"); + + // 断言:未入库 + assertEquals(0, resultMapper.selectCount()); + verify(resultDetailService, never()).createDetailList(anyList()); + } + + @Test + public void testUpdateIndicatorResult_success() { + // mock 数据 + MesQcIndicatorResultDO dbResult = randomPojo(MesQcIndicatorResultDO.class, o -> { + o.setQcType(MesQcTypeEnum.IQC.getType()); + }); + resultMapper.insert(dbResult); + // 准备参数 + MesQcIndicatorResultSaveReqVO reqVO = buildReqVO("updated text", MesQcResultValueTypeEnum.TEXT.getType()); + reqVO.setId(dbResult.getId()); + // mock 方法 + MesQcIndicatorDO indicator = new MesQcIndicatorDO(); + indicator.setId(reqVO.getItems().get(0).getIndicatorId()); + indicator.setName("检测项A"); + indicator.setResultType(MesQcResultValueTypeEnum.TEXT.getType()); + when(indicatorService.validateIndicatorListExists(anySet())) + .thenReturn(Map.of(indicator.getId(), indicator)); + + // 调用 + indicatorResultService.updateIndicatorResult(reqVO); + + // 断言 + MesQcIndicatorResultDO updatedResult = resultMapper.selectById(dbResult.getId()); + assertEquals(reqVO.getCode(), updatedResult.getCode()); + // qcId/qcType/itemId 不允许改挂,应保持原值 + assertEquals(dbResult.getQcId(), updatedResult.getQcId()); + assertEquals(dbResult.getQcType(), updatedResult.getQcType()); + assertEquals(dbResult.getItemId(), updatedResult.getItemId()); + verify(resultDetailService).createOrUpdateDetailList(anyList()); + } + + @Test + public void testUpdateIndicatorResult_notExists() { + // 准备参数 + MesQcIndicatorResultSaveReqVO reqVO = buildReqVO("text", MesQcResultValueTypeEnum.TEXT.getType()); + reqVO.setId(randomLongId()); + + // 调用,并断言异常 + assertServiceException(() -> indicatorResultService.updateIndicatorResult(reqVO), + QC_RESULT_NOT_EXISTS); + } + + @Test + public void testDeleteIndicatorResult_success() { + // mock 数据 + MesQcIndicatorResultDO dbResult = randomPojo(MesQcIndicatorResultDO.class); + resultMapper.insert(dbResult); + + // 调用 + indicatorResultService.deleteIndicatorResult(dbResult.getId()); + + // 断言 + assertNull(resultMapper.selectById(dbResult.getId())); + verify(resultDetailService).deleteDetailByResultId(dbResult.getId()); + } + + @Test + public void testDeleteIndicatorResult_notExists() { + // 调用,并断言异常 + assertServiceException(() -> indicatorResultService.deleteIndicatorResult(randomLongId()), + QC_RESULT_NOT_EXISTS); + } + + @Test + public void testGetIndicatorResult() { + // mock 数据 + MesQcIndicatorResultDO dbResult = randomPojo(MesQcIndicatorResultDO.class); + resultMapper.insert(dbResult); + + // 调用 + MesQcIndicatorResultDO result = indicatorResultService.getIndicatorResult(dbResult.getId()); + + // 断言 + assertPojoEquals(dbResult, result); + } + + @Test + public void testGetIndicatorResultPage() { + // mock 数据 + MesQcIndicatorResultDO dbResult = randomPojo(MesQcIndicatorResultDO.class, o -> { + o.setQcId(1L); + o.setQcType(MesQcTypeEnum.IQC.getType()); + o.setCode("SPL-001"); + o.setItemId(100L); + }); + resultMapper.insert(dbResult); + // 测试 qcId 不匹配 + resultMapper.insert(cloneIgnoreId(dbResult, o -> o.setQcId(2L))); + // 测试 qcType 不匹配 + resultMapper.insert(cloneIgnoreId(dbResult, o -> o.setQcType(MesQcTypeEnum.IPQC.getType()))); + // 测试 code 不匹配 + resultMapper.insert(cloneIgnoreId(dbResult, o -> o.setCode("SPL-999"))); + // 测试 itemId 不匹配 + resultMapper.insert(cloneIgnoreId(dbResult, o -> o.setItemId(999L))); + // 准备参数 + MesQcIndicatorResultPageReqVO pageReqVO = new MesQcIndicatorResultPageReqVO(); + pageReqVO.setQcId(1L); + pageReqVO.setQcType(MesQcTypeEnum.IQC.getType()); + pageReqVO.setCode("SPL-001"); + pageReqVO.setItemId(100L); + + // 调用 + PageResult pageResult = indicatorResultService.getIndicatorResultPage(pageReqVO); + + // 断言 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(dbResult, pageResult.getList().get(0)); + } + + @Test + public void testGetIndicatorResultCountByQcIdAndType() { + // mock 数据 + MesQcIndicatorResultDO result1 = randomPojo(MesQcIndicatorResultDO.class, o -> { + o.setQcId(1L); + o.setQcType(MesQcTypeEnum.IQC.getType()); + }); + resultMapper.insert(result1); + MesQcIndicatorResultDO result2 = randomPojo(MesQcIndicatorResultDO.class, o -> { + o.setQcId(1L); + o.setQcType(MesQcTypeEnum.IQC.getType()); + }); + resultMapper.insert(result2); + // 不匹配 + resultMapper.insert(randomPojo(MesQcIndicatorResultDO.class, o -> { + o.setQcId(2L); + o.setQcType(MesQcTypeEnum.IPQC.getType()); + })); + + // 调用 + Long count = indicatorResultService.getIndicatorResultCountByQcIdAndType(1L, MesQcTypeEnum.IQC.getType()); + + // 断言 + assertEquals(2L, count); + } + + @Test + public void testValidateIndicatorResultExistsByQcIdAndType_success() { + // mock 数据 + resultMapper.insert(randomPojo(MesQcIndicatorResultDO.class, o -> { + o.setQcId(1L); + o.setQcType(MesQcTypeEnum.IQC.getType()); + })); + + // 调用(不抛异常即通过) + indicatorResultService.validateIndicatorResultExistsByQcIdAndType(1L, MesQcTypeEnum.IQC.getType()); + } + + @Test + public void testValidateIndicatorResultExistsByQcIdAndType_notExists() { + // 调用,并断言异常 + assertServiceException( + () -> indicatorResultService.validateIndicatorResultExistsByQcIdAndType(randomLongId(), MesQcTypeEnum.IQC.getType()), + QC_FINISH_INDICATOR_RESULT_REQUIRED); + } + + // ==================== 辅助方法 ==================== + + private void mockIqcAndIndicator(MesQcIndicatorResultSaveReqVO reqVO, Integer resultType) { + MesQcIqcDO iqc = new MesQcIqcDO(); + iqc.setId(reqVO.getQcId()); + iqc.setItemId(100L); + when(iqcService.validateIqcExists(reqVO.getQcId())).thenReturn(iqc); + + MesQcIndicatorDO indicator = new MesQcIndicatorDO(); + indicator.setId(reqVO.getItems().get(0).getIndicatorId()); + indicator.setName("检测项A"); + indicator.setResultType(resultType); + when(indicatorService.validateIndicatorListExists(anySet())) + .thenReturn(Map.of(indicator.getId(), indicator)); + } + + private MesQcIndicatorResultSaveReqVO buildReqVO(String value, Integer resultType) { + MesQcIndicatorResultSaveReqVO.Item item = new MesQcIndicatorResultSaveReqVO.Item(); + item.setIndicatorId(10L); + item.setValue(value); + + MesQcIndicatorResultSaveReqVO reqVO = new MesQcIndicatorResultSaveReqVO(); + reqVO.setCode("SPL-001"); + reqVO.setQcId(1L); + reqVO.setQcType(MesQcTypeEnum.IQC.getType()); + reqVO.setItems(List.of(item)); + return reqVO; + } + +} diff --git a/yudao-module-mes/src/test/resources/sql/clean.sql b/yudao-module-mes/src/test/resources/sql/clean.sql index 05b58c8..8cb28c3 100644 --- a/yudao-module-mes/src/test/resources/sql/clean.sql +++ b/yudao-module-mes/src/test/resources/sql/clean.sql @@ -20,3 +20,4 @@ DELETE FROM "mes_wm_batch"; DELETE FROM "mes_wm_material_stock"; DELETE FROM "mes_pro_task"; DELETE FROM "mes_pro_route_process"; +DELETE FROM "mes_qc_indicator_result"; diff --git a/yudao-module-mes/src/test/resources/sql/create_tables.sql b/yudao-module-mes/src/test/resources/sql/create_tables.sql index 734f74e..881ac06 100644 --- a/yudao-module-mes/src/test/resources/sql/create_tables.sql +++ b/yudao-module-mes/src/test/resources/sql/create_tables.sql @@ -810,3 +810,23 @@ CREATE TABLE IF NOT EXISTS "mes_wm_product_sales_detail" ( "tenant_id" bigint NOT NULL DEFAULT 0, PRIMARY KEY ("id") ); + +-- ---------------------------- +-- MES 检验结果记录 +-- ---------------------------- +CREATE TABLE IF NOT EXISTS "mes_qc_indicator_result" ( + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "code" varchar(64) DEFAULT NULL, + "qc_id" bigint DEFAULT NULL, + "qc_type" int DEFAULT NULL, + "item_id" bigint DEFAULT NULL, + "sn" varchar(128) DEFAULT NULL, + "remark" varchar(500) DEFAULT NULL, + "creator" varchar(64) DEFAULT '', + "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updater" varchar(64) DEFAULT '', + "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + "deleted" bit NOT NULL DEFAULT FALSE, + "tenant_id" bigint NOT NULL DEFAULT 0, + PRIMARY KEY ("id") +); -- libgit2 0.21.4