From 5072520172e8f45e3ccb8afc26cf0c8186ba4cdd Mon Sep 17 00:00:00 2001
From: 云 <2163098428@qq.com>
Date: 星期一, 19 十月 2026 16:31:42 +0800
Subject: [PATCH] refactor(mes): 重构质量管理和批次绑定功能
---
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/oqc/MesQcOqcServiceImpl.java | 113 ---
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/bagcode/MesProBagCodeController.java | 7
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/qc/approver/MesQcApproverConfigMapper.java | 43 +
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/seedquality/MesQcSeedIndicatorRangeService.java | 45 +
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/item/MesMdItemServiceImpl.java | 14
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/qc/MesQcApprovalTypeEnum.java | 36 +
sql/mysql/mes_qc_seed_indicator_range_20261019.sql | 25
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/qc/approver/MesQcApproverConfigDO.java | 56 +
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/oqc/vo/MesQcOqcRespVO.java | 1
sql/mysql/mes_qc_oqc_retest_approver_20261019.sql | 39 +
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/batch/MesProBatchServiceImpl.java | 88 ++
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/bagcode/MesProBagCodeServiceImpl.java | 14
.playwright-mcp/page-2026-10-19T06-22-10-596Z.yml | 1
yudao-module-mes/src/test/resources/sql/create_tables.sql | 22
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/md/item/MesMdItemMapper.java | 4
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/seedquality/vo/MesQcSeedQualityApprovalReqVO.java | 3
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/seedquality/MesQcSeedQualityServiceImpl.java | 153 ++++
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/qc/seedquality/MesQcSeedIndicatorRangeDO.java | 20
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java | 7
yudao-module-mes/src/test/java/cn/iocoder/yudao/module/mes/service/qc/seedquality/SeedQualityWorkflowTest.java | 60 +
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/qc/MesQcApproveNodeEnum.java | 47 +
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/seedquality/MesQcSeedQualityService.java | 3
yudao-module-mes/src/test/java/cn/iocoder/yudao/module/mes/service/qc/seedquality/SeedQualityGroupTest.java | 29
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/seedquality/MesQcSeedQualityController.java | 66 +
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/seedquality/vo/MesQcSeedQualitySubmitReqVO.java | 6
yudao-module-mes/src/test/java/cn/iocoder/yudao/module/mes/service/qc/oqc/MesQcOqcServiceImplTest.java | 99 --
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/seedquality/vo/MesQcSeedQualityRespVO.java | 2
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/qc/seedquality/MesQcSeedIndicatorRangeMapper.java | 9
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/seedquality/vo/MesQcSeedIndicatorRangeSaveReqVO.java | 25
.playwright-mcp/page-2026-10-19T06-21-53-919Z.yml | 1
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/seedquality/vo/MesQcSeedQualityBatchRetestReqVO.java | 15
yudao-module-mes/src/test/java/cn/iocoder/yudao/module/mes/service/qc/seedquality/MesQcSeedIndicatorRangeServiceTest.java | 34 +
docs/production_quality_flow_20261019.md | 50
sql/mysql/mes_seed_quality_workflow_20261019.sql | 47 -
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/approver/MesQcApproverConfigController.java | 88 ++
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/seedquality/vo/MesQcSeedQualityScopeRetestReqVO.java | 18
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/batch/vo/MesProBatchSaveReqVO.java | 5
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/qc/seedquality/MesQcSeedQualityDO.java | 2
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/bagcode/MesProBagCodeService.java | 3
.playwright-mcp/page-2026-10-19T06-22-06-902Z.yml | 202 ++++++
sql/mysql/mes_qc_remove_sales_quality_20261019.sql | 28
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/oqc/vo/MesQcOqcPageReqVO.java | 2
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/approver/vo/MesQcApproverConfigRespVO.java | 36 +
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/qc/oqc/MesQcOqcMapper.java | 5
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/batch/MesProBatchController.java | 1
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/batch/vo/MesProBatchRespVO.java | 3
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/batch/MesProBatchService.java | 3
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/approver/MesQcApproverService.java | 57 +
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/bagcode/MesProBagCodeMapper.java | 10
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/oqc/MesQcOqcController.java | 26
/dev/null | 15
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/approver/vo/MesQcApproverConfigPageReqVO.java | 25
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/approver/MesQcApproverServiceImpl.java | 122 +++
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/seedquality/vo/MesQcSeedQualityBatchApprovalReqVO.java | 3
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/oqc/MesQcOqcService.java | 4
.playwright-mcp/page-2026-10-19T06-22-35-986Z.yml | 1
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/approver/vo/MesQcApproverConfigSaveReqVO.java | 33 +
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/qc/oqc/MesQcOqcDO.java | 2
58 files changed, 1,479 insertions(+), 399 deletions(-)
diff --git a/.playwright-mcp/page-2026-10-19T06-21-53-919Z.yml b/.playwright-mcp/page-2026-10-19T06-21-53-919Z.yml
new file mode 100644
index 0000000..6adf37e
--- /dev/null
+++ b/.playwright-mcp/page-2026-10-19T06-21-53-919Z.yml
@@ -0,0 +1 @@
+- generic [active]: 宸ヤ笟AI鏅洪�犲钩鍙�
\ No newline at end of file
diff --git a/.playwright-mcp/page-2026-10-19T06-22-06-902Z.yml b/.playwright-mcp/page-2026-10-19T06-22-06-902Z.yml
new file mode 100644
index 0000000..4c2f95e
--- /dev/null
+++ b/.playwright-mcp/page-2026-10-19T06-22-06-902Z.yml
@@ -0,0 +1,202 @@
+- generic [active] [ref=e4]:
+ - generic [ref=e201]:
+ - complementary [ref=e203]:
+ - generic [ref=e204]:
+ - generic [ref=e205] [cursor=pointer]
+ - link "宸ヤ笟AI鏅洪�犲钩鍙� 宸ヤ笟AI鏅洪�犲钩鍙�" [ref=e210] [cursor=pointer]:
+ - /url: javascript:void 0
+ - img "宸ヤ笟AI鏅洪�犲钩鍙�" [ref=e213]
+ - generic [ref=e214]: 宸ヤ笟AI鏅洪�犲钩鍙�
+ - menu [ref=e217]:
+ - menuitem "棣栭〉" [ref=e218] [cursor=pointer]
+ - listitem [ref=e222]:
+ - generic [ref=e223] [cursor=pointer]: 鍩虹鏁版嵁
+ - listitem [ref=e228]:
+ - generic [ref=e229] [cursor=pointer]: 缁忛攢鍟嗙鐞�
+ - listitem [ref=e234]:
+ - generic [ref=e235] [cursor=pointer]: 浠撳偍鐗╂祦
+ - listitem [ref=e240]:
+ - generic [ref=e241] [cursor=pointer]: 鍑哄簱娴侀�氱鐞�
+ - listitem [ref=e246]:
+ - generic [ref=e247] [cursor=pointer]: 闃蹭吉闃茬獪璐х鐞�
+ - listitem [ref=e252]:
+ - generic [ref=e253] [cursor=pointer]: 婧簮鍒嗘瀽
+ - listitem [ref=e258]:
+ - generic [ref=e259] [cursor=pointer]: 涓�琚嬩竴鐮佺鐞�
+ - listitem [ref=e264]:
+ - generic [ref=e265] [cursor=pointer]: 璐ㄩ噺绠$悊
+ - listitem [ref=e270]:
+ - generic [ref=e271] [cursor=pointer]: 缁熻鍒嗘瀽
+ - listitem [ref=e276]:
+ - generic [ref=e277] [cursor=pointer]: 绯荤粺绠$悊
+ - generic [ref=e283] [cursor=pointer]
+ - generic [ref=e288]:
+ - generic [ref=e289]:
+ - banner [ref=e290]:
+ - button [ref=e291] [cursor=pointer]
+ - button [ref=e293] [cursor=pointer]
+ - navigation "breadcrumb" [ref=e298]:
+ - list [ref=e299]:
+ - listitem [ref=e300]:
+ - link "棣栭〉" [disabled] [ref=e301]
+ - generic [ref=e305]:
+ - generic [ref=e307] [cursor=pointer]:
+ - generic [ref=e311]: 鎼滅储
+ - generic [ref=e312]: Ctrl K
+ - button [ref=e314] [cursor=pointer]
+ - button "dark" [ref=e319] [cursor=pointer]
+ - button [ref=e328] [cursor=pointer]
+ - button [ref=e334] [cursor=pointer]
+ - button [ref=e336] [cursor=pointer]
+ - button [ref=e342] [cursor=pointer]:
+ - button [ref=e344]
+ - button "宸ヤ綔鍙�" [ref=e348] [cursor=pointer]
+ - button [ref=e351] [cursor=pointer]:
+ - img "瓒呯骇绠$悊鍛�" [ref=e356]
+ - generic [ref=e358]:
+ - generic [ref=e359]: 棣栭〉
+ - generic [ref=e377]:
+ - button [ref=e378] [cursor=pointer]
+ - generic [ref=e385] [cursor=pointer]
+ - generic [ref=e389] [cursor=pointer]
+ - main [ref=e396]:
+ - generic [ref=e400]:
+ - generic [ref=e401]:
+ - generic [ref=e402]: 涓氬姟鍏ㄩ摼璺�
+ - generic [ref=e408]:
+ - generic [ref=e412] [cursor=pointer]:
+ - generic [ref=e413]: 鍝佺
+ - generic [ref=e414]: "0"
+ - generic [ref=e420] [cursor=pointer]:
+ - generic [ref=e421]: 浜х嚎
+ - generic [ref=e422]: "0"
+ - generic [ref=e428] [cursor=pointer]:
+ - generic [ref=e429]: 鐢熶骇鎵规
+ - generic [ref=e430]: "0"
+ - generic [ref=e436] [cursor=pointer]:
+ - generic [ref=e437]: 琚嬬爜
+ - generic [ref=e438]: "0"
+ - generic [ref=e444] [cursor=pointer]:
+ - generic [ref=e445]: 鎵樼洏鐮�
+ - generic [ref=e446]: "0"
+ - generic [ref=e452] [cursor=pointer]:
+ - generic [ref=e453]: 閿�鍞嚭搴�
+ - generic [ref=e454]: "0"
+ - generic [ref=e460] [cursor=pointer]:
+ - generic [ref=e461]: 娴侀�氭壂鐮�
+ - generic [ref=e462]: "0"
+ - generic [ref=e468] [cursor=pointer]:
+ - generic [ref=e469]: 闃茬獪/婧簮
+ - generic [ref=e470]: "0"
+ - generic [ref=e471]:
+ - generic [ref=e478] [cursor=pointer]:
+ - generic [ref=e479]: 鍝佺鎬绘暟
+ - generic [ref=e480]: "0"
+ - generic [ref=e481]: 鍩虹鏁版嵁
+ - generic [ref=e488] [cursor=pointer]:
+ - generic [ref=e489]: 鐢熶骇鎵规
+ - generic [ref=e490]: "0"
+ - generic [ref=e491]: 涓�琚嬩竴鐮�
+ - generic [ref=e498] [cursor=pointer]:
+ - generic [ref=e499]: 琚嬬爜
+ - generic [ref=e500]: "0"
+ - generic [ref=e501]: 璧嬬爜
+ - generic [ref=e508] [cursor=pointer]:
+ - generic [ref=e509]: 鎵樼洏鐮�
+ - generic [ref=e510]: "0"
+ - generic [ref=e511]: 鎵樼洏
+ - generic [ref=e518] [cursor=pointer]:
+ - generic [ref=e519]: 閿�鍞嚭搴撳崟
+ - generic [ref=e520]: "0"
+ - generic [ref=e521]: 鍑哄簱娴侀��
+ - generic [ref=e528] [cursor=pointer]:
+ - generic [ref=e529]: 绱鎵爜
+ - generic [ref=e530]: "0"
+ - generic [ref=e531]: 婧簮
+ - generic [ref=e538] [cursor=pointer]:
+ - generic [ref=e539]: 搴撳瓨棰勮
+ - generic [ref=e540]: "0"
+ - generic [ref=e541]: 浠撳偍
+ - generic [ref=e548] [cursor=pointer]:
+ - generic [ref=e549]: 寰呰瘎瀹′笉鍚堟牸
+ - generic [ref=e550]: "0"
+ - generic [ref=e551]: 璐ㄩ噺
+ - generic [ref=e552]:
+ - generic [ref=e556]:
+ - generic [ref=e557]: 琚嬬爜鐢熸垚瓒嬪娍
+ - generic [ref=e559]:
+ - generic [ref=e560] [cursor=pointer]:
+ - generic [ref=e561]:
+ - radio "杩� 7 澶�" [checked]
+ - generic [ref=e562]: 杩� 7 澶�
+ - generic [ref=e563] [cursor=pointer]:
+ - generic [ref=e564]:
+ - radio "杩� 30 澶�"
+ - generic [ref=e565]: 杩� 30 澶�
+ - generic [ref=e568]: 娑堣垂鑰呮壂鐮佸湴鍖哄垎甯�
+ - generic [ref=e577]:
+ - generic [ref=e578]: 鎵规鐘舵�佸垎甯�
+ - generic [ref=e585]: 琚嬬爜鐘舵�佸垎甯�
+ - generic [ref=e593]:
+ - generic [ref=e594]: 寰呭姙涓庨璀�
+ - generic [ref=e598]:
+ - generic [ref=e602] [cursor=pointer]:
+ - generic [ref=e603]: 绐滆揣棰勮
+ - generic [ref=e604]: 寰呭鐞嗙殑绐滆揣棰勮
+ - generic [ref=e608] [cursor=pointer]:
+ - generic [ref=e609]: 搴撳瓨棰勮
+ - generic [ref=e610]: 鏈鐞嗙殑搴撳瓨棰勮
+ - generic [ref=e614] [cursor=pointer]:
+ - generic [ref=e615]: 涓嶅悎鏍煎搧
+ - generic [ref=e616]: 寰呰瘎瀹$殑涓嶅悎鏍煎搧鍗�
+ - generic [ref=e617]:
+ - generic [ref=e618]: 蹇嵎鍏ュ彛
+ - generic [ref=e622]:
+ - generic [ref=e624]:
+ - generic [ref=e625]: 鍩虹鏁版嵁
+ - generic [ref=e626]:
+ - generic [ref=e627] [cursor=pointer]: 鍝佺绠$悊
+ - generic [ref=e630] [cursor=pointer]: 鍝佺鍒嗙被
+ - generic [ref=e633] [cursor=pointer]: 璁¢噺鍗曚綅
+ - generic [ref=e637]:
+ - generic [ref=e638]: 涓�琚嬩竴鐮佺敓浜�
+ - generic [ref=e639]:
+ - generic [ref=e640] [cursor=pointer]: 浜х嚎缁存姢
+ - generic [ref=e643] [cursor=pointer]: 鎵规鐢熶骇
+ - generic [ref=e646] [cursor=pointer]: 璧嬬爜绠$悊
+ - generic [ref=e649] [cursor=pointer]: 鎵樼洏鐮�
+ - generic [ref=e652] [cursor=pointer]: 鎵爜鍏ュ簱
+ - generic [ref=e656]:
+ - generic [ref=e657]: 鍑哄簱娴侀��
+ - generic [ref=e658]:
+ - generic [ref=e659] [cursor=pointer]: 鍙戣揣閫氱煡
+ - generic [ref=e662] [cursor=pointer]: 閿�鍞嚭搴�
+ - generic [ref=e665] [cursor=pointer]: 閿�鍞��璐�
+ - generic [ref=e669]:
+ - generic [ref=e670]: 闃蹭吉闃茬獪璐�
+ - generic [ref=e671]:
+ - generic [ref=e672] [cursor=pointer]: 绐滆揣棰勮
+ - generic [ref=e675] [cursor=pointer]: 鎵爜鍦扮悊鍒嗗竷
+ - generic [ref=e678] [cursor=pointer]: 瀹屾暣鎬ф牎楠�
+ - generic [ref=e682]:
+ - generic [ref=e683]: 婧簮鍒嗘瀽
+ - generic [ref=e684]: 娑堣垂鑰呮壂鐮佺粺璁�
+ - generic [ref=e689]:
+ - generic [ref=e690]: 浠撳偍鐗╂祦
+ - generic [ref=e691]:
+ - generic [ref=e692] [cursor=pointer]: 浠撳簱璁剧疆
+ - generic [ref=e695] [cursor=pointer]: 搴撳瓨鐜版湁閲�
+ - generic [ref=e698] [cursor=pointer]: 搴撳瓨棰勮
+ - generic [ref=e701] [cursor=pointer]: 杞Щ璋冩嫧
+ - generic [ref=e705]:
+ - generic [ref=e706]: 璐ㄩ噺绠$悊
+ - generic [ref=e707]:
+ - generic [ref=e708] [cursor=pointer]: 鎵规杩芥函
+ - generic [ref=e711] [cursor=pointer]: 涓嶅悎鏍煎搧
+ - generic [ref=e714] [cursor=pointer]: 绉嶅瓙璐ㄦ
+ - generic [ref=e719]:
+ - generic [ref=e721]:
+ - img "check-circle" [ref=e722]
+ - generic [ref=e726]: 鐧诲綍鎴愬姛
+ - generic [ref=e727]: 娆㈣繋鍥炴潵:瓒呯骇绠$悊鍛�
+ - img "close" [ref=e730] [cursor=pointer]
\ No newline at end of file
diff --git a/.playwright-mcp/page-2026-10-19T06-22-10-596Z.yml b/.playwright-mcp/page-2026-10-19T06-22-10-596Z.yml
new file mode 100644
index 0000000..6adf37e
--- /dev/null
+++ b/.playwright-mcp/page-2026-10-19T06-22-10-596Z.yml
@@ -0,0 +1 @@
+- generic [active]: 宸ヤ笟AI鏅洪�犲钩鍙�
\ No newline at end of file
diff --git a/.playwright-mcp/page-2026-10-19T06-22-35-986Z.yml b/.playwright-mcp/page-2026-10-19T06-22-35-986Z.yml
new file mode 100644
index 0000000..6adf37e
--- /dev/null
+++ b/.playwright-mcp/page-2026-10-19T06-22-35-986Z.yml
@@ -0,0 +1 @@
+- generic [active]: 宸ヤ笟AI鏅洪�犲钩鍙�
\ No newline at end of file
diff --git a/docs/production_quality_flow_20261019.md b/docs/production_quality_flow_20261019.md
index 20ae47f..f0e2c89 100644
--- a/docs/production_quality_flow_20261019.md
+++ b/docs/production_quality_flow_20261019.md
@@ -1,37 +1,27 @@
-# 鐢熶骇璐ㄦ娴佺▼涓庤彍鍗曟槧灏�
+# 绉嶅瓙璐ㄦ娴佺▼
-渚濇嵁鐢ㄦ埛鎻愪緵鐨勭敓浜ф祦绋嬪浘鍜屽綋鍓� `system_menu`锛屼繚鐣欏凡鏈夎川閲忕鐞嗚彍鍗曪紝鏂板鈥滈攢鍞川妫�鈥濆叆鍙c��
+鎸夎鐮佷繚瀛樿川妫�璁板綍锛涙墭鐩樼爜銆佹壒娆$爜鎻愪氦鏃讹紝姣忚鐢熸垚鐙珛璁板綍銆傜函搴︺�佸噣搴︺�佸彂鑺界巼銆佹按鍒嗗洓椤规寚鏍囧湪鍒濇銆侀噸鏂板垵妫�鍜屽妫�涓竴鑷淬�傛瘡娆℃楠屼繚瀛樻寚鏍囧揩鐓с�佹搷浣滀汉銆佹椂闂村拰涓嶅悎鏍煎師鍥犮��
-| 娴佺▼鍥捐妭鐐� | 绯荤粺鍏ュ彛 | 瀹炵幇 |
+璐ㄦ椤瑰悎鏍艰寖鍥撮厤缃〉缁存姢鍥涢」鎸囨爣鐨勯粯璁ょ櫨鍒嗘瘮涓婁笅闄愶紙鍚竟鐣岋級銆傝繖鏄~鍐欐ā鏉匡紱鏈厤缃椂鍙墜鍔ㄥ~鍐欙紝鍒濇銆侀噸鏂板垵妫�鍜屽妫�鍧囧彲淇敼鏈鑼冨洿銆傛湇鍔$鎸夋湰娆℃彁浜ょ殑瀹炴祴鍊煎拰鑼冨洿鍒ゅ畾锛屽苟淇濆瓨鑼冨洿蹇収锛涢厤缃洿鏂颁笉鏀瑰彉鍘嗗彶璁板綍銆傛闈㈢鍜屾祻瑙堝櫒绉诲姩绔潎鍙壂鎻忔墭鐩樼爜鎴栫敓浜ф壒娆$爜锛屾壒閲忓鐞嗚鑼冨洿鍐呭悓涓�寰呮鐘舵�佺殑鍏ㄩ儴琚嬬爜锛涙彁浜ゆ椂閲嶆柊鏍稿娓呭崟锛屼换涓�琚嬪け璐ュ垯鏁存壒鍥炴粴銆�
+
+| 鐘舵�� | 杩涘叆鏉′欢 | 涓嬩竴姝� |
| --- | --- | --- |
-| 48/100 琚嬫壂鐮佸叆搴撱�佺敓鎴愭墭鐩樼爜 | 涓�琚嬩竴鐮� / 浠撳偍鐗╂祦 | 鏃㈡湁琚嬬爜銆佹墭鐩樼爜銆佹壒娆$爜 |
-| 鍔犲伐閮ㄥ垵妫� | 璐ㄩ噺绠$悊 / 绉嶅瓙璐ㄦ | 鍙寜琚嬨�佹墭鐩樸�佹壒娆℃彁浜わ紱姣忚鐙珛璁板綍 |
-| 鍒濇涓嶅悎鏍笺�佸妫� | 璐ㄩ噺绠$悊 / 璐ㄦ璁板綍 | 淇濈暀鏆傚瓨搴撳瓨锛岃褰曞妫�缁撴灉涓庡巻娆℃寚鏍� |
-| 鍔犲伐閮ㄩ瀵煎鎵� | 璐ㄩ噺绠$悊 / 璐ㄦ璁板綍 | 鍗曟潯鎴栧悓鐘舵�佹壒閲忓鎵癸紝鍙┏鍥為噸妫� |
-| 鍏徃璐ㄦ瀹℃壒 | 璐ㄩ噺绠$悊 / 璐ㄦ璁板綍 | 鍗曟潯鎴栧悓鐘舵�佹壒閲忓鎵癸紱閫氳繃鍚庢墠杩佺Щ鎴栨姤搴熷簱瀛� |
-| 閿�鍞儴璐ㄦ | 璐ㄩ噺绠$悊 / 閿�鍞川妫� | 鐙珛鑿滃崟锛屽鐢ㄦ棦鏈� OQC 閿�鍞嚭搴撳崟妫�楠屽崟 |
-| 閿�鍞妫�涓庡鎵� | 璐ㄩ噺绠$悊 / 閿�鍞川妫� | 涓嶅悎鏍煎厛澶嶆锛岄攢鍞儴涓庡叕鍙歌川妫�瀹℃壒鍚庡洖鍐欏嚭搴撹川閲忕姸鎬� |
-| 涓嶅悎鏍煎搧鐣欑棔璇勫 | 璐ㄩ噺绠$悊 / 涓嶅悎鏍煎搧澶勭悊 | 鏃㈡湁 OQC/IPQC 鑷姩鍒涘缓 NCR |
-| 姝e紡鍏ュ簱銆佸嚭搴撱�佹壂鐮佽拷婧� | 浠撳偍鐗╂祦 / 鍑哄簱娴侀�� / 杩芥函 | 瀹℃壒鏀捐鍚庤鐮� `qc_status=20`锛涙湭鏀捐涓嶈兘鎵爜鍑哄簱 |
+| 20 寰呭垵妫�瀹℃牳 | 鍒濇鍚堟牸 | 閫氳繃 鈫� 10锛涢┏鍥� 鈫� 50 |
+| 25 寰呭垵妫�涓嶅悎鏍煎鐞� | 鍒濇涓嶅悎鏍� | 纭骞跺畨鎺掑妫� 鈫� 10锛涢┏鍥炲師妫�楠� 鈫� 50 |
+| 50 鍒濇椹冲洖寰呴噸妫� | 鍒濇瀹℃牳椹冲洖 | 閲嶆柊褰曞叆鍥涢」鎸囨爣 鈫� 20 鎴� 25 |
+| 10 寰呭妫� | 鍒濇瀹℃牳閫氳繃锛屾垨澶嶆瀹℃牳椹冲洖 | 褰曞叆鍥涢」鎸囨爣 鈫� 30 鎴� 60 |
+| 30 寰呭妫�瀹℃牳 | 澶嶆鍚堟牸 | 閫氳繃 鈫� 40锛涢┏鍥� 鈫� 10 |
+| 60 寰呭妫�涓嶅悎鏍煎鐞� | 澶嶆涓嶅悎鏍� | 纭鎶ュ簾 鈫� 70锛涢┏鍥為噸鏂板妫� 鈫� 10 |
+| 40 宸叉斁琛� | 澶嶆鍚堟牸涓斿鏍搁�氳繃 | 琚嬬爜杞叆閫夊畾鍚堟牸搴� |
+| 70 宸叉姤搴� | 澶嶆涓嶅悎鏍间笖瀹℃牳纭 | 鏆傚瓨搴撳瓨鎵e噺骞舵姤搴熻鐮� |
-## 绉嶅瓙璐ㄦ鐘舵��
+鍒濇涓庡妫�鏈熼棿搴撳瓨鐣欏湪鏆傚瓨搴撱�傚彧鏈夋渶缁堝鏍搁�氳繃鎵嶅彂鐢熷簱瀛樹簨鍔°�備笉鍚堟牸妫�楠屽繀椤诲~鍐欏師鍥狅紱澶勭疆浜洪渶濉啓瀹℃牳鎰忚銆傚妫�涓嶅悎鏍肩‘璁ゆ椂鏄庣‘鎵ц鎶ュ簾锛岄┏鍥炲垯閫�鍥炲妫�銆傛壒閲忓鏍稿湪鍚屼竴浜嬪姟鍐呭畬鎴愶紝浠讳竴琚嬪簱瀛樻祦杞け璐ュ垯鍏ㄩ儴鍥炴粴銆�
-- 10 寰呭妫�锛氬垵妫�澶辫触鎴栧鎵归┏鍥烇紱搴撳瓨浠嶅湪鏆傚瓨搴撱��
-- 20 寰呭姞宸ラ儴瀹℃壒锛氬垵妫�鎴栧妫�鍚堟牸銆�
-- 30 寰呭叕鍙歌川妫�瀹℃壒锛氬姞宸ラ儴鍚屾剰鏀捐銆�
-- 40 宸叉斁琛岋細鍏徃璐ㄦ鍚屾剰锛屼簨鍔℃�у湴灏嗚琚嬬敱鏆傚瓨搴撶Щ鍏ュ悎鏍煎簱銆�
-- 50 寰呭姞宸ラ儴涓嶅悎鏍艰瘎瀹★細澶嶆涓嶅悎鏍笺��
-- 60 寰呭叕鍙镐笉鍚堟牸瀹℃壒锛氬姞宸ラ儴鍚屾剰鎶ュ簾銆�
-- 70 宸叉姤搴燂細鍏徃璐ㄦ鍚屾剰锛屼簨鍔℃�у湴绉婚櫎璇ヨ鏆傚瓨搴撳瓨銆�
+鈥滆川妫�瀹℃牳浜洪厤缃�濅粎缁存姢绉嶅瓙璐ㄦ鐨勫垵妫�瀹℃牳锛堣妭鐐� 1锛夊拰澶嶆瀹℃牳锛堣妭鐐� 3锛夛紝鏀寔澶氫汉鍜屽仠鐢ㄣ�傛湇鍔$鍚屾椂鏍¢獙鎸夐挳鏉冮檺涓庡綋鍓嶅鏍镐汉閰嶇疆锛涜秴绾х鐞嗗憳鍙烦杩囧鏍镐汉閰嶇疆鏍¢獙銆傚師 process-approve / company-approve 鎺ュ彛鍙婃潈闄愮爜淇濈暀锛屽吋瀹瑰凡鍒嗛厤瑙掕壊銆�
-瀹℃壒椹冲洖鍥炲埌 10銆傛瘡娆″垵妫�銆佸妫�鍜屽鎵瑰啓鍏� `mes_qc_seed_quality_action`锛屽寘鍚搷浣滀汉銆佹椂闂淬�佹剰瑙佸拰妫�楠屾寚鏍囧揩鐓с�傛壒閲忓鎵瑰湪鍚屼竴鏁版嵁搴撲簨鍔″唴鎵ц锛屼换涓�琚嬪簱瀛樻祦杞け璐ュ垯鍏ㄩ儴鍥炴粴銆�
+## 閮ㄧ讲
-閿�鍞川妫�鐨勬祦绋嬬姸鎬佷笌绉嶅瓙璐ㄦ鐩稿悓锛屽叾涓� 20/50 鐢遍攢鍞儴瀹℃壒锛�40 琛ㄧず鍑鸿揣妫�楠岄�氳繃骞跺洖鍐欓攢鍞嚭搴撳崟琛岋紝70 琛ㄧず涓嶅悎鏍煎鎵瑰畬鎴愬苟鍥炲啓涓轰笉鍚堟牸锛屽悓鏃跺垱寤� NCR銆傚垵妫�涓庡妫�涓嶅洖鍐欏嚭搴撳崟璐ㄩ噺缁撴灉锛屽洜姝ゅ鎵瑰墠浠嶅浜庡緟妫�鐘舵�併�傚妫�鍓嶅悗鏁伴噺鍙婂鎵规剰瑙佸啓鍏� `mes_qc_oqc_action`銆�
-
-## 閮ㄧ讲椤哄簭
-
-1. 澶囦唤鏁版嵁搴擄紝鎵ц `sql/mysql/mes_seed_quality_workflow_20261019.sql`銆傝剼鏈槸涓�娆℃�ц縼绉伙紱鍘嗗彶宸叉祦杞殑鍚堟牸/涓嶅悎鏍艰褰曞垎鍒爣璁颁负 40/70锛岄伩鍏嶉噸澶嶅簱瀛樹簨鍔°��
-2. 閮ㄧ讲鍚庣銆佸墠绔�傚墠绔瀯寤轰骇鐗╁湪 `mom-pro2-before/dist.zip`銆�
-3. 涓哄姞宸ラ儴涓庡叕鍙歌川妫�瑙掕壊鍒嗗埆鎺堜簣 `mes:qc-seed-quality:process-approve`銆乣mes:qc-seed-quality:company-approve`锛涘妫�浜哄憳鎺堜簣 `mes:qc-seed-quality:retest`銆備负閿�鍞儴涓庡叕鍙歌川妫�瑙掕壊鍒嗗埆鎺堜簣 `mes:qc-oqc:sales-approve`銆乣mes:qc-oqc:company-approve`锛涢攢鍞妫�浜哄憳鎺堜簣 `mes:qc-oqc:retest`銆傛牳瀵光�滈攢鍞川妫�鈥濊彍鍗曡鑹叉潈闄愩��
-
-鈥滈攢鍞川妫�鈥濅笌鍘熲�滃嚭璐ф楠屸�濆叡鐢� OQC 妫�楠屽崟鍙婃棦鏈夊嚭璐ф楠岃〃鍗曪紝浣嗘湁鐙珛鑿滃崟涓庝笓闂ㄧ殑澶嶆銆佸鎵规搷浣溿�傚師鈥滆繃绋嬫楠岋紙IPQC锛夆�濅粛鏈嶅姟鐢熶骇浠诲姟鍜屾姤宸ワ紝鏈苟鍏ユ寜琚嬬爜娴佽浆鐨勭瀛愯川妫�瀹℃壒閾俱��
+1. 澶囦唤鏁版嵁搴擄紝鎵ц sql/mysql/mes_seed_quality_workflow_20261019.sql銆傚巻鍙插凡娴佽浆璁板綍鏍囦负宸叉斁琛屾垨宸叉姤搴燂紝閬垮厤閲嶅搴撳瓨浜嬪姟銆�
+2. 鎵ц sql/mysql/mes_qc_oqc_retest_approver_20261019.sql锛屽垱寤哄鏍镐汉閰嶇疆涓庤彍鍗曘�傝鑴氭湰浠呮秹鍙婄瀛愯川妫�锛屼笉淇敼鍏朵粬璐ㄦ琛ㄣ��
+3. 鎵ц sql/mysql/mes_qc_seed_indicator_range_20261019.sql锛屽垱寤鸿寖鍥存ā鏉胯〃鍜岄〉闈㈣彍鍗曪紱涓虹鐞嗗憳鍒嗛厤 mes:qc-seed-range:query銆乵es:qc-seed-range:update 鏉冮檺銆傚缓璁厤缃畬鏁村洓椤归粯璁よ寖鍥淬��
+4. 閮ㄧ讲鍚庣鍜� mom-pro2-before 鍓嶇銆傚垎閰� mes:qc-seed-quality:retest銆乵es:qc-seed-quality:process-approve銆乵es:qc-seed-quality:company-approve 鏉冮檺锛屽苟鍦ㄥ鏍镐汉閰嶇疆涓寚瀹氫袱鑺傜偣瀹℃牳浜恒��
diff --git a/sql/mysql/mes_qc_oqc_retest_approver_20261019.sql b/sql/mysql/mes_qc_oqc_retest_approver_20261019.sql
new file mode 100644
index 0000000..afd80d5
--- /dev/null
+++ b/sql/mysql/mes_qc_oqc_retest_approver_20261019.sql
@@ -0,0 +1,39 @@
+-- 璐ㄦ瀹℃牳浜洪厤缃細浠呯瀛愯川妫�锛氭寜鍒濇瀹℃牳/澶嶆瀹℃牳鑺傜偣缁存姢锛屽彲閰嶇疆澶氫汉銆�
+CREATE TABLE IF NOT EXISTS mes_qc_approver_config (
+ id bigint NOT NULL AUTO_INCREMENT,
+ qc_type tinyint NOT NULL COMMENT '璐ㄦ绫诲瀷锛�1绉嶅瓙璐ㄦ',
+ approve_node tinyint NOT NULL COMMENT '瀹℃牳鑺傜偣锛�1鍒濇瀹℃牳 3澶嶆瀹℃牳',
+ user_id bigint NOT NULL COMMENT '瀹℃牳浜虹敤鎴稩D',
+ status tinyint NOT NULL DEFAULT 0 COMMENT '鐘舵�侊細0鍚敤 1鍋滅敤',
+ remark varchar(255) DEFAULT NULL COMMENT '澶囨敞',
+ creator varchar(64) DEFAULT '',
+ create_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ updater varchar(64) DEFAULT '',
+ update_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ deleted bit(1) NOT NULL DEFAULT b'0',
+ PRIMARY KEY (id),
+ KEY idx_qc_type_node (qc_type, approve_node)
+) ENGINE=InnoDB COMMENT='璐ㄦ瀹℃牳浜洪厤缃�';
+
+-- 璐ㄩ噺绠$悊 / 璐ㄦ瀹℃牳浜� 鑿滃崟鍙婃寜閽潈闄�
+INSERT INTO system_menu (name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted)
+SELECT '璐ㄦ瀹℃牳浜�', '', 2, 9, 5500, 'approver-config', 'ep:user', 'mes/qc/approverConfig/index', 'MesQcApproverConfig', 0, b'1', b'1', b'1', '1', NOW(), '1', NOW(), b'0'
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM system_menu WHERE parent_id = 5500 AND path = 'approver-config' AND deleted = b'0');
+
+INSERT INTO system_menu (name, permission, type, sort, parent_id, path, icon, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted)
+SELECT '鏌ヨ', 'mes:qc-approver:query', 3, 1, id, '', '', 0, b'1', b'1', b'1', '1', NOW(), '1', NOW(), b'0'
+FROM system_menu WHERE parent_id = 5500 AND path = 'approver-config' AND deleted = b'0'
+ AND NOT EXISTS (SELECT 1 FROM system_menu m WHERE m.parent_id = system_menu.id AND m.permission = 'mes:qc-approver:query' AND m.deleted = b'0');
+INSERT INTO system_menu (name, permission, type, sort, parent_id, path, icon, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted)
+SELECT '鏂板', 'mes:qc-approver:create', 3, 2, id, '', '', 0, b'1', b'1', b'1', '1', NOW(), '1', NOW(), b'0'
+FROM system_menu WHERE parent_id = 5500 AND path = 'approver-config' AND deleted = b'0'
+ AND NOT EXISTS (SELECT 1 FROM system_menu m WHERE m.parent_id = system_menu.id AND m.permission = 'mes:qc-approver:create' AND m.deleted = b'0');
+INSERT INTO system_menu (name, permission, type, sort, parent_id, path, icon, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted)
+SELECT '淇敼', 'mes:qc-approver:update', 3, 3, id, '', '', 0, b'1', b'1', b'1', '1', NOW(), '1', NOW(), b'0'
+FROM system_menu WHERE parent_id = 5500 AND path = 'approver-config' AND deleted = b'0'
+ AND NOT EXISTS (SELECT 1 FROM system_menu m WHERE m.parent_id = system_menu.id AND m.permission = 'mes:qc-approver:update' AND m.deleted = b'0');
+INSERT INTO system_menu (name, permission, type, sort, parent_id, path, icon, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted)
+SELECT '鍒犻櫎', 'mes:qc-approver:delete', 3, 4, id, '', '', 0, b'1', b'1', b'1', '1', NOW(), '1', NOW(), b'0'
+FROM system_menu WHERE parent_id = 5500 AND path = 'approver-config' AND deleted = b'0'
+ AND NOT EXISTS (SELECT 1 FROM system_menu m WHERE m.parent_id = system_menu.id AND m.permission = 'mes:qc-approver:delete' AND m.deleted = b'0');
+
diff --git a/sql/mysql/mes_qc_remove_sales_quality_20261019.sql b/sql/mysql/mes_qc_remove_sales_quality_20261019.sql
new file mode 100644
index 0000000..c9a022d
--- /dev/null
+++ b/sql/mysql/mes_qc_remove_sales_quality_20261019.sql
@@ -0,0 +1,28 @@
+-- 涓嬬嚎閿�鍞川妫�涓氬姟绾匡細閫昏緫鍒犻櫎鈥滈攢鍞川妫�鈥濊彍鍗曞強鎸夐挳鏉冮檺锛屾竻鐞嗛攢鍞川妫�瀹℃牳浜洪厤缃��
+-- 鍑鸿揣妫�楠岋紙OQC锛夊熀纭�鍔熻兘淇濈暀銆�
+
+-- 1. 鍒犻櫎閿�鍞川妫�鎸夐挳鏉冮檺
+UPDATE system_menu SET deleted = b'1', update_time = NOW()
+WHERE deleted = b'0'
+ AND permission IN ('mes:qc-oqc:retest', 'mes:qc-oqc:sales-approve', 'mes:qc-oqc:company-approve');
+
+-- 2. 閫昏緫鍒犻櫎鈥滈攢鍞川妫�鈥濊彍鍗�
+UPDATE system_menu SET deleted = b'1', update_time = NOW()
+WHERE deleted = b'0' AND parent_id = 5500 AND path = 'sales-quality';
+
+-- 3. 娓呯悊瑙掕壊涓庨攢鍞川妫�鑿滃崟鐨勫叧鑱旓紙system_role_menu 鏃� deleted 鍒楋紝鐗╃悊鍒犻櫎锛�
+DELETE rm FROM system_role_menu rm
+JOIN system_menu m ON rm.menu_id = m.id
+WHERE m.permission IN ('mes:qc-oqc:retest', 'mes:qc-oqc:sales-approve', 'mes:qc-oqc:company-approve')
+ OR (m.parent_id = 5500 AND m.path = 'sales-quality');
+
+-- 4. 閫昏緫鍒犻櫎閿�鍞川妫�瀹℃牳浜洪厤缃�
+UPDATE mes_qc_approver_config SET deleted = b'1', update_time = NOW()
+WHERE deleted = b'0' AND qc_type = 2;
+
+-- 鍙�夛細纭鏃犲巻鍙叉暟鎹悗锛屽啀娓呯悊閿�鍞川妫�閬楃暀鐨勮〃缁撴瀯涓庡瓧娈�
+-- DROP TABLE IF EXISTS mes_qc_oqc_action;
+-- ALTER TABLE mes_qc_oqc
+-- DROP COLUMN workflow_status,
+-- DROP COLUMN inspection_round,
+-- DROP COLUMN retest_of_id;
diff --git a/sql/mysql/mes_qc_seed_indicator_range_20261019.sql b/sql/mysql/mes_qc_seed_indicator_range_20261019.sql
new file mode 100644
index 0000000..40ef471
--- /dev/null
+++ b/sql/mysql/mes_qc_seed_indicator_range_20261019.sql
@@ -0,0 +1,25 @@
+-- 绉嶅瓙璐ㄦ鍥涢」鍚堟牸鑼冨洿妯℃澘銆傚垵妫�涓庡妫�鍙慨鏀规湰娆¤寖鍥达紝鎸夊疄闄呮彁浜ゅ�煎垽瀹氥��
+CREATE TABLE IF NOT EXISTS mes_qc_seed_indicator_range (
+ indicator_code varchar(32) NOT NULL COMMENT 'purity/cleanliness/germination_rate/moisture',
+ min_value decimal(18,6) NOT NULL COMMENT '鍚堟牸涓嬮檺锛屽惈杈圭晫',
+ max_value decimal(18,6) NOT NULL COMMENT '鍚堟牸涓婇檺锛屽惈杈圭晫',
+ creator varchar(64) DEFAULT '',
+ create_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ updater varchar(64) DEFAULT '',
+ update_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ deleted bit(1) NOT NULL DEFAULT b'0',
+ PRIMARY KEY (indicator_code)
+) ENGINE=InnoDB COMMENT='绉嶅瓙璐ㄦ椤瑰悎鏍艰寖鍥撮厤缃�';
+
+INSERT INTO system_menu (name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted)
+SELECT '璐ㄦ椤瑰悎鏍艰寖鍥撮厤缃�', '', 2, 10, 5500, 'seed-range', 'ep:data-analysis', 'mes/qc/seedRange/index', 'MesQcSeedRange', 0, b'1', b'1', b'1', '1', NOW(), '1', NOW(), b'0'
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM system_menu WHERE parent_id = 5500 AND path = 'seed-range' AND deleted = b'0');
+
+INSERT INTO system_menu (name, permission, type, sort, parent_id, path, icon, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted)
+SELECT '鏌ヨ', 'mes:qc-seed-range:query', 3, 1, id, '', '', 0, b'1', b'1', b'1', '1', NOW(), '1', NOW(), b'0'
+FROM system_menu WHERE parent_id = 5500 AND path = 'seed-range' AND deleted = b'0'
+ AND NOT EXISTS (SELECT 1 FROM system_menu m WHERE m.parent_id = system_menu.id AND m.permission = 'mes:qc-seed-range:query' AND m.deleted = b'0');
+INSERT INTO system_menu (name, permission, type, sort, parent_id, path, icon, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted)
+SELECT '淇敼', 'mes:qc-seed-range:update', 3, 2, id, '', '', 0, b'1', b'1', b'1', '1', NOW(), '1', NOW(), b'0'
+FROM system_menu WHERE parent_id = 5500 AND path = 'seed-range' AND deleted = b'0'
+ AND NOT EXISTS (SELECT 1 FROM system_menu m WHERE m.parent_id = system_menu.id AND m.permission = 'mes:qc-seed-range:update' AND m.deleted = b'0');
diff --git a/sql/mysql/mes_seed_quality_workflow_20261019.sql b/sql/mysql/mes_seed_quality_workflow_20261019.sql
index d639fcb..8fe07d0 100644
--- a/sql/mysql/mes_seed_quality_workflow_20261019.sql
+++ b/sql/mysql/mes_seed_quality_workflow_20261019.sql
@@ -1,7 +1,7 @@
--- 鐢熶骇璐ㄦ锛氬垵妫�銆佸妫�銆佸姞宸ラ儴瀹℃壒銆佸叕鍙歌川妫�瀹℃壒鍚庢墠鏀捐搴撳瓨銆�
+-- 鐢熶骇璐ㄦ锛氬垵妫�瀹℃牳銆佸妫�銆佸妫�瀹℃牳鍚庢墠鏀捐鎴栧缃簱瀛樸��
-- 鍏堥儴缃叉暟鎹簱鍙樻洿锛屽啀閮ㄧ讲瀵瑰簲鍚庣涓庡墠绔紱鍘嗗彶鍚堟牸璁板綍宸插畬鎴愬簱瀛樻祦杞��
ALTER TABLE mes_qc_seed_quality
- ADD COLUMN workflow_status tinyint NOT NULL DEFAULT 40 COMMENT '10寰呭妫� 20寰呭姞宸ラ儴瀹℃壒 30寰呭叕鍙歌川妫�瀹℃壒 40宸叉斁琛� 50寰呭姞宸ラ儴涓嶅悎鏍艰瘎瀹� 60寰呭叕鍙镐笉鍚堟牸瀹℃壒 70宸叉姤搴�',
+ ADD COLUMN workflow_status tinyint NOT NULL DEFAULT 40 COMMENT '10寰呭妫� 20寰呭垵妫�瀹℃牳 25寰呭垵妫�涓嶅悎鏍煎鐞� 30寰呭妫�瀹℃牳 40宸叉斁琛� 50鍒濇椹冲洖寰呴噸妫� 60寰呭妫�涓嶅悎鏍煎鐞� 70宸叉姤搴�',
ADD COLUMN qualified_warehouse_id bigint DEFAULT NULL COMMENT '瀹℃壒閫氳繃鍚庣殑鐩爣鍚堟牸搴�',
ADD COLUMN retest_result tinyint DEFAULT NULL COMMENT '澶嶆缁撴灉 1鍚堟牸 2涓嶅悎鏍�',
ADD COLUMN retested_at datetime DEFAULT NULL COMMENT '澶嶆鏃堕棿',
@@ -30,49 +30,10 @@
FROM system_menu WHERE parent_id = 5500 AND path = 'seed-quality' AND deleted = b'0'
AND NOT EXISTS (SELECT 1 FROM system_menu m WHERE m.parent_id = system_menu.id AND m.permission = 'mes:qc-seed-quality:retest' AND m.deleted = b'0');
INSERT INTO system_menu (name, permission, type, sort, parent_id, path, icon, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted)
-SELECT '鍔犲伐閮ㄥ鎵�', 'mes:qc-seed-quality:process-approve', 3, 4, id, '', '', 0, b'1', b'1', b'1', '1', NOW(), '1', NOW(), b'0'
+SELECT '鍒濇瀹℃牳', 'mes:qc-seed-quality:process-approve', 3, 4, id, '', '', 0, b'1', b'1', b'1', '1', NOW(), '1', NOW(), b'0'
FROM system_menu WHERE parent_id = 5500 AND path = 'seed-quality' AND deleted = b'0'
AND NOT EXISTS (SELECT 1 FROM system_menu m WHERE m.parent_id = system_menu.id AND m.permission = 'mes:qc-seed-quality:process-approve' AND m.deleted = b'0');
INSERT INTO system_menu (name, permission, type, sort, parent_id, path, icon, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted)
-SELECT '鍏徃璐ㄦ瀹℃壒', 'mes:qc-seed-quality:company-approve', 3, 5, id, '', '', 0, b'1', b'1', b'1', '1', NOW(), '1', NOW(), b'0'
+SELECT '澶嶆瀹℃牳', 'mes:qc-seed-quality:company-approve', 3, 5, id, '', '', 0, b'1', b'1', b'1', '1', NOW(), '1', NOW(), b'0'
FROM system_menu WHERE parent_id = 5500 AND path = 'seed-quality' AND deleted = b'0'
AND NOT EXISTS (SELECT 1 FROM system_menu m WHERE m.parent_id = system_menu.id AND m.permission = 'mes:qc-seed-quality:company-approve' AND m.deleted = b'0');
-
--- 鐙珛閿�鍞川妫�鍏ュ彛锛涗繚鐣欏師鈥滃嚭璐ф楠屸�濊彍鍗曪紝澶嶇敤鍏跺凡瀹炵幇鐨勯攢鍞嚭搴撳崟妫�楠岃兘鍔涖��
-INSERT INTO system_menu (name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted)
-SELECT '閿�鍞川妫�', '', 2, 8, 5500, 'sales-quality', 'ep:document-checked', 'mes/qc/salesQuality/index', 'MesQcSalesQuality', 0, b'1', b'1', b'1', '1', NOW(), '1', NOW(), b'0'
-FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM system_menu WHERE parent_id = 5500 AND path = 'sales-quality' AND deleted = b'0');
-
--- 閿�鍞川妫�澶嶆鍙婁袱绾у鎵癸紱鍘嗗彶宸插畬鎴愬嚭璐ф楠屽崟缁存寔鏃㈡湁鏀捐缁撴灉銆�
-ALTER TABLE mes_qc_oqc
- ADD COLUMN workflow_status tinyint NOT NULL DEFAULT 0 COMMENT '0鑽夌 10寰呭妫� 20寰呴攢鍞儴瀹℃壒 30寰呭叕鍙歌川妫�瀹℃壒 40宸叉斁琛� 50寰呴攢鍞儴涓嶅悎鏍艰瘎瀹� 60寰呭叕鍙镐笉鍚堟牸瀹℃壒 70宸叉嫆缁濆嚭璐�';
-CREATE INDEX idx_mes_oqc_workflow ON mes_qc_oqc (workflow_status, id);
-UPDATE mes_qc_oqc SET workflow_status = CASE
- WHEN status = 0 THEN 0
- WHEN check_result = 1 THEN 40
- ELSE 70 END;
-CREATE TABLE IF NOT EXISTS mes_qc_oqc_action (
- id bigint NOT NULL AUTO_INCREMENT,
- oqc_id bigint NOT NULL,
- action varchar(32) NOT NULL,
- result tinyint DEFAULT NULL,
- opinion varchar(500) DEFAULT NULL,
- quantities_json text DEFAULT NULL,
- operator_id bigint DEFAULT NULL,
- create_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
- PRIMARY KEY (id),
- KEY idx_oqc_time (oqc_id, create_time)
-) ENGINE=InnoDB COMMENT='閿�鍞川妫�澶嶆鍜屽鎵圭暀鐥�';
-
-INSERT INTO system_menu (name, permission, type, sort, parent_id, path, icon, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted)
-SELECT '閿�鍞妫�', 'mes:qc-oqc:retest', 3, 1, id, '', '', 0, b'1', b'1', b'1', '1', NOW(), '1', NOW(), b'0'
-FROM system_menu WHERE parent_id = 5500 AND path = 'sales-quality' AND deleted = b'0'
- AND NOT EXISTS (SELECT 1 FROM system_menu m WHERE m.parent_id = system_menu.id AND m.permission = 'mes:qc-oqc:retest' AND m.deleted = b'0');
-INSERT INTO system_menu (name, permission, type, sort, parent_id, path, icon, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted)
-SELECT '閿�鍞儴瀹℃壒', 'mes:qc-oqc:sales-approve', 3, 2, id, '', '', 0, b'1', b'1', b'1', '1', NOW(), '1', NOW(), b'0'
-FROM system_menu WHERE parent_id = 5500 AND path = 'sales-quality' AND deleted = b'0'
- AND NOT EXISTS (SELECT 1 FROM system_menu m WHERE m.parent_id = system_menu.id AND m.permission = 'mes:qc-oqc:sales-approve' AND m.deleted = b'0');
-INSERT INTO system_menu (name, permission, type, sort, parent_id, path, icon, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted)
-SELECT '閿�鍞叕鍙歌川妫�瀹℃壒', 'mes:qc-oqc:company-approve', 3, 3, id, '', '', 0, b'1', b'1', b'1', '1', NOW(), '1', NOW(), b'0'
-FROM system_menu WHERE parent_id = 5500 AND path = 'sales-quality' AND deleted = b'0'
- AND NOT EXISTS (SELECT 1 FROM system_menu m WHERE m.parent_id = system_menu.id AND m.permission = 'mes:qc-oqc:company-approve' AND m.deleted = b'0');
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/bagcode/MesProBagCodeController.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/bagcode/MesProBagCodeController.java
index dc7c482..1cb2a19 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/bagcode/MesProBagCodeController.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/bagcode/MesProBagCodeController.java
@@ -164,6 +164,13 @@
return success(new PageResult<>(buildBagCodeRespVOList(pageResult.getList()), pageResult.getTotal()));
}
+ @GetMapping("/unbound-ton-bags")
+ @Operation(summary = "鑾峰緱鍙粦瀹氱敓浜ф壒娆$殑鍚ㄨ")
+ @PreAuthorize("@ss.hasAnyPermissions('mes:pro-batch:create', 'mes:pro-batch:update', 'mes:pro-bag-code:query')")
+ public CommonResult<List<MesProBagCodeRespVO>> getUnboundTonBags() {
+ return success(buildBagCodeRespVOList(bagCodeService.getUnboundTonBags()));
+ }
+
@GetMapping("/list-by-uuid")
@Operation(summary = "鑾峰緱鐢熸垚缁勭殑琚嬬爜鍒楄〃")
@Parameter(name = "uuid", description = "鐢熸垚缁� UUID", required = true)
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/batch/MesProBatchController.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/batch/MesProBatchController.java
index a83a15b..68b397b 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/batch/MesProBatchController.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/batch/MesProBatchController.java
@@ -148,6 +148,7 @@
return success(null);
}
MesProBatchRespVO respVO = buildBatchRespVOList(Collections.singletonList(batch)).get(0);
+ respVO.setBindingMode(batchService.getBindingMode(id));
// 濉厖浜哄憳閰嶇疆
respVO.setWorkers(buildWorkerRespVOList(batchService.getBatchWorkerListByBatchId(id)));
return success(respVO);
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/batch/vo/MesProBatchRespVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/batch/vo/MesProBatchRespVO.java
index eb6fcba..f79e5eb 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/batch/vo/MesProBatchRespVO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/batch/vo/MesProBatchRespVO.java
@@ -34,6 +34,9 @@
private String tempCode;
@ExcelIgnore
private Long itemId;
+ @Schema(description = "宸叉湁缁戝畾鏂瑰紡锛歱allet 鎴� tonBag")
+ @ExcelIgnore
+ private String bindingMode;
@ExcelProperty("鍝佺缂栫爜")
private String itemCode;
@ExcelProperty("鍝佺鍚嶇О")
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/batch/vo/MesProBatchSaveReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/batch/vo/MesProBatchSaveReqVO.java
index e258f96..47f5142 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/batch/vo/MesProBatchSaveReqVO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/batch/vo/MesProBatchSaveReqVO.java
@@ -20,7 +20,7 @@
@Schema(description = "缂栧彿", example = "1024")
private Long id;
- @Schema(description = "鍝佺缂栧彿锛岀敱缁戝畾鎵樼洏甯﹀叆骞剁粡鍚庣鏍¢獙")
+ @Schema(description = "鍝佺缂栧彿锛岀敱缁戝畾鎵樼洏鎴栧惃琚嬪甫鍏ュ苟缁忓悗绔牎楠�")
private Long itemId;
@Schema(description = "浜х嚎缂栧彿锛堥〉闈㈠睍绀轰负銆屽姞宸ュ崟浣嶃�嶏級", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@@ -54,6 +54,9 @@
@Schema(description = "缁戝畾鎵樼洏缂栧彿鍒楄〃锛堝彲閫夛紱缁戝畾鏃舵壒娆$洿鎺ヨ繘鍏ョ敓浜т腑锛屾墭鐩樹笅琚嬬爜绾ц仈褰曞叆鏈壒娆★紱鏂板/琛ュ綍/缂栬緫鍧囧彲浼犲叆锛岀紪杈戞椂浠呴渶浼犳湰娆℃柊澧炲嬀閫夌殑鎵樼洏锛�")
private List<Long> palletIds;
+ @Schema(description = "缁戝畾鍚ㄨ缂栧彿鍒楄〃锛堜粎璁¢噺鍗曚綅涓哄惃涓旀棤鎵樼洏鐨勮鐮侊紱涓庣粦瀹氭墭鐩樹簰鏂ワ級")
+ private List<Long> tonBagIds;
+
@Schema(description = "鐢熶骇浜哄憳閰嶇疆")
@Data
public static class Worker {
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/approver/MesQcApproverConfigController.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/approver/MesQcApproverConfigController.java
new file mode 100644
index 0000000..79cb55c
--- /dev/null
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/approver/MesQcApproverConfigController.java
@@ -0,0 +1,88 @@
+package cn.iocoder.yudao.module.mes.controller.admin.qc.approver;
+
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.mes.controller.admin.qc.approver.vo.MesQcApproverConfigPageReqVO;
+import cn.iocoder.yudao.module.mes.controller.admin.qc.approver.vo.MesQcApproverConfigRespVO;
+import cn.iocoder.yudao.module.mes.controller.admin.qc.approver.vo.MesQcApproverConfigSaveReqVO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.qc.approver.MesQcApproverConfigDO;
+import cn.iocoder.yudao.module.mes.service.qc.approver.MesQcApproverService;
+import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
+import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.annotation.Resource;
+import jakarta.validation.Valid;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+import java.util.Map;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
+import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen;
+
+@Tag(name = "绠$悊鍚庡彴 - MES 璐ㄦ瀹℃牳浜洪厤缃�")
+@RestController
+@RequestMapping("/mes/qc/approver-config")
+@Validated
+public class MesQcApproverConfigController {
+
+ @Resource
+ private MesQcApproverService approverService;
+ @Resource
+ private AdminUserApi adminUserApi;
+
+ @PostMapping("/create")
+ @Operation(summary = "鍒涘缓璐ㄦ瀹℃牳浜洪厤缃�")
+ @PreAuthorize("@ss.hasPermission('mes:qc-approver:create')")
+ public CommonResult<Long> createConfig(@Valid @RequestBody MesQcApproverConfigSaveReqVO reqVO) {
+ return success(approverService.createConfig(reqVO));
+ }
+
+ @PutMapping("/update")
+ @Operation(summary = "鏇存柊璐ㄦ瀹℃牳浜洪厤缃�")
+ @PreAuthorize("@ss.hasPermission('mes:qc-approver:update')")
+ public CommonResult<Boolean> updateConfig(@Valid @RequestBody MesQcApproverConfigSaveReqVO reqVO) {
+ approverService.updateConfig(reqVO);
+ return success(true);
+ }
+
+ @DeleteMapping("/delete")
+ @Operation(summary = "鍒犻櫎璐ㄦ瀹℃牳浜洪厤缃�")
+ @Parameter(name = "id", description = "缂栧彿", required = true)
+ @PreAuthorize("@ss.hasPermission('mes:qc-approver:delete')")
+ public CommonResult<Boolean> deleteConfig(@RequestParam("id") Long id) {
+ approverService.deleteConfig(id);
+ return success(true);
+ }
+
+ @GetMapping("/get")
+ @Operation(summary = "鑾峰緱璐ㄦ瀹℃牳浜洪厤缃�")
+ @Parameter(name = "id", description = "缂栧彿", required = true)
+ @PreAuthorize("@ss.hasPermission('mes:qc-approver:query')")
+ public CommonResult<MesQcApproverConfigRespVO> getConfig(@RequestParam("id") Long id) {
+ MesQcApproverConfigDO config = approverService.getConfig(id);
+ return success(buildRespVOList(List.of(config)).get(0));
+ }
+
+ @GetMapping("/page")
+ @Operation(summary = "鑾峰緱璐ㄦ瀹℃牳浜洪厤缃垎椤�")
+ @PreAuthorize("@ss.hasPermission('mes:qc-approver:query')")
+ public CommonResult<PageResult<MesQcApproverConfigRespVO>> getConfigPage(@Valid MesQcApproverConfigPageReqVO pageReqVO) {
+ PageResult<MesQcApproverConfigDO> pageResult = approverService.getConfigPage(pageReqVO);
+ return success(new PageResult<>(buildRespVOList(pageResult.getList()), pageResult.getTotal()));
+ }
+
+ private List<MesQcApproverConfigRespVO> buildRespVOList(List<MesQcApproverConfigDO> list) {
+ Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(
+ convertSet(list, MesQcApproverConfigDO::getUserId));
+ return BeanUtils.toBean(list, MesQcApproverConfigRespVO.class, vo ->
+ findAndThen(userMap, vo.getUserId(), user -> vo.setUserNickname(user.getNickname())));
+ }
+
+}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/approver/vo/MesQcApproverConfigPageReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/approver/vo/MesQcApproverConfigPageReqVO.java
new file mode 100644
index 0000000..c40f8e3
--- /dev/null
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/approver/vo/MesQcApproverConfigPageReqVO.java
@@ -0,0 +1,25 @@
+package cn.iocoder.yudao.module.mes.controller.admin.qc.approver.vo;
+
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+@Schema(description = "绠$悊鍚庡彴 - 璐ㄦ瀹℃牳浜洪厤缃垎椤� Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class MesQcApproverConfigPageReqVO extends PageParam {
+
+ @Schema(description = "璐ㄦ绫诲瀷锛�1绉嶅瓙璐ㄦ", example = "1")
+ private Integer qcType;
+
+ @Schema(description = "瀹℃牳鑺傜偣锛�1鍔犲伐閮ㄥ鎵� 3鍏徃璐ㄦ瀹℃壒", example = "3")
+ private Integer approveNode;
+
+ @Schema(description = "瀹℃牳浜虹敤鎴� ID", example = "1024")
+ private Long userId;
+
+ @Schema(description = "鐘舵�侊細0鍚敤 1鍋滅敤", example = "0")
+ private Integer status;
+
+}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/approver/vo/MesQcApproverConfigRespVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/approver/vo/MesQcApproverConfigRespVO.java
new file mode 100644
index 0000000..49d6203
--- /dev/null
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/approver/vo/MesQcApproverConfigRespVO.java
@@ -0,0 +1,36 @@
+package cn.iocoder.yudao.module.mes.controller.admin.qc.approver.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+@Schema(description = "绠$悊鍚庡彴 - 璐ㄦ瀹℃牳浜洪厤缃� Response VO")
+@Data
+public class MesQcApproverConfigRespVO {
+
+ @Schema(description = "缂栧彿", example = "1024")
+ private Long id;
+
+ @Schema(description = "璐ㄦ绫诲瀷锛�1绉嶅瓙璐ㄦ", example = "1")
+ private Integer qcType;
+
+ @Schema(description = "瀹℃牳鑺傜偣锛�1鍔犲伐閮ㄥ鎵� 3鍏徃璐ㄦ瀹℃壒", example = "3")
+ private Integer approveNode;
+
+ @Schema(description = "瀹℃牳浜虹敤鎴� ID", example = "1024")
+ private Long userId;
+
+ @Schema(description = "瀹℃牳浜烘樀绉�", example = "寮犱笁")
+ private String userNickname;
+
+ @Schema(description = "鐘舵�侊細0鍚敤 1鍋滅敤", example = "0")
+ private Integer status;
+
+ @Schema(description = "澶囨敞", example = "璐熻矗绉嶅瓙璐ㄦ鍏徃瀹℃壒")
+ private String remark;
+
+ @Schema(description = "鍒涘缓鏃堕棿")
+ private LocalDateTime createTime;
+
+}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/approver/vo/MesQcApproverConfigSaveReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/approver/vo/MesQcApproverConfigSaveReqVO.java
new file mode 100644
index 0000000..5258f6e
--- /dev/null
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/approver/vo/MesQcApproverConfigSaveReqVO.java
@@ -0,0 +1,33 @@
+package cn.iocoder.yudao.module.mes.controller.admin.qc.approver.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+
+@Schema(description = "绠$悊鍚庡彴 - 璐ㄦ瀹℃牳浜洪厤缃柊澧�/淇敼 Request VO")
+@Data
+public class MesQcApproverConfigSaveReqVO {
+
+ @Schema(description = "缂栧彿", example = "1024")
+ private Long id;
+
+ @Schema(description = "璐ㄦ绫诲瀷锛�1绉嶅瓙璐ㄦ", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+ @NotNull(message = "璐ㄦ绫诲瀷涓嶈兘涓虹┖")
+ private Integer qcType;
+
+ @Schema(description = "瀹℃牳鑺傜偣锛�1鍔犲伐閮ㄥ鎵� 3鍏徃璐ㄦ瀹℃壒", requiredMode = Schema.RequiredMode.REQUIRED, example = "3")
+ @NotNull(message = "瀹℃牳鑺傜偣涓嶈兘涓虹┖")
+ private Integer approveNode;
+
+ @Schema(description = "瀹℃牳浜虹敤鎴� ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ @NotNull(message = "瀹℃牳浜轰笉鑳戒负绌�")
+ private Long userId;
+
+ @Schema(description = "鐘舵�侊細0鍚敤 1鍋滅敤", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
+ @NotNull(message = "鐘舵�佷笉鑳戒负绌�")
+ private Integer status;
+
+ @Schema(description = "澶囨敞", example = "璐熻矗绉嶅瓙璐ㄦ鍏徃瀹℃壒")
+ private String remark;
+
+}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/oqc/MesQcOqcController.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/oqc/MesQcOqcController.java
index e34b23b..973218b 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/oqc/MesQcOqcController.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/oqc/MesQcOqcController.java
@@ -10,8 +10,6 @@
import cn.iocoder.yudao.module.mes.controller.admin.qc.oqc.vo.MesQcOqcPageReqVO;
import cn.iocoder.yudao.module.mes.controller.admin.qc.oqc.vo.MesQcOqcRespVO;
import cn.iocoder.yudao.module.mes.controller.admin.qc.oqc.vo.MesQcOqcSaveReqVO;
-import cn.iocoder.yudao.module.mes.controller.admin.qc.oqc.vo.MesQcOqcRetestReqVO;
-import cn.iocoder.yudao.module.mes.controller.admin.qc.oqc.vo.MesQcOqcApprovalReqVO;
import cn.iocoder.yudao.module.crm.api.customer.CrmCustomerApi;
import cn.iocoder.yudao.module.crm.api.customer.dto.CrmCustomerRespDTO;
import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO;
@@ -83,30 +81,6 @@
public CommonResult<Boolean> finishOqc(@RequestParam("id") Long id) {
oqcService.finishOqc(id);
return success(true);
- }
-
- @PostMapping("/retest") @Operation(summary = "閿�鍞川妫�澶嶆")
- @PreAuthorize("@ss.hasPermission('mes:qc-oqc:retest')")
- public CommonResult<Boolean> retestOqc(@Valid @RequestBody MesQcOqcRetestReqVO reqVO) {
- oqcService.retestOqc(reqVO);
- return success(true);
- }
- @PostMapping("/sales-approve") @Operation(summary = "閿�鍞儴瀹℃壒")
- @PreAuthorize("@ss.hasPermission('mes:qc-oqc:sales-approve')")
- public CommonResult<Boolean> salesApprove(@Valid @RequestBody MesQcOqcApprovalReqVO reqVO) {
- oqcService.salesApprove(reqVO.getId(), reqVO.getApproved(), reqVO.getOpinion());
- return success(true);
- }
- @PostMapping("/company-approve") @Operation(summary = "鍏徃璐ㄦ瀹℃壒閿�鍞嚭璐�")
- @PreAuthorize("@ss.hasPermission('mes:qc-oqc:company-approve')")
- public CommonResult<Boolean> companyApprove(@Valid @RequestBody MesQcOqcApprovalReqVO reqVO) {
- oqcService.companyApprove(reqVO.getId(), reqVO.getApproved(), reqVO.getOpinion());
- return success(true);
- }
- @GetMapping("/actions") @Operation(summary = "閿�鍞川妫�娴佺▼璁板綍")
- @PreAuthorize("@ss.hasPermission('mes:qc-oqc:query')")
- public CommonResult<List<cn.iocoder.yudao.module.mes.dal.dataobject.qc.oqc.MesQcOqcActionDO>> actions(@RequestParam Long id) {
- return success(oqcService.getActions(id));
}
@DeleteMapping("/delete")
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/oqc/vo/MesQcOqcApprovalReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/oqc/vo/MesQcOqcApprovalReqVO.java
deleted file mode 100644
index 7baa189..0000000
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/oqc/vo/MesQcOqcApprovalReqVO.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package cn.iocoder.yudao.module.mes.controller.admin.qc.oqc.vo;
-
-import jakarta.validation.constraints.NotBlank;
-import jakarta.validation.constraints.NotNull;
-import lombok.Data;
-
-@Data
-public class MesQcOqcApprovalReqVO {
- @NotNull private Long id;
- @NotNull private Boolean approved;
- @NotBlank private String opinion;
-}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/oqc/vo/MesQcOqcPageReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/oqc/vo/MesQcOqcPageReqVO.java
index ee70b3d..47926c1 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/oqc/vo/MesQcOqcPageReqVO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/oqc/vo/MesQcOqcPageReqVO.java
@@ -26,7 +26,5 @@
@Schema(description = "妫�娴嬬粨鏋�", example = "1")
private Integer checkResult;
- @Schema(description = "鏉ユ簮鍗曟嵁绫诲瀷")
- private Integer sourceDocType;
}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/oqc/vo/MesQcOqcRespVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/oqc/vo/MesQcOqcRespVO.java
index 7eefa7c..79d9bed 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/oqc/vo/MesQcOqcRespVO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/oqc/vo/MesQcOqcRespVO.java
@@ -142,7 +142,6 @@
@Schema(description = "鐘舵��", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
@ExcelProperty("鐘舵��")
private Integer status;
- private Integer workflowStatus;
@Schema(description = "澶囨敞", example = "澶囨敞")
@ExcelProperty("澶囨敞")
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/oqc/vo/MesQcOqcRetestReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/oqc/vo/MesQcOqcRetestReqVO.java
deleted file mode 100644
index 46427fc..0000000
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/oqc/vo/MesQcOqcRetestReqVO.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package cn.iocoder.yudao.module.mes.controller.admin.qc.oqc.vo;
-
-import jakarta.validation.constraints.DecimalMin;
-import jakarta.validation.constraints.NotNull;
-import lombok.Data;
-import java.math.BigDecimal;
-
-@Data
-public class MesQcOqcRetestReqVO {
- @NotNull private Long id;
- @NotNull @DecimalMin("0") private BigDecimal checkQuantity;
- @NotNull @DecimalMin("0") private BigDecimal qualifiedQuantity;
- @NotNull @DecimalMin("0") private BigDecimal unqualifiedQuantity;
- @NotNull private Integer checkResult;
- private String opinion;
-}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/seedquality/MesQcSeedQualityController.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/seedquality/MesQcSeedQualityController.java
index cde92bd..65ec3f5 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/seedquality/MesQcSeedQualityController.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/seedquality/MesQcSeedQualityController.java
@@ -9,7 +9,13 @@
import cn.iocoder.yudao.module.mes.controller.admin.qc.seedquality.vo.MesQcSeedQualityApprovalReqVO;
import cn.iocoder.yudao.module.mes.controller.admin.qc.seedquality.vo.MesQcSeedQualityRetestReqVO;
import cn.iocoder.yudao.module.mes.controller.admin.qc.seedquality.vo.MesQcSeedQualityBatchApprovalReqVO;
+import cn.iocoder.yudao.module.mes.controller.admin.qc.seedquality.vo.MesQcSeedQualityBatchRetestReqVO;
+import cn.iocoder.yudao.module.mes.controller.admin.qc.seedquality.vo.MesQcSeedQualityScopeRetestReqVO;
+import cn.iocoder.yudao.module.mes.controller.admin.qc.seedquality.vo.MesQcSeedIndicatorRangeSaveReqVO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.pro.bagcode.MesProBagCodeDO;
+import cn.iocoder.yudao.module.mes.dal.mysql.pro.bagcode.MesProBagCodeMapper;
import cn.iocoder.yudao.module.mes.service.qc.seedquality.MesQcSeedQualityService;
+import cn.iocoder.yudao.module.mes.service.qc.seedquality.MesQcSeedIndicatorRangeService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
@@ -17,12 +23,31 @@
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+import java.util.stream.Collectors;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@Tag(name = "绠$悊鍚庡彴 - MES 绉嶅瓙璐ㄦ")
@RestController @RequestMapping("/mes/qc/seed-quality") @Validated
public class MesQcSeedQualityController {
@Resource private MesQcSeedQualityService service;
+ @Resource private MesQcSeedIndicatorRangeService rangeService;
+ @Resource private MesProBagCodeMapper bagCodeMapper;
+ @GetMapping("/ranges") @Operation(summary = "鑾峰緱绉嶅瓙璐ㄦ鍚堟牸鑼冨洿")
+ @PreAuthorize("@ss.hasAnyPermissions('mes:qc-seed-quality:submit', 'mes:qc-seed-quality:retest', 'mes:qc-seed-range:query')")
+ public CommonResult<java.util.List<cn.iocoder.yudao.module.mes.dal.dataobject.qc.seedquality.MesQcSeedIndicatorRangeDO>> ranges() {
+ return success(rangeService.getRanges());
+ }
+
+ @PutMapping("/ranges") @Operation(summary = "閰嶇疆绉嶅瓙璐ㄦ鍚堟牸鑼冨洿")
+ @PreAuthorize("@ss.hasPermission('mes:qc-seed-range:update')")
+ public CommonResult<Boolean> saveRanges(@Valid @RequestBody MesQcSeedIndicatorRangeSaveReqVO reqVO) {
+ rangeService.saveRanges(reqVO);
+ return success(true);
+ }
@GetMapping("/resolve")
@Operation(summary = "瑙f瀽寰呰川妫�琚嬬爜鍙婄‘璁よ琚嬭川妫�缁撴灉")
@PreAuthorize("@ss.hasPermission('mes:qc-seed-quality:submit')")
@@ -33,7 +58,19 @@
@Operation(summary = "鑾峰緱绉嶅瓙璐ㄦ璁板綍鍒嗛〉")
@PreAuthorize("@ss.hasPermission('mes:qc-seed-quality:query')")
public CommonResult<PageResult<MesQcSeedQualityRespVO>> getQualityPage(@Valid MesQcSeedQualityPageReqVO pageReqVO) {
- return success(BeanUtils.toBean(service.getQualityPage(pageReqVO), MesQcSeedQualityRespVO.class));
+ PageResult<MesQcSeedQualityRespVO> page = BeanUtils.toBean(
+ service.getQualityPage(pageReqVO), MesQcSeedQualityRespVO.class);
+ List<String> codes = page.getList().stream().map(MesQcSeedQualityRespVO::getCode)
+ .filter(java.util.Objects::nonNull).distinct().toList();
+ if (!codes.isEmpty()) {
+ Map<String, MesProBagCodeDO> bagMap = bagCodeMapper.selectList(MesProBagCodeDO::getCode, codes).stream()
+ .collect(Collectors.toMap(MesProBagCodeDO::getCode, Function.identity(), (first, ignored) -> first));
+ page.getList().forEach(record -> {
+ MesProBagCodeDO bag = bagMap.get(record.getCode());
+ if (bag != null) record.setPalletCode(bag.getPalletCode());
+ });
+ }
+ return success(page);
}
@GetMapping("/indicators") @Operation(summary = "鑾峰緱绉嶅瓙璐ㄦ鏈�鏂版寚鏍�")
@@ -64,26 +101,45 @@
return success(true);
}
- @PostMapping("/process-approve") @Operation(summary = "鍔犲伐閮ㄥ鎵�")
+ @PostMapping("/retest-batch") @Operation(summary = "鍚屾壒娆$瀛愭壒閲忓妫�鎴栭噸鏂板垵妫�")
+ @PreAuthorize("@ss.hasPermission('mes:qc-seed-quality:retest')")
+ public CommonResult<Boolean> retestBatch(@Valid @RequestBody MesQcSeedQualityBatchRetestReqVO reqVO) {
+ service.retestBatch(reqVO);
+ return success(true);
+ }
+
+ @GetMapping("/retest-scope/resolve") @Operation(summary = "鎸夋墭鐩樼爜鎴栫敓浜ф壒娆$爜瑙f瀽寰呮壒閲忚川妫�璁板綍")
+ @PreAuthorize("@ss.hasPermission('mes:qc-seed-quality:retest')")
+ public CommonResult<java.util.Map<String, Object>> resolveRetestScope(@RequestParam String code, @RequestParam String scanType) {
+ return success(service.resolveRetestScope(code, scanType));
+ }
+
+ @PostMapping("/retest-scope") @Operation(summary = "鎸夋墭鐩樼爜鎴栫敓浜ф壒娆$爜鎵归噺澶嶆鎴栭噸鏂板垵妫�")
+ @PreAuthorize("@ss.hasPermission('mes:qc-seed-quality:retest')")
+ public CommonResult<java.util.Map<String, Object>> retestScope(@Valid @RequestBody MesQcSeedQualityScopeRetestReqVO reqVO) {
+ return success(service.retestScope(reqVO));
+ }
+
+ @PostMapping("/process-approve") @Operation(summary = "鍒濇瀹℃牳")
@PreAuthorize("@ss.hasPermission('mes:qc-seed-quality:process-approve')")
public CommonResult<Boolean> processApprove(@Valid @RequestBody MesQcSeedQualityApprovalReqVO reqVO) {
service.processApprove(reqVO.getId(), reqVO.getApproved(), reqVO.getOpinion());
return success(true);
}
- @PostMapping("/company-approve") @Operation(summary = "鍏徃璐ㄦ瀹℃壒骞舵祦杞簱瀛�")
+ @PostMapping("/company-approve") @Operation(summary = "澶嶆瀹℃牳骞舵祦杞簱瀛�")
@PreAuthorize("@ss.hasPermission('mes:qc-seed-quality:company-approve')")
public CommonResult<Boolean> companyApprove(@Valid @RequestBody MesQcSeedQualityApprovalReqVO reqVO) {
service.companyApprove(reqVO.getId(), reqVO.getApproved(), reqVO.getOpinion());
return success(true);
}
- @PostMapping("/process-approve-batch") @Operation(summary = "鎵归噺鍔犲伐閮ㄥ鎵�")
+ @PostMapping("/process-approve-batch") @Operation(summary = "鎵归噺鍒濇瀹℃牳")
@PreAuthorize("@ss.hasPermission('mes:qc-seed-quality:process-approve')")
public CommonResult<Boolean> processApproveBatch(@Valid @RequestBody MesQcSeedQualityBatchApprovalReqVO reqVO) {
service.processApproveBatch(reqVO.getIds(), reqVO.getApproved(), reqVO.getOpinion());
return success(true);
}
- @PostMapping("/company-approve-batch") @Operation(summary = "鎵归噺鍏徃璐ㄦ瀹℃壒骞舵祦杞簱瀛�")
+ @PostMapping("/company-approve-batch") @Operation(summary = "鎵归噺澶嶆瀹℃牳骞舵祦杞簱瀛�")
@PreAuthorize("@ss.hasPermission('mes:qc-seed-quality:company-approve')")
public CommonResult<Boolean> companyApproveBatch(@Valid @RequestBody MesQcSeedQualityBatchApprovalReqVO reqVO) {
service.companyApproveBatch(reqVO.getIds(), reqVO.getApproved(), reqVO.getOpinion());
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/seedquality/vo/MesQcSeedIndicatorRangeSaveReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/seedquality/vo/MesQcSeedIndicatorRangeSaveReqVO.java
new file mode 100644
index 0000000..5f9148b
--- /dev/null
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/seedquality/vo/MesQcSeedIndicatorRangeSaveReqVO.java
@@ -0,0 +1,25 @@
+package cn.iocoder.yudao.module.mes.controller.admin.qc.seedquality.vo;
+
+import jakarta.validation.Valid;
+import jakarta.validation.constraints.DecimalMax;
+import jakarta.validation.constraints.DecimalMin;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotEmpty;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.util.List;
+
+@Data
+public class MesQcSeedIndicatorRangeSaveReqVO {
+ @NotEmpty
+ private List<@Valid Item> ranges;
+
+ @Data
+ public static class Item {
+ @NotBlank private String indicatorCode;
+ @NotNull @DecimalMin("0") @DecimalMax("100") private BigDecimal minValue;
+ @NotNull @DecimalMin("0") @DecimalMax("100") private BigDecimal maxValue;
+ }
+}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/seedquality/vo/MesQcSeedQualityApprovalReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/seedquality/vo/MesQcSeedQualityApprovalReqVO.java
index 0878499..2463a4b 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/seedquality/vo/MesQcSeedQualityApprovalReqVO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/seedquality/vo/MesQcSeedQualityApprovalReqVO.java
@@ -1,6 +1,5 @@
package cn.iocoder.yudao.module.mes.controller.admin.qc.seedquality.vo;
-import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
@@ -8,5 +7,5 @@
public class MesQcSeedQualityApprovalReqVO {
@NotNull private Long id;
@NotNull private Boolean approved;
- @NotBlank private String opinion;
+ private String opinion;
}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/seedquality/vo/MesQcSeedQualityBatchApprovalReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/seedquality/vo/MesQcSeedQualityBatchApprovalReqVO.java
index 50b5ad2..ddfa80a 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/seedquality/vo/MesQcSeedQualityBatchApprovalReqVO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/seedquality/vo/MesQcSeedQualityBatchApprovalReqVO.java
@@ -1,6 +1,5 @@
package cn.iocoder.yudao.module.mes.controller.admin.qc.seedquality.vo;
-import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
@@ -11,5 +10,5 @@
public class MesQcSeedQualityBatchApprovalReqVO {
@NotEmpty private List<@NotNull Long> ids;
@NotNull private Boolean approved;
- @NotBlank private String opinion;
+ private String opinion;
}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/seedquality/vo/MesQcSeedQualityBatchRetestReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/seedquality/vo/MesQcSeedQualityBatchRetestReqVO.java
new file mode 100644
index 0000000..6cfbce3
--- /dev/null
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/seedquality/vo/MesQcSeedQualityBatchRetestReqVO.java
@@ -0,0 +1,15 @@
+package cn.iocoder.yudao.module.mes.controller.admin.qc.seedquality.vo;
+
+import jakarta.validation.Valid;
+import jakarta.validation.constraints.NotEmpty;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class MesQcSeedQualityBatchRetestReqVO {
+ @NotEmpty private List<@NotNull Long> ids;
+ @NotEmpty @Valid private List<MesQcSeedQualitySubmitReqVO.Indicator> indicators;
+ private String reason;
+}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/seedquality/vo/MesQcSeedQualityRespVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/seedquality/vo/MesQcSeedQualityRespVO.java
index c3c4c95..ca3b1f2 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/seedquality/vo/MesQcSeedQualityRespVO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/seedquality/vo/MesQcSeedQualityRespVO.java
@@ -11,6 +11,8 @@
private Long id;
private String code;
+ @Schema(description = "瀵瑰簲鎵樼洏鐮侊紱鏈粦瀹氭墭鐩樻椂涓虹┖")
+ private String palletCode;
private Long itemId;
private Long batchId;
private String batchCode;
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/seedquality/vo/MesQcSeedQualityScopeRetestReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/seedquality/vo/MesQcSeedQualityScopeRetestReqVO.java
new file mode 100644
index 0000000..0547673
--- /dev/null
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/seedquality/vo/MesQcSeedQualityScopeRetestReqVO.java
@@ -0,0 +1,18 @@
+package cn.iocoder.yudao.module.mes.controller.admin.qc.seedquality.vo;
+
+import jakarta.validation.Valid;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotEmpty;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+import java.util.List;
+
+@Data
+public class MesQcSeedQualityScopeRetestReqVO {
+ @NotBlank private String code;
+ @NotBlank private String scanType;
+ @NotNull private Integer workflowStatus;
+ @NotEmpty private List<@NotNull Long> qualityIds;
+ @NotEmpty @Valid private List<MesQcSeedQualitySubmitReqVO.Indicator> indicators;
+ private String reason;
+}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/seedquality/vo/MesQcSeedQualitySubmitReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/seedquality/vo/MesQcSeedQualitySubmitReqVO.java
index 1d8d9d3..1c4ef86 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/seedquality/vo/MesQcSeedQualitySubmitReqVO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/seedquality/vo/MesQcSeedQualitySubmitReqVO.java
@@ -16,8 +16,8 @@
@NotNull private Long qualifiedWarehouseId;
@Data public static class Indicator {
@NotBlank private String code;
- @NotNull @DecimalMin("0") private BigDecimal value;
- @NotNull @DecimalMin("0") private BigDecimal minValue;
- @NotNull @DecimalMin("0") private BigDecimal maxValue;
+ @NotNull @DecimalMin("0") @DecimalMax("100") private BigDecimal value;
+ @NotNull @DecimalMin("0") @DecimalMax("100") private BigDecimal minValue;
+ @NotNull @DecimalMin("0") @DecimalMax("100") private BigDecimal maxValue;
}
}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/qc/approver/MesQcApproverConfigDO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/qc/approver/MesQcApproverConfigDO.java
new file mode 100644
index 0000000..0a8840b
--- /dev/null
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/qc/approver/MesQcApproverConfigDO.java
@@ -0,0 +1,56 @@
+package cn.iocoder.yudao.module.mes.dal.dataobject.qc.approver;
+
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+import cn.iocoder.yudao.module.mes.enums.qc.MesQcApproveNodeEnum;
+import cn.iocoder.yudao.module.mes.enums.qc.MesQcApprovalTypeEnum;
+import com.baomidou.mybatisplus.annotation.KeySequence;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.*;
+
+/**
+ * MES 璐ㄦ瀹℃牳浜洪厤缃� DO
+ *
+ * @author 瓒呯骇绠$悊鍛�
+ */
+@TableName("mes_qc_approver_config")
+@KeySequence("mes_qc_approver_config_seq")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class MesQcApproverConfigDO extends BaseDO {
+
+ /**
+ * 缂栧彿
+ */
+ @TableId
+ private Long id;
+ /**
+ * 璐ㄦ绫诲瀷
+ *
+ * 鏋氫妇 {@link MesQcApprovalTypeEnum}
+ */
+ private Integer qcType;
+ /**
+ * 瀹℃牳鑺傜偣
+ *
+ * 鏋氫妇 {@link MesQcApproveNodeEnum}
+ */
+ private Integer approveNode;
+ /**
+ * 瀹℃牳浜虹敤鎴� ID
+ */
+ private Long userId;
+ /**
+ * 鐘舵�侊細0 鍚敤锛�1 鍋滅敤
+ */
+ private Integer status;
+ /**
+ * 澶囨敞
+ */
+ private String remark;
+
+}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/qc/oqc/MesQcOqcActionDO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/qc/oqc/MesQcOqcActionDO.java
deleted file mode 100644
index 6ca31e6..0000000
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/qc/oqc/MesQcOqcActionDO.java
+++ /dev/null
@@ -1,19 +0,0 @@
-package cn.iocoder.yudao.module.mes.dal.dataobject.qc.oqc;
-
-import com.baomidou.mybatisplus.annotation.TableId;
-import com.baomidou.mybatisplus.annotation.TableName;
-import lombok.Data;
-import java.time.LocalDateTime;
-
-@Data
-@TableName("mes_qc_oqc_action")
-public class MesQcOqcActionDO {
- @TableId private Long id;
- private Long oqcId;
- private String action;
- private Integer result;
- private String opinion;
- private String quantitiesJson;
- private Long operatorId;
- private LocalDateTime createTime;
-}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/qc/oqc/MesQcOqcDO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/qc/oqc/MesQcOqcDO.java
index 4ba8d04..27d8fa0 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/qc/oqc/MesQcOqcDO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/qc/oqc/MesQcOqcDO.java
@@ -181,8 +181,6 @@
* 鏋氫妇 {@link cn.iocoder.yudao.module.mes.enums.qc.MesQcStatusEnum}
*/
private Integer status;
- /** 0鑽夌锛�10寰呭妫�锛�20寰呴攢鍞儴瀹℃壒锛�30寰呭叕鍙歌川妫�瀹℃壒锛�40宸叉斁琛岋紱50寰呴攢鍞儴涓嶅悎鏍艰瘎瀹★紱60寰呭叕鍙镐笉鍚堟牸瀹℃壒锛�70宸叉嫆缁濆嚭璐с�� */
- private Integer workflowStatus;
/**
* 澶囨敞
*/
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/qc/seedquality/MesQcSeedIndicatorRangeDO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/qc/seedquality/MesQcSeedIndicatorRangeDO.java
new file mode 100644
index 0000000..d294b49
--- /dev/null
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/qc/seedquality/MesQcSeedIndicatorRangeDO.java
@@ -0,0 +1,20 @@
+package cn.iocoder.yudao.module.mes.dal.dataobject.qc.seedquality;
+
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.math.BigDecimal;
+
+@TableName("mes_qc_seed_indicator_range")
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class MesQcSeedIndicatorRangeDO extends BaseDO {
+ @TableId(type = IdType.INPUT)
+ private String indicatorCode;
+ private BigDecimal minValue;
+ private BigDecimal maxValue;
+}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/qc/seedquality/MesQcSeedQualityDO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/qc/seedquality/MesQcSeedQualityDO.java
index 32521fa..d0d1392 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/qc/seedquality/MesQcSeedQualityDO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/qc/seedquality/MesQcSeedQualityDO.java
@@ -17,7 +17,7 @@
private String batchCode;
private Integer result;
private String reason;
- /** 10 寰呭妫�锛�20 寰呭姞宸ラ儴瀹℃壒锛�30 寰呭叕鍙歌川妫�瀹℃壒锛�40 宸叉斁琛岋紱50 寰呭姞宸ラ儴涓嶅悎鏍艰瘎瀹★紱60 寰呭叕鍙镐笉鍚堟牸瀹℃壒锛�70 宸叉姤搴熴�� */
+ /** 10 寰呭妫�锛�20 寰呭垵妫�瀹℃牳锛�25 寰呭垵妫�涓嶅悎鏍煎鐞嗭紱30 寰呭妫�瀹℃牳锛�40 宸叉斁琛岋紱50 鍒濇椹冲洖寰呴噸妫�锛�60 寰呭妫�涓嶅悎鏍煎鐞嗭紱70 宸叉姤搴熴�� */
private Integer workflowStatus;
private Long qualifiedWarehouseId;
private Integer retestResult;
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/md/item/MesMdItemMapper.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/md/item/MesMdItemMapper.java
index 5a5a843..f692921 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/md/item/MesMdItemMapper.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/md/item/MesMdItemMapper.java
@@ -40,10 +40,6 @@
return selectOne(MesMdItemDO::getCode, code);
}
- default MesMdItemDO selectByName(String name) {
- return selectOne(MesMdItemDO::getName, name);
- }
-
default Long selectCountByItemTypeId(Long itemTypeId) {
return selectCount(MesMdItemDO::getItemTypeId, itemTypeId);
}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/bagcode/MesProBagCodeMapper.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/bagcode/MesProBagCodeMapper.java
index bc35f78..a921465 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/bagcode/MesProBagCodeMapper.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/bagcode/MesProBagCodeMapper.java
@@ -260,6 +260,16 @@
.orderByAsc(MesProBagCodeDO::getId));
}
+ default List<MesProBagCodeDO> selectUnboundPalletlessList() {
+ return selectList(new LambdaQueryWrapperX<MesProBagCodeDO>()
+ .isNull(MesProBagCodeDO::getBatchId)
+ .isNull(MesProBagCodeDO::getPalletId)
+ .in(MesProBagCodeDO::getStatus, MesProBagCodeStatusEnum.GENERATED.getStatus(),
+ MesProBagCodeStatusEnum.PRINTED.getStatus())
+ .isNotNull(MesProBagCodeDO::getItemId)
+ .orderByAsc(MesProBagCodeDO::getId));
+ }
+
/** 鎵规鍐呮湁鏁堣鐮佺殑鍝佺缂栧彿闆嗗悎锛堝拷鐣ュ巻鍙茬┖鍝佺琚嬬爜锛夛紝鐢ㄤ簬褰曞叆鎵规鏃剁殑鍝佺涓�鑷存�ф牎楠� */
@Select("SELECT DISTINCT item_id FROM mes_pro_bag_code " +
"WHERE deleted = 0 AND status <> 30 AND batch_id = #{batchId} AND item_id IS NOT NULL")
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/qc/approver/MesQcApproverConfigMapper.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/qc/approver/MesQcApproverConfigMapper.java
new file mode 100644
index 0000000..7490f42
--- /dev/null
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/qc/approver/MesQcApproverConfigMapper.java
@@ -0,0 +1,43 @@
+package cn.iocoder.yudao.module.mes.dal.mysql.qc.approver;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
+import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
+import cn.iocoder.yudao.module.mes.controller.admin.qc.approver.vo.MesQcApproverConfigPageReqVO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.qc.approver.MesQcApproverConfigDO;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * MES 璐ㄦ瀹℃牳浜洪厤缃� Mapper
+ *
+ * @author 瓒呯骇绠$悊鍛�
+ */
+@Mapper
+public interface MesQcApproverConfigMapper extends BaseMapperX<MesQcApproverConfigDO> {
+
+ default PageResult<MesQcApproverConfigDO> selectPage(MesQcApproverConfigPageReqVO reqVO) {
+ return selectPage(reqVO, new LambdaQueryWrapperX<MesQcApproverConfigDO>()
+ .eqIfPresent(MesQcApproverConfigDO::getQcType, reqVO.getQcType())
+ .eqIfPresent(MesQcApproverConfigDO::getApproveNode, reqVO.getApproveNode())
+ .eqIfPresent(MesQcApproverConfigDO::getUserId, reqVO.getUserId())
+ .eqIfPresent(MesQcApproverConfigDO::getStatus, reqVO.getStatus())
+ .orderByAsc(MesQcApproverConfigDO::getQcType)
+ .orderByAsc(MesQcApproverConfigDO::getApproveNode)
+ .orderByDesc(MesQcApproverConfigDO::getId));
+ }
+
+ default MesQcApproverConfigDO selectByUnique(Integer qcType, Integer approveNode, Long userId) {
+ return selectOne(new LambdaQueryWrapperX<MesQcApproverConfigDO>()
+ .eq(MesQcApproverConfigDO::getQcType, qcType)
+ .eq(MesQcApproverConfigDO::getApproveNode, approveNode)
+ .eq(MesQcApproverConfigDO::getUserId, userId));
+ }
+
+ default Long selectCountByNode(Integer qcType, Integer approveNode, Integer status) {
+ return selectCount(new LambdaQueryWrapperX<MesQcApproverConfigDO>()
+ .eq(MesQcApproverConfigDO::getQcType, qcType)
+ .eq(MesQcApproverConfigDO::getApproveNode, approveNode)
+ .eq(MesQcApproverConfigDO::getStatus, status));
+ }
+
+}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/qc/oqc/MesQcOqcActionMapper.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/qc/oqc/MesQcOqcActionMapper.java
deleted file mode 100644
index 62fa651..0000000
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/qc/oqc/MesQcOqcActionMapper.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package cn.iocoder.yudao.module.mes.dal.mysql.qc.oqc;
-
-import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
-import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
-import cn.iocoder.yudao.module.mes.dal.dataobject.qc.oqc.MesQcOqcActionDO;
-import org.apache.ibatis.annotations.Mapper;
-import java.util.List;
-
-@Mapper
-public interface MesQcOqcActionMapper extends BaseMapperX<MesQcOqcActionDO> {
- default List<MesQcOqcActionDO> selectByOqcId(Long id) {
- return selectList(new LambdaQueryWrapperX<MesQcOqcActionDO>()
- .eq(MesQcOqcActionDO::getOqcId, id).orderByAsc(MesQcOqcActionDO::getId));
- }
-}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/qc/oqc/MesQcOqcMapper.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/qc/oqc/MesQcOqcMapper.java
index 2b16f33..1a26e94 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/qc/oqc/MesQcOqcMapper.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/qc/oqc/MesQcOqcMapper.java
@@ -25,7 +25,6 @@
.likeIfPresent(MesQcOqcDO::getBatchCode, reqVO.getBatchCode())
.eqIfPresent(MesQcOqcDO::getItemId, reqVO.getItemId())
.eqIfPresent(MesQcOqcDO::getCheckResult, reqVO.getCheckResult())
- .eqIfPresent(MesQcOqcDO::getSourceDocType, reqVO.getSourceDocType())
.orderByDesc(MesQcOqcDO::getId));
}
@@ -39,7 +38,6 @@
.likeIfPresent(MesQcOqcDO::getBatchCode, reqVO.getBatchCode())
.eqIfPresent(MesQcOqcDO::getItemId, reqVO.getItemId())
.eqIfPresent(MesQcOqcDO::getCheckResult, reqVO.getCheckResult())
- .eqIfPresent(MesQcOqcDO::getSourceDocType, reqVO.getSourceDocType())
.orderByDesc(MesQcOqcDO::getId);
if (permittedClientIds != null) {
if (CollUtil.isEmpty(permittedClientIds)) {
@@ -52,9 +50,6 @@
default MesQcOqcDO selectByCode(String code) {
return selectOne(MesQcOqcDO::getCode, code);
- }
- default MesQcOqcDO selectByIdForUpdate(Long id) {
- return selectOne(new LambdaQueryWrapperX<MesQcOqcDO>().eq(MesQcOqcDO::getId, id).last("FOR UPDATE"));
}
}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/qc/seedquality/MesQcSeedIndicatorRangeMapper.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/qc/seedquality/MesQcSeedIndicatorRangeMapper.java
new file mode 100644
index 0000000..b43584e
--- /dev/null
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/qc/seedquality/MesQcSeedIndicatorRangeMapper.java
@@ -0,0 +1,9 @@
+package cn.iocoder.yudao.module.mes.dal.mysql.qc.seedquality;
+
+import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
+import cn.iocoder.yudao.module.mes.dal.dataobject.qc.seedquality.MesQcSeedIndicatorRangeDO;
+import org.apache.ibatis.annotations.Mapper;
+
+@Mapper
+public interface MesQcSeedIndicatorRangeMapper extends BaseMapperX<MesQcSeedIndicatorRangeDO> {
+}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java
index 5d0356b..ecb296a 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java
@@ -41,7 +41,6 @@
// ========== MES 鍩虹鏁版嵁-鐗╂枡锛�1-040-102-000锛� ==========
ErrorCode MD_ITEM_NOT_EXISTS = new ErrorCode(1_040_102_000, "鐗╂枡涓嶅瓨鍦�");
ErrorCode MD_ITEM_CODE_DUPLICATE = new ErrorCode(1_040_102_001, "鐗╂枡缂栫爜宸插瓨鍦�");
- ErrorCode MD_ITEM_NAME_DUPLICATE = new ErrorCode(1_040_102_002, "鐗╂枡鍚嶇О宸插瓨鍦�");
ErrorCode MD_ITEM_BATCH_REQUIRED = new ErrorCode(1_040_102_004, "褰撳墠鐗╂枡鍚敤浜嗘壒娆$鐞嗭紝璇烽�夋嫨鎵规");
ErrorCode MD_ITEM_IS_DISABLE = new ErrorCode(1_040_102_005, "鐗╂枡宸茬鐢�");
@@ -447,6 +446,12 @@
ErrorCode QC_NCR_NOT_REVIEWED = new ErrorCode(1_040_609_003, "鍙湁宸茶瘎瀹$姸鎬佺殑涓嶅悎鏍煎搧澶勭悊鍗曟墠鍙墽琛屽缃�");
ErrorCode QC_NCR_NOT_DISPOSED = new ErrorCode(1_040_609_004, "鍙湁宸插缃姸鎬佺殑涓嶅悎鏍煎搧澶勭悊鍗曟墠鍙叧闂�");
+ // ========== MES 璐ㄩ噺绠$悊-璐ㄦ瀹℃牳浜洪厤缃紙1-040-610-000锛� ==========
+ ErrorCode QC_APPROVER_CONFIG_NOT_EXISTS = new ErrorCode(1_040_610_000, "璐ㄦ瀹℃牳浜洪厤缃笉瀛樺湪");
+ ErrorCode QC_APPROVER_CONFIG_DUPLICATE = new ErrorCode(1_040_610_001, "璇ヨ川妫�绫诲瀷鍜屽鏍歌妭鐐逛笅宸插瓨鍦ㄨ瀹℃牳浜�");
+ ErrorCode QC_APPROVER_NODE_INVALID = new ErrorCode(1_040_610_002, "璐ㄦ绫诲瀷涓庡鏍歌妭鐐圭粍鍚堜笉鍚堟硶");
+ ErrorCode QC_APPROVER_NOT_CONFIGURED = new ErrorCode(1_040_610_003, "褰撳墠鐢ㄦ埛涓嶆槸璇ヨ妭鐐圭殑璐ㄦ瀹℃牳浜猴紝璇疯仈绯荤鐞嗗憳閰嶇疆");
+
// ========== MES 浠撳簱绠$悊-浠撳簱锛�1-040-700-000锛� ==========
ErrorCode WM_WAREHOUSE_NOT_EXISTS = new ErrorCode(1_040_700_000, "浠撳簱涓嶅瓨鍦�");
ErrorCode WM_WAREHOUSE_CODE_DUPLICATE = new ErrorCode(1_040_700_001, "浠撳簱缂栫爜宸插瓨鍦�");
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/qc/MesQcApprovalTypeEnum.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/qc/MesQcApprovalTypeEnum.java
new file mode 100644
index 0000000..1160c73
--- /dev/null
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/qc/MesQcApprovalTypeEnum.java
@@ -0,0 +1,36 @@
+package cn.iocoder.yudao.module.mes.enums.qc;
+
+import cn.iocoder.yudao.framework.common.core.ArrayValuable;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+import java.util.Arrays;
+
+/**
+ * MES 璐ㄦ瀹℃牳绫诲瀷鏋氫妇锛堢敤浜庡鏍镐汉閰嶇疆锛�
+ *
+ * @author 瓒呯骇绠$悊鍛�
+ */
+@Getter
+@AllArgsConstructor
+public enum MesQcApprovalTypeEnum implements ArrayValuable<Integer> {
+
+ SEED_QUALITY(1, "绉嶅瓙璐ㄦ");
+
+ public static final Integer[] ARRAYS = Arrays.stream(values()).map(MesQcApprovalTypeEnum::getType).toArray(Integer[]::new);
+
+ /**
+ * 绫诲瀷鍊�
+ */
+ private final Integer type;
+ /**
+ * 绫诲瀷鍚�
+ */
+ private final String name;
+
+ @Override
+ public Integer[] array() {
+ return ARRAYS;
+ }
+
+}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/qc/MesQcApproveNodeEnum.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/qc/MesQcApproveNodeEnum.java
new file mode 100644
index 0000000..53dcae9
--- /dev/null
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/qc/MesQcApproveNodeEnum.java
@@ -0,0 +1,47 @@
+package cn.iocoder.yudao.module.mes.enums.qc;
+
+import cn.iocoder.yudao.framework.common.core.ArrayValuable;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+import java.util.Arrays;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * MES 璐ㄦ瀹℃牳鑺傜偣鏋氫妇锛堢敤浜庡鏍镐汉閰嶇疆锛�
+ *
+ * @author 瓒呯骇绠$悊鍛�
+ */
+@Getter
+@AllArgsConstructor
+public enum MesQcApproveNodeEnum implements ArrayValuable<Integer> {
+
+ PROCESS(1, "鍒濇瀹℃牳"),
+ COMPANY(3, "澶嶆瀹℃牳");
+
+ public static final Integer[] ARRAYS = Arrays.stream(values()).map(MesQcApproveNodeEnum::getNode).toArray(Integer[]::new);
+
+ /**
+ * 鑺傜偣鍊�
+ */
+ private final Integer node;
+ /**
+ * 鑺傜偣鍚�
+ */
+ private final String name;
+
+ @Override
+ public Integer[] array() {
+ return ARRAYS;
+ }
+
+ /**
+ * 鏍¢獙璐ㄦ绫诲瀷涓庡鏍歌妭鐐圭殑缁勫悎鏄惁鍚堟硶
+ */
+ public static boolean isValidCombination(Integer qcType, Integer node) {
+ return Objects.equals(qcType, MesQcApprovalTypeEnum.SEED_QUALITY.getType())
+ && Set.of(PROCESS.getNode(), COMPANY.getNode()).contains(node);
+ }
+
+}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/item/MesMdItemServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/item/MesMdItemServiceImpl.java
index 012ba93..e7cda33 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/item/MesMdItemServiceImpl.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/item/MesMdItemServiceImpl.java
@@ -135,8 +135,6 @@
private void validateItemSaveData(MesMdItemSaveReqVO reqVO) {
// 鏍¢獙鐗╂枡缂栫爜鐨勫敮涓�鎬�
validateItemCodeUnique(reqVO.getId(), reqVO.getCode());
- // 鏍¢獙鐗╂枡鍚嶇О鐨勫敮涓�鎬�
- validateItemNameUnique(reqVO.getId(), reqVO.getName());
// 鏍¢獙鐗╂枡鍒嗙被瀛樺湪锛圡DM 鍝佺鍚屾涓嶄紶鍒嗙被锛屽厑璁镐负绌猴級
if (reqVO.getItemTypeId() != null) {
validateItemTypeExists(reqVO.getItemTypeId());
@@ -210,16 +208,6 @@
}
if (ObjUtil.notEqual(item.getId(), id)) {
throw exception(MD_ITEM_CODE_DUPLICATE);
- }
- }
-
- private void validateItemNameUnique(Long id, String name) {
- MesMdItemDO item = itemMapper.selectByName(name);
- if (item == null) {
- return;
- }
- if (ObjUtil.notEqual(item.getId(), id)) {
- throw exception(MD_ITEM_NAME_DUPLICATE);
}
}
@@ -421,4 +409,4 @@
return item;
}
-}
\ No newline at end of file
+}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/bagcode/MesProBagCodeService.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/bagcode/MesProBagCodeService.java
index 7208c12..399b08a 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/bagcode/MesProBagCodeService.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/bagcode/MesProBagCodeService.java
@@ -43,6 +43,9 @@
void bindBatch(@Valid MesProBagCodeBindBatchReqVO bindReqVO);
+ /** 灏氭湭缁戝畾鎵规銆佹病鏈夋墭鐩樹笖鍝佺璁¢噺鍗曚綅涓哄惃鐨勮鐮併�� */
+ List<MesProBagCodeDO> getUnboundTonBags();
+
/**
* 浣滃簾鐮存崯琚嬬爜骞跺湪鍘熸壒娆$敓鎴愮瓑閲忔浛鎹㈣鐮�
*/
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/bagcode/MesProBagCodeServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/bagcode/MesProBagCodeServiceImpl.java
index b60d9f8..1990cd8 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/bagcode/MesProBagCodeServiceImpl.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/bagcode/MesProBagCodeServiceImpl.java
@@ -209,6 +209,20 @@
return type;
}
+ @Override
+ public List<MesProBagCodeDO> getUnboundTonBags() {
+ Map<Long, Boolean> tonItems = new LinkedHashMap<>();
+ return bagCodeMapper.selectUnboundPalletlessList().stream()
+ .filter(bag -> tonItems.computeIfAbsent(bag.getItemId(), id -> {
+ MesMdmItemDO item = mdmItemService.getItem(id);
+ if (item == null || item.getUnitMeasureId() == null) return false;
+ CommonResult<MdmUnitMeasureRespDTO> result = unitMeasureApi.getUnitMeasure(item.getUnitMeasureId());
+ return result != null && result.isSuccess() && result.getData() != null
+ && UNIT_TYPE_TON.equals(StrUtil.trim(result.getData().getType()));
+ }))
+ .toList();
+ }
+
/**
* 瑙f瀽銆孨琚嬨�嶇被鍨嬪緱鍑烘瘡鎵樼洏琚嬫暟
*/
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/batch/MesProBatchService.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/batch/MesProBatchService.java
index 5e2e7c5..f316852 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/batch/MesProBatchService.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/batch/MesProBatchService.java
@@ -71,6 +71,9 @@
*/
MesProBatchDO getBatch(Long id);
+ /** 鎵规宸叉湁鐨勭粦瀹氭柟寮忥細pallet銆乼onBag 鎴栫┖銆� */
+ String getBindingMode(Long id);
+
/**
* 鏍¢獙鐢熶骇鎵规瀛樺湪
*
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/batch/MesProBatchServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/batch/MesProBatchServiceImpl.java
index bae3140..084b5a0 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/batch/MesProBatchServiceImpl.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/batch/MesProBatchServiceImpl.java
@@ -7,6 +7,10 @@
import cn.iocoder.yudao.module.mes.controller.admin.pro.batch.vo.MesProBatchPageReqVO;
import cn.iocoder.yudao.module.mes.controller.admin.pro.batch.vo.MesProBatchPreGenerateReqVO;
import cn.iocoder.yudao.module.mes.controller.admin.pro.batch.vo.MesProBatchSaveReqVO;
+import cn.iocoder.yudao.module.mes.controller.admin.pro.bagcode.vo.MesProBagCodeBindBatchReqVO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.pro.bagcode.MesProBagCodeDO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.mdm.MesMdmItemDO;
+import cn.iocoder.yudao.module.mdm.api.unit.MdmUnitMeasureApi;
import cn.iocoder.yudao.module.mes.controller.admin.pro.pallet.vo.MesProPalletBindBatchReqVO;
import cn.iocoder.yudao.module.mes.dal.dataobject.pro.batch.MesProBatchDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.pro.batch.MesProBatchWorkerDO;
@@ -20,6 +24,8 @@
import cn.iocoder.yudao.module.mes.enums.pro.MesProBatchStatusEnum;
import cn.iocoder.yudao.module.mes.service.md.autocode.MesMdAutoCodeRecordService;
import cn.iocoder.yudao.module.mes.service.pro.line.MesProLineService;
+import cn.iocoder.yudao.module.mes.service.pro.bagcode.MesProBagCodeService;
+import cn.iocoder.yudao.module.mes.service.mdm.MesMdmItemService;
import cn.iocoder.yudao.module.mes.service.pro.pallet.MesProPalletService;
import cn.iocoder.yudao.module.mes.service.trace.integrity.MesTraceIntegrityService;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
@@ -61,6 +67,12 @@
@Resource
private MesProPalletService palletService;
+ @Resource
+ private MesProBagCodeService bagCodeService;
+ @Resource
+ private MesMdmItemService mdmItemService;
+ @Resource
+ private MdmUnitMeasureApi unitMeasureApi;
@Resource
private MesCodeRedisDAO codeRedisDao;
@@ -86,7 +98,7 @@
String code = generateBatchCode(line.getCode());
// 3. 鎻掑叆鎵规锛堜骇绾跨紪鐮�/鍚嶇О鍐椾綑鍥炲~锛涘嬀閫夌粦瀹氭墭鐩樻椂鎵规鐩存帴杩涘叆鐢熶骇涓級
- boolean bindPallets = CollUtil.isNotEmpty(createReqVO.getPalletIds());
+ boolean hasBindings = hasBindings(createReqVO);
MesProBatchDO batch = BeanUtils.toBean(createReqVO, MesProBatchDO.class)
.setCode(code)
.setBusinessCode(codeRedisDao.generate())
@@ -94,7 +106,7 @@
.setLineName(line.getName())
.setBagQuantity(0)
.setPalletQuantity(0)
- .setStatus(bindPallets ? MesProBatchStatusEnum.PRODUCING.getStatus()
+ .setStatus(hasBindings ? MesProBatchStatusEnum.PRODUCING.getStatus()
: MesProBatchStatusEnum.DRAFT.getStatus());
batchMapper.insert(batch);
@@ -102,6 +114,7 @@
insertBatchWorkers(batch.getId(), createReqVO.getWorkers());
// 5. 缁戝畾鎵樼洏锛堢骇鑱旂敓鎴愭寮忔墭鐩樼爜骞跺綍鍏ユ墭鐩樹笅琚嬬爜锛屽け璐ユ暣浣撳洖婊氾級
bindPalletsToBatch(batch.getId(), createReqVO.getPalletIds());
+ bindTonBagsToBatch(batch.getId(), createReqVO.getTonBagIds());
// 6. 鐢熸垚鎵规瀹屾暣鎬ф憳瑕�
integrityService.recordBatchIntegrity(batch.getId());
return batch.getId();
@@ -145,12 +158,12 @@
fillReqVO.setItemId(resolveBindingItem(batch, fillReqVO));
String code = generateBatchCode(line.getCode());
// 3. 钀藉簱涓氬姟淇℃伅锛堜繚鐣欎复鏃舵壒娆$爜鐢ㄤ簬鍘嗗彶鎵爜杩芥函锛涗骇绾跨紪鐮�/鍚嶇О鍐椾綑鍥炲~锛涘嬀閫夌粦瀹氭墭鐩樻椂鎵规鐩存帴杩涘叆鐢熶骇涓級
- boolean bindPallets = CollUtil.isNotEmpty(fillReqVO.getPalletIds());
+ boolean hasBindings = hasBindings(fillReqVO);
MesProBatchDO updateObj = BeanUtils.toBean(fillReqVO, MesProBatchDO.class)
.setCode(code)
.setLineCode(line.getCode())
.setLineName(line.getName())
- .setStatus(bindPallets ? MesProBatchStatusEnum.PRODUCING.getStatus()
+ .setStatus(hasBindings ? MesProBatchStatusEnum.PRODUCING.getStatus()
: MesProBatchStatusEnum.DRAFT.getStatus());
batchMapper.updateById(updateObj);
// 4. 閲嶅缓鐢熶骇浜哄憳閰嶇疆
@@ -158,6 +171,7 @@
insertBatchWorkers(fillReqVO.getId(), fillReqVO.getWorkers());
// 5. 缁戝畾鎵樼洏锛堢骇鑱旂敓鎴愭寮忔墭鐩樼爜骞跺綍鍏ユ墭鐩樹笅琚嬬爜锛屽け璐ユ暣浣撳洖婊氾級
bindPalletsToBatch(fillReqVO.getId(), fillReqVO.getPalletIds());
+ bindTonBagsToBatch(fillReqVO.getId(), fillReqVO.getTonBagIds());
// 6. 鐢熸垚鎵规瀹屾暣鎬ф憳瑕侊紙琛ュ綍姝e紡淇℃伅鍚庤鐩栵級
integrityService.recordBatchIntegrity(fillReqVO.getId());
}
@@ -187,9 +201,9 @@
updateObj.setLineCode(line.getCode()).setLineName(line.getName());
}
// 4. 鏇存柊鎵规锛堝嬀閫夌粦瀹氭墭鐩樻椂鎵规鐩存帴杩涘叆鐢熶骇涓紱鍙栨秷鍕鹃�変笉鍥為��锛屽凡缁戝畾鎵樼洏涓嶅彲瑙g粦锛�
- boolean bindPallets = CollUtil.isNotEmpty(updateReqVO.getPalletIds());
+ boolean hasBindings = hasBindings(updateReqVO);
updateObj.setCode(code);
- if (bindPallets) {
+ if (hasBindings) {
updateObj.setStatus(MesProBatchStatusEnum.PRODUCING.getStatus());
}
batchMapper.updateById(updateObj);
@@ -199,6 +213,7 @@
insertBatchWorkers(updateReqVO.getId(), updateReqVO.getWorkers());
// 6. 缁戝畾鏂板鍕鹃�夌殑鎵樼洏锛堢骇鑱旂敓鎴愭寮忔墭鐩樼爜骞跺綍鍏ユ墭鐩樹笅琚嬬爜锛屽け璐ユ暣浣撳洖婊氾級
bindPalletsToBatch(updateReqVO.getId(), updateReqVO.getPalletIds());
+ bindTonBagsToBatch(updateReqVO.getId(), updateReqVO.getTonBagIds());
// 7. 鎽樿瑕嗙洊鑼冨洿鍚搧绉�/浜х嚎/鐢熶骇鏃ユ湡/璁″垝鏁伴噺锛岀紪杈戝悗閲嶆柊鐢熸垚閬垮厤璇姤绡℃敼
integrityService.recordBatchIntegrity(updateReqVO.getId());
}
@@ -252,6 +267,18 @@
@Override
public MesProBatchDO getBatch(Long id) {
return batchMapper.selectById(id);
+ }
+
+ @Override
+ public String getBindingMode(Long id) {
+ if (!palletMapper.selectListByBatchId(id).isEmpty()) return "pallet";
+ return bagCodeMapper.selectListByBatchId(id).stream()
+ .filter(bag -> bag.getPalletId() == null)
+ .map(MesProBagCodeDO::getItemId)
+ .filter(Objects::nonNull)
+ .distinct()
+ .anyMatch(this::isTonItem)
+ ? "tonBag" : null;
}
@Override
@@ -344,6 +371,15 @@
* 鐢熸垚姝e紡鎵樼洏鐮佸苟绾ц仈褰曞叆鎵樼洏涓嬫湭缁戞壒娆$殑琚嬬爜锛屽け璐ユ暣浣撳洖婊�
*/
private Long resolveBindingItem(MesProBatchDO batch, MesProBatchSaveReqVO req) {
+ boolean palletsRequested = CollUtil.isNotEmpty(req.getPalletIds());
+ boolean tonsRequested = CollUtil.isNotEmpty(req.getTonBagIds());
+ if (palletsRequested && tonsRequested) throw bindingError("缁戝畾鎵樼洏鍜岀粦瀹氬惃琚嬪彧鑳介�夋嫨涓�绉�");
+ if (batch != null && (palletsRequested || tonsRequested)) {
+ String existingMode = getBindingMode(batch.getId());
+ if ((tonsRequested && "pallet".equals(existingMode))
+ || (palletsRequested && "tonBag".equals(existingMode)))
+ throw bindingError("璇ユ壒娆″凡缁戝畾鍙︿竴绉嶇爜锛岀粦瀹氭墭鐩樺拰缁戝畾鍚ㄨ鍙兘閫夋嫨涓�绉�");
+ }
Long itemId = batch == null ? null : batch.getItemId();
if (batch != null) {
for (Long existing : bagCodeMapper.selectDistinctItemIdsByBatchId(batch.getId()))
@@ -359,12 +395,48 @@
if (candidate == null) throw new cn.iocoder.yudao.framework.common.exception.ServiceException(400, "鎵樼洏缂哄皯鍝佺锛岃鍏堢粦瀹氬悓鍝佺琚嬬爜");
itemId = cn.iocoder.yudao.module.mes.service.pro.pallet.MesProPalletItemResolver.merge(itemId, candidate);
}
- // 璇锋眰閲岀殑鍝佺鍙兘涓庡凡缁戝畾/寰呯粦瀹氭墭鐩樹竴鑷达紝涓嶈兘閫氳繃缂栬緫鏀瑰彉鎵规鍝佺銆�
+ if (tonsRequested) {
+ if (req.getTonBagIds().contains(null)) throw bindingError("璇烽�夋嫨鏈夋晥鐨勫惃琚�");
+ List<Long> ids = req.getTonBagIds().stream().distinct().sorted().toList();
+ List<MesProBagCodeDO> bags = bagCodeMapper.selectListByIdsForUpdate(ids);
+ if (bags.size() != ids.size()) throw bindingError("鎵�閫夊惃琚嬩笉瀛樺湪");
+ for (MesProBagCodeDO bag : bags) {
+ if (bag.getBatchId() != null || bag.getPalletId() != null || !isTonItem(bag.getItemId()))
+ throw bindingError("鍙兘缁戝畾鏈綍鍏ユ壒娆°�佹病鏈夋墭鐩樹笖璁¢噺鍗曚綅涓哄惃鐨勮鐮�");
+ itemId = cn.iocoder.yudao.module.mes.service.pro.pallet.MesProPalletItemResolver.merge(itemId, bag.getItemId());
+ }
+ }
+ // 璇锋眰閲岀殑鍝佺鍙兘涓庡凡缁戝畾鎴栧緟缁戝畾鐨勬墭鐩�/鍚ㄨ涓�鑷达紝涓嶈兘閫氳繃缂栬緫鏀瑰彉鎵规鍝佺銆�
if (req.getItemId() != null && !Objects.equals(req.getItemId(), itemId))
- throw new cn.iocoder.yudao.framework.common.exception.ServiceException(400, "鍝佺鐢辩粦瀹氭墭鐩樺甫鍏ワ紝涓嶅彲淇敼涓哄叾浠栧搧绉�");
+ throw bindingError("鍝佺鐢辩粦瀹氭墭鐩樻垨鍚ㄨ甯﹀叆锛屼笉鍙慨鏀逛负鍏朵粬鍝佺");
return itemId;
}
+ private boolean hasBindings(MesProBatchSaveReqVO req) {
+ return CollUtil.isNotEmpty(req.getPalletIds()) || CollUtil.isNotEmpty(req.getTonBagIds());
+ }
+
+ private boolean isTonItem(Long itemId) {
+ if (itemId == null) return false;
+ MesMdmItemDO item = mdmItemService.getItem(itemId);
+ if (item == null || item.getUnitMeasureId() == null) return false;
+ var result = unitMeasureApi.getUnitMeasure(item.getUnitMeasureId());
+ return result != null && result.isSuccess() && result.getData() != null
+ && "鍚�".equals(StrUtil.trim(result.getData().getType()));
+ }
+
+ private cn.iocoder.yudao.framework.common.exception.ServiceException bindingError(String message) {
+ return new cn.iocoder.yudao.framework.common.exception.ServiceException(400, message);
+ }
+
+ private void bindTonBagsToBatch(Long batchId, List<Long> tonBagIds) {
+ if (CollUtil.isEmpty(tonBagIds)) return;
+ MesProBagCodeBindBatchReqVO req = new MesProBagCodeBindBatchReqVO();
+ req.setBatchId(batchId);
+ req.setIds(tonBagIds);
+ bagCodeService.bindBatch(req);
+ }
+
private void bindPalletsToBatch(Long batchId, List<Long> palletIds) {
if (CollUtil.isEmpty(palletIds)) {
return;
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/approver/MesQcApproverService.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/approver/MesQcApproverService.java
new file mode 100644
index 0000000..741dc6b
--- /dev/null
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/approver/MesQcApproverService.java
@@ -0,0 +1,57 @@
+package cn.iocoder.yudao.module.mes.service.qc.approver;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.module.mes.controller.admin.qc.approver.vo.MesQcApproverConfigPageReqVO;
+import cn.iocoder.yudao.module.mes.controller.admin.qc.approver.vo.MesQcApproverConfigSaveReqVO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.qc.approver.MesQcApproverConfigDO;
+
+import java.util.List;
+
+/**
+ * MES 璐ㄦ瀹℃牳浜� Service 鎺ュ彛
+ *
+ * @author 瓒呯骇绠$悊鍛�
+ */
+public interface MesQcApproverService {
+
+ /**
+ * 鍒涘缓璐ㄦ瀹℃牳浜洪厤缃�
+ */
+ Long createConfig(MesQcApproverConfigSaveReqVO reqVO);
+
+ /**
+ * 鏇存柊璐ㄦ瀹℃牳浜洪厤缃�
+ */
+ void updateConfig(MesQcApproverConfigSaveReqVO reqVO);
+
+ /**
+ * 鍒犻櫎璐ㄦ瀹℃牳浜洪厤缃�
+ */
+ void deleteConfig(Long id);
+
+ /**
+ * 鑾峰緱璐ㄦ瀹℃牳浜洪厤缃�
+ */
+ MesQcApproverConfigDO getConfig(Long id);
+
+ /**
+ * 鑾峰緱璐ㄦ瀹℃牳浜洪厤缃垎椤�
+ */
+ PageResult<MesQcApproverConfigDO> getConfigPage(MesQcApproverConfigPageReqVO pageReqVO);
+
+ /**
+ * 鍒ゆ柇鐢ㄦ埛鏄惁涓烘寚瀹氳川妫�绫诲瀷鍜屽鏍歌妭鐐圭殑瀹℃牳浜�
+ */
+ boolean isApprover(Integer qcType, Integer approveNode, Long userId);
+
+ /**
+ * 鏍¢獙鐢ㄦ埛鏄惁涓烘寚瀹氳川妫�绫诲瀷鍜屽鏍歌妭鐐圭殑瀹℃牳浜猴紝涓嶆槸鍒欐姏鍑哄紓甯�
+ */
+ void validateApprover(Integer qcType, Integer approveNode, Long userId);
+
+ /**
+ * 鑾峰緱鎸囧畾璐ㄦ绫诲瀷鍜屽鏍歌妭鐐圭殑瀹℃牳浜虹敤鎴� ID 闆嗗悎
+ */
+ List<Long> getApproverUserIds(Integer qcType, Integer approveNode);
+
+}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/approver/MesQcApproverServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/approver/MesQcApproverServiceImpl.java
new file mode 100644
index 0000000..076ecdf
--- /dev/null
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/approver/MesQcApproverServiceImpl.java
@@ -0,0 +1,122 @@
+package cn.iocoder.yudao.module.mes.service.qc.approver;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
+import cn.iocoder.yudao.module.mes.controller.admin.qc.approver.vo.MesQcApproverConfigPageReqVO;
+import cn.iocoder.yudao.module.mes.controller.admin.qc.approver.vo.MesQcApproverConfigSaveReqVO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.qc.approver.MesQcApproverConfigDO;
+import cn.iocoder.yudao.module.mes.dal.mysql.qc.approver.MesQcApproverConfigMapper;
+import cn.iocoder.yudao.module.mes.enums.qc.MesQcApproveNodeEnum;
+import cn.iocoder.yudao.module.system.api.permission.PermissionApi;
+import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
+import jakarta.annotation.Resource;
+import org.springframework.stereotype.Service;
+import org.springframework.validation.annotation.Validated;
+
+import java.util.List;
+import java.util.Objects;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*;
+
+/**
+ * MES 璐ㄦ瀹℃牳浜� Service 瀹炵幇绫�
+ *
+ * @author 瓒呯骇绠$悊鍛�
+ */
+@Service
+@Validated
+public class MesQcApproverServiceImpl implements MesQcApproverService {
+
+ private static final String SUPER_ADMIN_ROLE = "super_admin";
+ private static final Integer STATUS_ENABLE = 0;
+
+ @Resource
+ private MesQcApproverConfigMapper approverConfigMapper;
+ @Resource
+ private AdminUserApi adminUserApi;
+ @Resource
+ private PermissionApi permissionApi;
+
+ @Override
+ public Long createConfig(MesQcApproverConfigSaveReqVO reqVO) {
+ validateConfigData(reqVO, null);
+ MesQcApproverConfigDO config = BeanUtils.toBean(reqVO, MesQcApproverConfigDO.class);
+ approverConfigMapper.insert(config);
+ return config.getId();
+ }
+
+ @Override
+ public void updateConfig(MesQcApproverConfigSaveReqVO reqVO) {
+ validateConfigExists(reqVO.getId());
+ validateConfigData(reqVO, reqVO.getId());
+ approverConfigMapper.updateById(BeanUtils.toBean(reqVO, MesQcApproverConfigDO.class));
+ }
+
+ @Override
+ public void deleteConfig(Long id) {
+ validateConfigExists(id);
+ approverConfigMapper.deleteById(id);
+ }
+
+ @Override
+ public MesQcApproverConfigDO getConfig(Long id) {
+ return approverConfigMapper.selectById(id);
+ }
+
+ @Override
+ public PageResult<MesQcApproverConfigDO> getConfigPage(MesQcApproverConfigPageReqVO pageReqVO) {
+ return approverConfigMapper.selectPage(pageReqVO);
+ }
+
+ @Override
+ public boolean isApprover(Integer qcType, Integer approveNode, Long userId) {
+ if (userId == null) {
+ return false;
+ }
+ // 瓒呯涓嶅彈瀹℃牳浜洪厤缃檺鍒�
+ if (permissionApi.hasAnyRoles(userId, SUPER_ADMIN_ROLE)) {
+ return true;
+ }
+ MesQcApproverConfigDO config = approverConfigMapper.selectByUnique(qcType, approveNode, userId);
+ return config != null && Objects.equals(config.getStatus(), STATUS_ENABLE);
+ }
+
+ @Override
+ public void validateApprover(Integer qcType, Integer approveNode, Long userId) {
+ if (!isApprover(qcType, approveNode, userId)) {
+ throw exception(QC_APPROVER_NOT_CONFIGURED);
+ }
+ }
+
+ @Override
+ public List<Long> getApproverUserIds(Integer qcType, Integer approveNode) {
+ return approverConfigMapper.selectList(new LambdaQueryWrapperX<MesQcApproverConfigDO>()
+ .eq(MesQcApproverConfigDO::getQcType, qcType)
+ .eq(MesQcApproverConfigDO::getApproveNode, approveNode)
+ .eq(MesQcApproverConfigDO::getStatus, STATUS_ENABLE))
+ .stream().map(MesQcApproverConfigDO::getUserId).toList();
+ }
+
+ private MesQcApproverConfigDO validateConfigExists(Long id) {
+ MesQcApproverConfigDO config = approverConfigMapper.selectById(id);
+ if (config == null) {
+ throw exception(QC_APPROVER_CONFIG_NOT_EXISTS);
+ }
+ return config;
+ }
+
+ private void validateConfigData(MesQcApproverConfigSaveReqVO reqVO, Long excludeId) {
+ if (!MesQcApproveNodeEnum.isValidCombination(reqVO.getQcType(), reqVO.getApproveNode())) {
+ throw exception(QC_APPROVER_NODE_INVALID);
+ }
+ adminUserApi.validateUser(reqVO.getUserId());
+ MesQcApproverConfigDO existed = approverConfigMapper.selectByUnique(
+ reqVO.getQcType(), reqVO.getApproveNode(), reqVO.getUserId());
+ if (existed != null && !Objects.equals(existed.getId(), excludeId)) {
+ throw exception(QC_APPROVER_CONFIG_DUPLICATE);
+ }
+ }
+
+}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/oqc/MesQcOqcService.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/oqc/MesQcOqcService.java
index b2eecba..b6425fd 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/oqc/MesQcOqcService.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/oqc/MesQcOqcService.java
@@ -38,10 +38,6 @@
* @param id 缂栧彿
*/
void finishOqc(Long id);
- void retestOqc(cn.iocoder.yudao.module.mes.controller.admin.qc.oqc.vo.MesQcOqcRetestReqVO reqVO);
- void salesApprove(Long id, boolean approved, String opinion);
- void companyApprove(Long id, boolean approved, String opinion);
- List<cn.iocoder.yudao.module.mes.dal.dataobject.qc.oqc.MesQcOqcActionDO> getActions(Long id);
/**
* 鍒犻櫎鍑鸿揣妫�楠屽崟
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/oqc/MesQcOqcServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/oqc/MesQcOqcServiceImpl.java
index 26811bf..57b4dd2 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/oqc/MesQcOqcServiceImpl.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/oqc/MesQcOqcServiceImpl.java
@@ -1,18 +1,14 @@
package cn.iocoder.yudao.module.mes.service.qc.oqc;
import cn.hutool.core.util.ObjUtil;
-import cn.hutool.json.JSONUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.mes.controller.admin.qc.oqc.vo.MesQcOqcPageReqVO;
import cn.iocoder.yudao.module.mes.controller.admin.qc.oqc.vo.MesQcOqcSaveReqVO;
-import cn.iocoder.yudao.module.mes.controller.admin.qc.oqc.vo.MesQcOqcRetestReqVO;
import cn.iocoder.yudao.module.mes.dal.dataobject.qc.defectrecord.MesQcDefectRecordDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.qc.oqc.MesQcOqcDO;
-import cn.iocoder.yudao.module.mes.dal.dataobject.qc.oqc.MesQcOqcActionDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.qc.template.MesQcTemplateItemDO;
import cn.iocoder.yudao.module.mes.dal.mysql.qc.oqc.MesQcOqcMapper;
-import cn.iocoder.yudao.module.mes.dal.mysql.qc.oqc.MesQcOqcActionMapper;
import cn.iocoder.yudao.module.mes.enums.qc.MesQcDefectLevelEnum;
import cn.iocoder.yudao.module.mes.enums.qc.MesQcStatusEnum;
import cn.iocoder.yudao.module.mes.enums.qc.MesQcTypeEnum;
@@ -40,11 +36,8 @@
import java.math.RoundingMode;
import java.util.List;
import java.util.Objects;
-import java.time.LocalDateTime;
-import java.util.Set;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
-import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*;
/**
@@ -56,13 +49,8 @@
@Validated
public class MesQcOqcServiceImpl implements MesQcOqcService {
- private static final int WAIT_RETEST = 10, WAIT_SALES = 20, WAIT_COMPANY = 30,
- RELEASED = 40, WAIT_SALES_FAIL = 50, WAIT_COMPANY_FAIL = 60, REJECTED = 70;
-
@Resource
private MesQcOqcMapper oqcMapper;
- @Resource
- private MesQcOqcActionMapper actionMapper;
@Resource
private MesQcTemplateItemService templateItemService;
@@ -145,114 +133,25 @@
@Transactional(rollbackFor = Exception.class)
public void finishOqc(Long id) {
// 1.1 鏍¢獙瀛樺湪 + 鑽夌鐘舵��
- MesQcOqcDO oqc = lock(id);
- if (!MesQcStatusEnum.DRAFT.getStatus().equals(oqc.getStatus())) throw exception(QC_OQC_NOT_PREPARE);
+ MesQcOqcDO oqc = validateOqcStatusPrepare(id);
// 1.2 鏍¢獙妫�娴嬬粨璁哄繀濉�
if (oqc.getCheckResult() == null) {
throw exception(QC_OQC_CHECK_RESULT_EMPTY);
- }
- if (oqc.getUnqualifiedQuantity() != null && oqc.getUnqualifiedQuantity().compareTo(BigDecimal.ZERO) > 0
- && MesQcCheckResultEnum.QUALIFIED.getType().equals(oqc.getCheckResult())) {
- throw new IllegalArgumentException("瀛樺湪涓嶅悎鏍煎搧鏃讹紝鍑鸿揣妫�楠岀粨璁轰笉鑳戒负鍚堟牸");
- }
- if ((oqc.getUnqualifiedQuantity() == null || oqc.getUnqualifiedQuantity().compareTo(BigDecimal.ZERO) == 0)
- && !MesQcCheckResultEnum.QUALIFIED.getType().equals(oqc.getCheckResult())) {
- throw new IllegalArgumentException("涓嶅悎鏍兼暟閲忎负 0 鏃讹紝鍑鸿揣妫�楠岀粨璁哄繀椤讳负鍚堟牸");
}
// 1.3 鏍¢獙鑷冲皯瀛樺湪涓�鏉℃娴嬬粨鏋�
indicatorResultService.validateIndicatorResultExistsByQcIdAndType(id, MesQcTypeEnum.OQC.getType());
// 2. 鏇存柊鐘舵�佷负宸插畬鎴�
MesQcOqcDO updateObj = new MesQcOqcDO()
- .setId(id).setStatus(MesQcStatusEnum.FINISHED.getStatus())
- .setWorkflowStatus(MesQcCheckResultEnum.QUALIFIED.getType().equals(oqc.getCheckResult()) ? WAIT_SALES : WAIT_RETEST);
+ .setId(id).setStatus(MesQcStatusEnum.FINISHED.getStatus());
oqcMapper.updateById(updateObj);
- recordAction(id, "INITIAL", oqc.getCheckResult(), null, oqc);
- // 閿�鍞嚭搴撴槑缁嗕粛涓哄緟妫�锛涘叕鍙歌川妫�瀹℃壒閫氳繃鍚庢墠鍥炲啓骞跺厑璁稿悗缁嚭搴撱��
- }
- @Override
- @Transactional(rollbackFor = Exception.class)
- public void retestOqc(MesQcOqcRetestReqVO req) {
- MesQcOqcDO oqc = requireStatus(req.getId(), WAIT_RETEST);
- if (req.getCheckQuantity().compareTo(req.getQualifiedQuantity().add(req.getUnqualifiedQuantity())) != 0)
- throw new IllegalArgumentException("妫�娴嬫暟閲忓繀椤荤瓑浜庡悎鏍间笌涓嶅悎鏍兼暟閲忎箣鍜�");
- if (req.getCheckQuantity().compareTo(oqc.getOutQuantity()) > 0)
- throw new IllegalArgumentException("妫�娴嬫暟閲忎笉鑳借秴杩囧嚭璐ф暟閲�");
- if (!Set.of(1, 2).contains(req.getCheckResult())) throw new IllegalArgumentException("澶嶆缁撹鍙兘涓哄悎鏍兼垨涓嶅悎鏍�");
- boolean passed = req.getCheckResult() == 1;
- if (passed != (req.getUnqualifiedQuantity().compareTo(BigDecimal.ZERO) == 0))
- throw new IllegalArgumentException("澶嶆缁撹涓庝笉鍚堟牸鏁伴噺涓嶄竴鑷�");
- if (!passed && (req.getOpinion() == null || req.getOpinion().isBlank()))
- throw new IllegalArgumentException("澶嶆涓嶅悎鏍煎繀椤诲~鍐欏師鍥�");
- MesQcOqcDO update = new MesQcOqcDO().setId(req.getId())
- .setCheckQuantity(req.getCheckQuantity()).setQualifiedQuantity(req.getQualifiedQuantity())
- .setUnqualifiedQuantity(req.getUnqualifiedQuantity()).setCheckResult(req.getCheckResult())
- .setInspectDate(LocalDateTime.now()).setInspectorUserId(getLoginUserId())
- .setWorkflowStatus(passed ? WAIT_SALES : WAIT_SALES_FAIL);
- oqcMapper.updateById(update);
- recordAction(req.getId(), "RETEST", req.getCheckResult(), req.getOpinion(), update);
- }
+ // 3. 涓嶅悎鏍兼椂鑷姩鍒涘缓 NCR
+ generateNcrIfNeeded(oqc);
- @Override
- @Transactional(rollbackFor = Exception.class)
- public void salesApprove(Long id, boolean approved, String opinion) {
- MesQcOqcDO oqc = lock(id);
- if (!Set.of(WAIT_SALES, WAIT_SALES_FAIL).contains(oqc.getWorkflowStatus()))
- throw new IllegalArgumentException("褰撳墠鐘舵�佷笉鑳借繘琛岄攢鍞儴瀹℃壒");
- requireOpinion(opinion);
- int next = approved ? (oqc.getWorkflowStatus() == WAIT_SALES ? WAIT_COMPANY : WAIT_COMPANY_FAIL) : WAIT_RETEST;
- oqcMapper.updateById(new MesQcOqcDO().setId(id).setWorkflowStatus(next));
- recordAction(id, approved ? "SALES_APPROVE" : "SALES_REJECT", oqc.getCheckResult(), opinion, oqc);
+ // 4. 鍥炲啓鏉ユ簮鍗曟嵁
+ writeBackSourceDoc(oqc);
}
-
- @Override
- @Transactional(rollbackFor = Exception.class)
- public void companyApprove(Long id, boolean approved, String opinion) {
- MesQcOqcDO oqc = lock(id);
- if (!Set.of(WAIT_COMPANY, WAIT_COMPANY_FAIL).contains(oqc.getWorkflowStatus()))
- throw new IllegalArgumentException("褰撳墠鐘舵�佷笉鑳借繘琛屽叕鍙歌川妫�瀹℃壒");
- requireOpinion(opinion);
- if (approved) {
- if (oqc.getWorkflowStatus() == WAIT_COMPANY_FAIL) generateNcrIfNeeded(oqc);
- writeBackSourceDoc(oqc);
- }
- int next = approved ? (oqc.getWorkflowStatus() == WAIT_COMPANY ? RELEASED : REJECTED) : WAIT_RETEST;
- oqcMapper.updateById(new MesQcOqcDO().setId(id).setWorkflowStatus(next));
- recordAction(id, approved ? "COMPANY_APPROVE" : "COMPANY_REJECT", oqc.getCheckResult(), opinion, oqc);
- }
-
- private MesQcOqcDO lock(Long id) {
- MesQcOqcDO oqc = oqcMapper.selectByIdForUpdate(id);
- if (oqc == null) throw exception(QC_OQC_NOT_EXISTS);
- return oqc;
- }
-
- private MesQcOqcDO requireStatus(Long id, int status) {
- MesQcOqcDO oqc = lock(id);
- if (!Objects.equals(oqc.getWorkflowStatus(), status))
- throw new IllegalArgumentException("閿�鍞川妫�鐘舵�佸凡鍙樺寲锛岃鍒锋柊鍚庨噸璇�");
- return oqc;
- }
-
- private void requireOpinion(String opinion) {
- if (opinion == null || opinion.isBlank()) throw new IllegalArgumentException("璇峰~鍐欏鎵规剰瑙�");
- }
-
- private void recordAction(Long id, String action, Integer result, String opinion, MesQcOqcDO snapshot) {
- MesQcOqcActionDO event = new MesQcOqcActionDO();
- event.setOqcId(id);event.setAction(action);event.setResult(result);event.setOpinion(opinion);
- java.util.Map<String, BigDecimal> quantities = new java.util.HashMap<>();
- quantities.put("checkQuantity", snapshot.getCheckQuantity());
- quantities.put("qualifiedQuantity", snapshot.getQualifiedQuantity());
- quantities.put("unqualifiedQuantity", snapshot.getUnqualifiedQuantity());
- event.setQuantitiesJson(JSONUtil.toJsonStr(quantities));
- event.setOperatorId(getLoginUserId());event.setCreateTime(LocalDateTime.now());
- actionMapper.insert(event);
- }
-
- @Override
- public List<MesQcOqcActionDO> getActions(Long id) { return actionMapper.selectByOqcId(id); }
/**
* 涓嶅悎鏍兼椂鑷姩鍒涘缓 NCR锛堜笉鍚堟牸鍝佸鐞嗗崟锛�
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/seedquality/MesQcSeedIndicatorRangeService.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/seedquality/MesQcSeedIndicatorRangeService.java
new file mode 100644
index 0000000..0318ac7
--- /dev/null
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/seedquality/MesQcSeedIndicatorRangeService.java
@@ -0,0 +1,45 @@
+package cn.iocoder.yudao.module.mes.service.qc.seedquality;
+
+import cn.iocoder.yudao.module.mes.controller.admin.qc.seedquality.vo.MesQcSeedIndicatorRangeSaveReqVO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.qc.seedquality.MesQcSeedIndicatorRangeDO;
+import cn.iocoder.yudao.module.mes.dal.mysql.qc.seedquality.MesQcSeedIndicatorRangeMapper;
+import jakarta.annotation.Resource;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.List;
+import java.util.Set;
+import java.math.BigDecimal;
+import java.util.stream.Collectors;
+
+@Service
+public class MesQcSeedIndicatorRangeService {
+ private static final Set<String> CODES = Set.of("purity", "cleanliness", "germination_rate", "moisture");
+ @Resource private MesQcSeedIndicatorRangeMapper mapper;
+
+ public List<MesQcSeedIndicatorRangeDO> getRanges() {
+ return mapper.selectList().stream().filter(item -> CODES.contains(item.getIndicatorCode())).toList();
+ }
+
+ @Transactional(rollbackFor = Exception.class)
+ public void saveRanges(MesQcSeedIndicatorRangeSaveReqVO request) {
+ List<MesQcSeedIndicatorRangeSaveReqVO.Item> items = request.getRanges();
+ if (items == null || items.size() != CODES.size() || items.stream().anyMatch(item -> item == null || item.getIndicatorCode() == null
+ || item.getMinValue() == null || item.getMaxValue() == null)
+ || !items.stream().map(MesQcSeedIndicatorRangeSaveReqVO.Item::getIndicatorCode)
+ .collect(Collectors.toSet()).equals(CODES))
+ throw new IllegalArgumentException("蹇呴』瀹屾暣閰嶇疆绾害銆佸噣搴︺�佸彂鑺界巼銆佹按鍒嗗洓椤规寚鏍�");
+ for (MesQcSeedIndicatorRangeSaveReqVO.Item item : items) {
+ if (item.getMinValue().compareTo(BigDecimal.ZERO) < 0 || item.getMaxValue().compareTo(new BigDecimal("100")) > 0
+ || item.getMinValue().compareTo(item.getMaxValue()) > 0)
+ throw new IllegalArgumentException("鎸囨爣鍚堟牸鑼冨洿蹇呴』澶勪簬 0鈥�100 涓斾笅闄愪笉澶т簬涓婇檺锛�" + item.getIndicatorCode());
+ MesQcSeedIndicatorRangeDO row = new MesQcSeedIndicatorRangeDO();
+ row.setIndicatorCode(item.getIndicatorCode());
+ row.setMinValue(item.getMinValue());
+ row.setMaxValue(item.getMaxValue());
+ if (mapper.selectById(item.getIndicatorCode()) == null) mapper.insert(row);
+ else mapper.updateById(row);
+ }
+ }
+
+}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/seedquality/MesQcSeedQualityService.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/seedquality/MesQcSeedQualityService.java
index 2d290f2..66740af 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/seedquality/MesQcSeedQualityService.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/seedquality/MesQcSeedQualityService.java
@@ -16,6 +16,9 @@
java.util.Map<String, Object> resolveScan(String code, String scanType);
java.util.Map<String, Object> submitGroup(cn.iocoder.yudao.module.mes.controller.admin.qc.seedquality.vo.MesQcSeedQualityGroupSubmitReqVO reqVO);
void retest(Long id, cn.iocoder.yudao.module.mes.controller.admin.qc.seedquality.vo.MesQcSeedQualityRetestReqVO reqVO);
+ void retestBatch(cn.iocoder.yudao.module.mes.controller.admin.qc.seedquality.vo.MesQcSeedQualityBatchRetestReqVO reqVO);
+ java.util.Map<String, Object> resolveRetestScope(String code, String scanType);
+ java.util.Map<String, Object> retestScope(cn.iocoder.yudao.module.mes.controller.admin.qc.seedquality.vo.MesQcSeedQualityScopeRetestReqVO reqVO);
void processApprove(Long id, boolean approved, String opinion);
void companyApprove(Long id, boolean approved, String opinion);
void processApproveBatch(List<Long> ids, boolean approved, String opinion);
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/seedquality/MesQcSeedQualityServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/seedquality/MesQcSeedQualityServiceImpl.java
index 2a3ba96..386ab71 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/seedquality/MesQcSeedQualityServiceImpl.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/seedquality/MesQcSeedQualityServiceImpl.java
@@ -22,11 +22,14 @@
import cn.iocoder.yudao.module.mes.dal.dataobject.wm.materialstockbag.MesWmMaterialStockBagDO;
import cn.iocoder.yudao.module.mes.dal.mysql.wm.materialstockbag.MesWmMaterialStockBagMapper;
import cn.iocoder.yudao.module.mes.enums.pro.MesProBagCodeQcStatusEnum;
+import cn.iocoder.yudao.module.mes.enums.qc.MesQcApproveNodeEnum;
+import cn.iocoder.yudao.module.mes.enums.qc.MesQcApprovalTypeEnum;
import cn.iocoder.yudao.module.mes.enums.wm.MesWmStockStateEnum;
import cn.iocoder.yudao.module.mes.enums.wm.MesWmTransactionTypeEnum;
import cn.iocoder.yudao.module.mes.enums.MesBizTypeConstants;
import cn.iocoder.yudao.module.mes.enums.wm.MesWmWarehouseTypeEnum;
import cn.iocoder.yudao.module.mes.service.pro.batch.MesProBatchService;
+import cn.iocoder.yudao.module.mes.service.qc.approver.MesQcApproverService;
import cn.iocoder.yudao.module.mes.service.wm.materialstockbag.MesWmMaterialStockBagService;
import cn.iocoder.yudao.module.mes.service.wm.transaction.MesWmTransactionService;
import cn.iocoder.yudao.module.mes.service.wm.transaction.dto.MesWmTransactionSaveReqDTO;
@@ -52,9 +55,10 @@
@Service @Validated @Slf4j
public class MesQcSeedQualityServiceImpl implements MesQcSeedQualityService {
private static final Set<String> REQUIRED = Set.of("purity", "cleanliness", "germination_rate", "moisture");
- private static final int WAIT_RETEST = 10, WAIT_PROCESS = 20, WAIT_COMPANY = 30,
- RELEASED = 40, WAIT_PROCESS_FAIL = 50, WAIT_COMPANY_FAIL = 60, SCRAPPED = 70;
+ private static final int WAIT_RETEST = 10, WAIT_PROCESS = 20, WAIT_INITIAL_FAIL_REVIEW = 25, WAIT_COMPANY = 30,
+ RELEASED = 40, WAIT_INITIAL_RECHECK = 50, WAIT_COMPANY_FAIL = 60, SCRAPPED = 70;
@Resource private MesQcSeedQualityMapper qualityMapper;
+ @Resource private MesQcApproverService approverService;
@Resource private MesQcSeedQualityActionMapper actionMapper;
@Resource private MesQcSeedQualityIndicatorMapper indicatorMapper;
@Resource private MesProBagCodeMapper bagCodeMapper;
@@ -210,8 +214,13 @@
.inspectedAt(LocalDateTime.now()).build();
qualityMapper.insert(quality);
for (MesQcSeedQualitySubmitReqVO.Indicator item : reqVO.getIndicators()) {
+ if (item == null || item.getCode() == null || item.getValue() == null || item.getMinValue() == null || item.getMaxValue() == null)
+ throw new IllegalArgumentException("鍥涢」鎸囨爣鐨勫疄娴嬪�煎拰鏈鍚堟牸鑼冨洿蹇呴』瀹屾暣");
if (!REQUIRED.contains(item.getCode()) || !codes.add(item.getCode())) throw new IllegalArgumentException("鎸囨爣蹇呴』涓虹函搴︺�佸噣搴︺�佸彂鑺界巼銆佹按鍒嗕笖涓嶅彲閲嶅");
if (item.getMinValue().compareTo(item.getMaxValue()) > 0) throw new IllegalArgumentException("鎸囨爣涓嬮檺涓嶈兘澶т簬涓婇檺");
+ if (item.getValue().compareTo(BigDecimal.ZERO) < 0 || item.getValue().compareTo(new BigDecimal("100")) > 0
+ || item.getMinValue().compareTo(BigDecimal.ZERO) < 0 || item.getMaxValue().compareTo(new BigDecimal("100")) > 0)
+ throw new IllegalArgumentException("鐧惧垎姣旀寚鏍囧繀椤诲浜� 0鈥�100");
if (item.getValue().compareTo(item.getMinValue()) < 0 || item.getValue().compareTo(item.getMaxValue()) > 0) passed = false;
indicatorMapper.insert(MesQcSeedQualityIndicatorDO.builder().qualityId(quality.getId()).indicatorCode(item.getCode())
.value(item.getValue()).minValue(item.getMinValue()).maxValue(item.getMaxValue()).build());
@@ -219,10 +228,10 @@
if (!codes.equals(REQUIRED)) throw new IllegalArgumentException("鍥涢」鎸囨爣涓嶅畬鏁�");
if (!passed && StrUtil.isBlank(reqVO.getReason())) throw new IllegalArgumentException("璐ㄦ涓嶅悎鏍煎繀椤诲~鍐欏師鍥�");
quality.setResult(passed ? 1 : 2);
- quality.setWorkflowStatus(passed ? WAIT_PROCESS : WAIT_RETEST);
+ quality.setWorkflowStatus(passed ? WAIT_PROCESS : WAIT_INITIAL_FAIL_REVIEW);
qualityMapper.updateById(quality);
recordAction(quality.getId(), "INITIAL", quality.getResult(), reqVO.getReason(), reqVO.getIndicators());
- // 鍒濇浠呰褰曠粨璁猴紱琚嬩粛鐣欏湪鏆傚瓨搴擄紝寰呭妫�鍙婁袱绾у鎵瑰悗鍐嶆斁琛屾垨鎶ュ簾銆�
+ // 鍒濇浠呰褰曠粨璁猴紱琚嬩粛鐣欏湪鏆傚瓨搴擄紝寰呭垵妫�瀹℃牳銆佸妫�鍙婃渶缁堝鏍稿悗鍐嶆斁琛屾垨鎶ュ簾銆�
return quality.getId();
}
@@ -310,15 +319,24 @@
@Override @Transactional(rollbackFor = Exception.class)
public void retest(Long id, cn.iocoder.yudao.module.mes.controller.admin.qc.seedquality.vo.MesQcSeedQualityRetestReqVO req) {
- MesQcSeedQualityDO quality = requireStatus(id, WAIT_RETEST);
- if (!Objects.equals(quality.getCode(), req.getCode())) throw new IllegalArgumentException("澶嶆琚嬬爜涓庡師璐ㄦ璁板綍涓嶄竴鑷�");
+ MesQcSeedQualityDO quality = qualityMapper.selectByIdForUpdate(id);
+ if (quality == null || !Set.of(WAIT_RETEST, WAIT_INITIAL_RECHECK).contains(quality.getWorkflowStatus()))
+ throw new IllegalArgumentException("褰撳墠鐘舵�佷笉鑳芥彁浜ゅ妫�锛岃鍒锋柊鍚庨噸璇�");
+ boolean initialRecheck = Objects.equals(quality.getWorkflowStatus(), WAIT_INITIAL_RECHECK);
+ if (!Objects.equals(quality.getCode(), req.getCode())) throw new IllegalArgumentException("妫�楠岃鐮佷笌鍘熻川妫�璁板綍涓嶄竴鑷�");
boolean passed = validateIndicators(req.getIndicators());
- if (!passed && StrUtil.isBlank(req.getReason())) throw new IllegalArgumentException("澶嶆涓嶅悎鏍煎繀椤诲~鍐欏師鍥�");
- recordAction(id, "RETEST", passed ? 1 : 2, req.getReason(), req.getIndicators());
- qualityMapper.updateById(MesQcSeedQualityDO.builder().id(id).result(passed ? 1 : 2)
- .reason(passed ? "" : req.getReason().trim()).retestResult(passed ? 1 : 2).retestedAt(LocalDateTime.now())
+ if (!passed && StrUtil.isBlank(req.getReason())) throw new IllegalArgumentException("妫�楠屼笉鍚堟牸蹇呴』濉啓鍘熷洜");
+ recordAction(id, initialRecheck ? "INITIAL_RECHECK" : "RETEST", passed ? 1 : 2, req.getReason(), req.getIndicators());
+ MesQcSeedQualityDO update = MesQcSeedQualityDO.builder().id(id).result(passed ? 1 : 2)
+ .reason(passed ? "" : req.getReason().trim())
.inspectorId(getLoginUserId()).inspectedAt(LocalDateTime.now())
- .workflowStatus(passed ? WAIT_PROCESS : WAIT_PROCESS_FAIL).build());
+ .workflowStatus(initialRecheck ? (passed ? WAIT_PROCESS : WAIT_INITIAL_FAIL_REVIEW)
+ : (passed ? WAIT_COMPANY : WAIT_COMPANY_FAIL)).build();
+ if (!initialRecheck) {
+ update.setRetestResult(passed ? 1 : 2);
+ update.setRetestedAt(LocalDateTime.now());
+ }
+ qualityMapper.updateById(update);
// 椤甸潰銆佸叕寮�杩芥函璇诲彇涓绘寚鏍囪〃锛涘悓姝ヤ负鏈�鏂颁竴娆℃祴鍊硷紝鍘嗘娴嬪�煎湪鎿嶄綔鐣欑棔琛ㄤ繚鐣欍��
Map<String, MesQcSeedQualityIndicatorDO> existing = new HashMap<>();
for (MesQcSeedQualityIndicatorDO indicator : indicatorMapper.selectListByQualityId(id))
@@ -332,12 +350,108 @@
}
@Override @Transactional(rollbackFor = Exception.class)
+ public void retestBatch(cn.iocoder.yudao.module.mes.controller.admin.qc.seedquality.vo.MesQcSeedQualityBatchRetestReqVO req) {
+ List<Long> ids = approvalIds(req.getIds());
+ String batchCode = null;
+ Integer workflowStatus = null;
+ boolean first = true;
+ List<MesQcSeedQualityDO> qualities = new ArrayList<>();
+ for (Long id : ids) {
+ MesQcSeedQualityDO quality = qualityMapper.selectByIdForUpdate(id);
+ if (quality == null || !Set.of(WAIT_RETEST, WAIT_INITIAL_RECHECK).contains(quality.getWorkflowStatus()))
+ throw new IllegalArgumentException("鎵�閫夎褰曞寘鍚笉鍙楠岀殑鐘舵�侊紝璇峰埛鏂板悗閲嶈瘯");
+ if (StrUtil.isBlank(quality.getBatchCode()))
+ throw new IllegalArgumentException("璁板綍缂哄皯鐢熶骇鎵规锛屼笉鑳芥壒閲忚川妫�");
+ if (first) {
+ batchCode = quality.getBatchCode();
+ workflowStatus = quality.getWorkflowStatus();
+ first = false;
+ } else if (!Objects.equals(batchCode, quality.getBatchCode()) || !Objects.equals(workflowStatus, quality.getWorkflowStatus())) {
+ throw new IllegalArgumentException("鎵归噺璐ㄦ鍙厑璁稿悓鐢熶骇鎵规銆佸悓娴佺▼鐘舵�佺殑璁板綍");
+ }
+ qualities.add(quality);
+ }
+ for (MesQcSeedQualityDO quality : qualities) {
+ cn.iocoder.yudao.module.mes.controller.admin.qc.seedquality.vo.MesQcSeedQualityRetestReqVO single =
+ new cn.iocoder.yudao.module.mes.controller.admin.qc.seedquality.vo.MesQcSeedQualityRetestReqVO();
+ single.setCode(quality.getCode());
+ single.setIndicators(req.getIndicators());
+ single.setReason(req.getReason());
+ retest(quality.getId(), single);
+ }
+ }
+
+ private void checkRetestScanType(String scanType) {
+ if (!Set.of("PALLET", "BATCH").contains(scanType))
+ throw new IllegalArgumentException("鎵归噺璐ㄦ鍙敮鎸佹墭鐩樼爜鎴栫敓浜ф壒娆$爜");
+ }
+
+ @Override
+ public Map<String, Object> resolveRetestScope(String code, String scanType) {
+ checkRetestScanType(scanType);
+ Scope scope = scope(code, scanType, false);
+ if (scope.canceled()) throw new IllegalArgumentException("璐ㄦ瀵硅薄宸蹭綔搴�");
+ List<String> codes = scope.bags().stream().filter(b -> !Integer.valueOf(30).equals(b.getStatus()) && b.getInboundEventId() != null)
+ .map(MesProBagCodeDO::getCode).toList();
+ List<MesQcSeedQualityDO> qualities = codes.isEmpty() ? List.of() : qualityMapper.selectListByCodes(codes);
+ List<Long> retestIds = qualities.stream().filter(q -> Objects.equals(q.getWorkflowStatus(), WAIT_RETEST))
+ .map(MesQcSeedQualityDO::getId).sorted().toList();
+ List<Long> initialRecheckIds = qualities.stream().filter(q -> Objects.equals(q.getWorkflowStatus(), WAIT_INITIAL_RECHECK))
+ .map(MesQcSeedQualityDO::getId).sorted().toList();
+ long pendingProcessCount = qualities.stream().filter(q -> Objects.equals(q.getWorkflowStatus(), WAIT_PROCESS)
+ || Objects.equals(q.getWorkflowStatus(), WAIT_INITIAL_FAIL_REVIEW)).count();
+ long pendingCompanyCount = qualities.stream().filter(q -> Objects.equals(q.getWorkflowStatus(), WAIT_COMPANY)
+ || Objects.equals(q.getWorkflowStatus(), WAIT_COMPANY_FAIL)).count();
+ Map<String, Object> result = new HashMap<>();
+ result.put("code", scope.code()); result.put("scanType", scanType); result.put("batchCode", scope.batchCode());
+ result.put("totalCount", codes.size()); result.put("retestIds", retestIds);
+ result.put("initialRecheckIds", initialRecheckIds);
+ result.put("pendingProcessCount", pendingProcessCount);
+ result.put("pendingCompanyCount", pendingCompanyCount);
+ return result;
+ }
+
+ @Override @Transactional(rollbackFor = Exception.class)
+ public Map<String, Object> retestScope(cn.iocoder.yudao.module.mes.controller.admin.qc.seedquality.vo.MesQcSeedQualityScopeRetestReqVO req) {
+ checkRetestScanType(req.getScanType());
+ if (!Set.of(WAIT_RETEST, WAIT_INITIAL_RECHECK).contains(req.getWorkflowStatus()))
+ throw new IllegalArgumentException("鎵归噺璐ㄦ鐘舵�佹棤鏁�");
+ List<Long> confirmed = approvalIds(req.getQualityIds());
+ Scope scope = scope(req.getCode(), req.getScanType(), true);
+ if (scope.canceled()) throw new IllegalArgumentException("璐ㄦ瀵硅薄宸蹭綔搴�");
+ List<MesProBagCodeDO> effective = scope.bags().stream()
+ .filter(b -> !Integer.valueOf(30).equals(b.getStatus()) && b.getInboundEventId() != null).toList();
+ if (effective.isEmpty()) throw new IllegalArgumentException("褰撳墠鑼冨洿娌℃湁宸插叆搴撶殑鏈夋晥琚嬬爜");
+ List<MesProBagCodeDO> locked = bagCodeMapper.selectListByIdsForUpdate(effective.stream().map(MesProBagCodeDO::getId).toList());
+ if (locked.size() != effective.size() || locked.stream().anyMatch(b -> Integer.valueOf(30).equals(b.getStatus()) || b.getInboundEventId() == null))
+ throw new IllegalArgumentException("琚嬬爜鐘舵�佸凡鍙樺寲锛岃閲嶆柊鎵弿");
+ Scope current = scope(req.getCode(), req.getScanType(), false);
+ Set<Long> currentIds = current.bags().stream().filter(b -> !Integer.valueOf(30).equals(b.getStatus()) && b.getInboundEventId() != null)
+ .map(MesProBagCodeDO::getId).collect(java.util.stream.Collectors.toSet());
+ if (!currentIds.equals(new HashSet<>(locked.stream().map(MesProBagCodeDO::getId).toList())))
+ throw new IllegalArgumentException("琚嬬爜褰掑睘宸插彉鍖栵紝璇烽噸鏂版壂鎻�");
+ List<MesQcSeedQualityDO> qualities = qualityMapper.selectListByCodesForUpdate(locked.stream().map(MesProBagCodeDO::getCode).toList());
+ List<MesQcSeedQualityDO> pending = qualities.stream().filter(q -> Objects.equals(q.getWorkflowStatus(), req.getWorkflowStatus()))
+ .sorted(Comparator.comparing(MesQcSeedQualityDO::getId)).toList();
+ if (pending.isEmpty() || !confirmed.equals(pending.stream().map(MesQcSeedQualityDO::getId).toList()))
+ throw new IllegalArgumentException("寰呰川妫�娓呭崟宸插彉鍖栵紝璇烽噸鏂版壂鎻忔牳瀵�");
+ for (MesQcSeedQualityDO quality : pending) {
+ var single = new cn.iocoder.yudao.module.mes.controller.admin.qc.seedquality.vo.MesQcSeedQualityRetestReqVO();
+ single.setCode(quality.getCode()); single.setIndicators(req.getIndicators()); single.setReason(req.getReason());
+ retest(quality.getId(), single);
+ }
+ return Map.of("processedCount", pending.size());
+ }
+
+ @Override @Transactional(rollbackFor = Exception.class)
public void processApprove(Long id, boolean approved, String opinion) {
MesQcSeedQualityDO quality = qualityMapper.selectByIdForUpdate(id);
- if (quality == null || !Set.of(WAIT_PROCESS, WAIT_PROCESS_FAIL).contains(quality.getWorkflowStatus()))
- throw new IllegalArgumentException("褰撳墠鐘舵�佷笉鑳借繘琛屽姞宸ラ儴瀹℃壒");
- if (StrUtil.isBlank(opinion)) throw new IllegalArgumentException("璇峰~鍐欏鎵规剰瑙�");
- int next = approved ? (quality.getWorkflowStatus() == WAIT_PROCESS ? WAIT_COMPANY : WAIT_COMPANY_FAIL) : WAIT_RETEST;
+ if (quality == null || !Set.of(WAIT_PROCESS, WAIT_INITIAL_FAIL_REVIEW).contains(quality.getWorkflowStatus()))
+ throw new IllegalArgumentException("褰撳墠鐘舵�佷笉鑳借繘琛屽垵妫�瀹℃牳");
+ approverService.validateApprover(MesQcApprovalTypeEnum.SEED_QUALITY.getType(),
+ MesQcApproveNodeEnum.PROCESS.getNode(), getLoginUserId());
+ if (!approved && StrUtil.isBlank(opinion)) throw new IllegalArgumentException("椹冲洖鏃惰濉啓瀹℃壒鎰忚");
+ int next = approved ? WAIT_RETEST : WAIT_INITIAL_RECHECK;
qualityMapper.updateById(MesQcSeedQualityDO.builder().id(id).workflowStatus(next)
.processApprovedAt(LocalDateTime.now()).build());
recordAction(id, approved ? "PROCESS_APPROVE" : "PROCESS_REJECT", quality.getResult(), opinion, null);
@@ -347,8 +461,10 @@
public void companyApprove(Long id, boolean approved, String opinion) {
MesQcSeedQualityDO quality = qualityMapper.selectByIdForUpdate(id);
if (quality == null || !Set.of(WAIT_COMPANY, WAIT_COMPANY_FAIL).contains(quality.getWorkflowStatus()))
- throw new IllegalArgumentException("褰撳墠鐘舵�佷笉鑳借繘琛屽叕鍙歌川妫�瀹℃壒");
- if (StrUtil.isBlank(opinion)) throw new IllegalArgumentException("璇峰~鍐欏鎵规剰瑙�");
+ throw new IllegalArgumentException("褰撳墠鐘舵�佷笉鑳借繘琛屽妫�瀹℃牳");
+ approverService.validateApprover(MesQcApprovalTypeEnum.SEED_QUALITY.getType(),
+ MesQcApproveNodeEnum.COMPANY.getNode(), getLoginUserId());
+ if (!approved && StrUtil.isBlank(opinion)) throw new IllegalArgumentException("椹冲洖鏃惰濉啓瀹℃壒鎰忚");
if (approved) finalizeStock(quality, quality.getWorkflowStatus() == WAIT_COMPANY);
int next = approved ? (quality.getWorkflowStatus() == WAIT_COMPANY ? RELEASED : SCRAPPED) : WAIT_RETEST;
qualityMapper.updateById(MesQcSeedQualityDO.builder().id(id).workflowStatus(next)
@@ -390,6 +506,9 @@
|| item.getValue() == null || item.getMinValue() == null || item.getMaxValue() == null)
throw new IllegalArgumentException("鎸囨爣蹇呴』涓虹函搴︺�佸噣搴︺�佸彂鑺界巼銆佹按鍒嗕笖涓嶅彲閲嶅");
if (item.getMinValue().compareTo(item.getMaxValue()) > 0) throw new IllegalArgumentException("鎸囨爣涓嬮檺涓嶈兘澶т簬涓婇檺");
+ if (item.getValue().compareTo(BigDecimal.ZERO) < 0 || item.getValue().compareTo(new BigDecimal("100")) > 0
+ || item.getMinValue().compareTo(BigDecimal.ZERO) < 0 || item.getMaxValue().compareTo(new BigDecimal("100")) > 0)
+ throw new IllegalArgumentException("鐧惧垎姣旀寚鏍囧繀椤诲浜� 0鈥�100");
if (item.getValue().compareTo(item.getMinValue()) < 0 || item.getValue().compareTo(item.getMaxValue()) > 0) passed = false;
}
return passed;
diff --git a/yudao-module-mes/src/test/java/cn/iocoder/yudao/module/mes/service/qc/oqc/MesQcOqcServiceImplTest.java b/yudao-module-mes/src/test/java/cn/iocoder/yudao/module/mes/service/qc/oqc/MesQcOqcServiceImplTest.java
index d24b047..c829afa 100644
--- a/yudao-module-mes/src/test/java/cn/iocoder/yudao/module/mes/service/qc/oqc/MesQcOqcServiceImplTest.java
+++ b/yudao-module-mes/src/test/java/cn/iocoder/yudao/module/mes/service/qc/oqc/MesQcOqcServiceImplTest.java
@@ -2,7 +2,6 @@
import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
import cn.iocoder.yudao.module.mes.dal.dataobject.qc.oqc.MesQcOqcDO;
-import cn.iocoder.yudao.module.mes.controller.admin.qc.oqc.vo.MesQcOqcRetestReqVO;
import cn.iocoder.yudao.module.mes.dal.mysql.qc.oqc.MesQcOqcMapper;
import cn.iocoder.yudao.module.mes.enums.MesBizTypeConstants;
import cn.iocoder.yudao.module.mes.enums.qc.MesQcStatusEnum;
@@ -76,9 +75,6 @@
o.setSourceDocType(MesBizTypeConstants.WM_PRODUCT_SALES);
o.setSourceLineId(sourceLineId);
o.setCheckResult(checkResult);
- o.setUnqualifiedQuantity(java.math.BigDecimal.ZERO);
- o.setQualifiedQuantity(java.math.BigDecimal.TEN);
- o.setCheckQuantity(java.math.BigDecimal.TEN);
});
oqcMapper.insert(oqc);
@@ -88,83 +84,9 @@
// 鏂█锛氶獙璇佺姸鎬佹洿鏂颁负宸插畬鎴�
MesQcOqcDO updatedOqc = oqcMapper.selectById(oqc.getId());
assertEquals(MesQcStatusEnum.FINISHED.getStatus(), updatedOqc.getStatus());
- assertEquals(20, updatedOqc.getWorkflowStatus());
- // 鍒濇瀹屾垚涓嶆斁琛岋紱閿�鍞儴鍜屽叕鍙歌川妫�鍧囧鎵瑰悗鎵嶅洖鍐欍��
- verify(productSalesLineService, never()).updateProductSalesLineWhenOqcFinish(anyLong(), anyLong(), anyInt());
- oqcService.salesApprove(oqc.getId(), true, "閿�鍞儴鍚屾剰");
- oqcService.companyApprove(oqc.getId(), true, "鍏徃璐ㄦ鍚屾剰");
+ // 鏂█锛氶獙璇佸洖鍐欓攢鍞嚭搴撳崟琛�
verify(productSalesLineService).updateProductSalesLineWhenOqcFinish(
eq(sourceLineId), eq(oqc.getId()), eq(checkResult));
- }
-
- @Test
- public void testFailedInitialRetestPassOnlyReleasesAfterBothApprovals() {
- Long sourceLineId = randomLongId();
- MesQcOqcDO oqc = randomPojo(MesQcOqcDO.class, o -> {
- o.setStatus(MesQcStatusEnum.DRAFT.getStatus());
- o.setSourceDocType(MesBizTypeConstants.WM_PRODUCT_SALES);
- o.setSourceLineId(sourceLineId);
- o.setOutQuantity(java.math.BigDecimal.valueOf(100));
- o.setCheckQuantity(java.math.BigDecimal.TEN);
- o.setQualifiedQuantity(java.math.BigDecimal.valueOf(9));
- o.setUnqualifiedQuantity(java.math.BigDecimal.ONE);
- o.setCheckResult(2);
- });
- oqcMapper.insert(oqc);
- oqcService.finishOqc(oqc.getId());
- assertEquals(10, oqcMapper.selectById(oqc.getId()).getWorkflowStatus());
- verifyNoInteractions(ncrService);
- verify(productSalesLineService, never()).updateProductSalesLineWhenOqcFinish(anyLong(), anyLong(), anyInt());
-
- MesQcOqcRetestReqVO retest = new MesQcOqcRetestReqVO();
- retest.setId(oqc.getId());
- retest.setCheckQuantity(java.math.BigDecimal.TEN);
- retest.setQualifiedQuantity(java.math.BigDecimal.TEN);
- retest.setUnqualifiedQuantity(java.math.BigDecimal.ZERO);
- retest.setCheckResult(1);
- oqcService.retestOqc(retest);
- assertEquals(20, oqcMapper.selectById(oqc.getId()).getWorkflowStatus());
- oqcService.salesApprove(oqc.getId(), true, "閿�鍞儴閫氳繃");
- assertEquals(30, oqcMapper.selectById(oqc.getId()).getWorkflowStatus());
- verify(productSalesLineService, never()).updateProductSalesLineWhenOqcFinish(anyLong(), anyLong(), anyInt());
- oqcService.companyApprove(oqc.getId(), true, "鍏徃璐ㄦ閫氳繃");
- assertEquals(40, oqcMapper.selectById(oqc.getId()).getWorkflowStatus());
- verify(productSalesLineService).updateProductSalesLineWhenOqcFinish(sourceLineId, oqc.getId(), 1);
- verifyNoInteractions(ncrService);
- }
-
- @Test
- public void testFailedRetestCreatesNcrOnlyAfterCompanyApproval() {
- Long sourceLineId = randomLongId();
- MesQcOqcDO oqc = randomPojo(MesQcOqcDO.class, o -> {
- o.setStatus(MesQcStatusEnum.DRAFT.getStatus());
- o.setSourceDocType(MesBizTypeConstants.WM_PRODUCT_SALES);
- o.setSourceLineId(sourceLineId);
- o.setOutQuantity(java.math.BigDecimal.valueOf(100));
- o.setCheckQuantity(java.math.BigDecimal.TEN);
- o.setQualifiedQuantity(java.math.BigDecimal.valueOf(9));
- o.setUnqualifiedQuantity(java.math.BigDecimal.ONE);
- o.setCheckResult(2);
- });
- oqcMapper.insert(oqc);
- oqcService.finishOqc(oqc.getId());
- MesQcOqcRetestReqVO retest = new MesQcOqcRetestReqVO();
- retest.setId(oqc.getId());
- retest.setCheckQuantity(java.math.BigDecimal.TEN);
- retest.setQualifiedQuantity(java.math.BigDecimal.valueOf(8));
- retest.setUnqualifiedQuantity(java.math.BigDecimal.valueOf(2));
- retest.setCheckResult(2);
- retest.setOpinion("澶嶆浠嶄笉鍚堟牸");
- oqcService.retestOqc(retest);
- assertEquals(50, oqcMapper.selectById(oqc.getId()).getWorkflowStatus());
- verifyNoInteractions(ncrService);
- oqcService.salesApprove(oqc.getId(), true, "閿�鍞儴纭涓嶅悎鏍�");
- assertEquals(60, oqcMapper.selectById(oqc.getId()).getWorkflowStatus());
- verifyNoInteractions(ncrService);
- oqcService.companyApprove(oqc.getId(), true, "鍏徃璐ㄦ纭涓嶅悎鏍�");
- assertEquals(70, oqcMapper.selectById(oqc.getId()).getWorkflowStatus());
- verify(ncrService).createNcr(any());
- verify(productSalesLineService).updateProductSalesLineWhenOqcFinish(sourceLineId, oqc.getId(), 2);
}
@Test
@@ -173,9 +95,6 @@
MesQcOqcDO oqc = randomPojo(MesQcOqcDO.class, o -> {
o.setStatus(MesQcStatusEnum.DRAFT.getStatus());
o.setCheckResult(1);
- o.setUnqualifiedQuantity(java.math.BigDecimal.ZERO);
- o.setQualifiedQuantity(java.math.BigDecimal.TEN);
- o.setCheckQuantity(java.math.BigDecimal.TEN);
o.setSourceDocType(null);
o.setSourceLineId(null);
});
@@ -198,17 +117,13 @@
MesQcOqcDO oqc = randomPojo(MesQcOqcDO.class, o -> {
o.setStatus(MesQcStatusEnum.DRAFT.getStatus());
o.setCheckResult(1);
- o.setUnqualifiedQuantity(java.math.BigDecimal.ZERO);
- o.setQualifiedQuantity(java.math.BigDecimal.TEN);
- o.setCheckQuantity(java.math.BigDecimal.TEN);
o.setSourceDocType(MesBizTypeConstants.WM_PRODUCT_SALES);
o.setSourceLineId(null); // 鑴忔暟鎹�
});
oqcMapper.insert(oqc);
- oqcService.finishOqc(oqc.getId());
- oqcService.salesApprove(oqc.getId(), true, "閿�鍞儴鍚屾剰");
- assertThrows(IllegalArgumentException.class, () -> oqcService.companyApprove(oqc.getId(), true, "鍏徃璐ㄦ鍚屾剰"));
+ // 璋冪敤锛屽苟鏂█寮傚父
+ assertThrows(IllegalArgumentException.class, () -> oqcService.finishOqc(oqc.getId()));
}
@Test
@@ -217,17 +132,13 @@
MesQcOqcDO oqc = randomPojo(MesQcOqcDO.class, o -> {
o.setStatus(MesQcStatusEnum.DRAFT.getStatus());
o.setCheckResult(1);
- o.setUnqualifiedQuantity(java.math.BigDecimal.ZERO);
- o.setQualifiedQuantity(java.math.BigDecimal.TEN);
- o.setCheckQuantity(java.math.BigDecimal.TEN);
o.setSourceDocType(99999); // 鏃犳硶璇嗗埆鐨勭被鍨�
o.setSourceLineId(randomLongId());
});
oqcMapper.insert(oqc);
- oqcService.finishOqc(oqc.getId());
- oqcService.salesApprove(oqc.getId(), true, "閿�鍞儴鍚屾剰");
- assertThrows(IllegalArgumentException.class, () -> oqcService.companyApprove(oqc.getId(), true, "鍏徃璐ㄦ鍚屾剰"));
+ // 璋冪敤锛屽苟鏂█寮傚父
+ assertThrows(IllegalArgumentException.class, () -> oqcService.finishOqc(oqc.getId()));
}
@Test
diff --git a/yudao-module-mes/src/test/java/cn/iocoder/yudao/module/mes/service/qc/seedquality/MesQcSeedIndicatorRangeServiceTest.java b/yudao-module-mes/src/test/java/cn/iocoder/yudao/module/mes/service/qc/seedquality/MesQcSeedIndicatorRangeServiceTest.java
new file mode 100644
index 0000000..308e1d4
--- /dev/null
+++ b/yudao-module-mes/src/test/java/cn/iocoder/yudao/module/mes/service/qc/seedquality/MesQcSeedIndicatorRangeServiceTest.java
@@ -0,0 +1,34 @@
+package cn.iocoder.yudao.module.mes.service.qc.seedquality;
+
+import cn.iocoder.yudao.module.mes.controller.admin.qc.seedquality.vo.MesQcSeedIndicatorRangeSaveReqVO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.qc.seedquality.MesQcSeedIndicatorRangeDO;
+import cn.iocoder.yudao.module.mes.dal.mysql.qc.seedquality.MesQcSeedIndicatorRangeMapper;
+import org.junit.jupiter.api.Test;
+import org.springframework.test.util.ReflectionTestUtils;
+
+import java.math.BigDecimal;
+import java.util.List;
+
+import static org.mockito.Mockito.*;
+
+class MesQcSeedIndicatorRangeServiceTest {
+ private final MesQcSeedIndicatorRangeService service = new MesQcSeedIndicatorRangeService();
+ private final MesQcSeedIndicatorRangeMapper mapper = mock(MesQcSeedIndicatorRangeMapper.class);
+
+ @Test
+ void savesTemplateWithoutRestrictingActualInspection() {
+ ReflectionTestUtils.setField(service, "mapper", mapper);
+ MesQcSeedIndicatorRangeSaveReqVO request = new MesQcSeedIndicatorRangeSaveReqVO();
+ request.setRanges(List.of(item("purity"), item("cleanliness"), item("germination_rate"), item("moisture")));
+ service.saveRanges(request);
+ verify(mapper, times(4)).insert(any(MesQcSeedIndicatorRangeDO.class));
+ }
+
+ private MesQcSeedIndicatorRangeSaveReqVO.Item item(String code) {
+ MesQcSeedIndicatorRangeSaveReqVO.Item row = new MesQcSeedIndicatorRangeSaveReqVO.Item();
+ row.setIndicatorCode(code);
+ row.setMinValue(new BigDecimal("90"));
+ row.setMaxValue(new BigDecimal("100"));
+ return row;
+ }
+}
diff --git a/yudao-module-mes/src/test/java/cn/iocoder/yudao/module/mes/service/qc/seedquality/SeedQualityGroupTest.java b/yudao-module-mes/src/test/java/cn/iocoder/yudao/module/mes/service/qc/seedquality/SeedQualityGroupTest.java
index ac70078..6ccfae7 100644
--- a/yudao-module-mes/src/test/java/cn/iocoder/yudao/module/mes/service/qc/seedquality/SeedQualityGroupTest.java
+++ b/yudao-module-mes/src/test/java/cn/iocoder/yudao/module/mes/service/qc/seedquality/SeedQualityGroupTest.java
@@ -78,4 +78,33 @@
var proxy=(MesQcSeedQualityService)factory.getProxy();
assertThrows(IllegalStateException.class,()->proxy.submitGroup(req));assertEquals(0,jdbc.queryForObject("SELECT COUNT(*) FROM qc_result",Integer.class));
}
+ @Test void retestScopePreviewSeparatesWorkflowStages() {
+ when(qualities.selectListByCodes(any())).thenReturn(List.of(
+ MesQcSeedQualityDO.builder().id(11L).code("B1").workflowStatus(10).build(),
+ MesQcSeedQualityDO.builder().id(12L).code("B2").workflowStatus(50).build()));
+ var result = service.resolveRetestScope("PALLET-BUS", "PALLET");
+ assertEquals(List.of(11L), result.get("retestIds"));
+ assertEquals(List.of(12L), result.get("initialRecheckIds"));
+ }
+ @Test void retestScopeRejectsStaleConfirmedList() {
+ when(qualities.selectListByCodesForUpdate(any())).thenReturn(List.of(
+ MesQcSeedQualityDO.builder().id(11L).code("B1").workflowStatus(10).build(),
+ MesQcSeedQualityDO.builder().id(12L).code("B2").workflowStatus(10).build()));
+ var request = new MesQcSeedQualityScopeRetestReqVO();
+ request.setCode("BATCH-BUS"); request.setScanType("BATCH"); request.setWorkflowStatus(10);
+ request.setQualityIds(List.of(11L)); request.setIndicators(List.of());
+ assertThrows(IllegalArgumentException.class, () -> service.retestScope(request));
+ verify(service, never()).retest(anyLong(), any());
+ }
+ @Test void retestScopeProcessesAllConfirmedBags() {
+ when(qualities.selectListByCodesForUpdate(any())).thenReturn(List.of(
+ MesQcSeedQualityDO.builder().id(11L).code("B1").workflowStatus(10).build(),
+ MesQcSeedQualityDO.builder().id(12L).code("B2").workflowStatus(10).build()));
+ doNothing().when(service).retest(anyLong(), any());
+ var request = new MesQcSeedQualityScopeRetestReqVO();
+ request.setCode("BATCH-BUS"); request.setScanType("BATCH"); request.setWorkflowStatus(10);
+ request.setQualityIds(List.of(11L, 12L)); request.setIndicators(List.of());
+ assertEquals(2, service.retestScope(request).get("processedCount"));
+ verify(service, times(2)).retest(anyLong(), any());
+ }
}
diff --git a/yudao-module-mes/src/test/java/cn/iocoder/yudao/module/mes/service/qc/seedquality/SeedQualityWorkflowTest.java b/yudao-module-mes/src/test/java/cn/iocoder/yudao/module/mes/service/qc/seedquality/SeedQualityWorkflowTest.java
index 45659c9..7e92e63 100644
--- a/yudao-module-mes/src/test/java/cn/iocoder/yudao/module/mes/service/qc/seedquality/SeedQualityWorkflowTest.java
+++ b/yudao-module-mes/src/test/java/cn/iocoder/yudao/module/mes/service/qc/seedquality/SeedQualityWorkflowTest.java
@@ -1,13 +1,17 @@
package cn.iocoder.yudao.module.mes.service.qc.seedquality;
import cn.iocoder.yudao.module.mes.dal.dataobject.qc.seedquality.MesQcSeedQualityDO;
+import cn.iocoder.yudao.module.mes.controller.admin.qc.seedquality.vo.MesQcSeedQualityRetestReqVO;
+import cn.iocoder.yudao.module.mes.controller.admin.qc.seedquality.vo.MesQcSeedQualityBatchRetestReqVO;
import cn.iocoder.yudao.module.mes.dal.mysql.qc.seedquality.MesQcSeedQualityActionMapper;
import cn.iocoder.yudao.module.mes.dal.mysql.qc.seedquality.MesQcSeedQualityMapper;
+import cn.iocoder.yudao.module.mes.service.qc.approver.MesQcApproverService;
import cn.iocoder.yudao.module.mes.service.wm.transaction.MesWmTransactionService;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
import org.springframework.test.util.ReflectionTestUtils;
+import java.util.List;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;
@@ -17,30 +21,76 @@
private final MesQcSeedQualityMapper qualityMapper = mock(MesQcSeedQualityMapper.class);
private final MesQcSeedQualityActionMapper actionMapper = mock(MesQcSeedQualityActionMapper.class);
private final MesWmTransactionService transactionService = mock(MesWmTransactionService.class);
+ private final MesQcApproverService approverService = mock(MesQcApproverService.class);
@BeforeEach
void setUp() {
ReflectionTestUtils.setField(service, "qualityMapper", qualityMapper);
ReflectionTestUtils.setField(service, "actionMapper", actionMapper);
ReflectionTestUtils.setField(service, "wmTransactionService", transactionService);
+ ReflectionTestUtils.setField(service, "approverService", approverService);
}
@Test
- void failedRetestNeedsBothApprovalsBeforeDisposal() {
+ void initialApprovalOnlyQueuesRetestAndFailedRetestCanReturnToRetest() {
when(qualityMapper.selectByIdForUpdate(1L)).thenReturn(
- MesQcSeedQualityDO.builder().id(1L).code("B1").result(2).workflowStatus(50).build(),
+ MesQcSeedQualityDO.builder().id(1L).code("B1").result(2).workflowStatus(20).build(),
MesQcSeedQualityDO.builder().id(1L).code("B1").result(2).workflowStatus(60).build());
- service.processApprove(1L, true, "纭涓嶅悎鏍硷紝閫佸叕鍙歌川妫�瀹℃壒");
+ service.processApprove(1L, true, "");
verifyNoInteractions(transactionService);
- service.companyApprove(1L, false, "杩斿洖澶嶆");
+ service.companyApprove(1L, false, "澶嶆涓嶅悎鏍硷紝閲嶆柊鍙栨牱");
ArgumentCaptor<MesQcSeedQualityDO> update = ArgumentCaptor.forClass(MesQcSeedQualityDO.class);
verify(qualityMapper, times(2)).updateById(update.capture());
- assertEquals(60, update.getAllValues().get(0).getWorkflowStatus());
+ assertEquals(10, update.getAllValues().get(0).getWorkflowStatus());
assertEquals(10, update.getAllValues().get(1).getWorkflowStatus());
verifyNoInteractions(transactionService);
}
@Test
+ void rejectedInitialInspectionNeedsRecheck() {
+ when(qualityMapper.selectByIdForUpdate(1L)).thenReturn(
+ MesQcSeedQualityDO.builder().id(1L).code("B1").result(2).workflowStatus(25).build());
+ service.processApprove(1L, false, "鍒濇鏍锋湰鏃犳晥锛岄噸鏂版娴�");
+ ArgumentCaptor<MesQcSeedQualityDO> update = ArgumentCaptor.forClass(MesQcSeedQualityDO.class);
+ verify(qualityMapper).updateById(update.capture());
+ assertEquals(50, update.getValue().getWorkflowStatus());
+ verifyNoInteractions(transactionService);
+ }
+
+ @Test
+ void rejectionRequiresOpinion() {
+ when(qualityMapper.selectByIdForUpdate(1L)).thenReturn(
+ MesQcSeedQualityDO.builder().id(1L).workflowStatus(20).build());
+ assertEquals("椹冲洖鏃惰濉啓瀹℃壒鎰忚", assertThrows(IllegalArgumentException.class,
+ () -> service.processApprove(1L, false, " ")).getMessage());
+ verify(qualityMapper, never()).updateById(any(MesQcSeedQualityDO.class));
+ verifyNoInteractions(actionMapper, transactionService);
+ }
+
+ @Test
+ void cannotRetestBeforeInitialReview() {
+ when(qualityMapper.selectByIdForUpdate(1L)).thenReturn(
+ MesQcSeedQualityDO.builder().id(1L).code("B1").workflowStatus(25).build());
+ assertThrows(IllegalArgumentException.class,
+ () -> service.retest(1L, new MesQcSeedQualityRetestReqVO()));
+ verify(qualityMapper, never()).updateById(any(MesQcSeedQualityDO.class));
+ verifyNoInteractions(transactionService, actionMapper);
+ }
+
+ @Test
+ void batchRetestRejectsDifferentProductionBatchesBeforeAnyWrite() {
+ when(qualityMapper.selectByIdForUpdate(1L)).thenReturn(
+ MesQcSeedQualityDO.builder().id(1L).code("B1").batchCode("A").workflowStatus(10).build());
+ when(qualityMapper.selectByIdForUpdate(2L)).thenReturn(
+ MesQcSeedQualityDO.builder().id(2L).code("B2").batchCode("B").workflowStatus(10).build());
+ MesQcSeedQualityBatchRetestReqVO request = new MesQcSeedQualityBatchRetestReqVO();
+ request.setIds(List.of(1L, 2L));
+ assertThrows(IllegalArgumentException.class, () -> service.retestBatch(request));
+ verify(qualityMapper, never()).updateById(any(MesQcSeedQualityDO.class));
+ verifyNoInteractions(transactionService, actionMapper);
+ }
+
+ @Test
void skipsApprovalWhenStatusChanged() {
when(qualityMapper.selectByIdForUpdate(1L)).thenReturn(
MesQcSeedQualityDO.builder().id(1L).workflowStatus(40).build());
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 1e8d1c7..53cdbba 100644
--- a/yudao-module-mes/src/test/resources/sql/create_tables.sql
+++ b/yudao-module-mes/src/test/resources/sql/create_tables.sql
@@ -413,7 +413,6 @@
"inspect_date" timestamp DEFAULT NULL,
"inspector_user_id" bigint DEFAULT NULL,
"status" tinyint NOT NULL DEFAULT 0,
- "workflow_status" tinyint NOT NULL DEFAULT 0,
"remark" varchar(500) DEFAULT '',
"creator" varchar(64) DEFAULT '',
"create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
@@ -424,15 +423,22 @@
PRIMARY KEY ("id")
);
-CREATE TABLE IF NOT EXISTS "mes_qc_oqc_action" (
+-- ----------------------------
+-- MES 璐ㄦ瀹℃牳浜洪厤缃�
+-- ----------------------------
+CREATE TABLE IF NOT EXISTS "mes_qc_approver_config" (
"id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
- "oqc_id" bigint NOT NULL,
- "action" varchar(32) NOT NULL,
- "result" tinyint DEFAULT NULL,
- "opinion" varchar(500) DEFAULT NULL,
- "quantities_json" varchar(4000) DEFAULT NULL,
- "operator_id" bigint DEFAULT NULL,
+ "qc_type" tinyint NOT NULL,
+ "approve_node" tinyint NOT NULL,
+ "user_id" bigint NOT NULL,
+ "status" tinyint NOT NULL DEFAULT 0,
+ "remark" varchar(255) 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")
);
--
Gitblit v1.9.3