Merge remote-tracking branch 'origin/dev_南通_苏珩' into dev_南通_苏珩
| | |
| | | { |
| | | "flows": [ |
| | | {"id": "sales", "name": "é宿µç¨", "mermaid": "mermaid/02-sales-flow.mmd", "color": "#4f9cff", |
| | | "summary": "线索转åå®¢æ· â åæºæ¨è¿ â æ¥ä»·(å¯AIè¯å«) â åå BPM å®¡æ¹ â çæ ERP éå®è®¢åå¹¶å®¡æ¹ â éç产è¡èªå¨å»º MPS â åè´§éç¥ â éå®åºåº(OQC)åå â å¼ç¥¨(BPM) â 忬¾(å
å¼ç¥¨æ ¡éª)ã", |
| | | "summary": "线索转åå®¢æ· â åæºæ¨è¿ â æ¥ä»·(å¯AIè¯å«) â åå BPM å®¡æ¹ â çæ ERP éå®è®¢åå¹¶å®¡æ¹ â éç产è¡èªå¨å»º MPS â åè´§éç¥ â éå®åºåºæäº¤(鿣éªè¡è½¬å¾
æ£æµ) â ç¬ç«å½å
¥ OQC åæç©æ+çå·+æ°éå
³èåå â æ£è´§åè¿ â å¼ç¥¨(BPM) â 忬¾(å
å¼ç¥¨æ ¡éª)ã", |
| | | "steps": [ |
| | | {"stage": "è·å®¢", "action": "线索转å客æ·ã建è系人ãç«é¡¹åæº", "roles": ["éå®å
å¤"]}, |
| | | {"stage": "æ¥ä»·", "action": "åæºèµ¢åå建æ¥ä»·å(AI OCR é¢å¡«)ï¼è½¬åå", "roles": ["éå®å
å¤"]}, |
| | | {"stage": "ç¾çº¦", "action": "å忥æºï¼æå·¥æ°å»º / æ¥ä»·å转å
¥ / Excel 导å
¥(ä¸ååå¤äº§åæç»è¡)ï¼æäº¤ BPM 审æ¹(å¯éæµç¨å®ä¹)ï¼éè¿=20", "roles": ["éå®", "审æ¹äºº"]}, |
| | | {"stage": "æ¥å", "action": "ååä¸é®çæéå®è®¢å(XSDD)ï¼éå®è®¢ååèµ° BPMï¼å®¡æ¹éè¿èªå¨ä¸º needProduction æç»å建 MPS", "roles": ["éå®", "计åå"]}, |
| | | {"stage": "交ä»", "action": "åè´§éç¥å®¡æ ¸(å ç¨)â éå®åºåº OQC â åè¿ â åºåºååé¨å/å
¨é¨åºåº", "roles": ["ä»ç®¡", "è´¨æ£"]}, |
| | | {"stage": "交ä»", "action": "åè´§éç¥å®¡æ ¸(å ç¨)â éå®åºåºæäº¤ï¼æ oqcCheckFlag è¡è½¬å¾
æ£æµï¼æäº¤æ¶ä¸åèªå¨å»º OQCï¼è´¨æ£åç¬ç«å½å
¥å¹¶å®æ OQC åï¼å¨æ£éªå详æ
æç©æ+çå·+æ°éä¸è´éæ©å¾
æ£åºåºè¡å
³èï¼å
¨é¨å¾
æ£è¡åæ ¼ååºåºå转å¾
æ£è´§ â åè¿ â åºåºååé¨å/å
¨é¨åºåº", "roles": ["ä»ç®¡", "è´¨æ£"]}, |
| | | {"stage": "忬¾", "action": "å¼ç¥¨ BPM(累计â¤ååé¢) â 忬¾å¼ºå¶å
å¼ç¥¨(累计â¤ååå©ä½ä¸å¼ç¥¨å©ä½)", "roles": ["è´¢å¡", "éå®"]}]}, |
| | | {"id": "purchase", "name": "éè´æµç¨", "mermaid": "mermaid/03-purchase-flow.mmd", "color": "#5fc79e", |
| | | "summary": "ä¾åºåæ¡£æ¡(å¤è系人/å¤é¶è¡Â·å«é¶è¡è¡å·) â 询价æ¯ä»·(产åÃä¾åºåæ¨ªåæ¥ä»·ï¼æäº§åé䏿 ) â 确认åæä¸æ ä¾åºåæéè´è®¢åèç¨¿å¹¶èµ°ç°æ BPM â 确认æ¶è´§çæ MES å°è´§éç¥ â IQC(åæ ¼/ç¹éå
¥åºÂ·éè´§/æ¥åº) â éè´å
¥åºåå订åä¸ç³è¯· â æ¥ç¥¨(AI OCR) â 仿¬¾å BPM â ä¾åºå徿¥å¯¹è´¦ï¼ææ ä¿è¯éå°è´¦ç¬ç«è®°å½ä¸æ ä¸éåã", |
| | |
| | | {"stage": "派工", "action": "å·¥å确认æå·¥èºè·¯çº¿éå·¥åºçæä»»å¡ï¼å¯ææ´¾/æå/åæ¶", "roles": ["车é´ä¸»ä»»"]}, |
| | | {"stage": "夿", "action": "çäº§é¢æååºåºæçº¿è¾¹èæåºå¤æ", "roles": ["ä»ç®¡"]}, |
| | | {"stage": "æ¥å·¥", "action": "æäº¤æ¥å·¥ï¼ä¸ä¸éå·¥åºæªæ¥æ»¡ç´æ¥æ¦æªï¼å¯ç¨ BPM 走审æ¹", "roles": ["æä½å·¥"]}, |
| | | {"stage": "èå¨", "action": "审æ¹éè¿æå·¥åºæ è®°: åå²âèªå¨ç©ææ¶èæ£çº¿è¾¹åº(å
许è´åºå)ï¼è´¨æ£â产åºå¾
æ£è¡ç IPQCï¼å
³é®éæ£âç´æ¥äº§åºå
¥åº", "roles": ["ç³»ç»èªå¨"]}, |
| | | {"stage": "èå¨", "action": "审æ¹éè¿æå·¥åºæ è®°: åå²âèªå¨ç©ææ¶èæ£çº¿è¾¹åº(å
许è´åºå)ï¼è´¨æ£âæ¥å·¥è½¬å¾
æ£éªå¹¶çæ PENDING 产åºè¡ï¼çå¾
è´¨æ£åç¬ç«å½å
¥ IPQCï¼å
³é®éæ£âç´æ¥äº§åºå
¥åº", "roles": ["ç³»ç»èªå¨"]}, |
| | | {"stage": "æ£éª", "action": "已宿 IPQC å¨è¯¦æ
页æç©æ+çå·+æ°éä¸è´éæ©å¾
æ£äº§åºè¡å
³èï¼å忥工宿并æååæ ¼/ä¸åæ ¼äº§åºå
¥åºï¼æªå
³èç已宿æ£éªåä¸åå", "roles": ["IPQC è´¨æ£å"]}, |
| | | {"stage": "å®å·¥", "action": "ä»
æ«éå·¥åºååå·¥åå·²ç产æ°éï¼è¾¾æ èªå¨å®æï¼MPS ç´¯è®¡å¤æå®æå¹¶åäºä»¶ç»éå®è®¢å", "roles": ["ç³»ç»èªå¨"]}]}, |
| | | {"id": "quality", "name": "è´¨éæµç¨", "mermaid": "mermaid/05-quality-flow.mmd", "color": "#e06c6c", |
| | | "summary": "å鿣éªé¸å£(IQC/IPQC/OQC/RQCï¼äºæ 0â4) + å¤å®åæ(åæ ¼/ç¹é/éè´§/æ¥åº) + NCR è¯å®¡å¤ç½®å
³éï¼AI æä¾å¤å®å»ºè®®ï¼NCR å½åä»
å°è´¦ä¸è§¦åè¿å·¥åï¼æ£éªåå¯ç±æºè½è´¨æ£æ¥åå¹³å°ä¸é®åºä»¶ï¼generate-from-qcï¼æ°æ®ä» MES åï¼äºéæ ¡éªå渲æè½åºï¼ã", |
| | | "summary": "å鿣éªé¸å£(IQC/IPQC/OQC/RQCï¼äºæ 0â4) + å®ææ¶æåæ ¼/ä¸åæ ¼æ°éèªå¨å¤å®(1 æ ¡éªéè¿/2 æ ¡éªä¸éè¿) + NCR è¯å®¡å¤ç½®å
³éï¼IPQC 宿åæç©æ+çå·+æ°éå
³èæ¥å·¥å¾
æ£è¡ï¼OQC 宿åæåæ ·è§åå
³èéå®åºåºå¾
æ£è¡ï¼AI æä¾å¤å®å»ºè®®ï¼NCR å½åä»
å°è´¦ä¸è§¦åè¿å·¥åï¼æ£éªåå¯ç±æºè½è´¨æ£æ¥åå¹³å°ä¸é®åºä»¶ï¼generate-from-qcï¼æ°æ®ä» MES åï¼äºéæ ¡éªå渲æè½åºï¼ã", |
| | | "steps": [ |
| | | {"stage": "æ¥æ", "action": "å°è´§éç¥/å¤åå
¥åºâIQCï¼ç»è®ºå忍è¿å¾
å
¥åºæè§¦åéè´§", "roles": ["IQC è´¨æ£å"]}, |
| | | {"stage": "è¿ç¨", "action": "æ¥å·¥è´¨æ£å·¥åºäº§åºè¡âIPQCï¼åæ ¼æè¡å
¥åºãä¸åæ ¼çæ NCR", "roles": ["IPQC è´¨æ£å"]}, |
| | | {"stage": "åºè´§", "action": "éå®åºåºæäº¤âOQCï¼å®æååºåºåè¿å
¥å¾
æ£è´§", "roles": ["OQC è´¨æ£å"]}, |
| | | {"stage": "è¿ç¨", "action": "æ¥å·¥è´¨æ£å·¥åºäº§åºè¡å¾
æ£âè´¨æ£åç¬ç«å½å
¥ IPQCï¼å®æåæç©æ+çå·+æ°éä¸è´å
³èæ¥å·¥å¾
æ£è¡ï¼åæ ¼æè¡å
¥åºãä¸åæ ¼çæ NCR", "roles": ["IPQC è´¨æ£å"]}, |
| | | {"stage": "åºè´§", "action": "éå®åºåºæäº¤åè¡è½¬å¾
æ£æµâè´¨æ£åç¬ç«å½å
¥ OQCï¼å®æåæç©æ+çå·+æ°éä¸è´å
³èåºåºå¾
æ£è¡ï¼å
¨é¨åæ ¼ååºåºåè¿å
¥å¾
æ£è´§", "roles": ["OQC è´¨æ£å"]}, |
| | | {"stage": "éè´§", "action": "éæ/éå®éè´§/å®åéè´§âRQCï¼ç»è®ºåè°åæ®ä¸å®å", "roles": ["RQC è´¨æ£å"]}, |
| | | {"stage": "导å
¥", "action": "IQC/IPQC/OQC ä¸åè¡¨åæ¯æ Excel æ¹é导å
¥(æé®å¨ãæ°å¢ãä¸ã导åºãä¹é´ï¼çº¯æ°å¢ä¸åæ´æ°è¦ç)ï¼ä¸è¡ä¸å¼ åï¼ç¼å·ç空èªå¨çæï¼è´¨æ£æ¹æ¡ç空æç©æ+æ£éªç±»åèªå¨å¹é
ï¼æ£æµäººåç空åå½åç»å½ç¨æ·ï¼ç©æ/ä¾åºå/客æ·/å·¥å/工使ç¼ç æå称精确å¹é
(IPQC ç©æç±å·¥åæ¨å¯¼ï¼æ¨¡æ¿ä¸å¡«)ï¼åæ ¼+ä¸åæ ¼=æ£æµ/æ¥æ¶æ°éãIPQC å·¥åº+æåº+å
¶ä»åºåâ¤ä¸åæ ¼ãOQC 客æ·é¡»å¨æ¬äººæ°æ®æéå
ï¼éè¡å¯¼å
¥é¨åæåï¼å¤±è´¥è¡è¿ failureList 带è¡å·ä¸å¯æ§è¡å¨ä½ï¼æååä¸å¾å¾
æ£éª0ï¼å䏿¹æ°æ®ä¸å¯éå¤å¯¼å
¥ï¼æä»¶å
éå¤è¡ä¸åºå
å·²åå¨åä¸å¡é®åæ®ï¼IQC ç©æ+ä¾åºå+ä¾åºåæ¹æ¬¡+æ¥ææ¥æãIPQC ç产工å+æ£éªç±»å+å·¥ä½+æ£æµæ¥æãOQC ç©æ+客æ·+æ¹æ¬¡å·+åºè´§æ¥æï¼åæè¯¥è¡ï¼æç¤ºå«ç»´åº¦ãåæ¹å®é
å¼ä¸ãå
å é¤è¯¥åæ®åéè¯ãå¨ä½", "roles": ["è´¨æ£å", "IQC è´¨æ£å", "IPQC è´¨æ£å", "OQC è´¨æ£å"]}, |
| | | {"stage": "ä¸åæ ¼", "action": "NCR: å¾
è¯å®¡âè¯å®¡âå¤ç½®(éè´§/æ¥åº/è¿å·¥/è®©æ¥æ¥æ¶/é级)âå
³é", "roles": ["è´¨éå·¥ç¨å¸"]}, |
| | |
| | | {"name": "主ç产计å", "module": "ç产", "table": "mes_pro_mps", "doc": "MPS计åï¼è稿0âå·²ä¸å1â宿2/åæ¶3ï¼å¯åå¹¶ä¸å", "upstream": ["éå®è®¢å"], "downstream": ["ç产工å"], "keywords": "MPS 主计å ç产计å"}, |
| | | {"name": "ç产工å", "module": "ç产", "table": "mes_pro_work_order", "doc": "è稿0â已确认1â宿2/åæ¶3ï¼ç¡®è®¤æ¶æå·¥èºè·¯çº¿çæä»»å¡ï¼æåä¸éå·¥åºæ¥å·¥ååå·²ç产æ°é", "upstream": ["MPS"], "downstream": ["ç产任å¡", "颿", "å®å·¥å
¥åº"], "keywords": "å·¥å ç产工å work order"}, |
| | | {"name": "ç产任å¡", "module": "ç产", "table": "mes_pro_task", "doc": "å·¥åºç²åº¦ï¼é¢å¤0âç产ä¸1âé¨å2â宿4ï¼å¯æå9åæ¶5", "upstream": ["ç产工å"], "downstream": ["æ¥å·¥"], "keywords": "ä»»å¡ task å·¥åº"}, |
| | | {"name": "æ¥å·¥å", "module": "ç产", "table": "mes_pro_feedback", "doc": "è稿0â审æ¹ä¸2âå¾
æ£3/宿4ï¼æå·¥åºé¡ºåºæ ¡éª(ä¸éå·¥åºæ¥æ»¡æå¯æ¥)ï¼èå¨å岿¶è/产åºå
¥åº/IPQC", "upstream": ["ç产任å¡"], "downstream": ["产å产åº", "ç©ææ¶è", "IPQC"], "keywords": "æ¥å·¥ feedback"}, |
| | | {"name": "æ¥å·¥å", "module": "ç产", "table": "mes_pro_feedback", "doc": "è稿0â审æ¹ä¸2âå¾
æ£3/宿4ï¼æå·¥åºé¡ºåºæ ¡éª(ä¸éå·¥åºæ¥æ»¡æå¯æ¥)ï¼èå¨å岿¶è/产åºå
¥åº/IPQCï¼è´¨æ£å·¥åºæ¥å·¥å®¡æ¹å转å¾
æ£éªå¹¶çæ PENDING 产åºè¡ï¼ç已宿 IPQC æç©æ+çå·+æ°éå
³èåæåå宿", "upstream": ["ç产任å¡"], "downstream": ["产å产åº", "ç©ææ¶è", "IPQC"], "keywords": "æ¥å·¥ feedback"}, |
| | | {"name": "å·¥èºè·¯çº¿", "module": "ç产", "table": "mes_pro_route", "doc": "å·¥åºé¡ºåº+è´¨æ£/å
³é®/å岿 è®°ï¼é©±å¨å·¥åä»»å¡ä¸æ¥å·¥è§å", "upstream": [], "downstream": ["ç产工å"], "keywords": "å·¥èº è·¯çº¿ route å·¥åº"}, |
| | | {"name": "å°è´§éç¥å", "module": "ä»å¨", "table": "mes_wm_arrival_notice", "doc": "éè´è®¢å确认æ¶è´§çæï¼è稿0âå¾
è´¨æ£2âå¾
å
¥åº3â宿4", "upstream": ["éè´è®¢å"], "downstream": ["IQC", "éè´å
¥åº"], "keywords": "å°è´§ æ¶è´§ arrival"}, |
| | | {"name": "éè´å
¥åºå", "module": "ä»å¨", "table": "mes_wm_item_receipt", "doc": "è稿0âå¾
䏿¶2âå¾
æ§è¡3â宿4ï¼å®æååºå+å¹¶åå ERP inCount/inStatus", "upstream": ["å°è´§éç¥"], "downstream": ["åºåå°è´¦", "éè´è®¢å(åå)"], "keywords": "éè´å
¥åº æ¶è´§å
¥åº receipt"}, |
| | | {"name": "çäº§é¢æå", "module": "ä»å¨", "table": "mes_wm_product_issue", "doc": "è稿0âå¾
æ£è´§2âå¾
æ§è¡3â宿4ï¼åºå-", "upstream": ["ç产工å"], "downstream": ["åºåå°è´¦"], "keywords": "颿 issue"}, |
| | | {"name": "éå®åºåºå", "module": "ä»å¨", "table": "mes_wm_product_sales", "doc": "åè´§éç¥å®¡æ ¸åçæï¼æäº¤âOQCæ£æµâæ£è´§âåè¿10âå¾
æ§è¡3â宿4ï¼ååéå®è®¢ååºåºæ°ä¸ç¶æ", "upstream": ["åè´§éç¥", "éå®è®¢å"], "downstream": ["åºåå°è´¦", "OQC"], "keywords": "éå®åºåº åè´§ åºåºå sales"}, |
| | | {"name": "éå®åºåºå", "module": "ä»å¨", "table": "mes_wm_product_sales", "doc": "åè´§éç¥å®¡æ ¸åçæï¼æäº¤åæ oqcCheckFlag è¡è½¬å¾
æ£æµ1ï¼æäº¤æ¶ä¸åèªå¨å»º OQCï¼ï¼éè´¨æ£åç¬ç«å½å
¥ OQC 并卿£éªå详æ
æç©æ+çå·+æ°éå
³èå¾
æ£è¡ï¼å
¨é¨å¾
æ£è¡åæ ¼å转å¾
æ£è´§2âåè¿10âå¾
æ§è¡3â宿4ï¼ååéå®è®¢ååºåºæ°ä¸ç¶æ", "upstream": ["åè´§éç¥", "éå®è®¢å"], "downstream": ["åºåå°è´¦", "OQC"], "keywords": "éå®åºåº åè´§ åºåºå sales"}, |
| | | {"name": "éå®éè´§å", "module": "ä»å¨", "table": "mes_wm_return_sales", "doc": "è稿âå¾
æ£éª(RQC)âå¾
䏿¶âå¾
å
¥åºâ宿ï¼å®åä¸æå·¥ä¸¤æ¥æº", "upstream": ["å®åéè´§ç³è¯·"], "downstream": ["åºåå°è´¦", "RQC"], "keywords": "éå®éè´§ éè´§å
¥åº"}, |
| | | {"name": "ä¾åºåéè´§å", "module": "ä»å¨", "table": "mes_wm_return_vendor", "doc": "è´¨éé¨åèµ·éè´§ï¼è稿0â审æ¹ä¸1(BPMï¼éè´âè´¨éâä»åº)âå¾
æ£è´§2âå¾
æ§è¡éè´§3â宿4ï¼å¯åæ¶5ï¼åºå-ï¼ä¸ä¼ éä»¶èµ° storage-attachmentï¼å¤çæ¹å¼ 1鿬¾(宿åèªå¨çæè´æ°å²çº¢ä»æ¬¾å) / 2æ¢è´§(宿åèªå¨çæå¾
è´¨æ£å°è´§éç¥åå¹¶å建 IQCï¼éæ°å
¥åºè´¨æ£)ï¼ååå·ä»éè´è®¢åå¿«ç
§", "upstream": ["IQC", "éè´è®¢å(ååå·)"], "downstream": ["åºåå°è´¦", "éè´è®¢å(returnCount)", "仿¬¾å(å²çº¢)", "å°è´§éç¥(æ¢è´§)"], "keywords": "ä¾åºåéè´§ éæ éè´§ vendor"}, |
| | | {"name": "è°æ¨å", "module": "ä»å¨", "table": "mes_wm_transfer", "doc": "å
é¨/å¤é¨è°æ¨ï¼æå¯¹ MOVE_OUT+MOVE_IN äºå¡ï¼å¨éæ°é", "upstream": [], "downstream": ["åºåå°è´¦"], "keywords": "è°æ¨ ç§»åº transfer"}, |
| | |
| | | {"name": "åºåå°è´¦", "module": "ä»å¨", "table": "mes_wm_material_stock", "doc": "ç©æÃä»åºÃåºåºÃåºä½Ãæ¹æ¬¡Ãä¾åºåå
å
ç»ï¼æ°é/å»ç»/å ç¨/å¨éåé", "upstream": ["å
¨é¨å
¥åºå"], "downstream": ["å
¨é¨åºåºå", "äºå¡æµæ°´"], "keywords": "åºå å°è´¦ stock å¯ç¨é"}, |
| | | {"name": "æ¹æ¬¡", "module": "ä»å¨", "table": "mes_wm_batch", "doc": "å
³èç©æ/å·¥å/ä¾åºå/客æ·/è´¨éç¶æï¼SN ç 嫿¹æ¬¡ uuidï¼æ¡ç æ¯æ18ç§ä¸å¡å¯¹è±¡", "upstream": ["å
¥åºåæ®"], "downstream": ["åºåå°è´¦"], "keywords": "æ¹æ¬¡ batch SN æ¡ç 追溯"}, |
| | | {"name": "IQCæ¥ææ£éª", "module": "è´¨é", "table": "mes_qc_iqc", "doc": "å°è´§éç¥/å¤åå
¥åºè§¦åï¼è稿0â宿4ï¼ç»è®ºå忥æºåæ®ï¼è¡æä½ãåºæ¥åãä»
å¨å·²å®ææ¶å¯è§ï¼æ¯æ Excel æ¹é导å
¥ï¼å·¥å
·æ ãæ¹é导å
¥ãï¼çº¯æ°å¢ã导å
¥å为è稿ãç¼å·å¯ç空èªå¨çæï¼ï¼å䏿¹æ°æ®ä¸å¯éå¤å¯¼å
¥ï¼ç©æ+ä¾åºå+ä¾åºåæ¹æ¬¡+æ¥ææ¥æï¼æä»¶å
éå¤è¡ä¸åºå
å·²æåé½æè¯¥è¡ï¼", "upstream": ["å°è´§éç¥", "å¤åå
¥åº", "Excel æ¹é导å
¥"], "downstream": ["éè´å
¥åº", "ä¾åºåéè´§", "NCR", "æ¥åå®ä¾(åºæ¥å)"], "keywords": "IQC æ¥ææ£éª åºæ¥å æ¹é导å
¥ 导å
¥æ¨¡æ¿"}, |
| | | {"name": "IPQCè¿ç¨æ£éª", "module": "è´¨é", "table": "mes_qc_ipqc", "doc": "æ¥å·¥è´¨æ£å·¥åºäº§åºè¡è§¦åï¼å®æåè°æ¨è¿æ¥å·¥ä¸äº§åºå
¥åºï¼è¡æä½ãåºæ¥åãä»
å¨å·²å®ææ¶å¯è§ï¼æ¯æ Excel æ¹é导å
¥ï¼äº§åç©æç±çäº§å·¥åæ¨å¯¼ï¼æ¨¡æ¿ä¸å¡«ç©æï¼å·¥åº+æåº+å
¶ä»åºåä¸å¾è¶
è¿ä¸åæ ¼åæ°éï¼ï¼å䏿¹æ°æ®ä¸å¯éå¤å¯¼å
¥ï¼ç产工å+æ£éªç±»å+å·¥ä½+æ£æµæ¥æï¼æä»¶å
éå¤è¡ä¸åºå
å·²æåé½æè¯¥è¡ï¼", "upstream": ["æ¥å·¥", "Excel æ¹é导å
¥"], "downstream": ["产åºå
¥åº", "NCR", "æ¥åå®ä¾(åºæ¥å)"], "keywords": "IPQC è¿ç¨æ£éª å·¡æ£ åºæ¥å æ¹é导å
¥ 导å
¥æ¨¡æ¿"}, |
| | | {"name": "OQCåºè´§æ£éª", "module": "è´¨é", "table": "mes_qc_oqc", "doc": "éå®åºåºæäº¤è§¦åï¼å®ææ¨è¿åºåºåå¾
æ£è´§ï¼è¡æä½ãåºæ¥åãä»
å¨å·²å®ææ¶å¯è§ï¼æ¯æ Excel æ¹é导å
¥ï¼å®¢æ·é¡»å¨å½åç»å½ç¨æ·çå®¢æ·æ°æ®æéèå´å
ï¼ï¼å䏿¹æ°æ®ä¸å¯éå¤å¯¼å
¥ï¼ç©æ+客æ·+æ¹æ¬¡å·+åºè´§æ¥æï¼æä»¶å
éå¤è¡ä¸åºå
å·²æåé½æè¯¥è¡ï¼", "upstream": ["éå®åºåºå", "Excel æ¹é导å
¥"], "downstream": ["éå®åºåºå(æ¨è¿)", "æ¥åå®ä¾(åºæ¥å)"], "keywords": "OQC åºè´§æ£éª åºåæ£éª åºæ¥å æ¹é导å
¥ 导å
¥æ¨¡æ¿"}, |
| | | {"name": "IPQCè¿ç¨æ£éª", "module": "è´¨é", "table": "mes_qc_ipqc", "doc": "æ¥å·¥è´¨æ£å·¥åºäº§åºè¡å¾
æ£åç¬ç«å½å
¥ï¼å®ææ¶æåæ ¼+ä¸åæ ¼=æ£æµæ°éèªå¨å¤å® 1 éè¿/2 ä¸éè¿ï¼éå·²ä¸ä¼ æ£éªéä»¶ï¼ï¼å·²å®æä¸æªç»å®æ¥æºçåæ®ï¼å¨è¯¦æ
æç©æ+çå·+æ°éä¸è´éæ©å¾
æ£äº§åºè¡å
³èï¼å忥工宿ä¸äº§åºå
¥åºï¼æªå
³èä¸ååãè¡æä½ãåºæ¥åãä»
å¨å·²å®ææ¶å¯è§ï¼æ¯æ Excel æ¹é导å
¥ï¼äº§åç©æç±çäº§å·¥åæ¨å¯¼ï¼æ¨¡æ¿ä¸å¡«ç©æï¼å·¥åº+æåº+å
¶ä»åºåä¸å¾è¶
è¿ä¸åæ ¼åæ°éï¼ï¼å䏿¹æ°æ®ä¸å¯éå¤å¯¼å
¥ï¼ç产工å+æ£éªç±»å+å·¥ä½+æ£æµæ¥æï¼æä»¶å
éå¤è¡ä¸åºå
å·²æåé½æè¯¥è¡ï¼", "upstream": ["æ¥å·¥", "Excel æ¹é导å
¥"], "downstream": ["产åºå
¥åº", "NCR", "æ¥åå®ä¾(åºæ¥å)"], "keywords": "IPQC è¿ç¨æ£éª å·¡æ£ çå·å
³è æ¥å·¥å
³è åºæ¥å æ¹é导å
¥ 导å
¥æ¨¡æ¿"}, |
| | | {"name": "OQCåºè´§æ£éª", "module": "è´¨é", "table": "mes_qc_oqc", "doc": "éå®åºåºæäº¤åå¾
æ£æµè¡ç¬ç«å½å
¥ï¼å®ææ¶æåæ ¼+ä¸åæ ¼=æ£æµæ°éèªå¨å¤å® 1 éè¿/2 ä¸éè¿ï¼éå·²ä¸ä¼ æ£éªéä»¶ï¼ï¼å·²å®æä¸æªç»å®æ¥æºçåæ®ï¼å¨è¯¦æ
æç©æ+çå·+æ°éä¸è´éæ©å¾
æ£åºåºè¡å
³èï¼åååºåºè¡è´¨éç¶æ PASS/FAILï¼å
¨é¨å¾
æ£è¡åæ ¼ååºåºå转å¾
æ£è´§ï¼ä¸åæ ¼è¡çå¾
åç»å¤ç½®ï¼ä¸èªå¨åæ¶åºåºåãè¡æä½ãåºæ¥åãä»
å¨å·²å®ææ¶å¯è§ï¼æ¯æ Excel æ¹é导å
¥ï¼å®¢æ·é¡»å¨å½åç»å½ç¨æ·çå®¢æ·æ°æ®æéèå´å
ï¼ï¼å䏿¹æ°æ®ä¸å¯éå¤å¯¼å
¥ï¼ç©æ+客æ·+æ¹æ¬¡å·+åºè´§æ¥æï¼æä»¶å
éå¤è¡ä¸åºå
å·²æåé½æè¯¥è¡ï¼", "upstream": ["éå®åºåºå", "Excel æ¹é导å
¥"], "downstream": ["éå®åºåºå(æ¨è¿)", "æ¥åå®ä¾(åºæ¥å)"], "keywords": "OQC åºè´§æ£éª åºåæ£éª çå·å
³è åºåºå
³è åºæ¥å æ¹é导å
¥ 导å
¥æ¨¡æ¿"}, |
| | | {"name": "RQCéè´§æ£éª", "module": "è´¨é", "table": "mes_qc_rqc", "doc": "ç产éæ/éå®éè´§/å®åé货触åï¼ç»è®ºåè°å®åï¼è¡æä½ãåºæ¥åãä»
å¨å·²å®ææ¶å¯è§ãæªè¾å·²ç»ä¸ä¸ºãéè´§æ£éªãï¼åèåç¶é¡¹ä¸ mes_qc_type åå
¸åãéææ£éªãï¼ä¸å端æä¸¾/表注é/èåæéå项ä¸ä¸è´ï¼RQC ä¸è
é½è¦çï¼æ
åãéè´§æ£éªãï¼", "upstream": ["éæ", "éè´§"], "downstream": ["éè´§å
¥åº", "å®ååè°", "æ¥åå®ä¾(åºæ¥å)"], "keywords": "RQC éè´§æ£éª éææ£éª åºæ¥å"}, |
| | | {"name": "NCRä¸åæ ¼å", "module": "è´¨é", "table": "mes_qc_ncr", "doc": "å¾
è¯å®¡0âå·²è¯å®¡6âå·²å¤ç½®7âå·²å
³é8ï¼å¤ç½®:éè´§/æ¥åº/è¿å·¥/è®©æ¥æ¥æ¶/é级", "upstream": ["IQC/IPQC/OQC/RQC"], "downstream": ["éè´§/æ¥åº/è¿å·¥(å°è´¦)"], "keywords": "NCR ä¸åæ ¼ å¤ç½® ç¹é æ¥åº"}, |
| | | {"name": "设å¤", "module": "设å¤", "table": "mes_dv_machinery", "doc": "å°è´¦ç¶æ:åæº/ç产ä¸/ä¿å
»ä¸ï¼ç¹æ£Â·ä¿å
»Â·ç»´ä¿®å·¥åï¼AI é£é©é¢æµæ¶è´¹å
¶æ°æ®", "upstream": [], "downstream": ["ç¹æ£", "ç»´ä¿®", "ç产é£é©é¢æµ"], "keywords": "è®¾å¤ ç¹æ£ ä¿å
» ç»´ä¿® machinery"}, |
| | |
| | | H -->|æäº¤BPM| I[éå®è®¢å审æ¹Â·å®¡æ¹ä¸15âå·²å®¡æ ¸20] |
| | | I -->|æç»éç产·èªå¨å建| J[MES 主ç产计å MPS] |
| | | I --> K[åè´§éç¥å] |
| | | K -->|å®¡æ ¸éè¿| L[éå®åºåºå·OQCâæ£è´§âåè¿âåºåºå®æ] |
| | | K -->|å®¡æ ¸éè¿| L0[éå®åºåºå·æäº¤] |
| | | L0 -->|鿣éªè¡ oqcCheckFlag=1| L1[å¾
æ£æµ1·åºåºè¡è´¨éç¶æ PENDING] |
| | | L0 -->|æ 鿣éª| L2[å¾
æ£è´§2] |
| | | L1 -->|已宿 OQC æç©æ+çå·+æ°éä¸è´éå¾
æ£è¡å
³è| L3[åºåºè¡è´¨éç¶æ PASS/FAIL] |
| | | L3 -->|å
¨é¨å¾
æ£è¡åæ ¼| L2 |
| | | L2 --> L[æ£è´§âåè¿âåºåºå®æ] |
| | | L -->|åååºåºæ°éä¸ç¶æ| M[éå®è®¢å é¨ååºåº2/å
¨é¨åºåº3] |
| | | G --> N[忬¾è®¡åÂ·æææ°åæ] |
| | | G -->|æäº¤BPM| O[å¼ç¥¨ KP·审æ¹ä¸10âéè¿20·累计ä¸è¶
ååé¢] |
| | |
| | | P5 -->|å¯ç¨BPMåæäº¤å®¡æ¹| P6{æ¥å·¥å®¡æ¹} |
| | | P6 -->|驳å| P5 |
| | | P6 -->|éè¿ä¸åå²å·¥åº| P7[æå·¥åBOMèªå¨çæç©ææ¶è·æ£çº¿è¾¹èæåºFIFOå
许è´åºå] |
| | | P6 -->|éè¿ä¸è´¨æ£å·¥åº| P8[产åºè¡å¾
æ£âIPQC è¿ç¨æ£éª] |
| | | P6 -->|éè¿ä¸è´¨æ£å·¥åº| P8[æ¥å·¥è½¬å¾
æ£éªÂ·äº§åºè¡ PENDING] |
| | | P6 -->|éè¿ä¸éè´¨æ£å
³é®å·¥åº| P9[产å产åºç´æ¥å®å·¥å
¥åº] |
| | | P8 -->|æ£éªåæ ¼| P10[æåæ ¼ä¸ä¸åæ ¼è¡å
¥åº] |
| | | P8 -->|ä¸åæ ¼| P11[NCR ä¸åæ ¼å] |
| | | P8 -->|已宿 IPQC æç©æ+çå·+æ°éä¸è´éå¾
æ£äº§åºè¡å
³è| P8L[ååæ¥å·¥å®æÂ·æ¥å·¥ç¶æâ宿4] |
| | | P8L -->|åæ ¼æ°é>0| P10[åæ ¼è¡å
¥åºÂ·ä¸åæ ¼æ°éæåºä¸ºä¸åæ ¼è¡] |
| | | P8L -->|ä¸åæ ¼æ°é>0| P11[NCR ä¸åæ ¼å·çå¾
åç»å¤ç½®] |
| | | P8 -.->|æªå
³èç已宿 IPQC ä¸åå·é卿£éªå详æ
æå¨å
³è| P8 |
| | | P9 --> P12[è¿åº¦åå·ä»
æåä¸éå·¥åºæ¥å·¥ææ´æ°å·¥åå·²ç产æ°é] |
| | | P10 --> P12 |
| | | P12 -->|å·²ç产æ°éâ¥è®¡åæ°é·èªå¨| P13[å·¥å宿2] |
| | |
| | | <pre style="display:none" class="mmd-src" data-mmd="05-quality-flow"> |
| | | flowchart TD |
| | | T1[å°è´§éç¥å æ å¤åå
¥åºå] --> A1[IQC æ¥ææ£éªÂ·è稿0â宿4] |
| | | T2[æ¥å·¥è´¨æ£å·¥åºéè¿å产åºè¡] --> A2[IPQC è¿ç¨æ£éªÂ·è稿0â宿4] |
| | | T3[éå®åºåºåæäº¤] --> A3[OQC åºè´§æ£éªÂ·è稿0â宿4] |
| | | T2[æ¥å·¥è´¨æ£å·¥åºéè¿å产åºè¡Â·ç¬ç«å½å
¥ IPQC] --> A2[IPQC è¿ç¨æ£éªÂ·è稿0â宿4] |
| | | T3[éå®åºåºåå¾
æ£æµè¡Â·ç¬ç«å½å
¥ OQC] --> A3[OQC åºè´§æ£éªÂ·è稿0â宿4] |
| | | T4[ç产éæå æ éå®éè´§å æ å®åéè´§] --> A4[RQC éè´§æ£éªÂ·è稿0â宿4] |
| | | T5[Excel æ¹é导å
¥Â·IQC IPQC OQC ä¸å表åä¸ä¸ªå
¥å£Â·æé®å¨æ°å¢ä¸å¯¼åºä¹é´] --> IMP{导å
¥é¸é¨Â·éè¡è§£æÂ·å¤±è´¥è¡äºä¸å½±å} |
| | | IMP -->|ç¼å·ç空èªå¨çæÂ·ç¼å·é夿å䏿¹æ°æ®éå¤åæè¯¥è¡| A1 |
| | |
| | | A2 --> R |
| | | A3 --> R |
| | | A4 --> R |
| | | R -->|1 åæ ¼| Q1[å
许å
¥åºÂ·å忥æºåæ®æ¨è¿ç¶æ] |
| | | R -->|2 ç¹é| Q2[å
许å
¥åºÂ·å¹¶çæNCRçç] |
| | | R -->|3 ä¸åæ ¼éè´§| Q3[çæNCR·走ä¾åºåéè´§æéå®éè´§] |
| | | R -->|4 ä¸åæ ¼æ¥åº| Q4[çæNCR·走æ¥åºåºåº] |
| | | A2 -->|åæ ¼æ°é| Q5[æ¥å·¥è½¬å®æÂ·äº§åºæè¡å
¥åº] |
| | | A3 -->|宿| Q6[éå®åºåºåæ¨è¿å¾
æ£è´§] |
| | | R -->|1 æ ¡éªéè¿| Q1[å
许å
¥åºÂ·å忥æºåæ®æ¨è¿ç¶æ] |
| | | R -->|2 æ ¡éªä¸éè¿| Q2[çæNCR·çå¾
åç»å¤ç½®Â·ä¸èªå¨åæ¶æ¥æºåæ®] |
| | | R -.->|3 ä¸åæ ¼éè´§ 4 ä¸åæ ¼æ¥åº 为åå²æä¸¾Â·å®ææ¶ä¸å产ç| Q4[éè´§/æ¥åºèµ°åç»åæ®] |
| | | A2 -->|已宿䏿ªç»å®æ¥æºÂ·æç©æ+çå·+æ°éä¸è´| Q5[å
³èæ¥å·¥å¾
æ£è¡Â·å忥工宿ä¸äº§åºå
¥åº] |
| | | A3 -->|已宿䏿ªç»å®æ¥æºÂ·æç©æ+çå·+æ°éä¸è´| Q6[å
³èéå®åºåºå¾
æ£è¡Â·åååºåºè¡è´¨éç¶æÂ·å
¨é¨åæ ¼æ¨è¿å¾
æ£è´§] |
| | | A4 -->|宿| Q7[éè´§åæ¨è¿ä¸æ¶æå
¥åºÂ·å®ååè°ç»è®º] |
| | | N1[NCR å¾
è¯å®¡0] -->|è¯å®¡| N2[å·²è¯å®¡6] |
| | | N2 -->|å¤ç½®æ¹å¼:éè´§1æ¥åº2è¿å·¥3è®©æ¥æ¥æ¶4é级使ç¨5| N3[å·²å¤ç½®7] |
| | |
| | | mes_wm_arrival_notice ||--o| mes_qc_iqc : "触åIQC" |
| | | mes_wm_arrival_notice ||--o{ mes_wm_item_receipt : "çæéè´å
¥åº" |
| | | erp_sale_order ||--o{ mes_wm_product_sales : "éå®åºåº" |
| | | mes_wm_product_sales ||--o| mes_qc_oqc : "触åOQC" |
| | | mes_pro_feedback ||--o| mes_qc_ipqc : "è´¨æ£å·¥åºè§¦åIPQC" |
| | | mes_wm_product_sales ||--o| mes_qc_oqc : "åºåºå¾
æ£è¡æç©æ+çå·+æ°éå
³èOQC" |
| | | mes_pro_feedback ||--o| mes_qc_ipqc : "æ¥å·¥å¾
æ£è¡æç©æ+çå·+æ°éå
³èIPQC" |
| | | mes_pro_feedback ||--o{ mes_wm_product_produce : "产åºå
¥åº" |
| | | mes_pro_feedback ||--o{ mes_wm_item_consume : "BOMå岿¶è" |
| | | mes_qc_iqc ||--o| mes_qc_ncr : "ä¸åæ ¼çæNCR" |
| | |
| | | H -->|æäº¤BPM| I[éå®è®¢å审æ¹Â·å®¡æ¹ä¸15âå·²å®¡æ ¸20] |
| | | I -->|æç»éç产·èªå¨å建| J[MES 主ç产计å MPS] |
| | | I --> K[åè´§éç¥å] |
| | | K -->|å®¡æ ¸éè¿| L[éå®åºåºå·OQCâæ£è´§âåè¿âåºåºå®æ] |
| | | K -->|å®¡æ ¸éè¿| L0[éå®åºåºå·æäº¤] |
| | | L0 -->|鿣éªè¡ oqcCheckFlag=1| L1[å¾
æ£æµ1·åºåºè¡è´¨éç¶æ PENDING] |
| | | L0 -->|æ 鿣éª| L2[å¾
æ£è´§2] |
| | | L1 -->|已宿 OQC æç©æ+çå·+æ°éä¸è´éå¾
æ£è¡å
³è| L3[åºåºè¡è´¨éç¶æ PASS/FAIL] |
| | | L3 -->|å
¨é¨å¾
æ£è¡åæ ¼| L2 |
| | | L2 --> L[æ£è´§âåè¿âåºåºå®æ] |
| | | L -->|åååºåºæ°éä¸ç¶æ| M[éå®è®¢å é¨ååºåº2/å
¨é¨åºåº3] |
| | | G --> N[忬¾è®¡åÂ·æææ°åæ] |
| | | G -->|æäº¤BPM| O[å¼ç¥¨ KP·审æ¹ä¸10âéè¿20·累计ä¸è¶
ååé¢] |
| | |
| | | P5 -->|å¯ç¨BPMåæäº¤å®¡æ¹| P6{æ¥å·¥å®¡æ¹} |
| | | P6 -->|驳å| P5 |
| | | P6 -->|éè¿ä¸åå²å·¥åº| P7[æå·¥åBOMèªå¨çæç©ææ¶è·æ£çº¿è¾¹èæåºFIFOå
许è´åºå] |
| | | P6 -->|éè¿ä¸è´¨æ£å·¥åº| P8[产åºè¡å¾
æ£âIPQC è¿ç¨æ£éª] |
| | | P6 -->|éè¿ä¸è´¨æ£å·¥åº| P8[æ¥å·¥è½¬å¾
æ£éªÂ·äº§åºè¡ PENDING] |
| | | P6 -->|éè¿ä¸éè´¨æ£å
³é®å·¥åº| P9[产å产åºç´æ¥å®å·¥å
¥åº] |
| | | P8 -->|æ£éªåæ ¼| P10[æåæ ¼ä¸ä¸åæ ¼è¡å
¥åº] |
| | | P8 -->|ä¸åæ ¼| P11[NCR ä¸åæ ¼å] |
| | | P8 -->|已宿 IPQC æç©æ+çå·+æ°éä¸è´éå¾
æ£äº§åºè¡å
³è| P8L[ååæ¥å·¥å®æÂ·æ¥å·¥ç¶æâ宿4] |
| | | P8L -->|åæ ¼æ°é>0| P10[åæ ¼è¡å
¥åºÂ·ä¸åæ ¼æ°éæåºä¸ºä¸åæ ¼è¡] |
| | | P8L -->|ä¸åæ ¼æ°é>0| P11[NCR ä¸åæ ¼å·çå¾
åç»å¤ç½®] |
| | | P8 -.->|æªå
³èç已宿 IPQC ä¸åå·é卿£éªå详æ
æå¨å
³è| P8 |
| | | P9 --> P12[è¿åº¦åå·ä»
æåä¸éå·¥åºæ¥å·¥ææ´æ°å·¥åå·²ç产æ°é] |
| | | P10 --> P12 |
| | | P12 -->|å·²ç产æ°éâ¥è®¡åæ°é·èªå¨| P13[å·¥å宿2] |
| | |
| | | flowchart TD |
| | | T1[å°è´§éç¥å æ å¤åå
¥åºå] --> A1[IQC æ¥ææ£éªÂ·è稿0â宿4] |
| | | T2[æ¥å·¥è´¨æ£å·¥åºéè¿å产åºè¡] --> A2[IPQC è¿ç¨æ£éªÂ·è稿0â宿4] |
| | | T3[éå®åºåºåæäº¤] --> A3[OQC åºè´§æ£éªÂ·è稿0â宿4] |
| | | T2[æ¥å·¥è´¨æ£å·¥åºéè¿å产åºè¡Â·ç¬ç«å½å
¥ IPQC] --> A2[IPQC è¿ç¨æ£éªÂ·è稿0â宿4] |
| | | T3[éå®åºåºåå¾
æ£æµè¡Â·ç¬ç«å½å
¥ OQC] --> A3[OQC åºè´§æ£éªÂ·è稿0â宿4] |
| | | T4[ç产éæå æ éå®éè´§å æ å®åéè´§] --> A4[RQC éè´§æ£éªÂ·è稿0â宿4] |
| | | T5[Excel æ¹é导å
¥Â·IQC IPQC OQC ä¸å表åä¸ä¸ªå
¥å£Â·æé®å¨æ°å¢ä¸å¯¼åºä¹é´] --> IMP{导å
¥é¸é¨Â·éè¡è§£æÂ·å¤±è´¥è¡äºä¸å½±å} |
| | | IMP -->|ç¼å·ç空èªå¨çæÂ·ç¼å·é夿å䏿¹æ°æ®éå¤åæè¯¥è¡| A1 |
| | |
| | | A2 --> R |
| | | A3 --> R |
| | | A4 --> R |
| | | R -->|1 åæ ¼| Q1[å
许å
¥åºÂ·å忥æºåæ®æ¨è¿ç¶æ] |
| | | R -->|2 ç¹é| Q2[å
许å
¥åºÂ·å¹¶çæNCRçç] |
| | | R -->|3 ä¸åæ ¼éè´§| Q3[çæNCR·走ä¾åºåéè´§æéå®éè´§] |
| | | R -->|4 ä¸åæ ¼æ¥åº| Q4[çæNCR·走æ¥åºåºåº] |
| | | A2 -->|åæ ¼æ°é| Q5[æ¥å·¥è½¬å®æÂ·äº§åºæè¡å
¥åº] |
| | | A3 -->|宿| Q6[éå®åºåºåæ¨è¿å¾
æ£è´§] |
| | | R -->|1 æ ¡éªéè¿| Q1[å
许å
¥åºÂ·å忥æºåæ®æ¨è¿ç¶æ] |
| | | R -->|2 æ ¡éªä¸éè¿| Q2[çæNCR·çå¾
åç»å¤ç½®Â·ä¸èªå¨åæ¶æ¥æºåæ®] |
| | | R -.->|3 ä¸åæ ¼éè´§ 4 ä¸åæ ¼æ¥åº 为åå²æä¸¾Â·å®ææ¶ä¸å产ç| Q4[éè´§/æ¥åºèµ°åç»åæ®] |
| | | A2 -->|已宿䏿ªç»å®æ¥æºÂ·æç©æ+çå·+æ°éä¸è´| Q5[å
³èæ¥å·¥å¾
æ£è¡Â·å忥工宿ä¸äº§åºå
¥åº] |
| | | A3 -->|已宿䏿ªç»å®æ¥æºÂ·æç©æ+çå·+æ°éä¸è´| Q6[å
³èéå®åºåºå¾
æ£è¡Â·åååºåºè¡è´¨éç¶æÂ·å
¨é¨åæ ¼æ¨è¿å¾
æ£è´§] |
| | | A4 -->|宿| Q7[éè´§åæ¨è¿ä¸æ¶æå
¥åºÂ·å®ååè°ç»è®º] |
| | | N1[NCR å¾
è¯å®¡0] -->|è¯å®¡| N2[å·²è¯å®¡6] |
| | | N2 -->|å¤ç½®æ¹å¼:éè´§1æ¥åº2è¿å·¥3è®©æ¥æ¥æ¶4é级使ç¨5| N3[å·²å¤ç½®7] |
| | |
| | | mes_wm_arrival_notice ||--o| mes_qc_iqc : "触åIQC" |
| | | mes_wm_arrival_notice ||--o{ mes_wm_item_receipt : "çæéè´å
¥åº" |
| | | erp_sale_order ||--o{ mes_wm_product_sales : "éå®åºåº" |
| | | mes_wm_product_sales ||--o| mes_qc_oqc : "触åOQC" |
| | | mes_pro_feedback ||--o| mes_qc_ipqc : "è´¨æ£å·¥åºè§¦åIPQC" |
| | | mes_wm_product_sales ||--o| mes_qc_oqc : "åºåºå¾
æ£è¡æç©æ+çå·+æ°éå
³èOQC" |
| | | mes_pro_feedback ||--o| mes_qc_ipqc : "æ¥å·¥å¾
æ£è¡æç©æ+çå·+æ°éå
³èIPQC" |
| | | mes_pro_feedback ||--o{ mes_wm_product_produce : "产åºå
¥åº" |
| | | mes_pro_feedback ||--o{ mes_wm_item_consume : "BOMå岿¶è" |
| | | mes_qc_iqc ||--o| mes_qc_ncr : "ä¸åæ ¼çæNCR" |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | import java.sql.*; |
| | | public class ItemSortMigration { |
| | | public static void main(String[] a) throws Exception { |
| | | try (Connection c = DriverManager.getConnection("jdbc:mysql://1.95.78.124:9000/mom-xgdl?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true", "root", System.getenv("MOM_DB_PASSWORD")); Statement s=c.createStatement()) { |
| | | if (a.length > 0) { for (String table : new String[]{"mdm_item", "mes_md_item"}) { try (ResultSet r=s.executeQuery("SELECT COUNT(*) FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name=\u0027"+table+"\u0027 AND column_name=\u0027sort\u0027")) { r.next(); if (r.getInt(1)==0) { try (Statement ddl=c.createStatement()) { ddl.executeUpdate("ALTER TABLE `"+table+"` ADD COLUMN sort INT NOT NULL DEFAULT 0 COMMENT \u0027æåºï¼æ°å¼è¶å°è¶é å\u0027"); } } } } System.out.println("Synchronized rows="+s.executeUpdate("UPDATE mes_md_item m JOIN mdm_item d ON m.mdm_item_id=d.id SET m.sort=d.sort WHERE m.sort <> d.sort")); } |
| | | try(ResultSet r=s.executeQuery("SELECT COUNT(*), SUM(m.mdm_item_id IS NOT NULL), SUM(d.id IS NOT NULL) FROM mes_md_item m LEFT JOIN mdm_item d ON m.mdm_item_id=d.id WHERE m.deleted=0")) {r.next(); System.out.println("MES active="+r.getLong(1)+" linked="+r.getLong(2)+" matched="+r.getLong(3));} |
| | | for(String table : new String[]{"mdm_item","mes_md_item"}) { |
| | | try(ResultSet r=s.executeQuery("SELECT COUNT(*) FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='"+table+"' AND column_name='sort'")) { r.next(); System.out.println(table+" sort columns="+r.getInt(1)); } |
| | | try(ResultSet r=s.executeQuery("SELECT COUNT(*) FROM `"+table+"`")) {r.next(); System.out.println(table+" rows="+r.getLong(1));} |
| | | } |
| | | } |
| | | } |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | -- è¡¥é½ç¦»èç³è¯·äº¤æ¥å段ï¼åªæ·»å ç¼ºå¤±åæ®µï¼å¯é夿§è¡ã |
| | | SET @target_db = DATABASE(); |
| | | SET @ddl = (SELECT IF(COUNT(*) = 0, |
| | | 'ALTER TABLE hrm_resignation_application ADD COLUMN handover_employee_id BIGINT NULL COMMENT ''交æ¥åå·¥ID''', |
| | | 'SELECT 1') FROM information_schema.columns WHERE table_schema = @target_db AND table_name = 'hrm_resignation_application' AND column_name = 'handover_employee_id'); |
| | | PREPARE handover_stmt FROM @ddl; |
| | | EXECUTE handover_stmt; |
| | | DEALLOCATE PREPARE handover_stmt; |
| | | SET @ddl = (SELECT IF(COUNT(*) = 0, |
| | | 'ALTER TABLE hrm_resignation_application ADD COLUMN handover_data_status TINYINT NOT NULL DEFAULT 0 COMMENT ''ç¨æ·æ°æ®äº¤æ¥ç¶æï¼0æªå¼å§ 10è¿è¡ä¸ 20已宿''', |
| | | 'SELECT 1') FROM information_schema.columns WHERE table_schema = @target_db AND table_name = 'hrm_resignation_application' AND column_name = 'handover_data_status'); |
| | | PREPARE handover_stmt FROM @ddl; |
| | | EXECUTE handover_stmt; |
| | | DEALLOCATE PREPARE handover_stmt; |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | -- ç©æææ¯æä»¶è¿½å è®°å½ï¼å·¥åä¿åå
¶ä¸åæ¡è®°å½çå¿«ç
§ã |
| | | CREATE TABLE IF NOT EXISTS `mdm_item_technical_file` ( |
| | | `id` bigint NOT NULL AUTO_INCREMENT, |
| | | `item_id` bigint NOT NULL COMMENT 'ç©æç¼å·', |
| | | `storage_blob_id` bigint NOT NULL COMMENT 'æä»¶åå¨ç¼å·', |
| | | `version_no` int NOT NULL COMMENT 'ä¸ä¼ åºå·', |
| | | `file_name` 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_item_version` (`item_id`, `version_no`) |
| | | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='ç©æææ¯æä»¶è®°å½'; |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | -- æå·¥åä¿åææ¯æä»¶æ¸
åï¼åå²å·¥åä¸åçæµæ§åå¡«ã |
| | | CREATE TABLE IF NOT EXISTS `mes_pro_work_order_technical_file` ( |
| | | `id` bigint NOT NULL AUTO_INCREMENT, |
| | | `work_order_id` bigint NOT NULL, |
| | | `source_file_id` bigint NOT NULL, |
| | | `blob_id` bigint NOT NULL, |
| | | `version_no` int DEFAULT NULL, |
| | | `file_name` varchar(255) DEFAULT NULL, |
| | | `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_work_order_id` (`work_order_id`) |
| | | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='çäº§å·¥åææ¯æä»¶å¿«ç
§'; |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | ALTER TABLE mdm_item ADD COLUMN sort INT NOT NULL DEFAULT 0 COMMENT 'æåºï¼æ°å¼è¶å°è¶é å'; |
| | | ALTER TABLE mes_md_item ADD COLUMN sort INT NOT NULL DEFAULT 0 COMMENT 'æåºï¼æ°å¼è¶å°è¶é å'; |
| | | UPDATE mes_md_item m JOIN mdm_item d ON m.mdm_item_id = d.id SET m.sort = d.sort WHERE m.sort <> d.sort; |
| | |
| | | return success(technicalFileService.createTechnicalFile(reqVO)); |
| | | } |
| | | |
| | | @DeleteMapping("/technical-file/delete") |
| | | @Operation(summary = "ä»ç©æç§»é¤ææ¯æä»¶") |
| | | @PreAuthorize("@ss.hasPermission('mdm:item:update')") |
| | | public CommonResult<Boolean> deleteTechnicalFile(@RequestParam("itemId") Long itemId, @RequestParam("id") Long id) { |
| | | technicalFileService.deleteTechnicalFile(itemId, id); |
| | | return success(true); |
| | | } |
| | | |
| | | @GetMapping("/technical-file/list") |
| | | @Operation(summary = "è·å¾äº§åææ¯æä»¶åå²") |
| | | public CommonResult<List<MdmItemTechnicalFileRespVO>> getTechnicalFileList(@RequestParam("itemId") Long itemId) { |
| | |
| | | import cn.iocoder.yudao.module.mdm.dal.dataobject.item.MdmItemTechnicalFileDO; |
| | | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
| | | import org.apache.ibatis.annotations.Mapper; |
| | | import org.apache.ibatis.annotations.Param; |
| | | import org.apache.ibatis.annotations.Select; |
| | | |
| | | import java.util.List; |
| | | |
| | |
| | | .orderByDesc(MdmItemTechnicalFileDO::getVersionNo)); |
| | | } |
| | | |
| | | default Integer selectMaxVersionNo(Long itemId) { |
| | | MdmItemTechnicalFileDO row = selectOne(new LambdaQueryWrapper<MdmItemTechnicalFileDO>() |
| | | .eq(MdmItemTechnicalFileDO::getItemId, itemId) |
| | | .orderByDesc(MdmItemTechnicalFileDO::getVersionNo) |
| | | .last("LIMIT 1")); |
| | | return row == null || row.getVersionNo() == null ? 0 : row.getVersionNo(); |
| | | } |
| | | // å
å«å·²ç§»é¤è®°å½ï¼é¿å
åç»ä¸ä¼ å¤ç¨å·²æå·¥åæ¾ç¤ºè¿çåºå·ã |
| | | @Select("SELECT COALESCE(MAX(version_no), 0) FROM mdm_item_technical_file WHERE item_id = #{itemId}") |
| | | Integer selectMaxVersionNo(@Param("itemId") Long itemId); |
| | | } |
| | |
| | | |
| | | public interface MdmItemTechnicalFileService { |
| | | Long createTechnicalFile(MdmItemTechnicalFileCreateReqVO reqVO); |
| | | void deleteTechnicalFile(Long itemId, Long id); |
| | | List<MdmItemTechnicalFileRespVO> getTechnicalFileList(Long itemId); |
| | | } |
| | |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void deleteTechnicalFile(Long itemId, Long id) { |
| | | MdmItemTechnicalFileDO file = mapper.selectById(id); |
| | | if (file == null || !java.util.Objects.equals(file.getItemId(), itemId)) { |
| | | throw new cn.iocoder.yudao.framework.common.exception.ServiceException(400, "ææ¯æä»¶ä¸å卿ä¸å±äºè¯¥ç©æ"); |
| | | } |
| | | // åªç§»é¤ç©æçå½åæä»¶è®°å½ãä¿çéä»¶åæä»¶æ¬ä½ï¼ä¾å·²æå·¥åå¿«ç
§ä½¿ç¨ã |
| | | mapper.deleteById(id); |
| | | } |
| | | |
| | | @Override |
| | | public List<MdmItemTechnicalFileRespVO> getTechnicalFileList(Long itemId) { |
| | | return mapper.selectListByItemId(itemId).stream().map(file -> { |
| | | MdmItemTechnicalFileRespVO resp = BeanUtils.toBean(file, MdmItemTechnicalFileRespVO.class); |
| | |
| | | public class MesProTaskController { |
| | | |
| | | @Resource |
| | | private cn.iocoder.yudao.module.mes.dal.mysql.pro.task.MesProTaskMapper pendingCountMapper; |
| | | |
| | | @GetMapping("/unfinished-workstation-counts") |
| | | @Operation(summary = "è·å¾åå·¥ä½ç«æªå®æä»»å¡æ°é") |
| | | public CommonResult<List<cn.iocoder.yudao.module.mes.controller.admin.pro.task.vo.MesProWorkstationPendingCountVO>> getPendingWorkstationCounts() { |
| | | Long userId = cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId(); |
| | | Long assigneeId = userId != null && !permissionApi.hasAnyRoles(userId, |
| | | cn.iocoder.yudao.module.system.enums.permission.RoleCodeEnum.SUPER_ADMIN.getCode()) ? userId : null; |
| | | return success(pendingCountMapper.selectPendingCounts(assigneeId, |
| | | cn.iocoder.yudao.module.mes.enums.pro.MesProTaskStatusEnum.PREPARE.getStatus(), |
| | | cn.iocoder.yudao.module.mes.enums.pro.MesProTaskStatusEnum.PRODUCING.getStatus(), |
| | | cn.iocoder.yudao.module.mes.enums.pro.MesProTaskStatusEnum.PARTIAL_FINISHED.getStatus(), |
| | | cn.iocoder.yudao.module.mes.enums.pro.MesProTaskStatusEnum.PAUSED.getStatus())); |
| | | } |
| | | |
| | | @Resource |
| | | private cn.iocoder.yudao.module.mes.service.pro.task.schedule.MesProBatchScheduleService batchScheduleService; |
| | | |
| | | @PostMapping("/auto-schedule/preview") |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.mes.controller.admin.pro.task.vo; |
| | | |
| | | import lombok.Data; |
| | | |
| | | @Data |
| | | public class MesProWorkstationPendingCountVO { |
| | | private Long workstationId; |
| | | private Long pendingCount; |
| | | } |
| | |
| | | private MesProTaskService taskService; |
| | | @Resource |
| | | private MesProProcessService processService; |
| | | @Resource |
| | | private cn.iocoder.yudao.module.mes.service.pro.workorder.MesProWorkOrderTechnicalFileService technicalFileService; |
| | | |
| | | @GetMapping("/technical-files") |
| | | @Operation(summary = "è·å¾å·¥åå建æ¶çææ¯æä»¶å¿«ç
§") |
| | | @PreAuthorize("@ss.hasPermission('mes:pro-work-order:query')") |
| | | public CommonResult<List<cn.iocoder.yudao.module.mdm.controller.admin.item.vo.MdmItemTechnicalFileRespVO>> getTechnicalFiles(@RequestParam("id") Long id) { |
| | | workOrderService.validateWorkOrderExists(id); |
| | | return success(technicalFileService.list(id)); |
| | | } |
| | | |
| | | @PostMapping("/create") |
| | | @Operation(summary = "å建ç产工å") |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.mes.controller.admin.qc.attachment; |
| | | |
| | | import cn.iocoder.yudao.framework.common.exception.ServiceException; |
| | | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| | | import cn.iocoder.yudao.module.mes.service.qc.iqc.MesQcIqcService; |
| | | import cn.iocoder.yudao.module.mes.service.qc.ipqc.MesQcIpqcService; |
| | | import cn.iocoder.yudao.module.mes.service.qc.oqc.MesQcOqcService; |
| | | import cn.iocoder.yudao.module.mes.service.qc.rqc.MesQcRqcService; |
| | | import cn.iocoder.yudao.module.system.api.storage.StorageAttachmentApi; |
| | | import cn.iocoder.yudao.module.system.api.storage.dto.StorageBlobRespDTO; |
| | | import jakarta.annotation.Resource; |
| | | import jakarta.validation.Valid; |
| | | import jakarta.validation.constraints.NotEmpty; |
| | | import jakarta.validation.constraints.NotNull; |
| | | import jakarta.validation.constraints.Pattern; |
| | | import jakarta.validation.constraints.Size; |
| | | import lombok.Data; |
| | | import org.springframework.security.access.prepost.PreAuthorize; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | import org.springframework.validation.annotation.Validated; |
| | | import org.springframework.web.bind.annotation.*; |
| | | import java.util.List; |
| | | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; |
| | | |
| | | /** è´¨æ£éä»¶ç¬ç«äºæ£éªç»è®ºï¼ä¸ä¼ éä»¶ä¸èªå¨å°äº§åå¤ä¸ºåæ ¼ã */ |
| | | @RestController |
| | | @RequestMapping("/mes/qc/attachment") |
| | | @Validated |
| | | public class MesQcAttachmentController { |
| | | @Resource private MesQcIqcService iqcService; |
| | | @Resource private MesQcIpqcService ipqcService; |
| | | @Resource private MesQcOqcService oqcService; |
| | | @Resource private MesQcRqcService rqcService; |
| | | @Resource private StorageAttachmentApi storageApi; |
| | | @Resource private org.springframework.jdbc.core.JdbcTemplate jdbcTemplate; |
| | | |
| | | @GetMapping("/list") |
| | | @PreAuthorize("@ss.hasPermission('mes:qc-' + #type.toLowerCase() + ':query')") |
| | | public CommonResult<List<StorageBlobRespDTO>> list( |
| | | @RequestParam @Pattern(regexp = "iqc|ipqc|oqc|rqc") String type, |
| | | @RequestParam @NotNull Long id) { |
| | | validateDocument(type, id); |
| | | var files = storageApi.listAttachments(recordType(type), id); |
| | | return success(files == null ? List.of() : files); |
| | | } |
| | | |
| | | @PutMapping("/save") |
| | | @PreAuthorize("@ss.hasPermission('mes:qc-' + #req.type.toLowerCase() + ':update')") |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public CommonResult<Boolean> save(@Valid @RequestBody SaveReq req) { |
| | | lockDocument(req.getType(), req.getId()); |
| | | validateDocument(req.getType(), req.getId()); |
| | | // bindAttachments ä»
æ¿æ¢å
³èï¼ä¸å é¤å
±äº«æä»¶æ¬ä½ã |
| | | storageApi.bindAttachments("file", recordType(req.getType()), req.getId(), req.getBlobIds().stream().distinct().toList()); |
| | | return success(true); |
| | | } |
| | | |
| | | @PostMapping("/append") |
| | | @PreAuthorize("@ss.hasPermission('mes:qc-' + #req.type.toLowerCase() + ':update')") |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public CommonResult<Boolean> append(@Valid @RequestBody AppendReq req) { |
| | | lockDocument(req.getType(), req.getId()); |
| | | validateDocument(req.getType(), req.getId()); |
| | | var existing = storageApi.listAttachments(recordType(req.getType()), req.getId()); |
| | | var ids = new java.util.LinkedHashSet<Long>(); |
| | | if (existing != null) existing.forEach(blob -> ids.add(blob.getId())); |
| | | ids.add(req.getBlobId()); |
| | | if (ids.size() > 50) throw new ServiceException(400, "æ¯å¼ è´¨æ£åæå¤ä¸ä¼ 50份éä»¶"); |
| | | storageApi.bindAttachments("file", recordType(req.getType()), req.getId(), List.copyOf(ids)); |
| | | return success(true); |
| | | } |
| | | |
| | | @DeleteMapping("/remove") |
| | | @PreAuthorize("@ss.hasPermission('mes:qc-' + #type.toLowerCase() + ':update')") |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public CommonResult<Boolean> remove( |
| | | @RequestParam @Pattern(regexp = "iqc|ipqc|oqc|rqc") String type, |
| | | @RequestParam @NotNull Long id, @RequestParam @NotNull Long blobId) { |
| | | lockDocument(type, id); |
| | | validateDocument(type, id); |
| | | storageApi.removeReference("file", recordType(type), id, blobId); |
| | | return success(true); |
| | | } |
| | | |
| | | private String recordType(String type) { |
| | | return switch (type) { |
| | | case "iqc", "ipqc", "oqc", "rqc" -> "mes_qc_" + type + "_attachment"; |
| | | default -> throw new ServiceException(400, "è´¨æ£ç±»åæ æ"); |
| | | }; |
| | | } |
| | | |
| | | private void lockDocument(String type, Long id) { |
| | | String table = switch (type) { |
| | | case "iqc" -> "mes_qc_iqc"; |
| | | case "ipqc" -> "mes_qc_ipqc"; |
| | | case "oqc" -> "mes_qc_oqc"; |
| | | case "rqc" -> "mes_qc_rqc"; |
| | | default -> throw new ServiceException(400, "è´¨æ£ç±»åæ æ"); |
| | | }; |
| | | var ids = jdbcTemplate.queryForList("SELECT id FROM " + table + " WHERE id = ? AND deleted = 0 FOR UPDATE", Long.class, id); |
| | | if (ids.isEmpty()) throw new ServiceException(400, "è´¨æ£åä¸åå¨"); |
| | | } |
| | | |
| | | private Integer validateDocument(String type, Long id) { |
| | | return switch (type) { |
| | | case "iqc" -> iqcService.validateIqcExists(id).getStatus(); |
| | | case "ipqc" -> ipqcService.validateIpqcExists(id).getStatus(); |
| | | case "oqc" -> oqcService.validateOqcExists(id).getStatus(); |
| | | case "rqc" -> rqcService.validateRqcExists(id).getStatus(); |
| | | default -> throw new ServiceException(400, "è´¨æ£ç±»åæ æ"); |
| | | }; |
| | | } |
| | | |
| | | @Data public static class SaveReq { |
| | | @NotNull @Pattern(regexp = "iqc|ipqc|oqc|rqc") private String type; |
| | | @NotNull private Long id; |
| | | @NotEmpty @Size(max = 50) private List<@NotNull Long> blobIds; |
| | | } |
| | | @Data public static class AppendReq { |
| | | @NotNull @Pattern(regexp = "iqc|ipqc|oqc|rqc") private String type; |
| | | @NotNull private Long id; |
| | | @NotNull private Long blobId; |
| | | } |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.mes.controller.admin.qc.link; |
| | | |
| | | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| | | import cn.iocoder.yudao.module.mes.service.qc.link.MesQcSourceLinkService; |
| | | import jakarta.annotation.Resource; |
| | | import jakarta.validation.constraints.NotNull; |
| | | import org.springframework.security.access.prepost.PreAuthorize; |
| | | import org.springframework.validation.annotation.Validated; |
| | | import org.springframework.web.bind.annotation.*; |
| | | import java.util.List; |
| | | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; |
| | | |
| | | @RestController |
| | | @RequestMapping("/mes/qc/source-link") |
| | | @Validated |
| | | public class MesQcSourceLinkController { |
| | | @Resource private MesQcSourceLinkService service; |
| | | @GetMapping("/feedback-candidates") |
| | | @PreAuthorize("@ss.hasPermission('mes:qc-ipqc:update')") |
| | | public CommonResult<List<MesQcSourceLinkService.Candidate>> feedbackCandidates(@RequestParam @NotNull Long qcId) { |
| | | return success(service.feedbackCandidates(qcId)); |
| | | } |
| | | @PostMapping("/feedback") |
| | | @PreAuthorize("@ss.hasPermission('mes:qc-ipqc:update')") |
| | | public CommonResult<Boolean> feedback(@RequestParam @NotNull Long qcId, @RequestParam @NotNull Long lineId) { |
| | | service.linkFeedback(qcId, lineId); return success(true); |
| | | } |
| | | @GetMapping("/sales-candidates") |
| | | @PreAuthorize("@ss.hasPermission('mes:qc-oqc:update')") |
| | | public CommonResult<List<MesQcSourceLinkService.Candidate>> salesCandidates(@RequestParam @NotNull Long qcId) { |
| | | return success(service.salesCandidates(qcId)); |
| | | } |
| | | @PostMapping("/sales") |
| | | @PreAuthorize("@ss.hasPermission('mes:qc-oqc:update')") |
| | | public CommonResult<Boolean> sales(@RequestParam @NotNull Long qcId, @RequestParam @NotNull Long lineId) { |
| | | service.linkSales(qcId, lineId); return success(true); |
| | | } |
| | | } |
| | |
| | | @Resource private MesProWorkOrderMapper workOrderMapper; |
| | | @Resource private MesWmTransactionService transactionService; |
| | | @Resource private MesWmWarehouseAreaService areaService; |
| | | @Resource private cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseService warehouseService; |
| | | @Resource private cn.iocoder.yudao.module.mdm.api.item.MdmItemApi itemApi; |
| | | |
| | | @GetMapping("/order-outputs") |
| | | @PreAuthorize("@ss.hasPermission('mes:wm-scrap-receipt:create')") |
| | | public CommonResult<List<OutputItem>> orderOutputs(@RequestParam("workOrderId") Long workOrderId) { |
| | | var order = workOrderMapper.selectById(workOrderId); |
| | | if (order == null || !java.util.Objects.equals(order.getStatus(), cn.iocoder.yudao.module.mes.enums.pro.MesProWorkOrderStatusEnum.FINISHED.getStatus())) |
| | | throw new ServiceException(400, "ä»
已宿çç产订åå¯ä»¥ç»è®°åºæ"); |
| | | var list = receiptMapper.selectOrderOutputs(workOrderId, cn.iocoder.yudao.module.mes.enums.wm.MesWmProductProduceStatusEnum.FINISHED.getStatus()); |
| | | var items = itemApi.getItemMap(list.stream().map(OutputItem::getItemId).collect(java.util.stream.Collectors.toSet())); |
| | | list.forEach(output -> { var item = items.get(output.getItemId()); if (item != null) { output.setItemName(item.getName()); output.setItemCode(item.getCode()); } }); |
| | | return success(list); |
| | | } |
| | | |
| | | @PostMapping("/create-from-output") |
| | | @PreAuthorize("@ss.hasPermission('mes:wm-scrap-receipt:create')") |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public CommonResult<Long> createFromOutput(@Valid @RequestBody CreateReq req) { |
| | | var locked = workOrderMapper.lockScheduleOrders(List.of(req.getWorkOrderId())); |
| | | if (locked.isEmpty() || !java.util.Objects.equals(locked.get(0).getStatus(), cn.iocoder.yudao.module.mes.enums.pro.MesProWorkOrderStatusEnum.FINISHED.getStatus())) |
| | | throw new ServiceException(400, "ä»
已宿çç产订åå¯ä»¥ç»è®°åºæ"); |
| | | if (receiptMapper.selectOrderOutputs(req.getWorkOrderId(), cn.iocoder.yudao.module.mes.enums.wm.MesWmProductProduceStatusEnum.FINISHED.getStatus()).stream() |
| | | .noneMatch(item -> java.util.Objects.equals(item.getItemId(), req.getItemId()) |
| | | && java.util.Objects.equals(item.getBatchId(), req.getBatchId()) |
| | | && java.util.Objects.equals(cn.hutool.core.util.StrUtil.blankToDefault(item.getBatchCode(), ""), |
| | | cn.hutool.core.util.StrUtil.blankToDefault(req.getBatchCode(), "")))) |
| | | throw new ServiceException(400, "æéç©æä¸æ¯è¯¥è®¢åçå·²å®æäº§åº"); |
| | | var warehouse = warehouseService.validateWarehouseExists(req.getWarehouseId()); |
| | | if (!java.util.Objects.equals("åºæä»", warehouse.getWarehouseType()) && !java.util.Objects.equals("åºæ", warehouse.getWarehouseType())) |
| | | throw new ServiceException(400, "è¯·éæ©ä»åºç±»åä¸ºåºæä»çä»åº"); |
| | | return create(req); |
| | | } |
| | | |
| | | @Data |
| | | public static class OutputItem { |
| | | private Long itemId; |
| | | private String itemCode; |
| | | private String itemName; |
| | | private Long batchId; |
| | | private String batchCode; |
| | | private BigDecimal quantity; |
| | | } |
| | | |
| | | @PostMapping("/create") |
| | | @PreAuthorize("@ss.hasPermission('mes:wm-scrap-receipt:create')") |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder; |
| | | |
| | | import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; |
| | | import com.baomidou.mybatisplus.annotation.TableId; |
| | | import com.baomidou.mybatisplus.annotation.TableName; |
| | | import lombok.Data; |
| | | import lombok.EqualsAndHashCode; |
| | | |
| | | @Data |
| | | @EqualsAndHashCode(callSuper = true) |
| | | @TableName("mes_pro_work_order_technical_file") |
| | | public class MesProWorkOrderTechnicalFileDO extends BaseDO { |
| | | @TableId private Long id; |
| | | private Long workOrderId; |
| | | private Long sourceFileId; |
| | | private Long blobId; |
| | | private Integer versionNo; |
| | | private String fileName; |
| | | } |
| | |
| | | import cn.iocoder.yudao.module.mes.enums.pro.MesProTaskStatusEnum; |
| | | import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; |
| | | import org.apache.ibatis.annotations.Mapper; |
| | | import org.apache.ibatis.annotations.Param; |
| | | import org.apache.ibatis.annotations.Select; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.util.List; |
| | |
| | | @Mapper |
| | | public interface MesProTaskMapper extends BaseMapperX<MesProTaskDO> { |
| | | |
| | | @Select({"<script>", |
| | | "SELECT t.workstation_id AS workstationId, COUNT(*) AS pendingCount FROM mes_pro_task t", |
| | | "WHERE t.deleted = 0 AND t.workstation_id IS NOT NULL AND t.status IN (#{prepare}, #{producing}, #{partial}, #{paused})", |
| | | "<if test='assigneeId != null'>AND EXISTS (SELECT 1 FROM mes_pro_task_assignee a", |
| | | "WHERE a.task_id=t.id AND a.user_id=#{assigneeId} AND a.deleted=0)</if>", |
| | | "GROUP BY t.workstation_id", "</script>"}) |
| | | java.util.List<cn.iocoder.yudao.module.mes.controller.admin.pro.task.vo.MesProWorkstationPendingCountVO> selectPendingCounts( |
| | | @Param("assigneeId") Long assigneeId, @Param("prepare") Integer prepare, |
| | | @Param("producing") Integer producing, @Param("partial") Integer partial, @Param("paused") Integer paused); |
| | | |
| | | /** æææäº§åå
¥å£ä»¥ç¸å顺åºéå®å·¥ä½ç«ï¼äºå¡æäº¤åéæ¾ï¼è·¨è¿ç¨é²æ¢èµæºç«æã */ |
| | | @org.apache.ibatis.annotations.Select("SELECT id FROM mes_md_workstation WHERE deleted = 0 ORDER BY id FOR UPDATE") |
| | | List<Long> lockSchedulingResources(); |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.mes.dal.mysql.pro.workorder; |
| | | |
| | | import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder.MesProWorkOrderTechnicalFileDO; |
| | | import org.apache.ibatis.annotations.Mapper; |
| | | import java.util.List; |
| | | |
| | | @Mapper |
| | | public interface MesProWorkOrderTechnicalFileMapper extends BaseMapperX<MesProWorkOrderTechnicalFileDO> { |
| | | default List<MesProWorkOrderTechnicalFileDO> selectByWorkOrderId(Long id) { |
| | | return selectList(MesProWorkOrderTechnicalFileDO::getWorkOrderId, id); |
| | | } |
| | | } |
| | |
| | | |
| | | @Mapper |
| | | public interface MesWmScrapReceiptMapper extends BaseMapperX<MesWmScrapReceiptDO> { |
| | | @Select("SELECT l.item_id AS itemId, l.batch_id AS batchId, l.batch_code AS batchCode, SUM(l.quantity) AS quantity FROM mes_wm_product_produce p " + |
| | | "JOIN mes_wm_product_produce_line l ON l.produce_id=p.id AND l.deleted=0 " + |
| | | "WHERE p.deleted=0 AND p.work_order_id=#{orderId} AND p.status=#{finished} " + |
| | | "AND l.item_id IS NOT NULL AND l.quantity > 0 GROUP BY l.item_id,l.batch_id,l.batch_code") |
| | | List<cn.iocoder.yudao.module.mes.controller.admin.wm.scrap.MesWmScrapReceiptController.OutputItem> selectOrderOutputs( |
| | | @Param("orderId") Long orderId, @Param("finished") Integer finished); |
| | | default MesWmScrapReceiptDO selectByCode(String code) { |
| | | return selectOne(MesWmScrapReceiptDO::getCode, code); |
| | | } |
| | |
| | | * 夿æ¯å¦å¯ä»¥å
¥åº |
| | | * |
| | | * @param type æ£æµç»æ |
| | | * @return true å¯ä»¥å
¥åº |
| | | * @return true å¯ä»¥å
¥åºãå½åè´¨æ£åå
¸å° 2 ç¨ä½ä¸éè¿ï¼ä¸è½ææ§âç¹éâå«ä¹æ¾è¡ã |
| | | */ |
| | | public static boolean canInbound(Integer type) { |
| | | return QUALIFIED.getType().equals(type) || SPECIAL_APPROVAL.getType().equals(type); |
| | | return QUALIFIED.getType().equals(type); |
| | | } |
| | | |
| | | } |
| | |
| | | private MesMdWorkstationService workstationService; |
| | | @Resource |
| | | private CrmCustomerApi customerApi; |
| | | @Resource |
| | | private MesProWorkOrderTechnicalFileService technicalFileService; |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | |
| | | MesProWorkOrderDO workOrder = BeanUtils.toBean(createReqVO, MesProWorkOrderDO.class); |
| | | workOrder.setStatus(MesProWorkOrderStatusEnum.PREPARE.getStatus()); |
| | | workOrderMapper.insert(workOrder); |
| | | technicalFileService.snapshot(workOrder.getId(), workOrder.getProductId()); |
| | | |
| | | // 3. èªå¨çæ BOMï¼æ ¹æ®äº§å BOM çæå·¥å BOM |
| | | workOrderBomService.generateWorkOrderBom(workOrder.getId(), createReqVO, false); |
| | |
| | | // å·¥åçå·æ²¿ç¨å建æ¶çæ¥æºå¿«ç
§ï¼é¿å
ä¸è®¡ååå·²çæç䏿¸¸è®°å½ä¸ä¸è´ã |
| | | updateObj.setReelNo(null); |
| | | workOrderMapper.updateById(updateObj); |
| | | if (productChanged) technicalFileService.replace(updateReqVO.getId(), updateReqVO.getProductId()); |
| | | } |
| | | |
| | | @Override |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.mes.service.pro.workorder; |
| | | |
| | | import cn.iocoder.yudao.module.mdm.controller.admin.item.vo.MdmItemTechnicalFileRespVO; |
| | | import cn.iocoder.yudao.module.mdm.service.item.MdmItemTechnicalFileService; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder.MesProWorkOrderTechnicalFileDO; |
| | | import cn.iocoder.yudao.module.mes.dal.mysql.pro.workorder.MesProWorkOrderTechnicalFileMapper; |
| | | import cn.iocoder.yudao.module.system.api.storage.StorageAttachmentApi; |
| | | import jakarta.annotation.Resource; |
| | | import org.springframework.stereotype.Service; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.function.Function; |
| | | import java.util.stream.Collectors; |
| | | |
| | | @Service |
| | | public class MesProWorkOrderTechnicalFileService { |
| | | private static final String RECORD_TYPE = "mes_work_order_technical_file"; |
| | | @Resource private MdmItemTechnicalFileService itemTechnicalFileService; |
| | | @Resource private MesProWorkOrderTechnicalFileMapper mapper; |
| | | @Resource private StorageAttachmentApi storageApi; |
| | | |
| | | /** è°ç¨æ¹å¨å·¥åäºå¡ä¸æ§è¡ï¼é¿å
æ¸
åä¸å·¥ååå»ºç»æä¸ä¸è´ã */ |
| | | public void snapshot(Long orderId, Long itemId) { |
| | | var files = itemTechnicalFileService.getTechnicalFileList(itemId); |
| | | for (var file : files) { |
| | | MesProWorkOrderTechnicalFileDO row = new MesProWorkOrderTechnicalFileDO(); |
| | | row.setWorkOrderId(orderId); |
| | | row.setSourceFileId(file.getId()); |
| | | row.setBlobId(file.getBlobId()); |
| | | row.setVersionNo(file.getVersionNo()); |
| | | row.setFileName(file.getFileName()); |
| | | mapper.insert(row); |
| | | } |
| | | if (!files.isEmpty()) storageApi.bindAttachments("file", RECORD_TYPE, orderId, |
| | | files.stream().map(MdmItemTechnicalFileRespVO::getBlobId).distinct().toList()); |
| | | } |
| | | |
| | | public void replace(Long orderId, Long itemId) { |
| | | // ä¸è°ç¨ deleteAttachmentsByRecordï¼è¯¥æ¥å£ä¼å é¤å
±äº«çåºå±æä»¶ã |
| | | mapper.delete(MesProWorkOrderTechnicalFileDO::getWorkOrderId, orderId); |
| | | snapshot(orderId, itemId); |
| | | } |
| | | |
| | | public List<MdmItemTechnicalFileRespVO> list(Long orderId) { |
| | | var blobs = storageApi.listAttachments(RECORD_TYPE, orderId); |
| | | var byId = blobs == null ? Map.<Long, cn.iocoder.yudao.module.system.api.storage.dto.StorageBlobRespDTO>of() |
| | | : blobs.stream().collect(Collectors.toMap(b -> b.getId(), Function.identity(), (a, b) -> a)); |
| | | return mapper.selectByWorkOrderId(orderId).stream().map(row -> { |
| | | MdmItemTechnicalFileRespVO result = new MdmItemTechnicalFileRespVO(); |
| | | result.setId(row.getSourceFileId()); result.setBlobId(row.getBlobId()); |
| | | result.setVersionNo(row.getVersionNo()); result.setFileName(row.getFileName()); |
| | | var blob = byId.get(row.getBlobId()); |
| | | if (blob != null) { result.setPreviewURL(blob.getPreviewURL()); result.setDownloadURL(blob.getDownloadURL()); } |
| | | return result; |
| | | }).toList(); |
| | | } |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.mes.service.qc; |
| | | |
| | | import cn.iocoder.yudao.framework.common.exception.ServiceException; |
| | | import cn.iocoder.yudao.module.system.api.storage.StorageAttachmentApi; |
| | | import jakarta.annotation.Resource; |
| | | import org.springframework.stereotype.Component; |
| | | import java.math.BigDecimal; |
| | | |
| | | /** ææ°éæ±æ»è´¨æ£ç»æï¼ä¸æ¨æä¸åæ ¼åçåç»å¤ç½®æ¹å¼ã */ |
| | | @Component |
| | | public class MesQcCompletionHelper { |
| | | @Resource private StorageAttachmentApi storageApi; |
| | | @Resource private org.springframework.jdbc.core.JdbcTemplate jdbcTemplate; |
| | | |
| | | public void lockDocument(String type, Long id) { |
| | | String table = switch (type) { |
| | | case "iqc", "ipqc", "oqc", "rqc" -> "mes_qc_" + type; |
| | | default -> throw new ServiceException(400, "è´¨æ£ç±»åæ æ"); |
| | | }; |
| | | var rows = jdbcTemplate.queryForList("SELECT id FROM " + table + " WHERE id = ? AND deleted = 0 FOR UPDATE", Long.class, id); |
| | | if (rows.isEmpty()) throw new ServiceException(400, "è´¨æ£åä¸åå¨"); |
| | | } |
| | | |
| | | public int validateAndGetResult(String type, Long id, BigDecimal qualified, BigDecimal unqualified, BigDecimal checked) { |
| | | if (qualified == null || unqualified == null || qualified.signum() < 0 || unqualified.signum() < 0) { |
| | | throw new ServiceException(400, "请填å大äºçäºé¶çåæ ¼æ°éåä¸åæ ¼æ°é"); |
| | | } |
| | | BigDecimal total = qualified.add(unqualified); |
| | | if (total.signum() <= 0 || checked == null || total.compareTo(checked) != 0) { |
| | | throw new ServiceException(400, "åæ ¼æ°éä¸ä¸åæ ¼æ°éä¹å须大äºé¶ä¸çäºæ£æµæ°é"); |
| | | } |
| | | var attachments = storageApi.listAttachments("mes_qc_" + type + "_attachment", id); |
| | | if (attachments == null || attachments.isEmpty()) throw new ServiceException(400, "请å
ä¸ä¼ æ£éªéä»¶"); |
| | | // ä¸ç°æ mes_qc_check_result åå
¸ä¸è´ï¼1 éè¿ï¼2 ä¸éè¿ã |
| | | return unqualified.signum() == 0 ? 1 : 2; |
| | | } |
| | | } |
| | |
| | | @Slf4j |
| | | public class MesQcIpqcServiceImpl implements MesQcIpqcService { |
| | | |
| | | @Resource |
| | | private cn.iocoder.yudao.module.mes.service.qc.MesQcCompletionHelper completionHelper; |
| | | |
| | | /** |
| | | * IPQC ä¿åæ°æ®æ ¡éªä¸ä¸æ |
| | | * |
| | |
| | | MesProWorkOrderDO workOrder = workOrderService.validateWorkOrderExists(createReqVO.getWorkOrderId()); |
| | | // 1.3 ç¡®å®æ£éªç©æï¼æä»»å¡æ¶åä»»å¡çç©æï¼æ 任塿¶åå·¥åç产å |
| | | Long itemId = (ctx.task() != null) ? ctx.task().getItemId() : workOrder.getProductId(); |
| | | // 1.4 æ ¹æ®ç©æ + IPQC ç±»åæ¥æ¾å¯ç¨è´¨æ£æ¹æ¡ï¼æ¯æå端æ¾å¼æå®ï¼ |
| | | List<MesQcTemplateItemDO> templateItems = templateItemService.getTemplateItemList( |
| | | itemId, MesQcTypeEnum.IPQC.getType(), null, null); |
| | | if (CollUtil.isEmpty(templateItems)) { |
| | | throw exception(QC_NO_TEMPLATE); |
| | | } |
| | | MesQcTemplateItemDO templateItem = templateItems.get(0); |
| | | if (createReqVO.getTemplateId() != null) { |
| | | templateItem = templateItems.stream() |
| | | .filter(available -> Objects.equals(available.getTemplateId(), createReqVO.getTemplateId())) |
| | | .findFirst().orElse(null); |
| | | if (templateItem == null) { |
| | | throw exception(QC_NO_TEMPLATE); // æå®äºæ¹æ¡ä½ä¸å¨å¹é
å表ä¸ï¼æç» |
| | | } |
| | | } |
| | | Long templateId = templateItem.getTemplateId(); |
| | | // æ°å»ºè´¨æ£åä¸ä¾èµè´¨æ£æ¹æ¡ã |
| | | // 1.5 è·åæ¥æºåæ®ç¼å· |
| | | String sourceDocCode = validateAndGetSourceDocCode( |
| | | createReqVO.getSourceDocType(), createReqVO.getSourceDocId(), createReqVO.getSourceLineId()); |
| | |
| | | .setItemId(itemId) |
| | | .setReelNo(workOrder.getReelNo()) |
| | | .setProcessId(getProcessId(itemId, ctx.workstation().getProcessId())) |
| | | .setTemplateId(templateId) |
| | | .setTemplateId(null) |
| | | .setSourceDocCode(sourceDocCode) |
| | | .setStatus(MesQcStatusEnum.DRAFT.getStatus()); |
| | | ipqcMapper.insert(ipqc); |
| | | |
| | | // 3. 仿¨¡æ¿ææ èªå¨çææ£éªè¡ |
| | | ipqcLineService.createLinesFromTemplate(ipqc.getId(), templateId); |
| | | return ipqc.getId(); |
| | | } |
| | | |
| | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void finishIpqc(Long id) { |
| | | completionHelper.lockDocument("ipqc", id); |
| | | // 1.1 æ ¡éªåå¨ + èç¨¿ç¶æ |
| | | MesQcIpqcDO ipqc = validateIpqcStatusPrepare(id); |
| | | // 1.2 æ ¡éªæ£æµç»è®ºå¿
å¡« |
| | | if (ipqc.getCheckResult() == null) { |
| | | throw exception(QC_IPQC_CHECK_RESULT_EMPTY); |
| | | } |
| | | // 1.3 æ ¡éªè³å°åå¨ä¸æ¡æ£æµç»æ |
| | | indicatorResultService.validateIndicatorResultExistsByQcIdAndType(id, MesQcTypeEnum.IPQC.getType()); |
| | | int result = completionHelper.validateAndGetResult("ipqc", id, ipqc.getQualifiedQuantity(), ipqc.getUnqualifiedQuantity(), ipqc.getCheckQuantity()); |
| | | ipqc.setCheckResult(result); |
| | | |
| | | |
| | | // 2. æ´æ°ç¶æä¸ºå·²å®æ |
| | | ipqcMapper.updateById(new MesQcIpqcDO() |
| | | .setId(id).setStatus(MesQcStatusEnum.FINISHED.getStatus())); |
| | | .setId(id).setStatus(MesQcStatusEnum.FINISHED.getStatus()).setCheckResult(result)); |
| | | |
| | | // 3. ä¸åæ ¼æ¶èªå¨å建 NCR |
| | | generateNcrIfNeeded(ipqc); |
| | |
| | | public class MesQcIqcServiceImpl implements MesQcIqcService { |
| | | |
| | | @Resource |
| | | private cn.iocoder.yudao.module.mes.service.qc.MesQcCompletionHelper completionHelper; |
| | | |
| | | @Resource |
| | | private MesQcIqcMapper iqcMapper; |
| | | |
| | | @Resource |
| | |
| | | // 1.2 æ ¡éªæ¥æºåæ®åæ°ï¼å¹¶éªè¯æ°æ®åå¨ |
| | | String sourceDocCode = validateAndGetSourceDocCode( |
| | | createReqVO.getSourceDocType(), createReqVO.getSourceDocId(), createReqVO.getSourceLineId()); |
| | | // 1.3 æ ¹æ®äº§å + IQC ç±»åæ¥æ¾å¯ç¨è´¨æ£æ¹æ¡ï¼æ¯æå端æ¾å¼æå®ï¼ |
| | | List<MesQcTemplateItemDO> templateItems = templateItemService.getTemplateItemList( |
| | | createReqVO.getItemId(), MesQcTypeEnum.IQC.getType(), null, null); |
| | | if (CollUtil.isEmpty(templateItems)) { |
| | | throw exception(QC_NO_TEMPLATE); |
| | | } |
| | | MesQcTemplateItemDO templateItem = templateItems.get(0); |
| | | if (createReqVO.getTemplateId() != null) { |
| | | templateItem = templateItems.stream() |
| | | .filter(item -> Objects.equals(item.getTemplateId(), createReqVO.getTemplateId())) |
| | | .findFirst().orElse(null); |
| | | if (templateItem == null) { |
| | | throw exception(QC_NO_TEMPLATE); // æå®äºæ¹æ¡ä½ä¸å¨å¹é
å表ä¸ï¼æç» |
| | | } |
| | | } |
| | | Long templateId = templateItem.getTemplateId(); |
| | | // æ°å»ºè´¨æ£åä¸ä¾èµè´¨æ£æ¹æ¡ã |
| | | |
| | | // 2. æå
¥ä¸»è¡¨ |
| | | MesQcIqcDO iqc = BeanUtils.toBean(createReqVO, MesQcIqcDO.class) |
| | | .setTemplateId(templateId) |
| | | .setTemplateId(null) |
| | | .setCheckQuantity(createReqVO.getQualifiedQuantity().add(createReqVO.getUnqualifiedQuantity())) |
| | | .setSourceDocCode(sourceDocCode) |
| | | .setStatus(MesQcStatusEnum.DRAFT.getStatus()); |
| | | iqcMapper.insert(iqc); |
| | | |
| | | // 3. 仿¨¡æ¿ææ èªå¨çææ£éªè¡ |
| | | iqcLineService.createLinesFromTemplate(iqc.getId(), templateId); |
| | | return iqc.getId(); |
| | | } |
| | | |
| | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void finishIqc(Long id) { |
| | | completionHelper.lockDocument("iqc", id); |
| | | // 1.1 æ ¡éªåå¨ + èç¨¿ç¶æ |
| | | MesQcIqcDO iqc = validateIqcStatusPrepare(id); |
| | | if (iqc.getCheckResult() == null) { |
| | | throw exception(QC_IQC_CHECK_RESULT_EMPTY); |
| | | } |
| | | // 1.2 æ ¡éªè³å°åå¨ä¸æ¡æ£æµç»æ |
| | | indicatorResultService.validateIndicatorResultExistsByQcIdAndType(id, MesQcTypeEnum.IQC.getType()); |
| | | int result = completionHelper.validateAndGetResult("iqc", id, iqc.getQualifiedQuantity(), iqc.getUnqualifiedQuantity(), iqc.getCheckQuantity()); |
| | | iqc.setCheckResult(result); |
| | | |
| | | |
| | | // 2. æ´æ°ç¶æä¸ºå·²å®æ |
| | | MesQcIqcDO updateObj = new MesQcIqcDO() |
| | | .setId(id).setStatus(MesQcStatusEnum.FINISHED.getStatus()); |
| | | .setId(id).setStatus(MesQcStatusEnum.FINISHED.getStatus()).setCheckResult(result); |
| | | iqcMapper.updateById(updateObj); |
| | | |
| | | // 3. ä¸åæ ¼æ¶èªå¨å建 NCR |
| | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public Long createIqcFromArrivalNotice(Long noticeId, MesWmArrivalNoticeLineDO line, String noticeCode, Long vendorId) { |
| | | // 1. æ ¡éªç©ææ¯å¦é
ç½®äº IQC æ£éªæ¨¡æ¿ |
| | | MesQcTemplateItemDO templateItem; |
| | | try { |
| | | templateItem = templateItemService.getRequiredTemplateByItemIdAndType( |
| | | line.getItemId(), MesQcTypeEnum.IQC.getType()); |
| | | } catch (Exception e) { |
| | | // è·åç©æä¿¡æ¯ï¼æä¾æ´æç¡®çé误æç¤º |
| | | String itemInfo = getItemInfo(line.getItemId()); |
| | | throw exception(QC_NO_TEMPLATE_FOR_ITEM, itemInfo); |
| | | } |
| | | Long templateId = templateItem.getTemplateId(); |
| | | |
| | | // 2. çææ£éªåç¼ç |
| | | String code = "IQC" + System.currentTimeMillis(); |
| | |
| | | MesQcIqcDO iqc = new MesQcIqcDO(); |
| | | iqc.setCode(code); |
| | | iqc.setName(noticeCode + "-ç©ææ£éª"); |
| | | iqc.setTemplateId(templateId); |
| | | |
| | | iqc.setSourceDocType(MesBizTypeConstants.WM_ARRIVAL_NOTICE); |
| | | iqc.setSourceDocId(noticeId); |
| | | iqc.setSourceLineId(line.getId()); |
| | |
| | | iqc.setStatus(MesQcStatusEnum.DRAFT.getStatus()); |
| | | iqcMapper.insert(iqc); |
| | | |
| | | // 4. 仿¨¡æ¿ææ èªå¨çææ£éªè¡ |
| | | iqcLineService.createLinesFromTemplate(iqc.getId(), templateId); |
| | | |
| | | return iqc.getId(); |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.mes.service.qc.link; |
| | | |
| | | import cn.iocoder.yudao.framework.common.exception.ServiceException; |
| | | import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; |
| | | import cn.iocoder.yudao.module.erp.api.sale.ErpSaleOrderApi; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.pro.feedback.MesProFeedbackDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.qc.ipqc.MesQcIpqcDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.qc.oqc.MesQcOqcDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.productproduce.MesWmProductProduceLineDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.productsales.MesWmProductSalesDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.productsales.MesWmProductSalesLineDO; |
| | | import cn.iocoder.yudao.module.mes.dal.mysql.pro.feedback.MesProFeedbackMapper; |
| | | import cn.iocoder.yudao.module.mes.dal.mysql.qc.ipqc.MesQcIpqcMapper; |
| | | import cn.iocoder.yudao.module.mes.dal.mysql.qc.oqc.MesQcOqcMapper; |
| | | import cn.iocoder.yudao.module.mes.dal.mysql.wm.productproduce.MesWmProductProduceLineMapper; |
| | | import cn.iocoder.yudao.module.mes.dal.mysql.wm.productsales.MesWmProductSalesLineMapper; |
| | | import cn.iocoder.yudao.module.mes.dal.mysql.wm.productsales.MesWmProductSalesMapper; |
| | | import cn.iocoder.yudao.module.mes.enums.MesBizTypeConstants; |
| | | import cn.iocoder.yudao.module.mes.enums.pro.MesProFeedbackStatusEnum; |
| | | import cn.iocoder.yudao.module.mes.enums.qc.MesQcStatusEnum; |
| | | import cn.iocoder.yudao.module.mes.enums.wm.MesWmProductSalesStatusEnum; |
| | | import cn.iocoder.yudao.module.mes.enums.wm.MesWmQualityStatusEnum; |
| | | import cn.iocoder.yudao.module.mes.service.pro.feedback.MesProFeedbackService; |
| | | import cn.iocoder.yudao.module.mes.service.wm.productsales.MesWmProductSalesLineService; |
| | | import jakarta.annotation.Resource; |
| | | import org.springframework.context.annotation.Lazy; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | import java.math.BigDecimal; |
| | | import java.util.*; |
| | | |
| | | /** ä¸å¼ å·²å®æè´¨æ£å对åºä¸æ¡æ°éå®å
¨ä¸è´çå¾
æ£ä¸å¡è¡ã */ |
| | | @Service |
| | | public class MesQcSourceLinkService { |
| | | @Resource private MesQcIpqcMapper ipqcMapper; |
| | | @Resource private MesQcOqcMapper oqcMapper; |
| | | @Resource private MesProFeedbackMapper feedbackMapper; |
| | | @Resource private MesWmProductProduceLineMapper produceLineMapper; |
| | | @Resource private MesWmProductSalesMapper salesMapper; |
| | | @Resource private MesWmProductSalesLineMapper salesLineMapper; |
| | | @Resource private ErpSaleOrderApi saleOrderApi; |
| | | @Resource @Lazy private MesProFeedbackService feedbackService; |
| | | @Resource @Lazy private MesWmProductSalesLineService salesLineService; |
| | | |
| | | public record Candidate(Long lineId, Long documentId, String documentCode, String reelNo, BigDecimal quantity) {} |
| | | |
| | | public List<Candidate> feedbackCandidates(Long qcId) { |
| | | MesQcIpqcDO qc = ipqcMapper.selectById(qcId); |
| | | requireIpqc(qc); |
| | | var lines = produceLineMapper.selectList(new LambdaQueryWrapperX<MesWmProductProduceLineDO>() |
| | | .eq(MesWmProductProduceLineDO::getItemId, qc.getItemId()) |
| | | .eq(MesWmProductProduceLineDO::getQualityStatus, MesWmQualityStatusEnum.PENDING.getStatus()) |
| | | .isNotNull(MesWmProductProduceLineDO::getFeedbackId).orderByDesc(MesWmProductProduceLineDO::getId)); |
| | | List<Candidate> result = new ArrayList<>(); |
| | | for (var line : lines) { |
| | | MesProFeedbackDO feedback = feedbackMapper.selectById(line.getFeedbackId()); |
| | | if (feedback != null && feedbackMismatch(qc, line, feedback) == null) { |
| | | result.add(new Candidate(line.getId(), feedback.getId(), feedback.getCode(), line.getReelNo(), line.getQuantity())); |
| | | } |
| | | } |
| | | return result; |
| | | } |
| | | |
| | | public List<Candidate> salesCandidates(Long qcId) { |
| | | MesQcOqcDO qc = oqcMapper.selectById(qcId); |
| | | requireOqc(qc); |
| | | var lines = salesLineMapper.selectList(new LambdaQueryWrapperX<MesWmProductSalesLineDO>() |
| | | .eq(MesWmProductSalesLineDO::getItemId, qc.getItemId()) |
| | | .eq(MesWmProductSalesLineDO::getOqcCheckFlag, true) |
| | | .isNull(MesWmProductSalesLineDO::getOqcId).orderByDesc(MesWmProductSalesLineDO::getId)); |
| | | List<Candidate> result = new ArrayList<>(); |
| | | for (var line : lines) { |
| | | var sales = salesMapper.selectById(line.getSalesId()); |
| | | String reel = salesReel(line); |
| | | if (sales != null && salesMismatch(qc, line, sales, reel) == null) { |
| | | result.add(new Candidate(line.getId(), sales.getId(), sales.getCode(), reel, line.getQuantity())); |
| | | } |
| | | } |
| | | return result; |
| | | } |
| | | |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void linkFeedback(Long qcId, Long lineId) { |
| | | var qc = ipqcMapper.selectOne(new LambdaQueryWrapperX<MesQcIpqcDO>().eq(MesQcIpqcDO::getId, qcId).last("FOR UPDATE")); |
| | | requireIpqc(qc); |
| | | var line = produceLineMapper.selectById(lineId); |
| | | if (line == null || line.getFeedbackId() == null) { |
| | | throw new ServiceException(400, "æéæ¥å·¥äº§åºè¡ä¸å卿æªå
³èæ¥å·¥åï¼è¯·å·æ°åéå表åéè¯"); |
| | | } |
| | | var feedback = feedbackMapper.selectByIdForUpdate(line.getFeedbackId()); |
| | | line = produceLineMapper.selectOne(new LambdaQueryWrapperX<MesWmProductProduceLineDO>() |
| | | .eq(MesWmProductProduceLineDO::getId, lineId).last("FOR UPDATE")); |
| | | String mismatch = feedbackMismatch(qc, line, feedback); |
| | | if (mismatch != null) throw new ServiceException(400, mismatch); |
| | | long used = ipqcMapper.selectCount(new LambdaQueryWrapperX<MesQcIpqcDO>() |
| | | .eq(MesQcIpqcDO::getSourceDocType, MesBizTypeConstants.PRO_FEEDBACK) |
| | | .eq(MesQcIpqcDO::getSourceLineId, lineId)); |
| | | if (used > 0) throw new ServiceException(400, "该å¾
æ£äº§åºè¡å·²è¢«å
¶ä»è¿ç¨æ£éªåå
³èï¼è¯·å·æ°åéå表åéè¯"); |
| | | ipqcMapper.updateById(new MesQcIpqcDO().setId(qcId).setSourceDocType(MesBizTypeConstants.PRO_FEEDBACK) |
| | | .setSourceDocId(feedback.getId()).setSourceLineId(lineId).setSourceDocCode(feedback.getCode())); |
| | | feedbackService.updateProFeedbackWhenIpqcFinish(feedback.getId(), lineId, qc.getQualifiedQuantity(), qc.getUnqualifiedQuantity(), |
| | | zero(qc.getLaborScrapQuantity()), zero(qc.getMaterialScrapQuantity()), zero(qc.getOtherScrapQuantity())); |
| | | } |
| | | |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void linkSales(Long qcId, Long lineId) { |
| | | var qc = oqcMapper.selectOne(new LambdaQueryWrapperX<MesQcOqcDO>().eq(MesQcOqcDO::getId, qcId).last("FOR UPDATE")); |
| | | requireOqc(qc); |
| | | var line = salesLineMapper.selectById(lineId); |
| | | if (line == null || line.getSalesId() == null) { |
| | | throw new ServiceException(400, "æééå®åºåºæç»ä¸å卿æªå
³èåºåºåï¼è¯·å·æ°åéå表åéè¯"); |
| | | } |
| | | var sales = salesMapper.selectOne(new LambdaQueryWrapperX<MesWmProductSalesDO>() |
| | | .eq(MesWmProductSalesDO::getId, line.getSalesId()).last("FOR UPDATE")); |
| | | line = salesLineMapper.selectOne(new LambdaQueryWrapperX<MesWmProductSalesLineDO>() |
| | | .eq(MesWmProductSalesLineDO::getId, lineId).last("FOR UPDATE")); |
| | | String mismatch = salesMismatch(qc, line, sales, salesReel(line)); |
| | | if (mismatch != null) throw new ServiceException(400, mismatch); |
| | | var linked = oqcMapper.selectOne(new LambdaQueryWrapperX<MesQcOqcDO>() |
| | | .eq(MesQcOqcDO::getSourceDocType, MesBizTypeConstants.WM_PRODUCT_SALES) |
| | | .eq(MesQcOqcDO::getSourceLineId, lineId).last("LIMIT 1")); |
| | | if (linked != null) { |
| | | throw new ServiceException(400, "该åºåºæç»å·²å
³èåºè´§æ£éªå[" + linked.getCode() + "]ï¼è¯·å·æ°åéå表åéè¯"); |
| | | } |
| | | oqcMapper.updateById(new MesQcOqcDO().setId(qcId).setSourceDocType(MesBizTypeConstants.WM_PRODUCT_SALES) |
| | | .setSourceDocId(sales.getId()).setSourceLineId(lineId).setSourceDocCode(sales.getCode())); |
| | | salesLineService.updateProductSalesLineWhenOqcFinish(lineId, qcId, qc.getCheckResult()); |
| | | } |
| | | |
| | | /** è¿å第ä¸å¤ä¸æ»¡è¶³çåå ï¼ä¸ºç©ºè¡¨ç¤ºå¯å
³èã */ |
| | | private String feedbackMismatch(MesQcIpqcDO q, MesWmProductProduceLineDO l, MesProFeedbackDO f) { |
| | | if (l == null) return "æéæ¥å·¥äº§åºè¡ä¸å卿已å é¤ï¼è¯·å·æ°åéå表åéè¯"; |
| | | if (f == null) return "å
³èçæ¥å·¥åä¸å卿已å é¤ï¼è¯·å·æ°åéå表åéè¯"; |
| | | if (!Objects.equals(f.getStatus(), MesProFeedbackStatusEnum.UNCHECK.getStatus())) { |
| | | return "æ¥å·¥å[" + f.getCode() + "]å½åç¶æä¸º[" + feedbackStatusName(f.getStatus()) + "]ï¼ä»
å¾
æ£éªæ¥å·¥å¯å
³èï¼è¯·éæ°éæ©"; |
| | | } |
| | | if (!Objects.equals(l.getQualityStatus(), MesWmQualityStatusEnum.PENDING.getStatus())) { |
| | | return "æ¥å·¥äº§åºè¡å½åè´¨éç¶æä¸º[" + qualityStatusName(l.getQualityStatus()) + "]ï¼å·²è¢«æ£éªæå·²å
¥åºï¼è¯·éæ°éæ©"; |
| | | } |
| | | if (!Objects.equals(q.getItemId(), l.getItemId())) { |
| | | return "ç©æä¸ä¸è´ï¼è´¨æ£åç©æID=" + display(q.getItemId()) + "ï¼æ¥å·¥äº§åºè¡ç©æID=" + display(l.getItemId()) + "ï¼è¯·éæ°éæ©"; |
| | | } |
| | | if (!Objects.equals(q.getWorkOrderId(), f.getWorkOrderId())) { |
| | | return "ç产工åä¸ä¸è´ï¼è´¨æ£åå·¥åID=" + display(q.getWorkOrderId()) + "ï¼æ¥å·¥åå·¥åID=" + display(f.getWorkOrderId()) + "ï¼è¯·éæ°éæ©"; |
| | | } |
| | | if (q.getTaskId() != null && !Objects.equals(q.getTaskId(), f.getTaskId())) { |
| | | return "ç产任å¡ä¸ä¸è´ï¼è´¨æ£åä»»å¡ID=" + display(q.getTaskId()) + "ï¼æ¥å·¥åä»»å¡ID=" + display(f.getTaskId()) + "ï¼è¯·éæ°éæ©"; |
| | | } |
| | | if (!sameReel(q.getReelNo(), l.getReelNo())) { |
| | | return "çå·ä¸ä¸è´ï¼è´¨æ£åçå·[" + display(q.getReelNo()) + "]ï¼æ¥å·¥äº§åºè¡çå·[" + display(l.getReelNo()) + "]ï¼è¯·éæ°éæ©"; |
| | | } |
| | | if (!sameQty(q.getCheckQuantity(), l.getQuantity())) { |
| | | return "æ°éä¸ä¸è´ï¼è´¨æ£åæ£æµæ°é[" + display(q.getCheckQuantity()) + "]ï¼å¾
æ£äº§åºè¡æ°é[" + display(l.getQuantity()) + "]ï¼è¯·éæ°éæ©"; |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | private String salesMismatch(MesQcOqcDO q, MesWmProductSalesLineDO l, MesWmProductSalesDO s, String reel) { |
| | | if (l == null) return "æééå®åºåºæç»ä¸å卿已å é¤ï¼è¯·å·æ°åéå表åéè¯"; |
| | | if (s == null) return "æå±éå®åºåºåä¸å卿已å é¤ï¼è¯·å·æ°åéå表åéè¯"; |
| | | if (!Objects.equals(s.getStatus(), MesWmProductSalesStatusEnum.CONFIRMED.getStatus())) { |
| | | return "éå®åºåºå[" + s.getCode() + "]å½åç¶æä¸º[" + salesStatusName(s.getStatus()) + "]ï¼ä»
å¾
æ£æµåºåºåå¯å
³èï¼è¯·éæ°éæ©"; |
| | | } |
| | | if (!Boolean.TRUE.equals(l.getOqcCheckFlag())) { |
| | | return "该åºåºæç»æªå¾éãéè¦åºè´§æ£éªãï¼æ æ³å
³èï¼è¯·å
确认åºåºæç»è®¾ç½®"; |
| | | } |
| | | if (l.getOqcId() != null) { |
| | | return "该åºåºæç»å·²å
³èè´¨æ£åID=" + l.getOqcId() + "ï¼è¯·å·æ°åéå表åéæ°éæ©"; |
| | | } |
| | | if (!Objects.equals(q.getItemId(), l.getItemId())) { |
| | | return "ç©æä¸ä¸è´ï¼è´¨æ£åç©æID=" + display(q.getItemId()) + "ï¼åºåºæç»ç©æID=" + display(l.getItemId()) + "ï¼è¯·éæ°éæ©"; |
| | | } |
| | | if (q.getClientId() != null && !Objects.equals(q.getClientId(), s.getClientId())) { |
| | | return "客æ·ä¸ä¸è´ï¼è´¨æ£å客æ·ID=" + display(q.getClientId()) + "ï¼éå®åºåºå客æ·ID=" + display(s.getClientId()) + "ï¼è¯·éæ°éæ©"; |
| | | } |
| | | if (!sameReel(q.getReelNo(), reel)) { |
| | | return "çå·ä¸ä¸è´ï¼è´¨æ£åçå·[" + display(q.getReelNo()) + "]ï¼åºåºæç»çå·[" + display(reel) + "]ï¼è¯·ç¡®è®¤éå®è®¢åæç»çå·åéæ°éæ©"; |
| | | } |
| | | if (!sameQty(q.getCheckQuantity(), l.getQuantity())) { |
| | | return "æ°éä¸ä¸è´ï¼è´¨æ£åæ£æµæ°é[" + display(q.getCheckQuantity()) + "]ï¼å¾
æ£åºåºæç»æ°é[" + display(l.getQuantity()) + "]ï¼è¯·éæ°éæ©"; |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | private String salesReel(MesWmProductSalesLineDO line) { |
| | | if (line == null || line.getSaleOrderItemId() == null) return null; |
| | | var item = saleOrderApi.getSaleOrderItem(line.getSaleOrderItemId()).getCheckedData(); |
| | | return item == null ? null : item.getReelNo(); |
| | | } |
| | | private static boolean sameReel(String a, String b) { return a != null && b != null && !a.isBlank() && a.trim().equals(b.trim()); } |
| | | private static boolean sameQty(BigDecimal a, BigDecimal b) { return a != null && b != null && a.signum() > 0 && a.compareTo(b) == 0; } |
| | | private static BigDecimal zero(BigDecimal value) { return value == null ? BigDecimal.ZERO : value; } |
| | | private static String display(Object value) { return value == null ? "空" : value.toString(); } |
| | | private static String feedbackStatusName(Integer status) { |
| | | for (var e : MesProFeedbackStatusEnum.values()) if (Objects.equals(e.getStatus(), status)) return e.getName(); |
| | | return "æªç¥(" + display(status) + ")"; |
| | | } |
| | | private static String qualityStatusName(Integer status) { |
| | | for (var e : MesWmQualityStatusEnum.values()) if (Objects.equals(e.getStatus(), status)) return e.getName(); |
| | | return "æªç¥(" + display(status) + ")"; |
| | | } |
| | | private static String salesStatusName(Integer status) { |
| | | for (var e : MesWmProductSalesStatusEnum.values()) if (Objects.equals(e.getStatus(), status)) return e.getName(); |
| | | return "æªç¥(" + display(status) + ")"; |
| | | } |
| | | private static void requireIpqc(MesQcIpqcDO q) { |
| | | if (q == null) throw new ServiceException(400, "è¿ç¨æ£éªåä¸å卿已å é¤ï¼è¯·å·æ°åéè¯"); |
| | | if (!Objects.equals(q.getStatus(), MesQcStatusEnum.FINISHED.getStatus())) { |
| | | throw new ServiceException(400, "ä»
已宿çè¿ç¨æ£éªåå¯å
³èï¼å½åç¶æä¸º[" + qcStatusName(q.getStatus()) + "]"); |
| | | } |
| | | if (q.getSourceDocType() != null || q.getSourceDocId() != null || q.getSourceLineId() != null) { |
| | | throw new ServiceException(400, "该è¿ç¨æ£éªåå·²å
³èæ¥æºåæ®[" + display(q.getSourceDocCode()) + "]ï¼ä¸è½éå¤å
³è"); |
| | | } |
| | | if (q.getReelNo() == null || q.getReelNo().isBlank()) { |
| | | throw new ServiceException(400, "该è¿ç¨æ£éªå缺å°çå·ï¼æ æ³æçå·çéå¾
æ£äº§åºè¡ï¼è¯·è¡¥å
çå·åéè¯"); |
| | | } |
| | | } |
| | | private static void requireOqc(MesQcOqcDO q) { |
| | | if (q == null) throw new ServiceException(400, "åºè´§æ£éªåä¸å卿已å é¤ï¼è¯·å·æ°åéè¯"); |
| | | if (!Objects.equals(q.getStatus(), MesQcStatusEnum.FINISHED.getStatus())) { |
| | | throw new ServiceException(400, "ä»
已宿çåºè´§æ£éªåå¯å
³èï¼å½åç¶æä¸º[" + qcStatusName(q.getStatus()) + "]"); |
| | | } |
| | | if (q.getSourceDocType() != null || q.getSourceDocId() != null || q.getSourceLineId() != null) { |
| | | throw new ServiceException(400, "该åºè´§æ£éªåå·²å
³èæ¥æºåæ®[" + display(q.getSourceDocCode()) + "]ï¼ä¸è½éå¤å
³è"); |
| | | } |
| | | if (q.getReelNo() == null || q.getReelNo().isBlank()) { |
| | | throw new ServiceException(400, "该åºè´§æ£éªå缺å°çå·ï¼æ æ³æçå·çéå¾
æ£åºåºæç»ï¼è¯·è¡¥å
çå·åéè¯"); |
| | | } |
| | | } |
| | | private static String qcStatusName(Integer status) { |
| | | for (var e : MesQcStatusEnum.values()) if (Objects.equals(e.getStatus(), status)) return e.getName(); |
| | | return "æªç¥(" + display(status) + ")"; |
| | | } |
| | | } |
| | |
| | | public class MesQcOqcServiceImpl implements MesQcOqcService { |
| | | |
| | | @Resource |
| | | private cn.iocoder.yudao.module.mes.service.qc.MesQcCompletionHelper completionHelper; |
| | | |
| | | @Resource |
| | | private MesQcOqcMapper oqcMapper; |
| | | |
| | | @Resource |
| | |
| | | // 1.2 æ ¡éªæ¥æºåæ®åæ°ï¼å¹¶éªè¯æ°æ®åå¨ |
| | | String sourceDocCode = validateAndGetSourceDocCode( |
| | | createReqVO.getSourceDocType(), createReqVO.getSourceLineId()); |
| | | // 1.3 æ ¹æ®äº§å + OQC ç±»åæ¥æ¾å¯ç¨è´¨æ£æ¹æ¡ï¼æ¯æå端æ¾å¼æå®ï¼ |
| | | List<MesQcTemplateItemDO> templateItems = templateItemService.getTemplateItemList( |
| | | createReqVO.getItemId(), MesQcTypeEnum.OQC.getType(), null, null); |
| | | if (CollUtil.isEmpty(templateItems)) { |
| | | throw exception(QC_NO_TEMPLATE); |
| | | } |
| | | MesQcTemplateItemDO templateItem = templateItems.get(0); |
| | | if (createReqVO.getTemplateId() != null) { |
| | | templateItem = templateItems.stream() |
| | | .filter(available -> Objects.equals(available.getTemplateId(), createReqVO.getTemplateId())) |
| | | .findFirst().orElse(null); |
| | | if (templateItem == null) { |
| | | throw exception(QC_NO_TEMPLATE); // æå®äºæ¹æ¡ä½ä¸å¨å¹é
å表ä¸ï¼æç» |
| | | } |
| | | } |
| | | Long templateId = templateItem.getTemplateId(); |
| | | // æ°å»ºè´¨æ£åä¸ä¾èµè´¨æ£æ¹æ¡ã |
| | | |
| | | // 2. æå
¥ä¸»è¡¨ |
| | | MesQcOqcDO oqc = BeanUtils.toBean(createReqVO, MesQcOqcDO.class) |
| | | .setTemplateId(templateId) |
| | | .setTemplateId(null) |
| | | .setSourceDocCode(sourceDocCode) |
| | | .setStatus(MesQcStatusEnum.DRAFT.getStatus()); |
| | | if (createReqVO.getSourceLineId() != null) { |
| | |
| | | .validateProductSalesLineExists(createReqVO.getSourceLineId()))); |
| | | } |
| | | oqcMapper.insert(oqc); |
| | | |
| | | // 3. 仿¨¡æ¿ææ èªå¨çææ£éªè¡ |
| | | oqcLineService.createLinesFromTemplate(oqc.getId(), templateId); |
| | | return oqc.getId(); |
| | | } |
| | | |
| | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void finishOqc(Long id) { |
| | | completionHelper.lockDocument("oqc", id); |
| | | // 1.1 æ ¡éªåå¨ + èç¨¿ç¶æ |
| | | MesQcOqcDO oqc = validateOqcStatusPrepare(id); |
| | | // 1.2 æ ¡éªæ£æµç»è®ºå¿
å¡« |
| | | if (oqc.getCheckResult() == null) { |
| | | throw exception(QC_OQC_CHECK_RESULT_EMPTY); |
| | | } |
| | | // 1.3 æ ¡éªè³å°åå¨ä¸æ¡æ£æµç»æ |
| | | indicatorResultService.validateIndicatorResultExistsByQcIdAndType(id, MesQcTypeEnum.OQC.getType()); |
| | | int result = completionHelper.validateAndGetResult("oqc", id, oqc.getQualifiedQuantity(), oqc.getUnqualifiedQuantity(), oqc.getCheckQuantity()); |
| | | oqc.setCheckResult(result); |
| | | |
| | | |
| | | // 2. æ´æ°ç¶æä¸ºå·²å®æ |
| | | MesQcOqcDO updateObj = new MesQcOqcDO() |
| | | .setId(id).setStatus(MesQcStatusEnum.FINISHED.getStatus()); |
| | | .setId(id).setStatus(MesQcStatusEnum.FINISHED.getStatus()).setCheckResult(result); |
| | | oqcMapper.updateById(updateObj); |
| | | |
| | | // 3. ä¸åæ ¼æ¶èªå¨å建 NCR |
| | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public Long createOqcFromProductSales(Long salesId, MesWmProductSalesLineDO line, String salesCode, Long clientId) { |
| | | // 1. æ ¡éªç©ææ¯å¦é
ç½®äº OQC æ£éªæ¨¡æ¿ |
| | | MesQcTemplateItemDO templateItem; |
| | | try { |
| | | templateItem = templateItemService.getRequiredTemplateByItemIdAndType( |
| | | line.getItemId(), MesQcTypeEnum.OQC.getType()); |
| | | } catch (Exception e) { |
| | | // è·åç©æä¿¡æ¯ï¼æä¾æ´æç¡®çé误æç¤º |
| | | String itemInfo = getItemInfo(line.getItemId()); |
| | | throw exception(QC_NO_TEMPLATE_FOR_ITEM, itemInfo); |
| | | } |
| | | Long templateId = templateItem.getTemplateId(); |
| | | |
| | | // 2. çææ£éªåç¼ç |
| | | String code = "OQC" + System.currentTimeMillis(); |
| | |
| | | MesQcOqcDO oqc = new MesQcOqcDO(); |
| | | oqc.setCode(code); |
| | | oqc.setName(salesCode + "-åºè´§æ£éª"); |
| | | oqc.setTemplateId(templateId); |
| | | |
| | | oqc.setSourceDocType(MesBizTypeConstants.WM_PRODUCT_SALES); |
| | | oqc.setSourceDocId(salesId); |
| | | oqc.setSourceLineId(line.getId()); |
| | |
| | | oqc.setStatus(MesQcStatusEnum.DRAFT.getStatus()); |
| | | oqcMapper.insert(oqc); |
| | | |
| | | // 4. 仿¨¡æ¿ææ èªå¨çææ£éªè¡ |
| | | oqcLineService.createLinesFromTemplate(oqc.getId(), templateId); |
| | | |
| | | return oqc.getId(); |
| | | } |
| | |
| | | public class MesQcRqcServiceImpl implements MesQcRqcService { |
| | | |
| | | @Resource |
| | | private cn.iocoder.yudao.module.mes.service.qc.MesQcCompletionHelper completionHelper; |
| | | |
| | | @Resource |
| | | private MesQcRqcMapper rqcMapper; |
| | | |
| | | @Resource |
| | |
| | | public Long createRqc(MesQcRqcSaveReqVO createReqVO) { |
| | | // 1.1 æ ¡éªæ°æ® |
| | | validateRqcSaveData(createReqVO); |
| | | // 1.2 æ ¹æ®ç©æ + RQC æ£æµç§ç±»æ¥æ¾å¯ç¨è´¨æ£æ¹æ¡ï¼æ¯æå端æ¾å¼æå®ï¼ |
| | | List<MesQcTemplateItemDO> templateItems = templateItemService.getTemplateItemList( |
| | | createReqVO.getItemId(), MesQcTypeEnum.RQC.getType(), null, null); |
| | | if (CollUtil.isEmpty(templateItems)) { |
| | | throw exception(QC_NO_TEMPLATE); |
| | | } |
| | | MesQcTemplateItemDO templateItem = templateItems.get(0); |
| | | if (createReqVO.getTemplateId() != null) { |
| | | templateItem = templateItems.stream() |
| | | .filter(available -> Objects.equals(available.getTemplateId(), createReqVO.getTemplateId())) |
| | | .findFirst().orElse(null); |
| | | if (templateItem == null) { |
| | | throw exception(QC_NO_TEMPLATE); // æå®äºæ¹æ¡ä½ä¸å¨å¹é
å表ä¸ï¼æç» |
| | | } |
| | | } |
| | | Long templateId = templateItem.getTemplateId(); |
| | | // æ°å»ºè´¨æ£åä¸ä¾èµè´¨æ£æ¹æ¡ã |
| | | // 1.3 è·åæ¥æºåæ®ç¼å· |
| | | String sourceDocCode = validateAndGetSourceDocCode( |
| | | createReqVO.getSourceDocType(), createReqVO.getSourceDocId()); |
| | | |
| | | // 2. æå
¥ä¸»è¡¨ |
| | | MesQcRqcDO rqc = BeanUtils.toBean(createReqVO, MesQcRqcDO.class) |
| | | .setTemplateId(templateId) |
| | | .setTemplateId(null) |
| | | .setSourceDocCode(sourceDocCode) |
| | | .setStatus(MesQcStatusEnum.DRAFT.getStatus()); |
| | | if (Objects.equals(createReqVO.getSourceDocType(), MesBizTypeConstants.WM_RETURN_SALES) |
| | |
| | | rqc.setBatchCode(line.getBatchCode()); |
| | | } |
| | | rqcMapper.insert(rqc); |
| | | |
| | | // 3. 仿¨¡æ¿ææ èªå¨çææ£éªè¡ |
| | | rqcLineService.createLinesFromTemplate(rqc.getId(), templateId); |
| | | return rqc.getId(); |
| | | } |
| | | |
| | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void finishRqc(Long id) { |
| | | completionHelper.lockDocument("rqc", id); |
| | | // 1.1 æ ¡éªåå¨ + èç¨¿ç¶æ |
| | | MesQcRqcDO rqc = validateRqcStatusPrepare(id); |
| | | // 1.2 æ ¡éªæ£æµç»è®ºå¿
å¡« |
| | | if (rqc.getCheckResult() == null) { |
| | | throw exception(QC_RQC_CHECK_RESULT_EMPTY); |
| | | } |
| | | // 1.3 æ ¡éªåæ ¼å + ä¸åæ ¼å = æ£æµæ°é |
| | | if (rqc.getCheckQuantity() != null && rqc.getCheckQuantity().compareTo(BigDecimal.ZERO) > 0) { |
| | | BigDecimal qualified = rqc.getQualifiedQuantity() != null ? rqc.getQualifiedQuantity() : BigDecimal.ZERO; |
| | | BigDecimal unqualified = rqc.getUnqualifiedQuantity() != null ? rqc.getUnqualifiedQuantity() : BigDecimal.ZERO; |
| | | if (qualified.add(unqualified).compareTo(rqc.getCheckQuantity()) != 0) { |
| | | throw exception(QC_RQC_QUANTITY_MISMATCH); |
| | | } |
| | | } |
| | | // 1.4 æ ¡éªè³å°åå¨ä¸æ¡æ£æµç»æ |
| | | indicatorResultService.validateIndicatorResultExistsByQcIdAndType(id, MesQcTypeEnum.RQC.getType()); |
| | | int result = completionHelper.validateAndGetResult("rqc", id, rqc.getQualifiedQuantity(), rqc.getUnqualifiedQuantity(), rqc.getCheckQuantity()); |
| | | rqc.setCheckResult(result); |
| | | |
| | | |
| | | // 2. æ´æ°ç¶æä¸ºå·²å®æ |
| | | MesQcRqcDO updateObj = new MesQcRqcDO().setId(id).setStatus(MesQcStatusEnum.FINISHED.getStatus()); |
| | | MesQcRqcDO updateObj = new MesQcRqcDO().setId(id).setStatus(MesQcStatusEnum.FINISHED.getStatus()).setCheckResult(result); |
| | | rqcMapper.updateById(updateObj); |
| | | |
| | | // 3. ä¸åæ ¼æ¶èªå¨å建 NCR |
| | |
| | | } |
| | | productSalesLineMapper.updateById(updateObj); |
| | | |
| | | // æ£æ¥æ¯å¦éè¦å建 OQC æ£éªåï¼ä»ä¸éè¦æ£éªå为éè¦æ£éª |
| | | if (Boolean.TRUE.equals(updateReqVO.getOqcCheckFlag()) |
| | | && !Boolean.TRUE.equals(oldLine.getOqcCheckFlag())) { |
| | | // è·ååºåºåä¿¡æ¯ |
| | | MesWmProductSalesDO sales = productSalesService.getProductSales(updateReqVO.getSalesId()); |
| | | if (sales == null) { |
| | | log.warn("[updateProductSalesLine] åºåºåä¸åå¨ï¼salesId={}", updateReqVO.getSalesId()); |
| | | return; |
| | | } |
| | | |
| | | // æå»ºåºåºæç» DO |
| | | MesWmProductSalesLineDO line = new MesWmProductSalesLineDO(); |
| | | line.setId(updateReqVO.getId()); |
| | | line.setItemId(updateReqVO.getItemId()); |
| | | line.setSaleOrderItemId(updateObj.getSaleOrderItemId() != null |
| | | ? updateObj.getSaleOrderItemId() : oldLine.getSaleOrderItemId()); |
| | | line.setBatchCode(updateReqVO.getBatchCode()); |
| | | line.setQuantity(updateReqVO.getQuantity()); |
| | | |
| | | // å建 OQC æ£éªåï¼è®©å¼å¸¸æåº |
| | | Long oqcId = oqcService.createOqcFromProductSales( |
| | | sales.getId(), line, sales.getCode(), sales.getClientId()); |
| | | |
| | | // æ´æ°åºåºæç»ç oqcId åè´¨éç¶æ |
| | | productSalesLineMapper.updateById(new MesWmProductSalesLineDO() |
| | | .setId(updateReqVO.getId()) |
| | | .setOqcId(oqcId) |
| | | .setQualityStatus(MesWmQualityStatusEnum.PENDING.getStatus())); |
| | | } |
| | | // æäº¤åºåºååç±è´¨æ£äººå鿩已宿çåºåæ£éªåã |
| | | } |
| | | |
| | | @Override |
| | |
| | | Long salesId = currentLine.getSalesId(); |
| | | List<MesWmProductSalesLineDO> allLines = productSalesLineMapper.selectListBySalesId(salesId); |
| | | |
| | | // 2.1 æ£æ¥æ¯å¦æä¸åæ ¼è¡ â åæ¶åºåºå |
| | | // ä¸åæ ¼è¡çå¾
åç»å¤ç½®ï¼ä¸è½å 为æ£éªç»æèªå¨åæ¶æ´å¼ åºåºåã |
| | | boolean hasNg = CollectionUtils.anyMatch(allLines, |
| | | line -> Boolean.TRUE.equals(line.getOqcCheckFlag()) |
| | | && Objects.equals(line.getQualityStatus(), MesWmQualityStatusEnum.FAIL.getStatus())); |
| | | if (hasNg) { |
| | | log.info("[updateProductSalesLineWhenOqcFinish][éå®åºåºå({}) åå¨è´¨æ£ä¸åæ ¼è¡ï¼åæ¶åºåºå]", salesId); |
| | | productSalesService.cancelProductSales(salesId); |
| | | log.info("[updateProductSalesLineWhenOqcFinish][éå®åºåºå({}) åå¨è´¨æ£ä¸åæ ¼è¡ï¼çå¾
åç»å¤ç½®]", salesId); |
| | | return; |
| | | } |
| | | |
| | | // 2.2 æ£æ¥æ¯å¦ææ OQC è¡é½å·²å®æï¼èªå¨æµè½¬ CONFIRMED â APPROVING |
| | | boolean hasUnchecked = CollectionUtils.anyMatch(allLines, |
| | | line -> Boolean.TRUE.equals(line.getOqcCheckFlag()) && line.getOqcId() == null); |
| | | line -> Boolean.TRUE.equals(line.getOqcCheckFlag()) && !Objects.equals(line.getQualityStatus(), MesWmQualityStatusEnum.PASS.getStatus())); |
| | | if (!hasUnchecked) { |
| | | log.info("[updateProductSalesLineWhenOqcFinish][éå®åºåºå({}) ææ OQC è¡æ£éªå®æï¼æµè½¬å°å¾
æ£è´§]", salesId); |
| | | productSalesService.confirmProductSales(salesId); |
| | |
| | | boolean needOqc = CollectionUtils.anyMatch(lines, |
| | | line -> Boolean.TRUE.equals(line.getOqcCheckFlag())); |
| | | if (needOqc) { |
| | | // 为éè¦ OQC æ£éªä¸å°æªå建æ£éªåçæç»å建 OQC æ£éªå |
| | | List<MesWmProductSalesLineDO> oqcLines = CollectionUtils.filterList(lines, |
| | | line -> Boolean.TRUE.equals(line.getOqcCheckFlag()) && line.getOqcId() == null); |
| | | for (MesWmProductSalesLineDO line : oqcLines) { |
| | | // ç´æ¥è°ç¨ï¼è®©å¼å¸¸æåºï¼ä¿è¯æ°æ®ä¸è´æ§ |
| | | Long oqcId = oqcService.createOqcFromProductSales( |
| | | sales.getId(), line, sales.getCode(), sales.getClientId()); |
| | | // æ´æ°åºåºæç»ç oqcId |
| | | productSalesLineMapper.updateById(new MesWmProductSalesLineDO() |
| | | .setId(line.getId()) |
| | | .setOqcId(oqcId)); |
| | | } |
| | | |
| | | // æ£éªåç±è´¨æ£äººåå
è¡å½å
¥ï¼å¾
æ£æç»éè¿çå·å
³èå·²å®æçæ£éªåã |
| | | // æ¹éåå§å OQC è¡çè´¨éç¶æä¸º"å¾
æ£éª" |
| | | List<Long> oqcLineIds = convertList( |
| | | CollectionUtils.filterList(lines, line -> Boolean.TRUE.equals(line.getOqcCheckFlag())), |
| | |
| | | import cn.iocoder.yudao.module.mes.service.pro.route.MesProRouteProductService; |
| | | import cn.iocoder.yudao.module.mes.service.pro.task.MesProTaskService; |
| | | import cn.iocoder.yudao.module.mes.service.pro.workorder.MesProWorkOrderService; |
| | | import cn.iocoder.yudao.module.mes.service.qc.MesQcCompletionHelper; |
| | | import cn.iocoder.yudao.module.mes.service.qc.defectrecord.MesQcDefectRecordService; |
| | | import cn.iocoder.yudao.module.mes.service.qc.indicatorresult.MesQcIndicatorResultService; |
| | | import cn.iocoder.yudao.module.mes.service.qc.template.MesQcTemplateItemService; |
| | | import cn.iocoder.yudao.module.mes.service.wm.productproduce.MesWmProductProduceLineService; |
| | | import cn.iocoder.yudao.module.system.api.user.AdminUserApi; |
| | | import jakarta.annotation.Resource; |
| | | import org.junit.jupiter.api.BeforeEach; |
| | | import org.junit.jupiter.api.Test; |
| | | import org.springframework.context.annotation.Import; |
| | | import org.springframework.test.context.bean.override.mockito.MockitoBean; |
| | |
| | | import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; |
| | | import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*; |
| | | import static org.junit.jupiter.api.Assertions.*; |
| | | import static org.mockito.ArgumentMatchers.*; |
| | | import static org.mockito.Mockito.*; |
| | | |
| | | /** |
| | |
| | | private MesQcIndicatorResultService indicatorResultService; |
| | | @MockitoBean |
| | | private MesWmProductProduceLineService productProduceLineService; |
| | | @MockitoBean |
| | | private MesQcCompletionHelper completionHelper; |
| | | |
| | | @BeforeEach |
| | | void stubCompletionHelper() { |
| | | when(completionHelper.validateAndGetResult(anyString(), anyLong(), any(), any(), any())).thenReturn(1); |
| | | } |
| | | |
| | | @Test |
| | | public void testFinishIpqc_writeBack_feedback() { |
| | |
| | | } |
| | | |
| | | @Test |
| | | public void testFinishIpqc_checkResultEmpty() { |
| | | // å夿°æ®ï¼checkResult 为空ï¼åºè¯¥æ¥é |
| | | public void testFinishIpqc_checkResultAutoComputed() { |
| | | // å夿°æ®ï¼æ£æµç»è®ºä¸åç±ç¨æ·å¡«åï¼å®ææ¶æåæ ¼/ä¸åæ ¼æ°éèªå¨å¤å® |
| | | MesQcIpqcDO ipqc = randomPojo(MesQcIpqcDO.class, o -> { |
| | | o.setStatus(MesQcStatusEnum.DRAFT.getStatus()); |
| | | o.setCheckResult(null); // æ£æµç»è®ºä¸ºç©º |
| | | o.setCheckResult(null); |
| | | o.setSourceDocType(null); |
| | | o.setSourceDocId(null); |
| | | o.setSourceLineId(null); |
| | | o.setCheckQuantity(BigDecimal.valueOf(100)); |
| | | o.setQualifiedQuantity(BigDecimal.valueOf(100)); |
| | | o.setUnqualifiedQuantity(BigDecimal.ZERO); |
| | | }); |
| | | ipqcMapper.insert(ipqc); |
| | | |
| | | // è°ç¨ï¼åºè¯¥æå¼å¸¸ï¼æ£æµç»è®ºå¿
å¡«ï¼ |
| | | assertThrows(Exception.class, () -> ipqcService.finishIpqc(ipqc.getId())); |
| | | // è°ç¨ |
| | | ipqcService.finishIpqc(ipqc.getId()); |
| | | |
| | | // æè¨ï¼æ£æµç»è®ºç±ç³»ç»å¤å®å¹¶åå |
| | | MesQcIpqcDO updatedIpqc = ipqcMapper.selectById(ipqc.getId()); |
| | | assertEquals(MesQcStatusEnum.FINISHED.getStatus(), updatedIpqc.getStatus()); |
| | | assertEquals(1, updatedIpqc.getCheckResult()); |
| | | } |
| | | |
| | | @Test |
| | |
| | | import cn.iocoder.yudao.module.mes.enums.MesBizTypeConstants; |
| | | import cn.iocoder.yudao.module.mes.enums.qc.MesQcStatusEnum; |
| | | import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService; |
| | | import cn.iocoder.yudao.module.mdm.api.item.MdmItemApi; |
| | | import cn.iocoder.yudao.module.mes.service.qc.MesQcCompletionHelper; |
| | | import cn.iocoder.yudao.module.mes.service.qc.defectrecord.MesQcDefectRecordService; |
| | | import cn.iocoder.yudao.module.mes.service.qc.imports.MesQcImportHelper; |
| | | import cn.iocoder.yudao.module.mes.service.qc.ncr.MesQcNcrService; |
| | | import cn.iocoder.yudao.module.srm.api.supplier.SrmSupplierApi; |
| | | import cn.iocoder.yudao.module.mes.service.qc.template.MesQcTemplateItemService; |
| | | import cn.iocoder.yudao.module.mes.service.wm.arrivalnotice.MesWmArrivalNoticeService; |
| | | import cn.iocoder.yudao.module.mes.service.wm.outsourcereceipt.MesWmOutsourceReceiptService; |
| | | import cn.iocoder.yudao.module.mes.service.qc.indicatorresult.MesQcIndicatorResultService; |
| | | import cn.iocoder.yudao.module.system.api.user.AdminUserApi; |
| | | import org.junit.jupiter.api.BeforeEach; |
| | | import org.junit.jupiter.api.Test; |
| | | import org.springframework.context.annotation.Import; |
| | | import org.springframework.test.context.bean.override.mockito.MockitoBean; |
| | |
| | | import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId; |
| | | import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; |
| | | import static org.junit.jupiter.api.Assertions.*; |
| | | import static org.mockito.ArgumentMatchers.*; |
| | | import static org.mockito.Mockito.*; |
| | | |
| | | /** |
| | |
| | | private AdminUserApi adminUserApi; |
| | | @MockitoBean |
| | | private MesQcIndicatorResultService indicatorResultService; |
| | | @MockitoBean |
| | | private MesQcCompletionHelper completionHelper; |
| | | @MockitoBean |
| | | private SrmSupplierApi srmSupplierApi; |
| | | @MockitoBean |
| | | private MdmItemApi mdmItemApi; |
| | | @MockitoBean |
| | | private MesQcNcrService ncrService; |
| | | @MockitoBean |
| | | private MesQcImportHelper qcImportHelper; |
| | | |
| | | @BeforeEach |
| | | void stubCompletionHelper() { |
| | | when(completionHelper.validateAndGetResult(anyString(), anyLong(), any(), any(), any())).thenReturn(1); |
| | | } |
| | | |
| | | @Test |
| | | public void testFinishIqc_writeBack_arrivalNotice() { |
| | |
| | | } |
| | | |
| | | @Test |
| | | public void testFinishIqc_checkResultEmpty() { |
| | | // å夿°æ®ï¼checkResult 为空ï¼åºè¯¥æ¥é |
| | | public void testFinishIqc_checkResultAutoComputed() { |
| | | // å夿°æ®ï¼æ£æµç»è®ºä¸åç±ç¨æ·å¡«åï¼å®ææ¶æåæ ¼/ä¸åæ ¼æ°éèªå¨å¤å® |
| | | MesQcIqcDO iqc = randomPojo(MesQcIqcDO.class, o -> { |
| | | o.setStatus(MesQcStatusEnum.DRAFT.getStatus()); |
| | | o.setCheckResult(null); // æ£æµç»è®ºä¸ºç©º |
| | | o.setCheckResult(null); |
| | | o.setSourceDocType(null); |
| | | o.setCheckQuantity(BigDecimal.valueOf(100)); |
| | | o.setQualifiedQuantity(BigDecimal.valueOf(100)); |
| | | o.setUnqualifiedQuantity(BigDecimal.ZERO); |
| | | }); |
| | | iqcMapper.insert(iqc); |
| | | |
| | | // è°ç¨ï¼åºè¯¥æå¼å¸¸ï¼æ£æµç»è®ºå¿
å¡«ï¼ |
| | | assertThrows(Exception.class, () -> iqcService.finishIqc(iqc.getId())); |
| | | // è°ç¨ |
| | | iqcService.finishIqc(iqc.getId()); |
| | | |
| | | // æè¨ï¼æ£æµç»è®ºç±ç³»ç»å¤å®å¹¶åå |
| | | MesQcIqcDO updatedIqc = iqcMapper.selectById(iqc.getId()); |
| | | assertEquals(MesQcStatusEnum.FINISHED.getStatus(), updatedIqc.getStatus()); |
| | | assertEquals(1, updatedIqc.getCheckResult()); |
| | | } |
| | | |
| | | @Test |
| | |
| | | import cn.iocoder.yudao.module.erp.api.sale.ErpSaleOrderApi; |
| | | import cn.iocoder.yudao.module.erp.api.sale.dto.ErpSaleOrderItemRespDTO; |
| | | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.qc.template.MesQcTemplateItemDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.productsales.MesWmProductSalesDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.productsales.MesWmProductSalesLineDO; |
| | | import cn.iocoder.yudao.module.mes.dal.mysql.qc.oqc.MesQcOqcMapper; |
| | | import cn.iocoder.yudao.module.mes.service.qc.template.MesQcTemplateItemService; |
| | | import cn.iocoder.yudao.module.mes.service.wm.productsales.MesWmProductSalesService; |
| | | import org.junit.jupiter.api.Test; |
| | | import org.junit.jupiter.api.extension.ExtendWith; |
| | |
| | | class MesQcOqcAutoCreateTest { |
| | | @InjectMocks private MesQcOqcServiceImpl service; |
| | | @Mock private MesQcOqcMapper mapper; |
| | | @Mock private MesQcTemplateItemService templates; |
| | | @Mock private MesQcOqcLineService lines; |
| | | @Mock private MesWmProductSalesService sales; |
| | | @Mock private ErpSaleOrderApi saleOrderApi; |
| | |
| | | @Test |
| | | void generatedInspectionUsesHistoricalShipmentDateAndPreservesPendingQuantities() { |
| | | LocalDateTime date = LocalDateTime.of(2026, 9, 23, 15, 30); |
| | | when(templates.getRequiredTemplateByItemIdAndType(10L, 3)) |
| | | .thenReturn(new MesQcTemplateItemDO().setTemplateId(20L)); |
| | | when(sales.getProductSales(30L)).thenReturn(new MesWmProductSalesDO().setSalesDate(date)); |
| | | MesWmProductSalesLineDO line = new MesWmProductSalesLineDO().setId(40L) |
| | | .setItemId(10L).setSaleOrderItemId(60L).setQuantity(BigDecimal.valueOf(200)).setBatchCode("B001"); |
| | |
| | | |
| | | @Test |
| | | void historicalShipmentWithoutSaleItemDoesNotGuessReel() { |
| | | when(templates.getRequiredTemplateByItemIdAndType(10L, 3)) |
| | | .thenReturn(new MesQcTemplateItemDO().setTemplateId(20L)); |
| | | MesWmProductSalesLineDO line = new MesWmProductSalesLineDO().setId(40L) |
| | | .setItemId(10L).setQuantity(BigDecimal.ONE); |
| | | |
| | |
| | | import cn.iocoder.yudao.module.mes.enums.MesBizTypeConstants; |
| | | import cn.iocoder.yudao.module.mes.enums.qc.MesQcStatusEnum; |
| | | import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService; |
| | | import cn.iocoder.yudao.module.mes.service.qc.MesQcCompletionHelper; |
| | | import cn.iocoder.yudao.module.mes.service.qc.defectrecord.MesQcDefectRecordService; |
| | | import cn.iocoder.yudao.module.mes.service.qc.template.MesQcTemplateItemService; |
| | | import cn.iocoder.yudao.module.mes.service.wm.productsales.MesWmProductSalesLineService; |
| | |
| | | import cn.iocoder.yudao.module.mes.service.qc.indicatorresult.MesQcIndicatorResultService; |
| | | import cn.iocoder.yudao.module.system.api.user.AdminUserApi; |
| | | import jakarta.annotation.Resource; |
| | | import org.junit.jupiter.api.BeforeEach; |
| | | import org.junit.jupiter.api.Test; |
| | | import org.springframework.context.annotation.Import; |
| | | import org.springframework.test.context.bean.override.mockito.MockitoBean; |
| | |
| | | import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; |
| | | import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*; |
| | | import static org.junit.jupiter.api.Assertions.*; |
| | | import static org.mockito.ArgumentMatchers.eq; |
| | | import static org.mockito.ArgumentMatchers.*; |
| | | import static org.mockito.Mockito.*; |
| | | |
| | | /** |
| | |
| | | private AdminUserApi adminUserApi; |
| | | @MockitoBean |
| | | private MesQcIndicatorResultService indicatorResultService; |
| | | @MockitoBean |
| | | private MesQcCompletionHelper completionHelper; |
| | | |
| | | @BeforeEach |
| | | void stubCompletionHelper() { |
| | | when(completionHelper.validateAndGetResult(anyString(), anyLong(), any(), any(), any())).thenReturn(1); |
| | | } |
| | | |
| | | @Test |
| | | public void testFinishOqc_writeBack_productSales() { |
| | |
| | | } |
| | | |
| | | @Test |
| | | public void testFinishOqc_checkResultEmpty() { |
| | | // å夿°æ®ï¼checkResult 为空ï¼åºè¯¥æ¥é |
| | | public void testFinishOqc_checkResultAutoComputed() { |
| | | // å夿°æ®ï¼æ£æµç»è®ºä¸åç±ç¨æ·å¡«åï¼å®ææ¶æåæ ¼/ä¸åæ ¼æ°éèªå¨å¤å® |
| | | MesQcOqcDO oqc = randomPojo(MesQcOqcDO.class, o -> { |
| | | o.setStatus(MesQcStatusEnum.DRAFT.getStatus()); |
| | | o.setCheckResult(null); // æ£æµç»è®ºä¸ºç©º |
| | | o.setCheckResult(null); |
| | | o.setSourceDocType(null); |
| | | o.setCheckQuantity(java.math.BigDecimal.valueOf(100)); |
| | | o.setQualifiedQuantity(java.math.BigDecimal.valueOf(100)); |
| | | o.setUnqualifiedQuantity(java.math.BigDecimal.ZERO); |
| | | }); |
| | | oqcMapper.insert(oqc); |
| | | |
| | | // è°ç¨ï¼åºè¯¥æå¼å¸¸ï¼æ£æµç»è®ºå¿
å¡«ï¼ |
| | | assertServiceException(() -> oqcService.finishOqc(oqc.getId()), QC_OQC_CHECK_RESULT_EMPTY); |
| | | // è°ç¨ |
| | | oqcService.finishOqc(oqc.getId()); |
| | | |
| | | // æè¨ï¼æ£æµç»è®ºç±ç³»ç»å¤å®å¹¶åå |
| | | MesQcOqcDO updatedOqc = oqcMapper.selectById(oqc.getId()); |
| | | assertEquals(MesQcStatusEnum.FINISHED.getStatus(), updatedOqc.getStatus()); |
| | | assertEquals(1, updatedOqc.getCheckResult()); |
| | | } |
| | | |
| | | @Test |
| | |
| | | import cn.iocoder.yudao.module.mes.enums.MesBizTypeConstants; |
| | | import cn.iocoder.yudao.module.mes.enums.qc.MesQcStatusEnum; |
| | | import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService; |
| | | import cn.iocoder.yudao.module.mes.service.qc.MesQcCompletionHelper; |
| | | import cn.iocoder.yudao.module.mes.service.qc.defectrecord.MesQcDefectRecordService; |
| | | import cn.iocoder.yudao.module.mes.service.qc.template.MesQcTemplateItemService; |
| | | import cn.iocoder.yudao.module.mes.service.wm.returnissue.MesWmReturnIssueLineService; |
| | |
| | | import cn.iocoder.yudao.module.mes.service.qc.ncr.MesQcNcrService; |
| | | import cn.iocoder.yudao.module.system.api.user.AdminUserApi; |
| | | import jakarta.annotation.Resource; |
| | | import org.junit.jupiter.api.BeforeEach; |
| | | import org.junit.jupiter.api.Test; |
| | | import org.springframework.context.annotation.Import; |
| | | import org.springframework.test.context.bean.override.mockito.MockitoBean; |
| | |
| | | import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.QC_RQC_NOT_PREPARE; |
| | | import static org.junit.jupiter.api.Assertions.assertEquals; |
| | | import static org.mockito.ArgumentMatchers.*; |
| | | import static org.mockito.Mockito.never; |
| | | import static org.mockito.Mockito.verify; |
| | | import static org.mockito.Mockito.*; |
| | | |
| | | /** |
| | | * {@link MesQcRqcServiceImpl} çåå
æµè¯ç±» |
| | |
| | | private MesQcIndicatorResultService indicatorResultService; |
| | | @MockitoBean |
| | | private MesQcNcrService ncrService; |
| | | @MockitoBean |
| | | private MesQcCompletionHelper completionHelper; |
| | | |
| | | @BeforeEach |
| | | void stubCompletionHelper() { |
| | | when(completionHelper.validateAndGetResult(anyString(), anyLong(), any(), any(), any())).thenReturn(1); |
| | | } |
| | | |
| | | @Test |
| | | public void testFinishRqc_successWithReturnIssue() { |
| | |
| | | } |
| | | |
| | | @Test |
| | | void enablingInspectionRetainsSalesItemForOqc() { |
| | | void enablingInspectionKeepsSalesItemAndDefersOqcToLink() { |
| | | var req = request(); |
| | | req.setId(6L); |
| | | req.setOqcCheckFlag(true); |
| | | when(mapper.selectById(6L)).thenReturn(MesWmProductSalesLineDO.builder() |
| | | .id(6L).salesId(1L).oqcCheckFlag(false).build()); |
| | | when(salesService.getProductSales(1L)).thenReturn(MesWmProductSalesDO.builder().id(1L).build()); |
| | | when(oqcService.createOqcFromProductSales(eq(1L), any(), any(), any())).thenReturn(7L); |
| | | service.updateProductSalesLine(req); |
| | | var line = ArgumentCaptor.forClass(MesWmProductSalesLineDO.class); |
| | | verify(oqcService).createOqcFromProductSales(eq(1L), line.capture(), any(), any()); |
| | | verify(mapper).updateById(line.capture()); |
| | | assertEquals(5L, line.getValue().getSaleOrderItemId()); |
| | | // æ£éªåç±è´¨æ£äººåå½å
¥åéè¿çå·å
³èï¼è¡ä¿åæ¶ä¸åèªå¨å建 OQCã |
| | | verifyNoInteractions(oqcService); |
| | | } |
| | | } |
| | |
| | | import org.springframework.context.annotation.Import; |
| | | import org.springframework.test.context.bean.override.mockito.MockitoBean; |
| | | |
| | | import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService; |
| | | import cn.iocoder.yudao.module.erp.api.sale.ErpSaleOrderApi; |
| | | import cn.iocoder.yudao.module.mes.service.mdm.MesMdmItemService; |
| | | import cn.iocoder.yudao.module.mes.service.qc.oqc.MesQcOqcService; |
| | | import cn.iocoder.yudao.module.mes.service.wm.batch.MesWmBatchService; |
| | | import cn.iocoder.yudao.module.mes.service.wm.salesnotice.MesWmSalesNoticeLineService; |
| | | |
| | | import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId; |
| | | import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; |
| | |
| | | private MesWmProductSalesDetailService productSalesDetailService; |
| | | |
| | | @MockitoBean |
| | | private MesMdItemService itemService; |
| | | private MesMdmItemService mdmItemService; |
| | | @MockitoBean |
| | | private MesWmBatchService batchService; |
| | | @MockitoBean |
| | | private MesWmSalesNoticeLineService salesNoticeLineService; |
| | | @MockitoBean |
| | | private MesQcOqcService oqcService; |
| | | @MockitoBean |
| | | private ErpSaleOrderApi saleOrderApi; |
| | | |
| | | @Test |
| | | public void testUpdateProductSalesLineWhenOqcFinish_pass() { |
| | |
| | | MesWmProductSalesLineDO updateLine = productSalesLineMapper.selectById(lineDO.getId()); |
| | | assertEquals(oqcId, updateLine.getOqcId()); |
| | | assertEquals(MesWmQualityStatusEnum.PASS.getStatus(), updateLine.getQualityStatus()); |
| | | // æè¨ï¼å
¨é¨éæ£è¡åæ ¼ â åºåºåèªå¨æµè½¬å¾
æ£è´§ |
| | | verify(productSalesService).confirmProductSales(lineDO.getSalesId()); |
| | | } |
| | | |
| | | @Test |
| | | public void testUpdateProductSalesLineWhenOqcFinish_fail() { |
| | | // åå¤åæ° |
| | | // åå¤åæ°ï¼2 è¡¨ç¤ºæ ¡éªä¸éè¿ |
| | | Long oqcId = randomLongId(); |
| | | Integer checkResult = MesQcCheckResultEnum.QUALIFIED.getType(); |
| | | Integer checkResult = 2; |
| | | |
| | | // mock æ°æ® |
| | | MesWmProductSalesLineDO lineDO = randomPojo(MesWmProductSalesLineDO.class, o -> { |
| | |
| | | MesWmProductSalesLineDO updateLine = productSalesLineMapper.selectById(lineDO.getId()); |
| | | assertEquals(oqcId, updateLine.getOqcId()); |
| | | assertEquals(MesWmQualityStatusEnum.FAIL.getStatus(), updateLine.getQualityStatus()); |
| | | // æè¨ï¼åå¨ä¸åæ ¼è¡æ¶ä¿æå¾
æ£æµï¼ä¸èªå¨åæ¶æ´å¼ åºåºå |
| | | verify(productSalesService, never()).cancelProductSales(anyLong()); |
| | | verify(productSalesService, never()).confirmProductSales(anyLong()); |
| | | } |
| | | |
| | | @Test |
| | | public void testUpdateProductSalesLineWhenOqcFinish_cancelWhenNg() { |
| | | public void testUpdateProductSalesLineWhenOqcFinish_noCancelWhenNg() { |
| | | // å夿°æ®ï¼åä¸åºåºåä¸ 2 è¡ï¼ç¬¬ 1 è¡å·²åæ ¼ï¼ç¬¬ 2 è¡å³å°åæ´ä¸ºä¸åæ ¼ |
| | | Long salesId = randomLongId(); |
| | | MesWmProductSalesLineDO line1 = randomPojo(MesWmProductSalesLineDO.class, o -> { |
| | |
| | | |
| | | // è°ç¨ï¼ç¬¬ 2 è¡è´¨æ£ä¸åæ ¼ |
| | | productSalesLineService.updateProductSalesLineWhenOqcFinish( |
| | | line2.getId(), randomLongId(), MesQcCheckResultEnum.QUALIFIED.getType()); |
| | | line2.getId(), randomLongId(), 2); |
| | | |
| | | // æè¨ï¼åºè¯¥è°ç¨ cancelProductSales |
| | | verify(productSalesService).cancelProductSales(eq(salesId)); |
| | | // æè¨ï¼ä¸åæ ¼è¡çå¾
åç»å¤ç½®ï¼ä¸è½èªå¨åæ¶åºåºå |
| | | verify(productSalesService, never()).cancelProductSales(anyLong()); |
| | | verify(productSalesService, never()).confirmProductSales(anyLong()); |
| | | } |
| | | |
| | | @Test |
| | | public void testUpdateProductSalesLineWhenOqcFinish_noCancelWhenAllPass() { |
| | | public void testUpdateProductSalesLineWhenOqcFinish_confirmWhenAllPass() { |
| | | // å夿°æ®ï¼åä¸åºåºåä¸ 2 è¡ï¼ç¬¬ 1 è¡å·²åæ ¼ï¼ç¬¬ 2 è¡å³å°åæ´ä¸ºåæ ¼ |
| | | Long salesId = randomLongId(); |
| | | MesWmProductSalesLineDO line1 = randomPojo(MesWmProductSalesLineDO.class, o -> { |
| | |
| | | productSalesLineService.updateProductSalesLineWhenOqcFinish( |
| | | line2.getId(), randomLongId(), MesQcCheckResultEnum.QUALIFIED.getType()); |
| | | |
| | | // æè¨ï¼ä¸åºè¯¥è°ç¨ cancelProductSales |
| | | // æè¨ï¼å
¨é¨éæ£è¡åæ ¼ â æµè½¬å¾
æ£è´§ï¼ä¸åæ¶åºåºå |
| | | verify(productSalesService).confirmProductSales(eq(salesId)); |
| | | verify(productSalesService, never()).cancelProductSales(anyLong()); |
| | | } |
| | | |
| | |
| | | }); |
| | | productSalesLineMapper.insert(line2); |
| | | |
| | | // è°ç¨ï¼ç¬¬ 2 è¡è´¨æ£ä¸åæ ¼ |
| | | // è°ç¨ï¼ç¬¬ 2 è¡è´¨æ£åæ ¼ |
| | | productSalesLineService.updateProductSalesLineWhenOqcFinish( |
| | | line2.getId(), randomLongId(), MesQcCheckResultEnum.QUALIFIED.getType()); |
| | | |
| | | // æè¨ï¼ç¬¬ 2 è¡ä¸åæ ¼ â åºè¯¥åæ¶åºåºå |
| | | verify(productSalesService).cancelProductSales(eq(salesId)); |
| | | // æè¨ï¼æªå¾éåºè´§æ£éªçè¡ä¸åä¸å¾
æ£å¤æ â å
¨é¨éæ£è¡åæ ¼åæµè½¬å¾
æ£è´§ |
| | | verify(productSalesService).confirmProductSales(eq(salesId)); |
| | | verify(productSalesService, never()).cancelProductSales(anyLong()); |
| | | } |
| | | |
| | | } |
| | |
| | | CREATE TABLE IF NOT EXISTS "mes_wm_product_sales_line" ( |
| | | "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, |
| | | "sales_id" bigint NOT NULL, |
| | | "sale_order_item_id" bigint DEFAULT NULL, |
| | | "notice_line_id" bigint DEFAULT NULL, |
| | | "item_id" bigint NOT NULL, |
| | | "quantity" decimal(20,6) NOT NULL, |
| | |
| | | |
| | | void deleteAttachmentsByRecord(String recordType, Long recordId); |
| | | |
| | | /** ä»
ç§»é¤æå®ä¸å¡å
³èï¼ä¸å é¤å
±äº«æä»¶ã */ |
| | | void removeReference(String application, String recordType, Long recordId, Long blobId); |
| | | |
| | | } |
| | |
| | | @Resource |
| | | private SystemStorageAttachmentService systemStorageAttachmentService; |
| | | |
| | | @Resource |
| | | private cn.iocoder.yudao.module.system.dal.mysql.storage.SystemStorageAttachmentMapper attachmentMapper; |
| | | |
| | | @Override |
| | | @org.springframework.transaction.annotation.Transactional(rollbackFor = Exception.class) |
| | | public void removeReference(String application, String recordType, Long recordId, Long blobId) { |
| | | attachmentMapper.delete(new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<cn.iocoder.yudao.module.system.dal.dataobject.storage.SystemStorageAttachmentDO>() |
| | | .eq(cn.iocoder.yudao.module.system.dal.dataobject.storage.SystemStorageAttachmentDO::getApplication, application) |
| | | .eq(cn.iocoder.yudao.module.system.dal.dataobject.storage.SystemStorageAttachmentDO::getRecordType, recordType) |
| | | .eq(cn.iocoder.yudao.module.system.dal.dataobject.storage.SystemStorageAttachmentDO::getRecordId, recordId) |
| | | .eq(cn.iocoder.yudao.module.system.dal.dataobject.storage.SystemStorageAttachmentDO::getStorageBlobId, blobId)); |
| | | } |
| | | |
| | | @Override |
| | | public void bindAttachments(String application, String recordType, Long recordId, List<Long> blobIds) { |
| | | if (blobIds == null || blobIds.isEmpty()) { |
| | |
| | | MES_PD_DOCUMENT("mes_pd_document", "MES è®¾è®¡èµæ"), |
| | | |
| | | MDM_ITEM_TECHNICAL_FILE("mdm_item_technical_file", "MDM ç©æææ¯æä»¶"), |
| | | MES_WORK_ORDER_TECHNICAL_FILE("mes_work_order_technical_file", "çäº§å·¥åææ¯æä»¶å¿«ç
§"), |
| | | MES_QC_IQC_ATTACHMENT("mes_qc_iqc_attachment", "æ¥æè´¨æ£éä»¶"), |
| | | MES_QC_IPQC_ATTACHMENT("mes_qc_ipqc_attachment", "è¿ç¨è´¨æ£éä»¶"), |
| | | MES_QC_OQC_ATTACHMENT("mes_qc_oqc_attachment", "åºè´§è´¨æ£éä»¶"), |
| | | MES_QC_RQC_ATTACHMENT("mes_qc_rqc_attachment", "éè´§è´¨æ£éä»¶"), |
| | | |
| | | // ===== SRM ===== |
| | | SRM_SUPPLIER_CERTIFICATE("srm_supplier_certificate", "SRM ä¾åºåèµè´¨è¯ä¹¦"), |
| | |
| | | if (CollUtil.isEmpty(storageBlobIds)) { |
| | | return; |
| | | } |
| | | // ç产工åä¾èµåå§æä»¶åæ åå²çæ¬ï¼ä¸å
许éè¿å
¶ä»éä»¶å
¥å£å é¤è¿äºå
±äº«æä»¶ã |
| | | Long snapshotReferences = storageAttachmentMapper.selectCount( |
| | | new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<SystemStorageAttachmentDO>() |
| | | .eq(SystemStorageAttachmentDO::getRecordType, "mes_work_order_technical_file") |
| | | .in(SystemStorageAttachmentDO::getStorageBlobId, storageBlobIds)); |
| | | if (snapshotReferences != null && snapshotReferences > 0) { |
| | | throw new cn.iocoder.yudao.framework.common.exception.ServiceException(400, "ææ¯æä»¶å·²è¢«ç产工åçåï¼ä¸è½å é¤"); |
| | | } |
| | | // åæ¶å é¤ç£çæä»¶ |
| | | List<SystemStorageBlobDO> blobs = storageBlobMapper.selectByIds(storageBlobIds); |
| | | for (SystemStorageBlobDO blob : blobs) { |
| | |
| | | storage: # æä»¶ä¸ä¼ é
ç½® |
| | | path: D:/uploads # æä»¶å卿 ¹ç®å½ï¼æå®é
æå¡å¨è·¯å¾é
ç½®ï¼ |
| | | url-prefix: /admin-api/system/storage-blob # URLè·¯å¾åç¼ |
| | | domain: http://192.168.1.6:48080 # åååç¼ï¼æå®é
ååé
ç½®ï¼ |
| | | domain: http://192.168.0.10:48080 # åååç¼ï¼æå®é
ååé
ç½®ï¼ |
| | | expired: 120 # tokenè¿ææ¶é´ï¼åéï¼ |
| | | use-limit: 10 # tokenä½¿ç¨æ¬¡æ°ä¸é |
| | | jwt-secret: abcdefghijklmnopqrstuvwxyz0123456789ABCDEFG # JWTå¯é¥ï¼è³å°32åç¬¦ï¼ |