feat: 打通销售采购财务闭环并完成累计业务优化
财务与销售采购:
- 来票必须同时绑定采购订单与 MES 采购入库单,按两层剩余额度校验
- 开票申请绑定销售订单与 MES 销售出库单,审批后录入发票(发票号/日期/附件)
- 录入发票时填写合同款/预付款/到货款/验收款/质保金收款节点,落库回款计划
- 回款核销明细支持拆分到销售订单/销售出库/开票,审核后回写回款计划
- 新增客户应收对账、已发货未开票、未核销应收账龄、月度开票回款趋势
- 记账凭证增加来源单据关联(sourceType/sourceId/sourceNo)
累计改动:
- 售后工单流转与仓储退货、离职交接流程、通知公告附件记录类型
- Excel 必填表头标记、到货通知合同号、MES 入库/出库金额与 API
- 同步合并初始化 SQL、前端联调文档与业务可视化文档
Co-Authored-By: Claude Code <noreply@anthropic.com>
| | |
| | | |------|---------|------| |
| | | | å®åå·¥åå表 | `/aftersales/ticket` | å·¥åå表ãæç´¢ãç¶æçé | |
| | | | å®åå·¥å详æ
/ç¼è¾ | `/aftersales/ticket/detail?id=:id` | æ°å»º/ç¼è¾å·¥åãæ¥ç详æ
| |
| | | | éè´§ç³è¯·å表 | `/aftersales/return` | éè´§ç³è¯·å表ãæç´¢ | |
| | | | éè´§ç³è¯·è¯¦æ
| `/aftersales/return/detail?id=:id` | é货详æ
ãå®¡æ ¸æä½ | |
| | | |
| | | > éè´§ç³è¯·é¡µé¢å·²ä¸çº¿ï¼éè´§ç»ä¸ç±ä»å¨ç©æµæ¨¡ååèµ·ï¼å®åå·¥ååªä¿çéè´§ç¶æèå¨ã |
| | | |
| | | ## ä¸å¡æµç¨ä¸æ°æ®å¸¦å
¥ |
| | | |
| | | ### æµç¨ä¸ï¼ä¸è¬é®é¢å·¥å |
| | | |
| | | ``` |
| | | å建工å â åé
å¤ç人 â é®é¢å¤å®ï¼ä¸è¬é®é¢ï¼â å¤ç â å®ç» â å
³é |
| | | å建工åï¼å¿
éå¤ç人ï¼ç´æ¥è¿å
¥å¤çä¸ï¼â é®é¢å¤å®ï¼ä¸è¬é®é¢ï¼â å¤ç â å®ç» â å
³é |
| | | ``` |
| | | |
| | | ### æµç¨äºï¼éè´§é®é¢å·¥å |
| | | |
| | | ``` |
| | | å建工å â åé
å¤ç人 â é®é¢å¤å®ï¼éè´§é®é¢ï¼ |
| | | â å建éè´§ç³è¯· â éå®å®¡æ ¸ â [MESéè´§æµç¨èªå¨æ§è¡] â 鿬¾/æ¢è´§å®æ â å®ç» â å
³é |
| | | å建工åï¼å¿
éå¤ç人ï¼ç´æ¥è¿å
¥å¤çä¸ï¼â é®é¢å¤å®ï¼éè´§é®é¢ï¼ |
| | | â ä»å¨ç©æµåèµ·éå®éè´§ â éå®å®¡æ ¸ â [MESéè´§æµç¨èªå¨æ§è¡] â 鿬¾/æ¢è´§å®æ â å®ç» â å
³é |
| | | ``` |
| | | |
| | | ### æµç¨ä¸ï¼ç»´ä¿®é®é¢å·¥å |
| | | |
| | | ``` |
| | | å建工å â åé
å¤ç人 â é®é¢å¤å®ï¼ç»´ä¿®é®é¢ï¼ |
| | | å建工åï¼å¿
éå¤ç人ï¼ç´æ¥è¿å
¥å¤çä¸ï¼â é®é¢å¤å®ï¼ç»´ä¿®é®é¢ï¼ |
| | | â åå»ºç»´ä¿®è®°å½ â ç»´ä¿®å®æ â å®ç» â å
³é |
| | | ``` |
| | | |
| | |
| | | | æ¹æ³ | è·¯å¾ | æé | 说æ | |
| | | |------|------|------|------| |
| | | | POST | `/aftersales/ticket/create` | `aftersales:ticket:create` | å建工å | |
| | | | PUT | `/aftersales/ticket/update` | `aftersales:ticket:update` | æ´æ°å·¥åï¼ä»
èç¨¿ç¶æå¯æ´æ°ï¼ | |
| | | | PUT | `/aftersales/ticket/update` | `aftersales:ticket:update` | æ´æ°å·¥åï¼è稿/å¤çä¸ç¶æå¯æ´æ°ï¼ | |
| | | | DELETE | `/aftersales/ticket/delete` | `aftersales:ticket:delete` | å é¤å·¥åï¼ä»
è稿/å·²åæ¶ç¶æå¯å é¤ï¼ | |
| | | | GET | `/aftersales/ticket/get` | `aftersales:ticket:query` | è·åå·¥å详æ
| |
| | | | GET | `/aftersales/ticket/page` | `aftersales:ticket:query` | å页æ¥è¯¢å·¥å | |
| | | | POST | `/aftersales/ticket/assign` | `aftersales:ticket:update` | åé
å¤ç人 | |
| | | | POST | `/aftersales/ticket/classify` | `aftersales:ticket:update` | é®é¢å¤å® | |
| | | | PUT | `/aftersales/ticket/resolve` | `aftersales:ticket:update` | å®ç»å·¥å | |
| | | | PUT | `/aftersales/ticket/close` | `aftersales:ticket:update` | å
³éå·¥å | |
| | |
| | | |
| | | #### 1.2 æ´æ°å·¥å `PUT /aftersales/ticket/update` |
| | | |
| | | 请æ±åæ°ä¸å建ç¸åï¼é¢å¤éè¦ `id` åæ®µãä»
èç¨¿ç¶æå¯æ´æ°ã |
| | | 请æ±åæ°ä¸å建ç¸åï¼é¢å¤éè¦ `id` åæ®µãä»
è稿æå¤çä¸ç¶æå¯æ´æ°ã |
| | | |
| | | #### 1.3 å é¤å·¥å `DELETE /aftersales/ticket/delete` |
| | | |
| | |
| | | |
| | | **注æï¼** å页å表ååºä¸çæ¯æ¡è®°å½ç»æä¸è¯¦æ
æ¥å£ä¸è´ï¼å« `items` åå
³èåç§°åæ®µï¼ï¼ä½åè¡¨åºæ¯ä¸ `items` å¯ä¸ºç©ºã |
| | | |
| | | #### 1.6 åé
å¤ç人 `POST /aftersales/ticket/assign` |
| | | |
| | | | åæ° | ç±»å | å¿
å¡« | 说æ | |
| | | |------|------|------|------| |
| | | | id | Long | æ¯ | å·¥åç¼å·ï¼Query åæ°ï¼ | |
| | | | handlerUserId | Long | æ¯ | å¤çäººç¨æ·ç¼å·ï¼Query åæ°ï¼ | |
| | | |
| | | **ä¸å¡è§åï¼** ä»
è稿ãå¤çä¸ç¶æå¯åé
ãåé
åç¶æèªå¨å为"å¤çä¸"ã |
| | | |
| | | #### 1.7 é®é¢å¤å® `POST /aftersales/ticket/classify` |
| | | #### 1.6 é®é¢å¤å® `POST /aftersales/ticket/classify` |
| | | |
| | | | åæ° | ç±»å | å¿
å¡« | 说æ | |
| | | |------|------|------|------| |
| | |
| | | | issueCategory | String | å¦ | é®é¢åç±»ï¼å¦"å¤è§ç¼ºé·"ã"åè½æ
é"çï¼ | |
| | | | severityLevel | Integer | å¦ | 严éç¨åº¦ï¼0-轻微 1-ä¸è¬ 2-严é 3-è´å½ | |
| | | |
| | | **ä¸å¡è§åï¼** ä»
å¤çä¸ç¶æå¯å¤å®ãå¤å®ä¸ºéè´§é®é¢åï¼åºå¼å¯¼ç¨æ·å建éè´§ç³è¯·ã |
| | | **ä¸å¡è§åï¼** ä»
å¤çä¸ç¶æå¯å¤å®ãå¤å®ä¸ºéè´§é®é¢åï¼ç±ä»å¨ç©æµæ¨¡ååèµ·éå®éè´§ã |
| | | |
| | | #### 1.8 å®ç»å·¥å `PUT /aftersales/ticket/resolve` |
| | | |
| | |
| | | | å¼ | åç§° | 说æ | |
| | | |----|------|------| |
| | | | 0 | è稿 | å¯ç¼è¾ãå¯å é¤ãå¯åæ¶ | |
| | | | 10 | å¤çä¸ | å¯åé
ãå¯å¤å®ãå¯åæ¶ | |
| | | | 10 | å¤çä¸ | å¯ç¼è¾ãå¯å¤å®ãå¯å®ç»ãå¯åæ¶ | |
| | | | 30 | å¾
éè´§ | éè´§æµç¨è¿è¡ä¸ | |
| | | | 40 | å¾
鿬¾/æ¢è´§ | çå¾
鿬¾ææ¢è´§å®æ | |
| | | | 50 | å·²å®ç» | å¯å
³é | |
| | |
| | | | issueDescription | åºæ¬ä¿¡æ¯ | é®é¢æè¿° | |
| | | | severityLevel | åºæ¬ä¿¡æ¯ | 严éç¨åº¦ï¼å¤å®åæ¾ç¤ºï¼ | |
| | | | ownerUserId / ownerUserName | åºæ¬ä¿¡æ¯ | è´è´£äººï¼å建æ¶èªå¨è®¾ä¸ºå½åç¨æ·ï¼ | |
| | | | handlerUserId / handlerUserName | åºæ¬ä¿¡æ¯ | å¤ç人ï¼åé
åæ¾ç¤ºï¼ | |
| | | | handlerUserId / handlerUserName | åºæ¬ä¿¡æ¯ | å¤çäººï¼æ°å¢æ¶å¿
éï¼åå»ºåæ¾ç¤ºï¼ | |
| | | | returnId | åºæ¬ä¿¡æ¯ | å
³èéè´§ç³è¯·ï¼å¯ç¹å»è·³è½¬ï¼ | |
| | | | repairId | åºæ¬ä¿¡æ¯ | å
³è维修记å½ï¼å¯ç¹å»è·³è½¬ï¼ | |
| | | | resolvedTime | åºæ¬ä¿¡æ¯ | è§£å³æ¶é´ï¼å®ç»åæ¾ç¤ºï¼ | |
| | |
| | | |
| | | | æä½ | è稿(0) | å¤çä¸(10) | å¾
éè´§(30) | å¾
鿬¾(40) | å·²å®ç»(50) | å·²å
³é(60) | 已忶(99) | |
| | | |------|---------|------------|------------|------------|------------|------------|------------| |
| | | | ç¼è¾ | â
| â | â | â | â | â | â | |
| | | | ç¼è¾ | â
| â
| â | â | â | â | â | |
| | | | å é¤ | â
| â | â | â | â | â | â
| |
| | | | åé
å¤ç人 | â
| â
| â | â | â | â | â | |
| | | | é®é¢å¤å® | â | â
| â | â | â | â | â | |
| | | | å建éè´§ç³è¯· | â | â
(å¤å®ä¸ºéè´§å) | â | â | â | â | â | |
| | | | å®ç» | â | â
| â
| â
| â | â | â | |
| | | | å
³é | â | â | â | â | â
| â | â | |
| | | | åæ¶ | â
| â
| â | â | â | â | â | |
| | | |
| | | ### éè´§ç³è¯·æä½æé®æ¾éè§å |
| | | |
| | | | æä½ | è稿(0) | å®¡æ ¸ä¸(10) | 已忥MES(20) | æ£éªä¸(30) | æ£éªå®æ(40) | å·²å
¥åº(50) | 鿬¾å®æ(60) | |
| | | |------|---------|------------|---------------|------------|--------------|------------|--------------| |
| | | | å®¡æ ¸éè¿ | â
| â | â | â | â | â | â | |
| | | | æ¥ç详æ
| â
| â
| â
| â
| â
| â
| â
| |
| | | |
| | | ### å页æ¥è¯¢æ°æ®æé说æ |
| | | |
| | |
| | | |
| | | 1. **æç»è¡æ´æ°çç¥**ï¼æ´æ°å·¥åæ¶ï¼æç»è¡éç¨"å
å åå¢"çç¥ï¼å端å¿
é¡»ä¼ å
¥å®æ´çæç»è¡å表ï¼å
æ¬æªä¿®æ¹çè¡ï¼ï¼å¦åä¼å¯¼è´æç»è¡ä¸¢å¤±ã |
| | | 2. **åå·çæ**ï¼å·¥ååå·ï¼ASåç¼ï¼åéè´§åå·ï¼RTåç¼ï¼ç±å端èªå¨çæï¼å端ä¸éè¦ä¼ å
¥ã |
| | | 3. **ç¶ææµè½¬**ï¼ææç¶æåæ´æä½ï¼åé
ãå¤å®ãå®ç»ãå
³éãåæ¶ãå®¡æ ¸ï¼å端é½ä¼æ ¡éªå½åç¶ææ¯å¦å
许ï¼åç«¯åºæ ¹æ®æé®æ¾éè§åæ§å¶æä½å
¥å£ã |
| | | 3. **ç¶ææµè½¬**ï¼ææç¶æåæ´æä½ï¼å¤å®ãå®ç»ãå
³éãåæ¶ãå®¡æ ¸ï¼å端é½ä¼æ ¡éªå½åç¶ææ¯å¦å
许ï¼åç«¯åºæ ¹æ®æé®æ¾éè§åæ§å¶æä½å
¥å£ã |
| | | 4. **éè´§å®¡æ ¸åèªå¨åæ¥ MES**ï¼å®¡æ ¸éè¿éè´§ç³è¯·åï¼å端èªå¨è°ç¨ MES å建éå®éè´§åï¼åç» MES æµç¨ï¼è´¨æ£âå
¥åºâ鿬¾ï¼ç±åè°èªå¨æ¨è¿ç¶æï¼å端åªéè½®è¯¢å·æ°æ¥çææ°ç¶æã |
| | | 5. **æ°æ®å¸¦å
¥**ï¼å建éè´§ç³è¯·æ¶ï¼å¿
é¡»ä»å·¥å详æ
页跳转并带å
¥ `ticketId`ã`customerId`ã`saleOrderId` 以åå·¥åæç»è¡ä¸æ 记为"éè¦éè´§"çè¡ã |
| | | 6. **æéæ§å¶**ï¼æææ¥å£é½æ `@PreAuthorize` æéæ ¡éªï¼å端èååæé®éè¦å¯¹åºé
ç½®æéæ è¯ã |
| | |
| | | ], |
| | | [ |
| | | "å®åå¦ä½éç¯", |
| | | "å·¥åå¤å®éè´§ â éè´§ç³è¯·å®¡æ ¸ â èªå¨å»º MES éå®éè´§å â RQC è´¨æ£/å
¥åºåè° â 鿬¾åè° â å·¥åå®ç»å
³é" |
| | | "å·¥åå¤å®éè´§ â ä»å¨ç©æµåèµ·éå®éè´§ï¼åå®åéè´§ç³è¯·é¡µé¢å·²ä¸çº¿ï¼ â 建 MES éå®éè´§å â RQC è´¨æ£/å
¥åºåè° â 鿬¾åè° â å·¥åå®ç»å
³é" |
| | | ], |
| | | [ |
| | | "AI å¨åªéåä¸", |
| | |
| | | { |
| | | "flows": [ |
| | | {"id": "sales", "name": "é宿µç¨", "mermaid": "mermaid/02-sales-flow.mmd", "color": "#4f9cff", |
| | | "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": "åè´§éç¥å®¡æ ¸(å ç¨)â éå®åºåºæäº¤ï¼æ 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 â ä¾åºå徿¥å¯¹è´¦ï¼ææ ä¿è¯éå°è´¦ç¬ç«è®°å½ä¸æ ä¸éåã", |
| | | "steps": [ |
| | | {"stage": "寻æº", "action": "ä¾åºåæ¡£æ¡ç»´æ¤å¤ä¸ªè系人ä¸å¤ä¸ªé¶è¡è´¦æ·(å«é¶è¡è¡å·)ï¼æ°å¢è¯¢ä»·åæ¶ä¸å¹¶å½å
¥äº§åÃåä¸ä¾åºåæ¥ä»·å¹¶é宿¯ä¸ªäº§åç䏿 ä¾åºåï¼åè¡¨ç´æ¥ç¡®è®¤åæä¸æ ä¾åºåçæéè´è®¢åèç¨¿ï¼ææ ä¿è¯éå°è´¦è®°å½æ¯å¦ä¸æ ä¸éåç¶æ/éé¢/æ¥æ", "roles": ["éè´å", "ä¾åºå管çå"]}, |
| | | {"stage": "ç³è¯·", "action": "éè´ç³è¯·(CGSQ)æäº¤ BPMï¼é©³åå¯éç½®åè稿ï¼éè¿ä¸æä¾åºåèªå¨çæè®¢å", "roles": ["éè´å", "审æ¹äºº"]}, |
| | | {"stage": "ä¸å", "action": "éè´è®¢å(CGDD)èªå¨æäº¤ BPM(15â20)", "roles": ["éè´å"]}, |
| | | {"stage": "æ¶è´§", "action": "确认æ¶è´§çæå°è´§éç¥(0âå¾
è´¨æ£2/å¾
å
¥åº3â4)ï¼éæ£ç©æèªå¨å建 IQC", "roles": ["ä»ç®¡", "IQC è´¨æ£å"]}, |
| | | {"stage": "å
¥åº", "action": "IQC åæ ¼/ç¹éâéè´å
¥åº(å¾
䏿¶âå¾
æ§è¡â宿)åºå+ï¼åå订å inCount/inStatus ä¸ç³è¯·æç»", "roles": ["ä»ç®¡"]}, |
| | | {"stage": "éè´§", "action": "IQC ä¸åæ ¼éè´§âä¾åºåéè´§åºåº(éæéå®å°è®¢åè¡)ï¼æ¥åºèµ° NCR", "roles": ["ä»ç®¡"]}, |
| | | {"stage": "仿¬¾", "action": "éè´æ¥ç¥¨(FPD, AI OCR, â¤è®¢åæ»ä»·) â 仿¬¾å(FKD å
³èæ¥ç¥¨+éä»¶, â¤æ¥ç¥¨éé¢) BPM 审æ¹", "roles": ["è´¢å¡", "审æ¹äºº"]}, |
| | | {"stage": "对账", "action": "ä¾åºå徿¥æä¾åºåæ±æ»ï¼å·¦ä¾§éè´è®¢åæµæ°´å«å·²å¼ç¥¨/æªå¼ç¥¨éé¢ï¼å³ä¾§æ¥ç¥¨æµæ°´å«å¼ç¥¨éé¢/å·²ä»/å©ä½åºä»å¹¶é仿¬¾æµæ°´ï¼é¡¶é¨æ±æ»ç´¯è®¡éè´/å¼ç¥¨/仿¬¾/æªä»ä½é¢", "roles": ["è´¢å¡", "éè´å"]}]}, |
| | | {"id": "production", "name": "ç产æµç¨", "mermaid": "mermaid/04-production-flow.mmd", "color": "#e0b34f", |
| | | "summary": "éå®è®¢åé©±å¨ MPS â ä¸åå·¥å â æå·¥èºè·¯çº¿æå·¥åºä»»å¡ â 颿/çº¿è¾¹å¤æ â æ¥å·¥(å·¥åºé¡ºåºç¡¬æ ¡éª+BPM) â å岿¶è/产åºå
¥åº/IPQC â æ«éå·¥åºååè¿åº¦ â èªå¨å®å·¥ â ProductionFinishedEvent ååéå®è®¢åã", |
| | | "steps": [ |
| | | {"stage": "计å", "action": "MPS å建(æå·¥æéå®è®¢åèªå¨)âä¸åæåå¹¶ä¸å为工å", "roles": ["计åå"]}, |
| | | {"stage": "派工", "action": "å·¥å确认æå·¥èºè·¯çº¿éå·¥åºçæä»»å¡ï¼å¯ææ´¾/æå/åæ¶", "roles": ["车é´ä¸»ä»»"]}, |
| | | {"stage": "夿", "action": "çäº§é¢æååºåºæçº¿è¾¹èæåºå¤æ", "roles": ["ä»ç®¡"]}, |
| | | {"stage": "æ¥å·¥", "action": "æäº¤æ¥å·¥ï¼ä¸ä¸éå·¥åºæªæ¥æ»¡ç´æ¥æ¦æªï¼å¯ç¨ BPM 走审æ¹", "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) + å®ææ¶æåæ ¼/ä¸åæ ¼æ°éèªå¨å¤å®(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": "éæ/éå®éè´§/å®åéè´§â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": ["è´¨éå·¥ç¨å¸"]}, |
| | | {"stage": "åºä»¶", "action": "两æ¡åºä»¶å
¥å£ï¼â éç¨ generate/preview(è°ç¨æ¹èªå¸¦ä¸ä¸æ) 渲æ HTML å¹¶å»ç»æ°æ®å¿«ç
§ï¼ç¼å· QR+æ¥æ+4使µæ°´æå¤©ç¬ç«ï¼preview åªæ¸²æä¸è½åºä¸æ¶èç¼å·ï¼regenerate ç¨å»ç»å¿«ç
§éæ¸²ä¸æ°æ®ä¸ç¼å·ä¸åå¹¶ä½åºå·²å½æ¡£ PDFï¼å¯¼åº PDF ç±åç«¯è° Chromium æå°å®ä¾å·²åç HTML å彿¡£éä»¶ä¸å¿ï¼â¡generate-from-qc ç±è´¨æ£åç´æ¥åºä»¶(æ°æ®ç» MesQcReportApi ä» MES åï¼åç«¯ä¸æ¼ä¸ä¸æ)ï¼åºä»¶åäºéæ ¡éªæä¸å¡ä¼å
çº§åªæ¥ç¬¬ä¸å¤ï¼ç±»åéæ³/åæ®ä¸åå¨/æªå®ææ£éª/æªå¡«å¤å®/模æ¿ç±»åä¸ç¬¦/æ å¯ç¨æ£éªé¡¹ï¼æ¥å头å¦å¸¦åæ®åå¤å® qcResult+qcResultText ä¸å¼æå¤å®å¹¶åï¼ååºå undecidableCount å¾
å¤å®é¡¹æ°ä¸ warnings(åç»æ é¢è·³è¿/ææ å·²å /æªå½å®æµå¼/æ ·åè¶
3)ï¼åä¸å¼ åæ®å¯åå¤åºå¤ä»½", "roles": ["è´¨æ£å"]}, |
| | | {"stage": "建模æ¿", "action": "AI 导å
¥ï¼ä¸ä¼ æ¢ææ£éªæ¥åæä»¶(æ«æä»¶/ç
§çãçµåç PDFãWord/Excel) â è¯å«ææ¨¡æ¿è稿(ä¸è½åº) â 人工å¨è®¾è®¡å¨ç¡®è®¤è°æ´åä¿åä¸ºçæ¬ï¼.doc/.xls æ§æ ¼å¼ä¸æ¯æ", "roles": ["è´¨æ£å", "è´¨éå·¥ç¨å¸"]}]}, |
| | | {"id": "warehouse", "name": "ä»å¨æµç¨", "mermaid": "mermaid/06-warehouse-flow.mmd", "color": "#7e6bd6", |
| | | "summary": "15 ç±»åæ®é©±å¨åºåå°è´¦(å
å
ç»ãåé)åå¨ï¼å
¨é¨ç»äºå¡æµæ°´ççï¼æ¯æè°æ¨å¨éãçç¹è°æ´ãæ¹æ¬¡/SN 追溯ãåºåå ç¨ä¸å级å»ç»ã线边èæåºè´åºåï¼å¯¹å¤ WmsStockApi ä¾ ERP æ¶åã", |
| | | "steps": [ |
| | | {"stage": "å
¥åº", "action": "éè´å
¥åº/ç产å
¥åº/产åºå
¥åº/éè´§å
¥åº/å¤åå
¥åº/æé¡¹å
¥åº â IN äºå¡ï¼æ¹æ¬¡æ··æ¾æ ¡éªãå级å»ç»æ ¡éª", "roles": ["ä»ç®¡"]}, |
| | | {"stage": "åºåº", "action": "éå®åºåº/颿/æ¶è/å¤ååæ/ä¾åºåéè´§/æé¡¹åºåº â OUT äºå¡ï¼checkFlag æ§å¶å¯å¦è´åºå", "roles": ["ä»ç®¡", "ç³»ç»èªå¨"]}, |
| | | {"stage": "ç§»åº", "action": "å
é¨/å¤é¨è°æ¨æå¯¹ MOVE äºå¡ï¼å¨éæ°éè·è¸ª", "roles": ["ä»ç®¡"]}, |
| | | {"stage": "çç¹", "action": "æ¹æ¡âä»»å¡âæç»è¡âç»æï¼çç ADJUST_INãçäº ADJUST_OUTï¼å¯å»ç»ä¸ç²ç", "roles": ["çç¹å"]}, |
| | | {"stage": "追溯", "action": "æ¹æ¬¡/SN(uuid)/æ¡ç (18ç±»)/è£
ç®±åµå¥æ¯ææ£åå追溯", "roles": ["è´¨é", "å®å"]}]}, |
| | | {"id": "aftersales", "name": "å®åæµç¨", "mermaid": "mermaid/07-after-sales-flow.mmd", "color": "#c78bd6", |
| | | "summary": "å·¥å(å
æ+é®é¢å¤å®) â ç»´ä¿®ä¸ç±»åæéè´§ç³è¯· â å®¡æ ¸èªå¨å»º MES éå®éè´§å â RQC è´¨æ£/å
¥åº/鿬¾ä¸åè°é级æ¨è¿ â å·¥åå®ç»å
³éã", |
| | | "steps": [ |
| | | {"stage": "åç", "action": "人工å½å
¥å·¥å(å
³è客æ·/订å/åå)ï¼åé
å¤ç人è¿å
¥å¤çä¸", "roles": ["客æ"]}, |
| | | {"stage": "å¤å®", "action": "é®é¢å¤å®: ä¸è¬/ç»´ä¿®/éè´§ï¼ä¸¥é度 0-3", "roles": ["å®åå·¥ç¨å¸"]}, |
| | | {"stage": "ç»´ä¿®", "action": "ç°åº/è¿å/è¿ç¨ç»´ä¿®ï¼è´¹ç¨ä¸ç»æè®°å½ï¼å®æèå¨å·¥åå®ç»", "roles": ["维修工ç¨å¸"]}, |
| | | {"stage": "éè´§", "action": "éè´§ç³è¯·å®¡æ ¸âèªå¨å»º MES éå®éè´§å(RQC)âè´¨æ£/å
¥åºåè°â鿬¾åè°âå
³é", "roles": ["å®å", "è´¨æ£", "è´¢å¡"]}]}, |
| | | {"id": "finance", "name": "ä¼è®¡æ ¸ç®æµç¨", "mermaid": "mermaid/12-finance-flow.mmd", "color": "#3ec9a7", |
| | | "summary": "ç¬ç«æ ¸ç®æ¨¡å yudao-module-financeï¼ä¼è®¡ç§ç®å»ºè´¦ â è®°è´¦åè¯å½å
¥(åè´·å¹³è¡¡æ ¡éª) â è¿è´¦ â æ»è´¦/æç»è´¦ â èµäº§è®¡æææ§ä¸æé â è´¢å¡æ¥è¡¨çæ¿åæ° ERP å·²å®¡æ ¸åæ®ã", |
| | | "steps": [ |
| | | {"stage": "建账", "action": "ç»´æ¤ä¼è®¡ç§ç® tree(subjectCode å¯ä¸ï¼å¯å»ºä¸çº§)ï¼é¦æ¬¡å¯å¯¼å
¥çº¦ 68 æ¡ä¸çº§ç§ç®ç§å", "roles": ["ä¼è®¡"]}, |
| | | {"stage": "è®°è´¦", "action": "å½å
¥åè¯(åå·ç空èªå¨çæ)+åå½ï¼åå½éè¡éç§ç®å¹¶å¡«å/è´·ï¼æ ¡éªè³å°ä¸è¡ãåè´·é½ä¸å¾åæ¶å¤§äº0ãå计ç¸çä¸å¤§äº0", "roles": ["ä¼è®¡"]}, |
| | | {"stage": "è¿è´¦", "action": "æªè¿è´¦0 â post è¿è´¦ â å·²è¿è´¦10(ä¸å¯åä¿®æ¹)ï¼æªè¿è´¦0 æ å·²è¿è´¦10 åå¯ cancel ä½åº â å·²ä½åº20", "roles": ["ä¼è®¡", "è´¢å¡ä¸»ç®¡"]}, |
| | | {"stage": "æ¥è´¦", "action": "æ»è´¦ææé´éææ±æ»ãæç»è´¦éæ¡åå½å¹¶ç»è½¬ä½é¢ï¼ä¸¤è
åªç»è®¡å·²è¿è´¦10çåè¯ï¼å¹¶æ¯æå¯¼åº", "roles": ["ä¼è®¡", "è´¢å¡ä¸»ç®¡"]}, |
| | | {"stage": "èµäº§", "action": "åºå®èµäº§(1å¨ç¨/2é²ç½®/3ç»´ä¿®ä¸/4å·²æ¥åº)䏿 å½¢èµäº§(1å¨ç¨/2已失æ/3å·²æéå®)计æï¼ä¼ ids æéä¸è®¡æï¼ids 为空对å
¨é¨æªæ¥åº/æªå¤±æèµäº§è®¡æä¸ä¸ªæ", "roles": ["èµäº§ä¼è®¡"]}, |
| | | {"stage": "æ¥è¡¨", "action": "çæ¿æ±æ»èµäº§ä¸åè¯æ¶ç¹æ° + ç» ErpFinanceStatisticsApi å ERP å·²å®¡æ ¸æ¶è´§ä»æ¬¾ä¸è´ééé¢ï¼è¾åºæåº¦æ¶æ¯è¶å¿", "roles": ["è´¢å¡ä¸»ç®¡", "管çå±"]}]}, |
| | | {"id": "ai", "name": "AI ä¸å¡æµç¨", "mermaid": "mermaid/11-ai-business-flow.mmd", "color": "#56c8d8", |
| | | "summary": "ç»ä¸æ¨¡å¼ï¼ä¸å¡ä¾§æ¶éä¸ä¸æ(å¿
è¦æ¶è° MDM/SRM/CRM API ååç§°)âç»è£
Promptâchat/chatWithImageâè§£æ JSONâå端é¢å¡«æå»ºè®®ï¼æ Function Callingï¼RAG ç¥è¯åºå·²å»ºæä½ææ ä¸å¡æ¶è´¹ãæºè½ä½ç©æå¯¼å
¥ä¸ºè§å+Java 颿£é¾è·¯ï¼ç»äººå·¥ç¡®è®¤åå¹çæäº¤ã", |
| | | "steps": [ |
| | | {"stage": "å½å
¥ææ", "action": "å票 OCR(å¾ç夿¨¡æ/PDFææ¬)ãæ¥ä»·å OCR â ç»æåé¢å¡«", "roles": ["éè´å", "éå®"]}, |
| | | {"stage": "ä¸»æ°æ®å¯¼å
¥", "action": "ä¸ä¼ ç©æ CSV/XLSX â Python è§£æåé â Java åªè¯»é¢æ£åç±»/åä½/éå¤ç¼ç â 人工修订确认 â å¹çæäº¤ â éè¡åæ§ï¼åªæ°å»ºã䏿´æ°ãä¸åæ¥ MES", "roles": ["ç©æç®¡çå"]}, |
| | | {"stage": "è¾
å©å¤å®", "action": "è´¨æ£å+ææ +ç¼ºé· â å»ºè®®åæ ¼/ç¹é/éè´§/æ¥åº+çç±", "roles": ["è´¨æ£å"]}, |
| | | {"stage": "å³ç颿µ", "action": "缺æ/ç产æ¶é¿/ç产é£é©/交ä»åç±»é¢æµä¾è®¡åæäº§åè", "roles": ["计åå"]}, |
| | | {"stage": "模æ¿è¯å«", "action": "ä¸ä¼ æ¢ææ£éªæ¥åæä»¶(æ«æä»¶/ç
§çãçµåç PDFãWord/Excel) â åééæ½å(æææ¬å±èµ°ææ¬ãæ«æçé页转å¾) â 大模åæå端ä¸ä¼ çç»ä»¶æ¸
åäº§åºæå¹³ç»ä»¶è稿 â 人工å¨è®¾è®¡å¨ç¡®è®¤åä¿å为模æ¿çæ¬", "roles": ["è´¨æ£å", "è´¨éå·¥ç¨å¸"]}, |
| | | {"stage": "ç¥è¯æ£ç´¢", "action": "ææ¡£âåçâMilvus åéâæ£ç´¢æ¥å£(é¢ç)", "roles": ["â"]}]} |
| | | { |
| | | "id": "sales", |
| | | "name": "é宿µç¨", |
| | | "mermaid": "mermaid/02-sales-flow.mmd", |
| | | "color": "#4f9cff", |
| | | "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": "åè´§éç¥å®¡æ ¸(å ç¨)â éå®åºåºæäº¤ï¼æ 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 â ä¾åºå徿¥å¯¹è´¦ï¼ææ ä¿è¯éå°è´¦ç¬ç«è®°å½ä¸æ ä¸éåã", |
| | | "steps": [ |
| | | { |
| | | "stage": "寻æº", |
| | | "action": "ä¾åºåæ¡£æ¡ç»´æ¤å¤ä¸ªè系人ä¸å¤ä¸ªé¶è¡è´¦æ·(å«é¶è¡è¡å·)ï¼æ°å¢è¯¢ä»·åæ¶ä¸å¹¶å½å
¥äº§åÃåä¸ä¾åºåæ¥ä»·å¹¶é宿¯ä¸ªäº§åç䏿 ä¾åºåï¼åè¡¨ç´æ¥ç¡®è®¤åæä¸æ ä¾åºåçæéè´è®¢åèç¨¿ï¼ææ ä¿è¯éå°è´¦è®°å½æ¯å¦ä¸æ ä¸éåç¶æ/éé¢/æ¥æ", |
| | | "roles": [ |
| | | "éè´å", |
| | | "ä¾åºå管çå" |
| | | ] |
| | | }, |
| | | { |
| | | "stage": "ç³è¯·", |
| | | "action": "éè´ç³è¯·(CGSQ)æäº¤ BPMï¼é©³åå¯éç½®åè稿ï¼éè¿ä¸æä¾åºåèªå¨çæè®¢å", |
| | | "roles": [ |
| | | "éè´å", |
| | | "审æ¹äºº" |
| | | ] |
| | | }, |
| | | { |
| | | "stage": "ä¸å", |
| | | "action": "éè´è®¢å(CGDD)èªå¨æäº¤ BPM(15â20)", |
| | | "roles": [ |
| | | "éè´å" |
| | | ] |
| | | }, |
| | | { |
| | | "stage": "æ¶è´§", |
| | | "action": "确认æ¶è´§çæå°è´§éç¥(0âå¾
è´¨æ£2/å¾
å
¥åº3â4)ï¼éæ£ç©æèªå¨å建 IQC", |
| | | "roles": [ |
| | | "ä»ç®¡", |
| | | "IQC è´¨æ£å" |
| | | ] |
| | | }, |
| | | { |
| | | "stage": "å
¥åº", |
| | | "action": "IQC åæ ¼/ç¹éâéè´å
¥åº(å¾
䏿¶âå¾
æ§è¡â宿)åºå+ï¼åå订å inCount/inStatus ä¸ç³è¯·æç»", |
| | | "roles": [ |
| | | "ä»ç®¡" |
| | | ] |
| | | }, |
| | | { |
| | | "stage": "éè´§", |
| | | "action": "IQC ä¸åæ ¼éè´§âä¾åºåéè´§åºåº(éæéå®å°è®¢åè¡)ï¼æ¥åºèµ° NCR", |
| | | "roles": [ |
| | | "ä»ç®¡" |
| | | ] |
| | | }, |
| | | { |
| | | "stage": "仿¬¾", |
| | | "action": "éè´æ¥ç¥¨(FPD, AI OCR, â¤è®¢åæ»ä»·) â 仿¬¾å(FKD å
³èæ¥ç¥¨+éä»¶, â¤æ¥ç¥¨éé¢) BPM 审æ¹", |
| | | "roles": [ |
| | | "è´¢å¡", |
| | | "审æ¹äºº" |
| | | ] |
| | | }, |
| | | { |
| | | "stage": "对账", |
| | | "action": "ä¾åºå徿¥æä¾åºåæ±æ»ï¼å·¦ä¾§éè´è®¢åæµæ°´å«å·²å¼ç¥¨/æªå¼ç¥¨éé¢ï¼å³ä¾§æ¥ç¥¨æµæ°´å«å¼ç¥¨éé¢/å·²ä»/å©ä½åºä»å¹¶é仿¬¾æµæ°´ï¼é¡¶é¨æ±æ»ç´¯è®¡éè´/å¼ç¥¨/仿¬¾/æªä»ä½é¢", |
| | | "roles": [ |
| | | "è´¢å¡", |
| | | "éè´å" |
| | | ] |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | "id": "production", |
| | | "name": "ç产æµç¨", |
| | | "mermaid": "mermaid/04-production-flow.mmd", |
| | | "color": "#e0b34f", |
| | | "summary": "éå®è®¢åé©±å¨ MPS â ä¸åå·¥å â æå·¥èºè·¯çº¿æå·¥åºä»»å¡ â 颿/çº¿è¾¹å¤æ â æ¥å·¥(å·¥åºé¡ºåºç¡¬æ ¡éª+BPM) â å岿¶è/产åºå
¥åº/IPQC â æ«éå·¥åºååè¿åº¦ â èªå¨å®å·¥ â ProductionFinishedEvent ååéå®è®¢åã", |
| | | "steps": [ |
| | | { |
| | | "stage": "计å", |
| | | "action": "MPS å建(æå·¥æéå®è®¢åèªå¨)âä¸åæåå¹¶ä¸å为工å", |
| | | "roles": [ |
| | | "计åå" |
| | | ] |
| | | }, |
| | | { |
| | | "stage": "派工", |
| | | "action": "å·¥å确认æå·¥èºè·¯çº¿éå·¥åºçæä»»å¡ï¼å¯ææ´¾/æå/åæ¶", |
| | | "roles": [ |
| | | "车é´ä¸»ä»»" |
| | | ] |
| | | }, |
| | | { |
| | | "stage": "夿", |
| | | "action": "çäº§é¢æååºåºæçº¿è¾¹èæåºå¤æ", |
| | | "roles": [ |
| | | "ä»ç®¡" |
| | | ] |
| | | }, |
| | | { |
| | | "stage": "æ¥å·¥", |
| | | "action": "æäº¤æ¥å·¥ï¼ä¸ä¸éå·¥åºæªæ¥æ»¡ç´æ¥æ¦æªï¼å¯ç¨ BPM 走审æ¹", |
| | | "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) + å®ææ¶æåæ ¼/ä¸åæ ¼æ°éèªå¨å¤å®(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": "éæ/éå®éè´§/å®åéè´§â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": [ |
| | | "è´¨éå·¥ç¨å¸" |
| | | ] |
| | | }, |
| | | { |
| | | "stage": "åºä»¶", |
| | | "action": "两æ¡åºä»¶å
¥å£ï¼â éç¨ generate/preview(è°ç¨æ¹èªå¸¦ä¸ä¸æ) 渲æ HTML å¹¶å»ç»æ°æ®å¿«ç
§ï¼ç¼å· QR+æ¥æ+4使µæ°´æå¤©ç¬ç«ï¼preview åªæ¸²æä¸è½åºä¸æ¶èç¼å·ï¼regenerate ç¨å»ç»å¿«ç
§éæ¸²ä¸æ°æ®ä¸ç¼å·ä¸åå¹¶ä½åºå·²å½æ¡£ PDFï¼å¯¼åº PDF ç±åç«¯è° Chromium æå°å®ä¾å·²åç HTML å彿¡£éä»¶ä¸å¿ï¼â¡generate-from-qc ç±è´¨æ£åç´æ¥åºä»¶(æ°æ®ç» MesQcReportApi ä» MES åï¼åç«¯ä¸æ¼ä¸ä¸æ)ï¼åºä»¶åäºéæ ¡éªæä¸å¡ä¼å
çº§åªæ¥ç¬¬ä¸å¤ï¼ç±»åéæ³/åæ®ä¸åå¨/æªå®ææ£éª/æªå¡«å¤å®/模æ¿ç±»åä¸ç¬¦/æ å¯ç¨æ£éªé¡¹ï¼æ¥å头å¦å¸¦åæ®åå¤å® qcResult+qcResultText ä¸å¼æå¤å®å¹¶åï¼ååºå undecidableCount å¾
å¤å®é¡¹æ°ä¸ warnings(åç»æ é¢è·³è¿/ææ å·²å /æªå½å®æµå¼/æ ·åè¶
3)ï¼åä¸å¼ åæ®å¯åå¤åºå¤ä»½", |
| | | "roles": [ |
| | | "è´¨æ£å" |
| | | ] |
| | | }, |
| | | { |
| | | "stage": "建模æ¿", |
| | | "action": "AI 导å
¥ï¼ä¸ä¼ æ¢ææ£éªæ¥åæä»¶(æ«æä»¶/ç
§çãçµåç PDFãWord/Excel) â è¯å«ææ¨¡æ¿è稿(ä¸è½åº) â 人工å¨è®¾è®¡å¨ç¡®è®¤è°æ´åä¿åä¸ºçæ¬ï¼.doc/.xls æ§æ ¼å¼ä¸æ¯æ", |
| | | "roles": [ |
| | | "è´¨æ£å", |
| | | "è´¨éå·¥ç¨å¸" |
| | | ] |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | "id": "warehouse", |
| | | "name": "ä»å¨æµç¨", |
| | | "mermaid": "mermaid/06-warehouse-flow.mmd", |
| | | "color": "#7e6bd6", |
| | | "summary": "15 ç±»åæ®é©±å¨åºåå°è´¦(å
å
ç»ãåé)åå¨ï¼å
¨é¨ç»äºå¡æµæ°´ççï¼æ¯æè°æ¨å¨éãçç¹è°æ´ãæ¹æ¬¡/SN 追溯ãåºåå ç¨ä¸å级å»ç»ã线边èæåºè´åºåï¼å¯¹å¤ WmsStockApi ä¾ ERP æ¶åã", |
| | | "steps": [ |
| | | { |
| | | "stage": "å
¥åº", |
| | | "action": "éè´å
¥åº/ç产å
¥åº/产åºå
¥åº/éè´§å
¥åº/å¤åå
¥åº/æé¡¹å
¥åº â IN äºå¡ï¼æ¹æ¬¡æ··æ¾æ ¡éªãå级å»ç»æ ¡éª", |
| | | "roles": [ |
| | | "ä»ç®¡" |
| | | ] |
| | | }, |
| | | { |
| | | "stage": "åºåº", |
| | | "action": "éå®åºåº/颿/æ¶è/å¤ååæ/ä¾åºåéè´§/æé¡¹åºåº â OUT äºå¡ï¼checkFlag æ§å¶å¯å¦è´åºå", |
| | | "roles": [ |
| | | "ä»ç®¡", |
| | | "ç³»ç»èªå¨" |
| | | ] |
| | | }, |
| | | { |
| | | "stage": "ç§»åº", |
| | | "action": "å
é¨/å¤é¨è°æ¨æå¯¹ MOVE äºå¡ï¼å¨éæ°éè·è¸ª", |
| | | "roles": [ |
| | | "ä»ç®¡" |
| | | ] |
| | | }, |
| | | { |
| | | "stage": "çç¹", |
| | | "action": "æ¹æ¡âä»»å¡âæç»è¡âç»æï¼çç ADJUST_INãçäº ADJUST_OUTï¼å¯å»ç»ä¸ç²ç", |
| | | "roles": [ |
| | | "çç¹å" |
| | | ] |
| | | }, |
| | | { |
| | | "stage": "追溯", |
| | | "action": "æ¹æ¬¡/SN(uuid)/æ¡ç (18ç±»)/è£
ç®±åµå¥æ¯ææ£åå追溯", |
| | | "roles": [ |
| | | "è´¨é", |
| | | "å®å" |
| | | ] |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | "id": "aftersales", |
| | | "name": "å®åæµç¨", |
| | | "mermaid": "mermaid/07-after-sales-flow.mmd", |
| | | "color": "#c78bd6", |
| | | "summary": "å·¥å(å
æ+é®é¢å¤å®) â 客æ·è¯æ±/å¤çç»æé件䏿µè½¬è®°å½çç â ç»´ä¿®ä¸ç±»åæç±ä»å¨ç©æµåèµ·éå®éè´§(éè´§åå建å³ååå·¥åæµè½¬è®°å½) â RQC è´¨æ£/å
¥åº/鿬¾ä¸åè°é级æ¨è¿ â å·¥åå®ç»å
³éã", |
| | | "steps": [ |
| | | { |
| | | "stage": "åç", |
| | | "action": "人工å½å
¥å·¥å(å
³è客æ·/订å/åå)ï¼å¡«å客æ·è¯æ±åé¦æè¿°å¹¶ä¸ä¼ éä»¶ï¼åå»ºæ¶æå®çå¤çäººç´æ¥è¿å
¥å¤çä¸", |
| | | "roles": [ |
| | | "客æ" |
| | | ] |
| | | }, |
| | | { |
| | | "stage": "å¤å®", |
| | | "action": "é®é¢å¤å®: ä¸è¬/ç»´ä¿®/éè´§ï¼ä¸¥é度 0-3", |
| | | "roles": [ |
| | | "å®åå·¥ç¨å¸" |
| | | ] |
| | | }, |
| | | { |
| | | "stage": "å¤ç", |
| | | "action": "å¡«åå¤çç»æå¹¶ä¸ä¼ å¤çç»æéä»¶ï¼åå»ºãæ´æ°ãå¤å®ãå®ç»ã彿¡£ãåæ¶ãå访ååå
¥æµè½¬è®°å½", |
| | | "roles": [ |
| | | "å®åå·¥ç¨å¸" |
| | | ] |
| | | }, |
| | | { |
| | | "stage": "ç»´ä¿®", |
| | | "action": "ç°åº/è¿å/è¿ç¨ç»´ä¿®ï¼è´¹ç¨ä¸ç»æè®°å½ï¼å®æèå¨å·¥åå®ç»", |
| | | "roles": [ |
| | | "维修工ç¨å¸" |
| | | ] |
| | | }, |
| | | { |
| | | "stage": "éè´§", |
| | | "action": "å®åä¸ååèµ·éè´§ç³è¯·ï¼ç±ä»å¨ç©æµåèµ·éå®éè´§å(RQC)âè´¨æ£/å
¥åºåè°â鿬¾åè°âå
³éï¼å建éè´§åæ¶æéå®è®¢åå¹é
æè¿ä¸å¼ æªå
³é/æªåæ¶å·¥åï¼åå
¥ãä»å¨éè´§ãæµè½¬è®°å½ï¼è稿æå¤çä¸å·¥åæ¨è¿ä¸ºå¾
éè´§", |
| | | "roles": [ |
| | | "ä»å¨", |
| | | "è´¨æ£", |
| | | "è´¢å¡" |
| | | ] |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | "id": "finance", |
| | | "name": "ä¼è®¡æ ¸ç®æµç¨", |
| | | "mermaid": "mermaid/12-finance-flow.mmd", |
| | | "color": "#3ec9a7", |
| | | "summary": "ä¼è®¡æ ¸ç®ï¼åè¯/åå½/å贷平衡 -> è¿è´¦ -> æ»è´¦/æç»è´¦/æ¥è¡¨ï¼åºå®èµäº§ææ§ãæ å½¢èµäº§æéãéå®éè´è´¢å¡éç¯ï¼ERP éå®è®¢å + MES 已宿åºåºå -> CRM å¼ç¥¨ç³è¯·ï¼ç»å®è®¢å+åºåºåï¼-> 审æ¹éè¿ -> å½å
¥å票并填åå忬¾/é¢ä»æ¬¾/å°è´§æ¬¾/éªæ¶æ¬¾/è´¨ä¿éæ¶æ¬¾èç¹ -> CRM 忬¾ææ ¸éæç»åæå°è®¢å/åºåº/å¼ç¥¨ -> 客æ·åºæ¶å¯¹è´¦ãå·²åè´§æªå¼ç¥¨ãæªæ ¸éåºæ¶è´¦é¾ã䏿忬¾è®¡åï¼æ¥ç¥¨å¿
须忶ç»å®éè´è®¢åä¸ MES éè´å
¥åºåï¼åè¯å¯å
³èæ¥æºåæ®ï¼å¼ç¥¨/忬¾/æ¥ç¥¨/仿¬¾ï¼ã", |
| | | "steps": [ |
| | | { |
| | | "stage": "建账", |
| | | "action": "ç»´æ¤ä¼è®¡ç§ç® tree(subjectCode å¯ä¸ï¼å¯å»ºä¸çº§)ï¼é¦æ¬¡å¯å¯¼å
¥çº¦ 68 æ¡ä¸çº§ç§ç®ç§å", |
| | | "roles": [ |
| | | "ä¼è®¡" |
| | | ] |
| | | }, |
| | | { |
| | | "stage": "è®°è´¦", |
| | | "action": "å½å
¥åè¯(åå·ç空èªå¨çæ)+åå½ï¼åå½éè¡éç§ç®å¹¶å¡«å/è´·ï¼æ ¡éªè³å°ä¸è¡ãåè´·é½ä¸å¾åæ¶å¤§äº0ãå计ç¸çä¸å¤§äº0", |
| | | "roles": [ |
| | | "ä¼è®¡" |
| | | ] |
| | | }, |
| | | { |
| | | "stage": "è¿è´¦", |
| | | "action": "æªè¿è´¦0 â post è¿è´¦ â å·²è¿è´¦10(ä¸å¯åä¿®æ¹)ï¼æªè¿è´¦0 æ å·²è¿è´¦10 åå¯ cancel ä½åº â å·²ä½åº20", |
| | | "roles": [ |
| | | "ä¼è®¡", |
| | | "è´¢å¡ä¸»ç®¡" |
| | | ] |
| | | }, |
| | | { |
| | | "stage": "æ¥è´¦", |
| | | "action": "æ»è´¦ææé´éææ±æ»ãæç»è´¦éæ¡åå½å¹¶ç»è½¬ä½é¢ï¼ä¸¤è
åªç»è®¡å·²è¿è´¦10çåè¯ï¼å¹¶æ¯æå¯¼åº", |
| | | "roles": [ |
| | | "ä¼è®¡", |
| | | "è´¢å¡ä¸»ç®¡" |
| | | ] |
| | | }, |
| | | { |
| | | "stage": "èµäº§", |
| | | "action": "åºå®èµäº§(1å¨ç¨/2é²ç½®/3ç»´ä¿®ä¸/4å·²æ¥åº)䏿 å½¢èµäº§(1å¨ç¨/2已失æ/3å·²æéå®)计æï¼ä¼ ids æéä¸è®¡æï¼ids 为空对å
¨é¨æªæ¥åº/æªå¤±æèµäº§è®¡æä¸ä¸ªæ", |
| | | "roles": [ |
| | | "èµäº§ä¼è®¡" |
| | | ] |
| | | }, |
| | | { |
| | | "stage": "æ¥è¡¨", |
| | | "action": "çæ¿æ±æ»èµäº§ä¸åè¯æ¶ç¹æ° + ç» ErpFinanceStatisticsApi å ERP å·²å®¡æ ¸æ¶è´§ä»æ¬¾ä¸è´ééé¢ï¼è¾åºæåº¦æ¶æ¯è¶å¿", |
| | | "roles": [ |
| | | "è´¢å¡ä¸»ç®¡", |
| | | "管çå±" |
| | | ] |
| | | }, |
| | | { |
| | | "stage": "æ¥ç¥¨", |
| | | "action": "éæ©éè´è®¢å -> éæ©è¯¥è®¢åä¸å·²å®æ MES éè´å
¥åºå -> ä¿åæ¥ç¥¨ï¼item_receipt_id/item_receipt_codeï¼", |
| | | "roles": [ |
| | | "éè´", |
| | | "è´¢å¡" |
| | | ] |
| | | }, |
| | | { |
| | | "stage": "å¼ç¥¨ç³è¯·", |
| | | "action": "éæ©ååãéå®è®¢åã该订åä¸å·²å®æåºåºåï¼å¡«åå¼ç¥¨éé¢åæäº¤ BPM 审æ¹", |
| | | "roles": [ |
| | | "éå®", |
| | | "è´¢å¡" |
| | | ] |
| | | }, |
| | | { |
| | | "stage": "å½å
¥å票", |
| | | "action": "审æ¹éè¿åå½å
¥å票å·ç ãæ¥æãéä»¶ï¼å¹¶æéå®è®¢åå¡«åå忬¾/é¢ä»æ¬¾/å°è´§æ¬¾/éªæ¶æ¬¾/è´¨ä¿éååèªæ¶é´èç¹", |
| | | "roles": [ |
| | | "è´¢å¡" |
| | | ] |
| | | }, |
| | | { |
| | | "stage": "忬¾æ ¸é", |
| | | "action": "忬¾åéè¿ items æé颿 ¸éå°éå®è®¢å/éå®åºåº/å¼ç¥¨ï¼æç»å计å¿
é¡»çäºå款éé¢ï¼å®¡æ ¸éè¿åå忬¾è®¡åå®é
éé¢ä¸ç¶æ", |
| | | "roles": [ |
| | | "è´¢å¡" |
| | | ] |
| | | }, |
| | | { |
| | | "stage": "对账æ¥è¡¨", |
| | | "action": "æå®¢æ·æ±æ»è®¢åãåºåºãå¼ç¥¨ã忬¾ï¼è¾åºæªæ ¸éåºæ¶ãå·²åè´§æªå¼ç¥¨ãè´¦é¾ã䏿忬¾è®¡åä¸æåº¦è¶å¿", |
| | | "roles": [ |
| | | "è´¢å¡", |
| | | "éå®" |
| | | ] |
| | | }, |
| | | { |
| | | "stage": "å
¥è´¦", |
| | | "action": "è®°è´¦åè¯å¡«å sourceType/sourceId/sourceNo å
³èå¼ç¥¨ã忬¾ãæ¥ç¥¨ã仿¬¾çæ¥æºåæ®", |
| | | "roles": [ |
| | | "è´¢å¡" |
| | | ] |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | "id": "ai", |
| | | "name": "AI ä¸å¡æµç¨", |
| | | "mermaid": "mermaid/11-ai-business-flow.mmd", |
| | | "color": "#56c8d8", |
| | | "summary": "ç»ä¸æ¨¡å¼ï¼ä¸å¡ä¾§æ¶éä¸ä¸æ(å¿
è¦æ¶è° MDM/SRM/CRM API ååç§°)âç»è£
Promptâchat/chatWithImageâè§£æ JSONâå端é¢å¡«æå»ºè®®ï¼æ Function Callingï¼RAG ç¥è¯åºå·²å»ºæä½ææ ä¸å¡æ¶è´¹ãæºè½ä½ç©æå¯¼å
¥ä¸ºè§å+Java 颿£é¾è·¯ï¼ç»äººå·¥ç¡®è®¤åå¹çæäº¤ã", |
| | | "steps": [ |
| | | { |
| | | "stage": "å½å
¥ææ", |
| | | "action": "å票 OCR(å¾ç夿¨¡æ/PDFææ¬)ãæ¥ä»·å OCR â ç»æåé¢å¡«", |
| | | "roles": [ |
| | | "éè´å", |
| | | "éå®" |
| | | ] |
| | | }, |
| | | { |
| | | "stage": "ä¸»æ°æ®å¯¼å
¥", |
| | | "action": "ä¸ä¼ ç©æ CSV/XLSX â Python è§£æåé â Java åªè¯»é¢æ£åç±»/åä½/éå¤ç¼ç â 人工修订确认 â å¹çæäº¤ â éè¡åæ§ï¼åªæ°å»ºã䏿´æ°ãä¸åæ¥ MES", |
| | | "roles": [ |
| | | "ç©æç®¡çå" |
| | | ] |
| | | }, |
| | | { |
| | | "stage": "è¾
å©å¤å®", |
| | | "action": "è´¨æ£å+ææ +ç¼ºé· â å»ºè®®åæ ¼/ç¹é/éè´§/æ¥åº+çç±", |
| | | "roles": [ |
| | | "è´¨æ£å" |
| | | ] |
| | | }, |
| | | { |
| | | "stage": "å³ç颿µ", |
| | | "action": "缺æ/ç产æ¶é¿/ç产é£é©/交ä»åç±»é¢æµä¾è®¡åæäº§åè", |
| | | "roles": [ |
| | | "计åå" |
| | | ] |
| | | }, |
| | | { |
| | | "stage": "模æ¿è¯å«", |
| | | "action": "ä¸ä¼ æ¢ææ£éªæ¥åæä»¶(æ«æä»¶/ç
§çãçµåç PDFãWord/Excel) â åééæ½å(æææ¬å±èµ°ææ¬ãæ«æçé页转å¾) â 大模åæå端ä¸ä¼ çç»ä»¶æ¸
åäº§åºæå¹³ç»ä»¶è稿 â 人工å¨è®¾è®¡å¨ç¡®è®¤åä¿å为模æ¿çæ¬", |
| | | "roles": [ |
| | | "è´¨æ£å", |
| | | "è´¨éå·¥ç¨å¸" |
| | | ] |
| | | }, |
| | | { |
| | | "stage": "ç¥è¯æ£ç´¢", |
| | | "action": "ææ¡£âåçâMilvus åéâæ£ç´¢æ¥å£(é¢ç)", |
| | | "roles": [ |
| | | "â" |
| | | ] |
| | | } |
| | | ] |
| | | } |
| | | ] |
| | | } |
| | | } |
| | |
| | | {"key": "crm", "name": "éå®ç®¡çï¼å®¢æ·å
³ç³»ï¼", "color": "#4f9cff", "tag": "CRM", "flow": "sales", |
| | | "positioning": "éå®å端ï¼ä»çº¿ç´¢å°å款ç客æ·ç»è¥", |
| | | "problem": "客æ·èµäº§æ²æ·ãåæºè½¬åãåå审æ¹ä¸å¼ç¥¨å款管æ§", |
| | | "features": ["线索转å客æ·", "å
¬æµ·æ± ä¸é¢åä¸é", "è系人", "åæºèªå®ä¹é¶æ®µ", "è·è¿è®°å½", "æ¥ä»·å(AI OCR)", "åå(BPM审æ¹âçæéå®è®¢åÂ·æ¯æExcel导å
¥)", "å¼ç¥¨(BPM审æ¹Â·æ¯æExcel导å
¥Â·å䏿¹æ°æ®ä¸å¯éå¤å¯¼å
¥)â忬¾(å
å¼ç¥¨æ ¡éª)", "忬¾è®¡å", "éå®ç®æ ", "æ°æ®æéä¸çº§(è´è´£äºº/åªè¯»/读å)"], |
| | | "objects": ["线索", "客æ·", "è系人", "åæº", "æ¥ä»·å", "åå", "å票", "忬¾", "éå®ç®æ "], |
| | | "features": ["线索转å客æ·", "å
¬æµ·æ± ä¸é¢åä¸é", "è系人", "åæºèªå®ä¹é¶æ®µ", "è·è¿è®°å½", "æ¥ä»·å(AI OCR)", "åå(BPM审æ¹âçæéå®è®¢åÂ·æ¯æExcel导å
¥)", "å¼ç¥¨ç³è¯·(ç»å®éå®è®¢å+MESéå®åºåºå)â审æ¹âå½å
¥å票(å票å·/æ¥æ/éä»¶+å忬¾/é¢ä»æ¬¾/å°è´§æ¬¾/éªæ¶æ¬¾/è´¨ä¿éæ¶æ¬¾èç¹)", "å¼ç¥¨(BPM审æ¹Â·æ¯æExcel导å
¥Â·å䏿¹æ°æ®ä¸å¯éå¤å¯¼å
¥)â忬¾(å
å¼ç¥¨æ ¡éªÂ·æ ¸éæç»å¯æåå°è®¢å/åºåº/å¼ç¥¨)", "忬¾è®¡å(æ¶æ¬¾èç¹åå已忬¾/å®é
æ¶é´/ç¶æ)", "客æ·åºæ¶å¯¹è´¦/å·²åè´§æªå¼ç¥¨/æªæ ¸éåºæ¶è´¦é¾/æåº¦å¼ç¥¨å款è¶å¿", "éå®ç®æ ", "æ°æ®æéä¸çº§(è´è´£äºº/åªè¯»/读å)"], |
| | | "objects": ["线索", "客æ·", "è系人", "åæº", "æ¥ä»·å", "åå", "å票", "忬¾", "忬¾æ ¸éæç»", "éå®ç®æ "], |
| | | "roles": ["éå®å
å¤", "éå®ç»ç", "è´¢å¡(å¼ç¥¨å款)"], |
| | | "upstream": ["ä¸»æ°æ®(ç©æ)"], "downstream": ["è¿éå(éå®è®¢å)", "å®å(客æ·)", "AI(æ¥ä»·OCR)"], |
| | | "coreTables": ["crm_clue", "crm_customer", "crm_contact", "crm_business", "crm_sale_quotation", "crm_contract", "crm_invoice", "crm_receivable", "crm_receivable_plan", "crm_permission"]}, |
| | |
| | | {"key": "erp", "name": "è¿éåä¸è´¢å¡", "color": "#5fc79e", "tag": "ERP", "flow": "purchase", |
| | | "positioning": "åè´¸ä¸èµé忮䏿¢ï¼å MES åèµ·å®ç©æ¶å", |
| | | "problem": "éè´éå®åæ®å®¡æ¹ãæ¥ç¥¨ä»æ¬¾æ§å¶ãè®¢åæ§è¡è¿åº¦åå", |
| | | "features": ["éè´ç³è¯·(BPM)â订å(èªå¨/æå¨çæ)", "确认æ¶è´§âMESå°è´§éç¥", "å
¥åº/éè´§æ°éç¶æåå", "éè´æ¥ç¥¨(éé¢â¤è®¢å)", "仿¬¾å(å¿
é¡»å
³èæ¥ç¥¨Â·BPM)", "ä¾åºå徿¥(订å/æ¥ç¥¨/仿¬¾ä¸æµæ°´Â·å·¦å³å±ç¤ºå¼ç¥¨éé¢)", "éå®è®¢å(BPM·审æ¹éè¿èªå¨å»ºMPS)", "åºåºç¶æåå", "æ¶æ¬¾å(å
³èCRM客æ·)", "ç»ç®è´¦æ·", "AIå票OCR"], |
| | | "features": ["éè´ç³è¯·(BPM)â订å(èªå¨/æå¨çæ)", "确认æ¶è´§âMESå°è´§éç¥", "å
¥åº/éè´§æ°éç¶æåå", "éè´æ¥ç¥¨(ç»å®éè´è®¢å+MESéè´å
¥åºå·åå±å©ä½é¢åº¦æ ¡éª)", "仿¬¾å(å¿
é¡»å
³èæ¥ç¥¨Â·BPM)", "ä¾åºå徿¥(订å/æ¥ç¥¨/仿¬¾ä¸æµæ°´Â·å·¦å³å±ç¤ºå¼ç¥¨éé¢)", "éå®è®¢å(BPM·审æ¹éè¿èªå¨å»ºMPS)", "åºåºç¶æåå", "æ¶æ¬¾å(å
³èCRM客æ·)", "ç»ç®è´¦æ·", "AIå票OCR"], |
| | | "objects": ["éè´ç³è¯·", "éè´è®¢å", "éè´æ¥ç¥¨", "仿¬¾å", "ä¾åºå徿¥", "éå®è®¢å", "æ¶æ¬¾å", "ç»ç®è´¦æ·"], |
| | | "roles": ["éè´å", "éå®å", "åºçº³", "ä¼è®¡"], |
| | | "upstream": ["CRM(åå)", "SRM(询价确认)", "ä¸»æ°æ®"], "downstream": ["ç产(MPS)", "ä»å¨(æ¶å)"], |
| | | "upstream": ["CRM(åå)", "SRM(询价确认)", "ä¸»æ°æ®"], "downstream": ["ç产(MPS)", "ä»å¨(æ¶å)", "è´¢å¡(æ¥ç¥¨ä»æ¬¾å
¥è´¦)"], |
| | | "coreTables": ["erp_purchase_request", "erp_purchase_order", "erp_purchase_invoice", "erp_finance_payment", "erp_sale_order", "erp_finance_receipt", "erp_account"]}, |
| | | {"key": "finance", "name": "è´¢å¡ç®¡çï¼ä¼è®¡æ ¸ç®ï¼", "color": "#3ec9a7", "tag": "FIN", "flow": "finance", |
| | | "positioning": "ç¬ç«æ ¸ç®æ¨¡åï¼ä¼è®¡æ ¸ç® + èµäº§æ ¸ç® + è´¢å¡æ¥è¡¨çæ¿ï¼ä¸ ERP è¿éåè´¢å¡åæ®å离ï¼yudao-module-financeï¼", |
| | | "problem": "è¿éååªç®¡åæ®ä¸ç®¡è´¦ï¼ç¼ºå°ä¼è®¡ç§ç®/åè¯/账簿ä¸èµäº§ææ§æéæ²æ·ï¼æ æ³åºè´¦è¡¨ä¸èµäº§åå¼", |
| | | "features": ["ä¼è®¡ç§ç®æ (约68æ¡ä¸çº§ç§ç®ç§å·å¯å»ºä¸çº§)", "è®°è´¦åè¯(åå·èªå¨çæÂ·åå½å贷平衡åå端åéæ ¡éª)", "åè¯ç¶ææº æªè¿è´¦0âè¿è´¦10/ä½åº20ï¼å·²è¿è´¦ä¸å¯æ¹", "æ»è´¦ææé´éææ±æ»", "æç»è´¦éæ¡åå½å¹¶ç»è½¬ä½é¢", "åºå®èµäº§+è®¡æææ§", "æ å½¢èµäº§+计ææé", "ä¼è®¡æ ¸ç®çæ¿(æ¶æ¯/èµäº§/åè¯/æåº¦è¶å¿)", "éä»¶èµ°ç³»ç»éä»¶ä¸å¿ recordType=fin_voucher"], |
| | | "features": ["ä¼è®¡ç§ç®æ (约68æ¡ä¸çº§ç§ç®ç§å·å¯å»ºä¸çº§)", "è®°è´¦åè¯(åå·èªå¨çæÂ·åå½å贷平衡åå端åéæ ¡éª)", "åè¯ç¶ææº æªè¿è´¦0âè¿è´¦10/ä½åº20ï¼å·²è¿è´¦ä¸å¯æ¹", "æ»è´¦ææé´éææ±æ»", "æç»è´¦éæ¡åå½å¹¶ç»è½¬ä½é¢", "åºå®èµäº§+è®¡æææ§", "æ å½¢èµäº§+计ææé", "ä¼è®¡æ ¸ç®çæ¿(æ¶æ¯/èµäº§/åè¯/æåº¦è¶å¿)", "åè¯æ¥æºåæ®å
³è(sourceType/sourceId/sourceNoï¼å¯å溯å¼ç¥¨/忬¾/æ¥ç¥¨/仿¬¾)", "æ¥è¡¨åæ°æ¥å
¥CRM客æ·åºæ¶å¯¹è´¦/å·²åè´§æªå¼ç¥¨/æªæ ¸éåºæ¶è´¦é¾/æåº¦å¼ç¥¨å款è¶å¿", "éä»¶èµ°ç³»ç»éä»¶ä¸å¿ recordType=fin_voucher"], |
| | | "objects": ["ä¼è®¡ç§ç®", "è®°è´¦åè¯", "åè¯åå½", "åºå®èµäº§", "æ å½¢èµäº§"], |
| | | "roles": ["ä¼è®¡", "è´¢å¡ä¸»ç®¡", "èµäº§ä¼è®¡", "管çå±"], |
| | | "upstream": ["è¿éå(ERP å·²å®¡æ ¸æ¶è´§/仿¬¾/è´éåæ®)"], "downstream": ["è´¢å¡æ¥è¡¨çæ¿", "BI 管ç驾驶è±"], |
| | | "upstream": ["è¿éå(ERP å·²å®¡æ ¸æ¶è´§/仿¬¾/è´éåæ®)", "CRM(å¼ç¥¨/忬¾/æ ¸é/对账æ¥è¡¨)"], "downstream": ["è´¢å¡æ¥è¡¨çæ¿", "BI 管ç驾驶è±"], |
| | | "coreTables": ["fin_account_subject", "fin_voucher", "fin_voucher_entry", "fin_fixed_asset", "fin_intangible_asset"]}, |
| | | {"key": "pro", "name": "ç产管ç", "color": "#e0b34f", "tag": "MES-PRO", "flow": "production", |
| | | "positioning": "ç产æ§è¡æ ¸å¿ï¼è®¡å-å·¥å-ä»»å¡-æ¥å·¥", |
| | |
| | | {"key": "aftersales", "name": "å®åæå¡", "color": "#c78bd6", "tag": "AFTER", "flow": "aftersales", |
| | | "positioning": "客æ·åé¦å°éè´§/ç»´ä¿®/鿬¾éç¯", |
| | | "problem": "å®åå·¥åæµè½¬ãéè´§ä¸è´¨æ£å
¥åºé款ç跨系ç»èå¨", |
| | | "features": ["å·¥åå
æ(è稿âå¤çä¸âå¾
å
¥åºâå¾
鿬¾âå®ç»âå
³é)", "é®é¢å¤å®(ä¸è¬/ç»´ä¿®/éè´§)", "ç»´ä¿®(ç°åº/è¿å/è¿ç¨)", "éè´§ç³è¯·âèªå¨å»º MES éå®éè´§å", "è´¨æ£ç»è®º/å
¥åº/鿬¾ä¸éåè°", "è¡çº§æ°æ®æéåè§å¾"], |
| | | "objects": ["å®åå·¥å", "维修记å½", "éè´§ç³è¯·"], |
| | | "features": ["å·¥åå
æ(è稿âå¤çä¸âå¾
å
¥åºâå¾
鿬¾âå®ç»âå
³é)", "é®é¢å¤å®(ä¸è¬/ç»´ä¿®/éè´§)", "客æ·è¯æ±åé¦æè¿°+éä»¶", "å¤çç»æ+éä»¶", "å·¥åæµè½¬è®°å½", "ç»´ä¿®(ç°åº/è¿å/è¿ç¨)", "éè´§ç±ä»å¨ç©æµåèµ·âMES éå®éè´§å(åå®åéè´§ç³è¯·é¡µé¢å·²ä¸çº¿)", "è´¨æ£ç»è®º/å
¥åº/鿬¾ä¸éåè°", "è¡çº§æ°æ®æéåè§å¾"], |
| | | "objects": ["å®åå·¥å", "å·¥åæµè½¬è®°å½", "维修记å½", "éè´§ç³è¯·(åå°ä¿ç)"], |
| | | "roles": ["客æ", "维修工ç¨å¸", "å®å管çå"], |
| | | "upstream": ["CRM(客æ·)", "ERP(éå®è®¢å)"], "downstream": ["ä»å¨(éå®éè´§)", "è´¨é(RQC)", "è´¢å¡(鿬¾)"], |
| | | "coreTables": ["after_sale_ticket", "after_sale_ticket_item", "after_sale_repair", "after_sale_return", "after_sale_permission"]}, |
| | | "coreTables": ["after_sale_ticket", "after_sale_ticket_item", "after_sale_ticket_flow", "after_sale_repair", "after_sale_return", "after_sale_permission"]}, |
| | | {"key": "hrm", "name": "人åèµæº", "color": "#9db85a", "tag": "HRM", "flow": null, |
| | | "positioning": "åå·¥å
¥è½¬è°ç¦»ä¸èå¤èªé
¬", |
| | | "problem": "äººäºæµç¨å®¡æ¹åãç¦»èæ°æ®ä¸ä¸¢(交æ¥)ãç®èªèªå¨å", |
| | | "features": ["å工档æ¡(å
¥èèªå¨å»ºç³»ç»è´¦å·)", "请å/å ç/è°å²/离è BPM 审æ¹", "离èäº¤æ¥æ å° expandUserIds", "èå¤(ç§»å¨ç«¯æçèå¤ç¶æÂ·æå¡Â·è§å·æç·补å¡å®¡æ¹Â·æåº¦æ±æ»)", "èªé
¬(åºå-社ä¿å
¬ç§¯é-个ç¨-è¯·åæ£æ¬¾Â·1.5/2/3åå çè´¹Â·åæ¾å°è´¦)", "å¹è®è¯ä¹¦(SQLå
è¡å¾
å®ç°)"], |
| | | "features": ["å工档æ¡(å
¥èèªå¨å»ºç³»ç»è´¦å·)", "请å/å ç/è°å²/离è BPM 审æ¹", "离è交æ¥åæ¶è½¬ç§»åå·¥ID/ç¨æ·ID/ä¸å¡æ°æ® expandUserIds", "离èå°æèªå¨æåå·¥ç¶ææ¹ä¸ºç¦»èå¹¶åç¨ç³»ç»è´¦å·", "èå¤(ç§»å¨ç«¯æçèå¤ç¶æÂ·æå¡Â·è§å·æç·补å¡å®¡æ¹Â·æåº¦æ±æ»)", "èªé
¬(åºå-社ä¿å
¬ç§¯é-个ç¨-è¯·åæ£æ¬¾Â·1.5/2/3åå çè´¹Â·åæ¾å°è´¦)", "å¹è®è¯ä¹¦(SQLå
è¡å¾
å®ç°)"], |
| | | "objects": ["åå·¥", "请åå", "离èç³è¯·", "äº¤æ¥æ å°", "èå¤è®°å½", "èªé
¬æ ¸ç®"], |
| | | "roles": ["HR", "é¨é¨ä¸»ç®¡", "åå·¥æ¬äºº"], |
| | | "upstream": [], "downstream": ["忍¡å(æ°æ®å¯è§æ§æ©å±)", "system(è´¦å·)"], |
| | |
| | | {"name": "åæº", "module": "éå®ç®¡ç", "table": "crm_business", "doc": "é宿ºä¼ï¼DB é
ç½®å¼é¶æ®µæ¨è¿ï¼ç»ææ: èµ¢/è¾/æ æ", "upstream": ["客æ·"], "downstream": ["æ¥ä»·å", "åå"], "keywords": "åæº business èµ¢å è¾å é¶æ®µ"}, |
| | | {"name": "æ¥ä»·å", "module": "éå®ç®¡ç", "table": "crm_sale_quotation", "doc": "QTç¼å·ï¼é MDM ç©ææ¥ä»·ï¼AI OCR å½å
¥ï¼è稿â已转åå", "upstream": ["åæº"], "downstream": ["åå"], "keywords": "æ¥ä»· quotation QT"}, |
| | | {"name": "åå", "module": "éå®ç®¡ç", "table": "crm_contract", "doc": "HTç¼å·ï¼BPM 审æ¹(0è稿/10审æ¹ä¸/20éè¿/30驳å/40åæ¶/50ä½åº)ï¼éè¿åå¯çæéå®è®¢åï¼æ¯æ Excel 导å
¥ï¼ä¸ååå¤äº§åæç»è¡ãåå¹¶åå
æ ¼èªå¨æå¹³ï¼å®¢æ·ä¸ç©ææåç§°/ç¼ç æ ¡éªï¼ï¼äº§åæç»å¸¦åºç©æåç§°/ç¼ç /æ¡ç /è§æ ¼åå·/计éåä½ï¼å é¤ååæ¶è¿å¸¦å é¤äº§åæç»ï¼ä¸çå¤å¿æ°æ®", "upstream": ["æ¥ä»·å"], "downstream": ["éå®è®¢å", "忬¾è®¡å", "å¼ç¥¨"], "keywords": "åå contract å®¡æ¹ å¯¼å
¥"}, |
| | | {"name": "å票", "module": "éå®ç®¡ç", "table": "crm_invoice", "doc": "KPç¼å·ï¼å¯ç空èªå¨çæãç³»ç»å
å¯ä¸ï¼ï¼BPM 审æ¹ï¼ç´¯è®¡å¼ç¥¨â¤ååé¢ï¼éä»¶å¿
ä¼ ï¼æ¯æ Excel 导å
¥ï¼ä»
æ°å¢ä¸æ´æ°ï¼ååé¡»å®¡æ ¸éè¿ä¸æ¬æ¬¡éé¢â¤ååå©ä½å¯å¼ç¥¨é¢ï¼å䏿¹æ°æ®ä¸å¯éå¤å¯¼å
¥ââåååä¸å票å·ç ç¸åãæå票å·ç ç空æ¶å¼ç¥¨éé¢+å票æ¬å¤´+å¼ç¥¨æ¥æç¸åå³å¤éå¤ï¼æä»¶å
éå¤è¡ä¸åºå
å·²æåé½æè¯¥è¡å¹¶åæ¾ç»´åº¦ä¸å®é
å¼ï¼", "upstream": ["åå"], "downstream": ["忬¾"], "keywords": "å¼ç¥¨ å票 invoice 导å
¥ å»é"}, |
| | | {"name": "忬¾", "module": "éå®ç®¡ç", "table": "crm_receivable", "doc": "HKç¼å·ï¼å建å³å®¡æ¹ä¸(æå¨å®¡æ ¸)ï¼å¼ºå¶å
å¼ç¥¨ï¼éé¢åæ ¡éª", "upstream": ["åå", "å票"], "downstream": ["æ¶æ¬¾å(å
³è)"], "keywords": "忬¾ æ¶æ¬¾è®¡å receivable"}, |
| | | {"name": "å票", "module": "éå®ç®¡ç", "table": "crm_invoice", "doc": "KPç¼å·ï¼å¯ç空èªå¨çæãç³»ç»å
å¯ä¸ï¼ï¼BPM 审æ¹ï¼ç´¯è®¡å¼ç¥¨â¤ååé¢ï¼éä»¶å¿
ä¼ ï¼å¼ç¥¨ç³è¯·é¡»ç»å® ERP éå®è®¢åä¸ MES éå®åºåºåï¼å®¡æ¹éè¿åè¿å
¥å½å
¥åç¥¨é¶æ®µ(entry_status 0å¾
å½å
¥â10å·²å½å
¥)ï¼å½å
¥æ¶å¡«åå票å·ç /æ¥æ/é件并设置å忬¾/é¢ä»æ¬¾/å°è´§æ¬¾/éªæ¶æ¬¾/è´¨ä¿éæ¶æ¬¾èç¹ï¼æ¯æ Excel 导å
¥ï¼ä»
æ°å¢ä¸æ´æ°ï¼ååé¡»å®¡æ ¸éè¿ä¸æ¬æ¬¡éé¢â¤ååå©ä½å¯å¼ç¥¨é¢ï¼å䏿¹æ°æ®ä¸å¯éå¤å¯¼å
¥ââåååä¸å票å·ç ç¸åãæå票å·ç ç空æ¶å¼ç¥¨éé¢+å票æ¬å¤´+å¼ç¥¨æ¥æç¸åå³å¤éå¤ï¼æä»¶å
éå¤è¡ä¸åºå
å·²æåé½æè¯¥è¡å¹¶åæ¾ç»´åº¦ä¸å®é
å¼ï¼", "upstream": ["åå", "éå®è®¢å", "éå®åºåºå"], "downstream": ["忬¾", "忬¾è®¡å", "è®°è´¦åè¯"], "keywords": "å¼ç¥¨ å票 invoice 导å
¥ å»é å¼ç¥¨ç³è¯· å½å
¥å票 åºåºå"}, |
| | | {"name": "忬¾", "module": "éå®ç®¡ç", "table": "crm_receivable", "doc": "HKç¼å·ï¼å建å³å®¡æ¹ä¸(æå¨å®¡æ ¸)ï¼å¼ºå¶å
å¼ç¥¨ï¼éé¢åæ ¡éªï¼æ°å¢/ç¼è¾å¯å¸¦æ ¸éæç» items(20éå®è®¢å/21éå®åºåº/23å¼ç¥¨)ï¼æç»å计å¿
é¡»çäºå款éé¢ï¼å®¡æ ¸éè¿ååå忬¾è®¡å已忬¾é¢/å®é
忬¾æ¶é´/ç¶æ(0æªå款10é¨å忬¾20已忏
)", "upstream": ["åå", "å票", "éå®è®¢å", "éå®åºåºå"], "downstream": ["æ¶æ¬¾å(å
³è)", "忬¾æ ¸éæç»", "忬¾è®¡å", "è®°è´¦åè¯"], "keywords": "忬¾ æ¶æ¬¾è®¡å receivable æ ¸é"}, |
| | | {"name": "忬¾æ ¸éæç»", "module": "éå®ç®¡ç", "table": "crm_receivable_item", "doc": "æ¯è¡æå款é颿 ¸éå°ä¸å¼ ä¸å¡åæ®ï¼biz_type 20éå®è®¢å/21éå®åºåº/23å¼ç¥¨ï¼biz_noãåæ®éé¢ãå·²æ ¸ééé¢ç±å端æ biz_id åå¡«ï¼æ¯è¡æ ¸éé¢ä¸å¾è¶
è¿è¯¥åæ®å©ä½åºæ¶ï¼ä¸ä¼ items ä¸å¸¦ invoice_id æ¶èªå¨çæä¸æ¡å¼ç¥¨æ ¸éè¡", "upstream": ["忬¾", "éå®è®¢å", "éå®åºåºå", "å票"], "downstream": ["客æ·åºæ¶å¯¹è´¦", "æªæ ¸éåºæ¶æ¥è¡¨"], "keywords": "æ ¸é æ ¸éæç» write off item receivable_item"}, |
| | | {"name": "éå®ç®æ ", "module": "éå®ç®¡ç", "table": "crm_sales_target", "doc": "å¹´/å£/æÃ个人/é¨é¨/产å维度çåå忬¾çç®æ ", "upstream": [], "downstream": ["ä¸ç»©ç»è®¡"], "keywords": "ç®æ target ä¸ç»©"}, |
| | | {"name": "ä¾åºå", "module": "ä¾åºå管ç", "table": "srm_supplier", "doc": "ä¾åºåæ¡£æ¡ï¼æ§ç
§/ç¨å·ï¼å¤ä¸ªè系人(srm_supplier_contact)ä¸å¤ä¸ªé¶è¡è´¦æ·(srm_supplier_bank·å«é¶è¡è¡å·)ï¼ä¸»è¡¨ä¿çé»è®¤è系人/é»è®¤é¶è¡å段ï¼ERP ä¸ MES å
±ç¨", "upstream": ["æå·¥å»ºæ¡£/Excel 导å
¥"], "downstream": ["询价æ¯ä»·", "ææ ä¿è¯é", "éè´è®¢å", "å°è´§éç¥", "ä¾åºåéè´§", "ä¾åºå徿¥"], "keywords": "ä¾åºå supplier vendor è系人 弿·è¡ é¶è¡è¡å·"}, |
| | | {"name": "询价æ¯ä»·", "module": "ä¾åºå管ç", "table": "srm_inquiry", "doc": "XJç¼å·ï¼è稿0â已转订å20â已忶30(10询价ä¸ä¸ºåå²ç¶æ)ï¼æ°å¢/ç¼è¾æ¶ä¸å¹¶å½å
¥äº§åè¡Ãåä¸ä¾åºåæ¥ä»·(srm_inquiry_quote)å¹¶é宿¯ä¸ªäº§åç䏿 ä¾åºåï¼æ éåç¬çæ¥ä»·/æ¯ä»·æ¥éª¤ï¼ç¡®è®¤åæä¸æ ä¾åºåæåçæéè´è®¢åèç¨¿å¹¶è®°å½ srm_inquiry_order", "upstream": ["ä¾åºå", "ä¸»æ°æ®(ç©æ)"], "downstream": ["éè´è®¢å(è稿)"], "keywords": "询价 æ¯ä»· æ¥ä»· 䏿 inquiry quote"}, |
| | | {"name": "ææ ä¿è¯é", "module": "ä¾åºå管ç", "table": "srm_bid_bond", "doc": "BZç¼å·å°è´¦ï¼å
³èä¾åºå/询价å/éè´è®¢åï¼è®°å½ä¿è¯ééé¢ãç¼´çº³æ¥æãæ¯å¦ä¸æ ãéåç¶æ(0æªé1é¨å2å·²é3æ éé)/éåéé¢/é忥æ", "upstream": ["ä¾åºå", "询价æ¯ä»·", "éè´è®¢å"], "downstream": ["ä¾åºå徿¥(åè)"], "keywords": "ææ ä¿è¯é 䏿 éå bid bond"}, |
| | | {"name": "éè´ç³è¯·", "module": "è¿éå", "table": "erp_purchase_request", "doc": "CGSQç¼å·ï¼BPM 审æ¹ï¼éè¿åæä¾åºåèªå¨çæè®¢å", "upstream": ["ç产缺å£(人工)"], "downstream": ["éè´è®¢å"], "keywords": "éè´ç³è¯· è¯·è´ request"}, |
| | | {"name": "éè´è®¢å", "module": "è¿éå", "table": "erp_purchase_order", "doc": "èååãéè´å°è´¦ãï¼CGDDç¼å·ï¼BPM 审æ¹(è稿0â审æ¹ä¸15âå·²å®¡æ ¸20)ï¼å
¥åºç¶æ:æª0é¨å1å
¨é¨2ï¼è¡¨å¤´å«éè´ç±»å(ç产/åå
¬ç¨å/å
¶ä»)ãååå·(æå·¥è¾å
¥ä¸èªå¨çæ)ã项ç®åç§°ã仿¬¾æ¥æ(å¿
å¡«ï¼è¶
30å¤©è´¦ææ çº¢)ã仿¬¾æ¹å¼(çµæ±/æ±ç¥¨/ç°é/ææºæ¯ä»)ï¼æç»äº§åç¼å·å¿«ç
§ MDM ç©æç¼ç ï¼æ¥æºå¯ä¸ºéè´ç³è¯·ã询价æ¯ä»·ç¡®è®¤çæçè稿æéå®è®¢å/ç产工å(æ¥æºåå·å溯)ï¼å价为å«ç¨åä»·ï¼ä»·ç¨å计=åä»·Ãæ°éï¼ç¨é¢ä»å«ç¨éé¢ä¸åç®(ä¸åé¢å¤å ç¨)", "upstream": ["éè´ç³è¯·", "询价æ¯ä»·(ç¡®è®¤ä¸æ )"], "downstream": ["å°è´§éç¥", "éè´æ¥ç¥¨", "ä¾åºåéè´§(约æç©æ)", "ä¾åºå徿¥"], "keywords": "éè´è®¢å purchase"}, |
| | | {"name": "éè´æ¥ç¥¨", "module": "è¿éå", "table": "erp_purchase_invoice", "doc": "FPDç¼å·ï¼AI OCR é¢å¡«ï¼ç´¯è®¡â¤è®¢åæ»ä»·ï¼ä»æ¬¾åçåç½®ï¼ä¾åºå徿¥å³ä¾§å±ç¤ºå¼ç¥¨éé¢/å·²ä»/å©ä½åºä»", "upstream": ["éè´è®¢å"], "downstream": ["仿¬¾å", "ä¾åºå徿¥"], "keywords": "æ¥ç¥¨ å票 éè´å票"}, |
| | | {"name": "éè´æ¥ç¥¨", "module": "è¿éå", "table": "erp_purchase_invoice", "doc": "FPDç¼å·ï¼AI OCR é¢å¡«ï¼ç´¯è®¡â¤è®¢åæ»ä»·ï¼ä»æ¬¾åçåç½®ï¼å¿
须忶ç»å®éè´è®¢åä¸ MES éè´å
¥åºå(item_receipt_id)ï¼æè®¢åä¸å
¥åºå两å±å©ä½å¯æ¥ç¥¨é¢åº¦æ ¡éªï¼ä¾åºå徿¥å³ä¾§å±ç¤ºå¼ç¥¨éé¢/å·²ä»/å©ä½åºä»", "upstream": ["éè´è®¢å", "MES éè´å
¥åºå"], "downstream": ["仿¬¾å", "ä¾åºå徿¥", "è®°è´¦åè¯"], "keywords": "æ¥ç¥¨ å票 éè´å票 å
¥åºå"}, |
| | | {"name": "仿¬¾å", "module": "è´¢å¡", "table": "erp_finance_payment", "doc": "FKDç¼å·ï¼å¿
é¡»å
³èæ¥ç¥¨+éä»¶ï¼ç´¯è®¡â¤æ¥ç¥¨éé¢ï¼BPM 审æ¹", "upstream": ["éè´æ¥ç¥¨"], "downstream": ["ç»ç®è´¦æ·", "ä¾åºå徿¥"], "keywords": "仿¬¾ åºä» payment"}, |
| | | {"name": "ä¾åºå徿¥", "module": "è¿éå", "table": "æ ç¬ç«è¡¨(èåè§å¾)", "doc": "æä¾åºå+æ¶é´èå´èåéè´è®¢å/æ¥ç¥¨/仿¬¾ï¼æ±æ»ç´¯è®¡éè´é¢ã累计å¼ç¥¨é¢ãç´¯è®¡ä»æ¬¾é¢ãæªä»ä½é¢ï¼å·¦ä¾§è®¢åè¡å«å·²å¼ç¥¨/æªå¼ç¥¨éé¢ï¼å³ä¾§æ¥ç¥¨è¡å«å¼ç¥¨éé¢/å·²ä»/å©ä½åºä»", "upstream": ["éè´è®¢å", "éè´æ¥ç¥¨", "仿¬¾å"], "downstream": [], "keywords": "ä¾åºå徿¥ 对账 å¼ç¥¨éé¢ åºä» statement"}, |
| | | {"name": "æ¶æ¬¾å", "module": "è´¢å¡", "table": "erp_finance_receipt", "doc": "SKDç¼å·ï¼å
³è CRM å®¢æ·æ ¡éªï¼æ BPM(æå¨å®¡æ ¸)", "upstream": ["éå®(å¼±å
³è)"], "downstream": ["ç»ç®è´¦æ·"], "keywords": "æ¶æ¬¾ åºæ¶ receipt"}, |
| | | {"name": "ä¼è®¡ç§ç®", "module": "ä¼è®¡æ ¸ç®", "table": "fin_account_subject", "doc": "ç§ç®æ ï¼parent_id èªå
³èï¼ç§ç®ç±»å1èµäº§2è´åº3æç4ææ¬5æçï¼ä½é¢æ¹å1å2è´·ï¼ç¶æ0å¯ç¨1ç¦ç¨ï¼è´¦è¡¨ä¸åå½ç»ä¸æ subject_code åæ°", "upstream": ["ä¼è®¡ç§ç®ç§å约68æ¡ä¸çº§ç§ç®"], "downstream": ["è®°è´¦åè¯åå½", "æ»è´¦", "æç»è´¦"], "keywords": "ä¼è®¡ç§ç® ç§ç® subject account èµäº§ç±» è´åºç±» æçç±»"}, |
| | | {"name": "è®°è´¦åè¯", "module": "ä¼è®¡æ ¸ç®", "table": "fin_voucher", "doc": "åè¯åå·å¯ç空ç±å端èªå¨çæï¼ç¶æ æªè¿è´¦0/å·²è¿è´¦10/å·²ä½åº20ï¼å·²è¿è´¦ä¸å¯æ¹ï¼æªè¿è´¦ä¸å·²è¿è´¦åå¯ä½åºï¼æªè¿è´¦ä¸å·²ä½åºå¯å é¤ï¼éä»¶æ recordType=fin_voucher æç³»ç»éä»¶ä¸å¿", "upstream": ["ä¼è®¡ç§ç®"], "downstream": ["æ»è´¦", "æç»è´¦", "è´¢å¡æ¥è¡¨çæ¿"], "keywords": "è®°è´¦åè¯ åè¯ voucher è¿è´¦ ä½åº å贷平衡"}, |
| | | {"name": "è®°è´¦åè¯", "module": "ä¼è®¡æ ¸ç®", "table": "fin_voucher", "doc": "åè¯åå·å¯ç空ç±å端èªå¨çæï¼ç¶æ æªè¿è´¦0/å·²è¿è´¦10/å·²ä½åº20ï¼å·²è¿è´¦ä¸å¯æ¹ï¼æªè¿è´¦ä¸å·²è¿è´¦åå¯ä½åºï¼æªè¿è´¦ä¸å·²ä½åºå¯å é¤ï¼å¯éè¿ source_type/source_id/source_no å
³èå¼ç¥¨/忬¾/æ¥ç¥¨/仿¬¾çæ¥æºåæ®å¹¶æ¯æææ¥æºåå·æ£ç´¢ï¼éä»¶æ recordType=fin_voucher æç³»ç»éä»¶ä¸å¿", "upstream": ["ä¼è®¡ç§ç®", "å¼ç¥¨", "忬¾", "éè´æ¥ç¥¨", "仿¬¾å"], "downstream": ["æ»è´¦", "æç»è´¦", "è´¢å¡æ¥è¡¨çæ¿"], "keywords": "è®°è´¦åè¯ åè¯ voucher è¿è´¦ ä½åº å贷平衡"}, |
| | | {"name": "åè¯åå½", "module": "ä¼è®¡æ ¸ç®", "table": "fin_voucher_entry", "doc": "åè¯ä¸éè¡åå½ï¼ç§ç®ç¼ç +å/è´·éé¢+è¾
婿 ¸ç®(1客æ·2ä¾åºå3é¨é¨4åå·¥5项ç®)ï¼ä¸è¡ä¸å¯åè´·åæ¶å¤§äº0ï¼å
¨è¡¨åè´·å计å¿
é¡»ç¸çä¸å¤§äº0", "upstream": ["è®°è´¦åè¯", "ä¼è®¡ç§ç®"], "downstream": ["æ»è´¦", "æç»è´¦"], "keywords": "åè¯åå½ åå½ entry åæ¹ è´·æ¹ è¾
婿 ¸ç®"}, |
| | | {"name": "åºå®èµäº§", "module": "ä¼è®¡æ ¸ç®", "table": "fin_fixed_asset", "doc": "èµäº§å¡çï¼ç¶æ 1å¨ç¨/2é²ç½®/3ç»´ä¿®ä¸/4å·²æ¥åºï¼æææ§é¢=(åå¼Ã(1-æ®å¼ç))÷(å¹´éÃ12)ï¼ç´¯è®¡ææ§ä¸åå¼ç±è®¡æç´¯å ï¼ä¸æ¥æ¶åç«¯ä¼ å¼", "upstream": [], "downstream": ["è´¢å¡æ¥è¡¨çæ¿", "æ»è´¦"], "keywords": "åºå®èµäº§ ææ§ èµäº§å¡ç fixed asset æ®å¼ç"}, |
| | | {"name": "æ å½¢èµäº§", "module": "ä¼è®¡æ ¸ç®", "table": "fin_intangible_asset", "doc": "æ å½¢èµäº§å¡ç(è¯ä¹¦ç¼å·/æææ)ï¼ç¶æ 1å¨ç¨/2已失æ/3å·²æéå®ï¼ææéé¢=(åå¼Ã(1-æ®å¼ç))÷(æéå¹´éÃ12)ï¼ç´¯è®¡æéä¸åå¼ç±è®¡æç´¯å ", "upstream": [], "downstream": ["è´¢å¡æ¥è¡¨çæ¿", "æ»è´¦"], "keywords": "æ å½¢èµäº§ æé 软件è使 ä¸å© intangible æææ"}, |
| | |
| | | {"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ï¼è´¨æ£å·¥åºæ¥å·¥å®¡æ¹å转å¾
æ£éªå¹¶çæ 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_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": "åè´§éç¥å®¡æ ¸åçæï¼æäº¤åæ 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_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_stock_taking_task", "doc": "éæ/卿çç¹ï¼è¡ç»æ:æ£å¸¸/çç(ADJUST_IN)/çäº(ADJUST_OUT)ï¼å¯å»ç»åºåãç²ç", "upstream": ["åºåå°è´¦"], "downstream": ["åºåå°è´¦(è°æ´)"], "keywords": "çç¹ çç çäº stock taking"}, |
| | |
| | | {"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"}, |
| | | {"name": "å®åå·¥å", "module": "å®å", "table": "after_sale_ticket", "doc": "è稿0âå¤çä¸10âå¾
å
¥åº30âå¾
鿬¾40âå®ç»50âå
³é60/åæ¶99ï¼å¤å®:ä¸è¬/ç»´ä¿®/éè´§", "upstream": ["客æ·åé¦(人工å½å
¥)"], "downstream": ["维修记å½", "éè´§ç³è¯·"], "keywords": "å®å å·¥å ticket ç»´ä¿®"}, |
| | | {"name": "éè´§ç³è¯·", "module": "å®å", "table": "after_sale_return", "doc": "è稿0âå·²å®¡æ ¸20(èªå¨å»ºMESéè´§å)â已质æ£40âå·²å
¥åº50â已鿬¾60âå
³é70ï¼ç±»å:鿬¾éè´§/æ¢è´§/ä»
鿬¾", "upstream": ["å®åå·¥å"], "downstream": ["éå®éè´§å", "鿬¾"], "keywords": "å®åéè´§ return"}, |
| | | {"name": "åå·¥", "module": "人å", "table": "hrm_employee", "doc": "å¨è1/è¯ç¨2/离è3ï¼å
¥èèªå¨å»ºç³»ç»è´¦å·", "upstream": [], "downstream": ["äº¤æ¥æ å°", "èå¤", "èªé
¬"], "keywords": "åå·¥ å
¥è employee"}, |
| | | {"name": "离è交æ¥", "module": "人å", "table": "hrm_user_handover", "doc": "fromâto æ å°ï¼å·²å®æ20 å expandUserIds æ©å±äº¤æ¥äººå¯è§æ°æ®ï¼å½ååä¸å¡æ¨¡åå°æªå®é
æ¥å
¥è°ç¨ï¼", "upstream": ["离èç³è¯·"], "downstream": ["忍¡åæçæ°æ®æ¥è¯¢"], "keywords": "äº¤æ¥ ç¦»è handover expandUserIds"}, |
| | | {"name": "å®åå·¥å", "module": "å®å", "table": "after_sale_ticket", "doc": "è稿0âå¤çä¸10âå¾
å
¥åº30âå¾
鿬¾40âå®ç»50âå
³é60/åæ¶99ï¼å¤å®:ä¸è¬/ç»´ä¿®/éè´§ï¼å®¢æ·è¯æ±åé¦æè¿°+éä»¶ãå¤çç»æ+éä»¶ï¼å建/æ´æ°/å¤å®/å®ç»/彿¡£/åæ¶/å访åå
¥æµè½¬è®°å½", "upstream": ["客æ·åé¦(人工å½å
¥)"], "downstream": ["维修记å½", "ä»å¨éå®éè´§(åéè´§ç³è¯·é¡µé¢å·²ä¸çº¿)"], "keywords": "å®å å·¥å ticket ç»´ä¿® 客æ·è¯æ± å¤çç»æ æµè½¬è®°å½"}, |
| | | {"name": "å·¥åæµè½¬è®°å½", "module": "å®å", "table": "after_sale_ticket_flow", "doc": "å®åå·¥åæ¯æ¬¡å¨ä½ççï¼å¨ä½ç¼ç /åç§°ãåæ´ååç¶æãå
容ãæä½äººãæ¶é´", "upstream": ["å®åå·¥å"], "downstream": [], "keywords": "å®å æµè½¬è®°å½ flow"}, |
| | | {"name": "éè´§ç³è¯·", "module": "å®å", "table": "after_sale_return", "doc": "åå°ä¿çï¼å®å页é¢å·²ä¸çº¿ï¼è稿0âå·²å®¡æ ¸20(èªå¨å»ºMESéè´§å)â已质æ£40âå·²å
¥åº50â已鿬¾60âå
³é70ï¼ç±»å:鿬¾éè´§/æ¢è´§/ä»
鿬¾", "upstream": ["å®åå·¥å"], "downstream": ["éå®éè´§å", "鿬¾"], "keywords": "å®åéè´§ return"}, |
| | | {"name": "åå·¥", "module": "人å", "table": "hrm_employee", "doc": "å¨è1/è¯ç¨2/离è3ï¼å
¥èèªå¨å»ºç³»ç»è´¦å·ï¼ç¦»èç³è¯·å°æèªå¨ç½®ä¸ºç¦»è3å¹¶åç¨ç³»ç»è´¦å·", "upstream": [], "downstream": ["äº¤æ¥æ å°", "èå¤", "èªé
¬"], "keywords": "åå·¥ å
¥è employee 离è"}, |
| | | {"name": "离èç³è¯·", "module": "人å", "table": "hrm_resignation_application", "doc": "è稿0â审æ¹ä¸10âéè¿20/驳å30/æ¤é40ï¼å®¡æ¹éè¿åå¯äº¤æ¥0â10â20ï¼å°æä»»å¡åå®é
ç¦»èæ¥æãæåå·¥ç¶ææ¹ä¸ºç¦»è3å¹¶åç¨ç³»ç»è´¦å·", "upstream": ["åå·¥"], "downstream": ["å工档æ¡ç¶æ", "离è交æ¥"], "keywords": "离è resignation å®¡æ¹ äº¤æ¥ èªå¨ç¦»è"}, |
| | | {"name": "离è交æ¥", "module": "人å", "table": "hrm_user_handover", "doc": "åæ¶è®°å½ç¦»è/交æ¥åæ¹åå·¥IDä¸ç¨æ·IDï¼äº¤æ¥å®æ20 å expandUserIds æ©å±äº¤æ¥äººå¯è§æ°æ®ï¼å®¡æ¹éè¿ä¸å°é¢è®¡ç¦»èæ¥æåèªå¨æåå·¥ç¶ææ¹ä¸ºç¦»è3å¹¶åç¨ç³»ç»è´¦å·", "upstream": ["离èç³è¯·"], "downstream": ["忍¡åæçæ°æ®æ¥è¯¢", "å工档æ¡ç¶æ"], "keywords": "äº¤æ¥ ç¦»è handover expandUserIds èªå¨ç¦»è"}, |
| | | {"name": "æç计å", "module": "设å¤", "table": "mes_cal_plan", "doc": "çç»Ãçæ¬¡Ãæ¥ææçï¼ä¾ç产ä¸èå¤å¼ç¨", "upstream": [], "downstream": ["ç产任å¡", "èå¤"], "keywords": "æç çç» çæ¬¡ æ¥å"}, |
| | | {"name": "æ¥å模æ¿", "module": "è´¨æ£æ¥å", "table": "qc_report_template", "doc": "æºè½è´¨æ£æ¥å模æ¿ï¼å¯ç¨0/åç¨1ï¼ç»å¸å
容åå¨ qc_report_template_versionï¼è稿0/å·²åå¸1/å·²åç¨2ï¼å·²åå¸ä¸å¯è¦çï¼ï¼currentVersion æåå½åå·²åå¸çæ¬ï¼æºæä»¶ç» AI 导å
¥è¯å«æè稿åç±äººå·¥ç¡®è®¤ææä¸ºçæ¬ï¼å䏿¨¡æ¿éå¤å¯¼å
¥æãæ¿æ¢ãå¤çââå
å æ§éä»¶ï¼è¿å¸¦ blob è¡ä¸ç£çæä»¶ï¼åç»æ°çï¼ä¸çå¤å¿æä»¶ï¼å 餿¨¡æ¿ä¼è¿å¸¦æ¸
éä»¶", "upstream": ["人工设计(GrapesJS 设计å¨)", "AI 导å
¥è稿(qc-report/ai-import/draft)"], "downstream": ["模æ¿çæ¬", "æ¥åå®ä¾"], "keywords": "æ¥åæ¨¡æ¿ è´¨æ£æ¥å template è®¾è®¡å¨ çæ¬ AI导å
¥ è¯å« è稿 æºæä»¶æ¿æ¢"}, |
| | | {"name": "æ¥åå®ä¾", "module": "è´¨æ£æ¥å", "table": "qc_report_instance", "doc": "åºä»¶äº§ç©ï¼ç¼å· QR+yyyyMMdd+4使µæ°´æå¤©ç¬ç«ä¸ä¸å¡å¯ä¸ï¼å¯æ¾å¼æå®è¦çï¼æ³¨æ uk_report_no ä¸åºå软å é¤ï¼å æçå·ä¸åæ¶ï¼ï¼ä¸¤æ¡åºä»¶å
¥å£ï¼éç¨ generateï¼è°ç¨æ¹èªå¸¦ contextï¼ä¸ generate-from-qcï¼æ°æ®ä» MES è´¨æ£ååï¼æéç qc-report:instance:generate å·²å
¥ system_menu id=1075416ï¼äºéæ ¡éªæä¸å¡ä¼å
çº§åªæ¥ç¬¬ä¸å¤ï¼105_000 ç±»åéæ³ / 105_001 åæ®ä¸åå¨ / 105_002 æªå®æ / 105_003 æªå¤å® / 105_005 模æ¿ç±»åä¸ç¬¦ / 105_006 æ å¯ç¨æ£éªé¡¹ï¼åå¼ è´¨æ£åå表çè¡æä½ãåºæ¥åãä»
å¨ status=已宿æ¶å¯è§ï¼å¼¹çªåªå reportType ä¸è´ã模æ¿å¯ç¨ãä¸ currentVersion æåççæ¬å·²åå¸ç模æ¿ï¼å端 /qc-report/template/selectable å¤å®ââåç¨çæ¬ä¸æ¸
空 currentVersionï¼å端æ¿åé¡µç»æèªå·±æ¨å¯¼ä¼æ¼ï¼ï¼ç»æå°±å°å±ç¤ºå¹¶è·³æ¬é¡µå表ï¼ï¼å»ç» data_snapshotï¼å¤å®åæ°æ®ï¼å«å端ç®å¥½ç PASS/FAIL ä¸åæ ¼çï¼ä¸ render_htmlï¼regenerate åªé渲æçãæ°æ®ä¸ç¼å·ä¸åï¼business_id/business_type å MES 表åï¼mes_qc_iqc çï¼ä¸åæ® IDï¼å¯åæ¥ãä¸åå¯åºå¤ä»½ï¼æ¥å头å¦å¸¦åæ®åå¤å® qcResult(æ°)/qcResultText(䏿ï¼åæ ¼/ç¹é/ä¸åæ ¼éè´§/ä¸åæ ¼æ¥åº)ï¼ä¸å¼æä¸æå¤å®å¹¶åäºä¸è¦çï¼ååºå¸¦ undecidableCount=å¿«ç
§ä¸ result 为空串ç项æ°ä¸ warningsï¼åç»æ é¢è·³è¿/ææ å·²å /æªå½å®æµå¼/æ ·åè¶
3ï¼ï¼ä¸¤è
é½ä¸è½åºãäºåçä¸å°", "upstream": ["æ¥å模æ¿çæ¬", "è´¨æ£åä¸ä¸æ(éç¨ generate ç±è°ç¨æ¹ä¼ å
¥)", "MES è´¨æ£å IQC/IPQC/OQC/RQC(generate-from-qc ç» MesQcReportApi åæ°)"], "downstream": ["å端å®ä¾é¡µ /qc/report-instance(å表·iframeé¢è§Â·å¿«ç
§é¡µç¾Â·å¯¼åºPDF)", "PDF彿¡£(system_storage_attachment recordType=qc_report_instance)"], "keywords": "æ¥åå®ä¾ åºä»¶ QRç¼å· å¿«ç
§ å¤ç° regenerate PDF彿¡£ æ¥åå®ä¾é¡µ 导åºPDF generate-from-qc è´¨æ£ååºæ¥å åºæ¥åå¼¹çª qcResult undecidableCount warnings å¾
å¤å® 忥 ä¸å¡åæ®çé"} |
| | |
| | | {"role": "ä»ç®¡å", "modules": ["MES-WM"], "operations": ["15 ç±»åºå
¥åºåæ®æ§è¡", "è°æ¨", "çç¹", "æ¡ç è£
ç®±"], "data": ["mes_wm_*"], "scope": "ä»åºç»´åº¦ï¼WMS 坿ä»åºé
ç½®åºå
¥åº/è°æ¨/çç¹æ¯å¦èµ° BPM"}, |
| | | {"role": "è´¨æ£å", "modules": ["MES-QC"], "operations": ["IQC/IPQC/OQC/RQC æ£éª", "NCR è¯å®¡å¤ç½®"], "data": ["mes_qc_*"], "scope": "inspectorUserId å½å±"}, |
| | | {"role": "设å¤å/维修工", "modules": ["MES-DV"], "operations": ["ç¹æ£ä¿å
»", "维修工å", "å·¥è£
é¢ç¨"], "data": ["mes_dv_*", "mes_tm_*"], "scope": "chargeUserId å½å±"}, |
| | | {"role": "客æ/å®åå·¥ç¨å¸", "modules": ["å®å"], "operations": ["å·¥ååçæ´¾å·¥", "ç»´ä¿®", "éè´§ç³è¯·"], "data": ["after_sale_*"], "scope": "è¡çº§æ°æ®æéåè§å¾ï¼æè´è´£/æåä¸/ä¸å±è´è´£/å
¨é¨(aftersales:view-all)"}, |
| | | {"role": "客æ/å®åå·¥ç¨å¸", "modules": ["å®å"], "operations": ["å·¥ååçæ´¾å·¥", "客æ·è¯æ±/å¤çç»æéä»¶", "ç»´ä¿®", "é货转ä»å¨åèµ·"], "data": ["after_sale_*"], "scope": "è¡çº§æ°æ®æéåè§å¾ï¼æè´è´£/æåä¸/ä¸å±è´è´£/å
¨é¨(aftersales:view-all)"}, |
| | | {"role": "è´¢å¡", "modules": ["ERP", "CRM", "FIN"], "operations": ["æ¶æ¬¾å", "仿¬¾å", "å¼ç¥¨å®¡æ ¸", "ç»ç®è´¦æ·", "ä¼è®¡ç§ç®ç»´æ¤", "è®°è´¦åè¯å½å
¥ä¸è¿è´¦/ä½åº", "æ»è´¦ä¸æç»è´¦æ¥è¯¢", "åºå®èµäº§ææ§è®¡æ", "æ å½¢èµäº§æé计æ", "ä¼è®¡æ ¸ç®çæ¿"], "data": ["erp_finance_*", "crm_invoice", "crm_receivable", "fin_account_subject", "fin_voucher", "fin_voucher_entry", "fin_fixed_asset", "fin_intangible_asset"], "scope": "financeUserId å½å±ï¼è´¢å¡æ ¸ç®æ¨¡åæ finance:* æ¥å£æé + system_menu ææï¼ææ æ°æ®æéåæ®µ"}, |
| | | {"role": "HR", "modules": ["HRM"], "operations": ["å工档æ¡å
¥è½¬è°ç¦»", "èå¤è§åæç", "èªé
¬æ ¸ç®åæ¾", "离è交æ¥"], "data": ["hrm_*"], "scope": "é¨é¨èå´ dataScope"}, |
| | | {"role": "管çå±", "modules": ["BI"], "operations": ["æ¥çéè´éå®/ä»åº/ç产设å¤/è´¨é/人åäºå¤§ä¸»é¢å¤§å±"], "data": ["bi_dashboard"], "scope": "åªè¯»"} |
| | |
| | | ], |
| | | [ |
| | | "å®åå¦ä½éç¯", |
| | | "å·¥åå¤å®éè´§ â éè´§ç³è¯·å®¡æ ¸ â èªå¨å»º MES éå®éè´§å â RQC è´¨æ£/å
¥åºåè° â 鿬¾åè° â å·¥åå®ç»å
³é" |
| | | "å·¥åå¤å®éè´§ â ä»å¨ç©æµåèµ·éå®éè´§ï¼åå®åéè´§ç³è¯·é¡µé¢å·²ä¸çº¿ï¼ â 建 MES éå®éè´§å â RQC è´¨æ£/å
¥åºåè° â 鿬¾åè° â å·¥åå®ç»å
³é" |
| | | ], |
| | | [ |
| | | "AI å¨åªéåä¸", |
| | |
| | | {"key": "crm", "name": "éå®ç®¡çï¼å®¢æ·å
³ç³»ï¼", "color": "#4f9cff", "tag": "CRM", "flow": "sales", |
| | | "positioning": "éå®å端ï¼ä»çº¿ç´¢å°å款ç客æ·ç»è¥", |
| | | "problem": "客æ·èµäº§æ²æ·ãåæºè½¬åãåå审æ¹ä¸å¼ç¥¨å款管æ§", |
| | | "features": ["线索转å客æ·", "å
¬æµ·æ± ä¸é¢åä¸é", "è系人", "åæºèªå®ä¹é¶æ®µ", "è·è¿è®°å½", "æ¥ä»·å(AI OCR)", "åå(BPM审æ¹âçæéå®è®¢åÂ·æ¯æExcel导å
¥)", "å¼ç¥¨(BPM审æ¹Â·æ¯æExcel导å
¥Â·å䏿¹æ°æ®ä¸å¯éå¤å¯¼å
¥)â忬¾(å
å¼ç¥¨æ ¡éª)", "忬¾è®¡å", "éå®ç®æ ", "æ°æ®æéä¸çº§(è´è´£äºº/åªè¯»/读å)"], |
| | | "objects": ["线索", "客æ·", "è系人", "åæº", "æ¥ä»·å", "åå", "å票", "忬¾", "éå®ç®æ "], |
| | | "features": ["线索转å客æ·", "å
¬æµ·æ± ä¸é¢åä¸é", "è系人", "åæºèªå®ä¹é¶æ®µ", "è·è¿è®°å½", "æ¥ä»·å(AI OCR)", "åå(BPM审æ¹âçæéå®è®¢åÂ·æ¯æExcel导å
¥)", "å¼ç¥¨ç³è¯·(ç»å®éå®è®¢å+MESéå®åºåºå)â审æ¹âå½å
¥å票(å票å·/æ¥æ/éä»¶+å忬¾/é¢ä»æ¬¾/å°è´§æ¬¾/éªæ¶æ¬¾/è´¨ä¿éæ¶æ¬¾èç¹)", "å¼ç¥¨(BPM审æ¹Â·æ¯æExcel导å
¥Â·å䏿¹æ°æ®ä¸å¯éå¤å¯¼å
¥)â忬¾(å
å¼ç¥¨æ ¡éªÂ·æ ¸éæç»å¯æåå°è®¢å/åºåº/å¼ç¥¨)", "忬¾è®¡å(æ¶æ¬¾èç¹åå已忬¾/å®é
æ¶é´/ç¶æ)", "客æ·åºæ¶å¯¹è´¦/å·²åè´§æªå¼ç¥¨/æªæ ¸éåºæ¶è´¦é¾/æåº¦å¼ç¥¨å款è¶å¿", "éå®ç®æ ", "æ°æ®æéä¸çº§(è´è´£äºº/åªè¯»/读å)"], |
| | | "objects": ["线索", "客æ·", "è系人", "åæº", "æ¥ä»·å", "åå", "å票", "忬¾", "忬¾æ ¸éæç»", "éå®ç®æ "], |
| | | "roles": ["éå®å
å¤", "éå®ç»ç", "è´¢å¡(å¼ç¥¨å款)"], |
| | | "upstream": ["ä¸»æ°æ®(ç©æ)"], "downstream": ["è¿éå(éå®è®¢å)", "å®å(客æ·)", "AI(æ¥ä»·OCR)"], |
| | | "coreTables": ["crm_clue", "crm_customer", "crm_contact", "crm_business", "crm_sale_quotation", "crm_contract", "crm_invoice", "crm_receivable", "crm_receivable_plan", "crm_permission"]}, |
| | |
| | | {"key": "erp", "name": "è¿éåä¸è´¢å¡", "color": "#5fc79e", "tag": "ERP", "flow": "purchase", |
| | | "positioning": "åè´¸ä¸èµé忮䏿¢ï¼å MES åèµ·å®ç©æ¶å", |
| | | "problem": "éè´éå®åæ®å®¡æ¹ãæ¥ç¥¨ä»æ¬¾æ§å¶ãè®¢åæ§è¡è¿åº¦åå", |
| | | "features": ["éè´ç³è¯·(BPM)â订å(èªå¨/æå¨çæ)", "确认æ¶è´§âMESå°è´§éç¥", "å
¥åº/éè´§æ°éç¶æåå", "éè´æ¥ç¥¨(éé¢â¤è®¢å)", "仿¬¾å(å¿
é¡»å
³èæ¥ç¥¨Â·BPM)", "éå®è®¢å(BPM·审æ¹éè¿èªå¨å»ºMPS)", "åºåºç¶æåå", "æ¶æ¬¾å(å
³èCRM客æ·)", "ç»ç®è´¦æ·", "AIå票OCR"], |
| | | "features": ["éè´ç³è¯·(BPM)â订å(èªå¨/æå¨çæ)", "确认æ¶è´§âMESå°è´§éç¥", "å
¥åº/éè´§æ°éç¶æåå", "éè´æ¥ç¥¨(ç»å®éè´è®¢å+MESéè´å
¥åºå·åå±å©ä½é¢åº¦æ ¡éª)", "仿¬¾å(å¿
é¡»å
³èæ¥ç¥¨Â·BPM)", "éå®è®¢å(BPM·审æ¹éè¿èªå¨å»ºMPS)", "åºåºç¶æåå", "æ¶æ¬¾å(å
³èCRM客æ·)", "ç»ç®è´¦æ·", "AIå票OCR"], |
| | | "objects": ["éè´ç³è¯·", "éè´è®¢å", "éè´æ¥ç¥¨", "仿¬¾å", "éå®è®¢å", "æ¶æ¬¾å", "ç»ç®è´¦æ·"], |
| | | "roles": ["éè´å", "éå®å", "åºçº³", "ä¼è®¡"], |
| | | "upstream": ["CRM(åå)", "SRM(宿 )", "ä¸»æ°æ®"], "downstream": ["ç产(MPS)", "ä»å¨(æ¶å)"], |
| | |
| | | {"key": "finance", "name": "è´¢å¡ç®¡çï¼ä¼è®¡æ ¸ç®ï¼", "color": "#3ec9a7", "tag": "FIN", "flow": "finance", |
| | | "positioning": "ç¬ç«æ ¸ç®æ¨¡åï¼ä¼è®¡æ ¸ç® + èµäº§æ ¸ç® + è´¢å¡æ¥è¡¨çæ¿ï¼ä¸ ERP è¿éåè´¢å¡åæ®å离ï¼yudao-module-financeï¼", |
| | | "problem": "è¿éååªç®¡åæ®ä¸ç®¡è´¦ï¼ç¼ºå°ä¼è®¡ç§ç®/åè¯/账簿ä¸èµäº§ææ§æéæ²æ·ï¼æ æ³åºè´¦è¡¨ä¸èµäº§åå¼", |
| | | "features": ["ä¼è®¡ç§ç®æ (约68æ¡ä¸çº§ç§ç®ç§å·å¯å»ºä¸çº§)", "è®°è´¦åè¯(åå·èªå¨çæÂ·åå½å贷平衡åå端åéæ ¡éª)", "åè¯ç¶ææº æªè¿è´¦0âè¿è´¦10/ä½åº20ï¼å·²è¿è´¦ä¸å¯æ¹", "æ»è´¦ææé´éææ±æ»", "æç»è´¦éæ¡åå½å¹¶ç»è½¬ä½é¢", "åºå®èµäº§+è®¡æææ§", "æ å½¢èµäº§+计ææé", "ä¼è®¡æ ¸ç®çæ¿(æ¶æ¯/èµäº§/åè¯/æåº¦è¶å¿)", "éä»¶èµ°ç³»ç»éä»¶ä¸å¿ recordType=fin_voucher"], |
| | | "features": ["ä¼è®¡ç§ç®æ (约68æ¡ä¸çº§ç§ç®ç§å·å¯å»ºä¸çº§)", "è®°è´¦åè¯(åå·èªå¨çæÂ·åå½å贷平衡åå端åéæ ¡éª)", "åè¯ç¶ææº æªè¿è´¦0âè¿è´¦10/ä½åº20ï¼å·²è¿è´¦ä¸å¯æ¹", "æ»è´¦ææé´éææ±æ»", "æç»è´¦éæ¡åå½å¹¶ç»è½¬ä½é¢", "åºå®èµäº§+è®¡æææ§", "æ å½¢èµäº§+计ææé", "ä¼è®¡æ ¸ç®çæ¿(æ¶æ¯/èµäº§/åè¯/æåº¦è¶å¿)", "åè¯æ¥æºåæ®å
³è(sourceType/sourceId/sourceNoï¼å¯å溯å¼ç¥¨/忬¾/æ¥ç¥¨/仿¬¾)", "æ¥è¡¨åæ°æ¥å
¥CRM客æ·åºæ¶å¯¹è´¦/å·²åè´§æªå¼ç¥¨/æªæ ¸éåºæ¶è´¦é¾/æåº¦å¼ç¥¨å款è¶å¿", "éä»¶èµ°ç³»ç»éä»¶ä¸å¿ recordType=fin_voucher"], |
| | | "objects": ["ä¼è®¡ç§ç®", "è®°è´¦åè¯", "åè¯åå½", "åºå®èµäº§", "æ å½¢èµäº§"], |
| | | "roles": ["ä¼è®¡", "è´¢å¡ä¸»ç®¡", "èµäº§ä¼è®¡", "管çå±"], |
| | | "upstream": ["è¿éå(ERP å·²å®¡æ ¸æ¶è´§/仿¬¾/è´éåæ®)"], "downstream": ["è´¢å¡æ¥è¡¨çæ¿", "BI 管ç驾驶è±"], |
| | | "upstream": ["è¿éå(ERP å·²å®¡æ ¸æ¶è´§/仿¬¾/è´éåæ®)", "CRM(å¼ç¥¨/忬¾/æ ¸é/对账æ¥è¡¨)"], "downstream": ["è´¢å¡æ¥è¡¨çæ¿", "BI 管ç驾驶è±"], |
| | | "coreTables": ["fin_account_subject", "fin_voucher", "fin_voucher_entry", "fin_fixed_asset", "fin_intangible_asset"]}, |
| | | {"key": "pro", "name": "ç产管ç", "color": "#e0b34f", "tag": "MES-PRO", "flow": "production", |
| | | "positioning": "ç产æ§è¡æ ¸å¿ï¼è®¡å-å·¥å-ä»»å¡-æ¥å·¥", |
| | |
| | | {"key": "aftersales", "name": "å®åæå¡", "color": "#c78bd6", "tag": "AFTER", "flow": "aftersales", |
| | | "positioning": "客æ·åé¦å°éè´§/ç»´ä¿®/鿬¾éç¯", |
| | | "problem": "å®åå·¥åæµè½¬ãéè´§ä¸è´¨æ£å
¥åºé款ç跨系ç»èå¨", |
| | | "features": ["å·¥åå
æ(è稿âå¤çä¸âå¾
å
¥åºâå¾
鿬¾âå®ç»âå
³é)", "é®é¢å¤å®(ä¸è¬/ç»´ä¿®/éè´§)", "ç»´ä¿®(ç°åº/è¿å/è¿ç¨)", "éè´§ç³è¯·âèªå¨å»º MES éå®éè´§å", "è´¨æ£ç»è®º/å
¥åº/鿬¾ä¸éåè°", "è¡çº§æ°æ®æéåè§å¾"], |
| | | "objects": ["å®åå·¥å", "维修记å½", "éè´§ç³è¯·"], |
| | | "features": ["å·¥åå
æ(è稿âå¤çä¸âå¾
å
¥åºâå¾
鿬¾âå®ç»âå
³é)", "é®é¢å¤å®(ä¸è¬/ç»´ä¿®/éè´§)", "客æ·è¯æ±åé¦æè¿°+éä»¶", "å¤çç»æ+éä»¶", "å·¥åæµè½¬è®°å½", "ç»´ä¿®(ç°åº/è¿å/è¿ç¨)", "éè´§ç±ä»å¨ç©æµåèµ·âMES éå®éè´§å(åå®åéè´§ç³è¯·é¡µé¢å·²ä¸çº¿)", "è´¨æ£ç»è®º/å
¥åº/鿬¾ä¸éåè°", "è¡çº§æ°æ®æéåè§å¾"], |
| | | "objects": ["å®åå·¥å", "å·¥åæµè½¬è®°å½", "维修记å½", "éè´§ç³è¯·(åå°ä¿ç)"], |
| | | "roles": ["客æ", "维修工ç¨å¸", "å®å管çå"], |
| | | "upstream": ["CRM(客æ·)", "ERP(éå®è®¢å)"], "downstream": ["ä»å¨(éå®éè´§)", "è´¨é(RQC)", "è´¢å¡(鿬¾)"], |
| | | "coreTables": ["after_sale_ticket", "after_sale_ticket_item", "after_sale_repair", "after_sale_return", "after_sale_permission"]}, |
| | | {"key": "hrm", "name": "人åèµæº", "color": "#9db85a", "tag": "HRM", "flow": null, |
| | | "positioning": "åå·¥å
¥è½¬è°ç¦»ä¸èå¤èªé
¬", |
| | | "problem": "äººäºæµç¨å®¡æ¹åãç¦»èæ°æ®ä¸ä¸¢(交æ¥)ãç®èªèªå¨å", |
| | | "features": ["å工档æ¡(å
¥èèªå¨å»ºç³»ç»è´¦å·)", "请å/å ç/è°å²/离è BPM 审æ¹", "离èäº¤æ¥æ å° expandUserIds", "èå¤(æå¡Â·è§å·æç·补å¡å®¡æ¹Â·æåº¦æ±æ»)", "èªé
¬(åºå-社ä¿å
¬ç§¯é-个ç¨-è¯·åæ£æ¬¾Â·1.5/2/3åå çè´¹Â·åæ¾å°è´¦)", "å¹è®è¯ä¹¦(SQLå
è¡å¾
å®ç°)"], |
| | | "features": ["å工档æ¡(å
¥èèªå¨å»ºç³»ç»è´¦å·)", "请å/å ç/è°å²/离è BPM 审æ¹", "离è交æ¥åæ¶è½¬ç§»åå·¥ID/ç¨æ·ID/ä¸å¡æ°æ® expandUserIds", "离èå°æèªå¨æåå·¥ç¶ææ¹ä¸ºç¦»èå¹¶åç¨ç³»ç»è´¦å·", "èå¤(æå¡Â·è§å·æç·补å¡å®¡æ¹Â·æåº¦æ±æ»)", "èªé
¬(åºå-社ä¿å
¬ç§¯é-个ç¨-è¯·åæ£æ¬¾Â·1.5/2/3åå çè´¹Â·åæ¾å°è´¦)", "å¹è®è¯ä¹¦(SQLå
è¡å¾
å®ç°)"], |
| | | "objects": ["åå·¥", "请åå", "离èç³è¯·", "äº¤æ¥æ å°", "èå¤è®°å½", "èªé
¬æ ¸ç®"], |
| | | "roles": ["HR", "é¨é¨ä¸»ç®¡", "åå·¥æ¬äºº"], |
| | | "upstream": [], "downstream": ["忍¡å(æ°æ®å¯è§æ§æ©å±)", "system(è´¦å·)"], |
| | |
| | | {"name": "åæº", "module": "éå®ç®¡ç", "table": "crm_business", "doc": "é宿ºä¼ï¼DB é
ç½®å¼é¶æ®µæ¨è¿ï¼ç»ææ: èµ¢/è¾/æ æ", "upstream": ["客æ·"], "downstream": ["æ¥ä»·å", "åå"], "keywords": "åæº business èµ¢å è¾å é¶æ®µ"}, |
| | | {"name": "æ¥ä»·å", "module": "éå®ç®¡ç", "table": "crm_sale_quotation", "doc": "QTç¼å·ï¼é MDM ç©ææ¥ä»·ï¼AI OCR å½å
¥ï¼è稿â已转åå", "upstream": ["åæº"], "downstream": ["åå"], "keywords": "æ¥ä»· quotation QT"}, |
| | | {"name": "åå", "module": "éå®ç®¡ç", "table": "crm_contract", "doc": "HTç¼å·ï¼BPM 审æ¹(0è稿/10审æ¹ä¸/20éè¿/30驳å/40åæ¶/50ä½åº)ï¼éè¿åå¯çæéå®è®¢åï¼æ¯æ Excel 导å
¥ï¼ä¸ååå¤äº§åæç»è¡ãåå¹¶åå
æ ¼èªå¨æå¹³ï¼å®¢æ·ä¸ç©ææåç§°/ç¼ç æ ¡éªï¼ï¼äº§åæç»å¸¦åºç©æåç§°/ç¼ç /æ¡ç /è§æ ¼åå·/计éåä½ï¼å é¤ååæ¶è¿å¸¦å é¤äº§åæç»ï¼ä¸çå¤å¿æ°æ®", "upstream": ["æ¥ä»·å"], "downstream": ["éå®è®¢å", "忬¾è®¡å", "å¼ç¥¨"], "keywords": "åå contract å®¡æ¹ å¯¼å
¥"}, |
| | | {"name": "å票", "module": "éå®ç®¡ç", "table": "crm_invoice", "doc": "KPç¼å·ï¼å¯ç空èªå¨çæãç³»ç»å
å¯ä¸ï¼ï¼BPM 审æ¹ï¼ç´¯è®¡å¼ç¥¨â¤ååé¢ï¼éä»¶å¿
ä¼ ï¼æ¯æ Excel 导å
¥ï¼ä»
æ°å¢ä¸æ´æ°ï¼ååé¡»å®¡æ ¸éè¿ä¸æ¬æ¬¡éé¢â¤ååå©ä½å¯å¼ç¥¨é¢ï¼å䏿¹æ°æ®ä¸å¯éå¤å¯¼å
¥ââåååä¸å票å·ç ç¸åãæå票å·ç ç空æ¶å¼ç¥¨éé¢+å票æ¬å¤´+å¼ç¥¨æ¥æç¸åå³å¤éå¤ï¼æä»¶å
éå¤è¡ä¸åºå
å·²æåé½æè¯¥è¡å¹¶åæ¾ç»´åº¦ä¸å®é
å¼ï¼", "upstream": ["åå"], "downstream": ["忬¾"], "keywords": "å¼ç¥¨ å票 invoice 导å
¥ å»é"}, |
| | | {"name": "忬¾", "module": "éå®ç®¡ç", "table": "crm_receivable", "doc": "HKç¼å·ï¼å建å³å®¡æ¹ä¸(æå¨å®¡æ ¸)ï¼å¼ºå¶å
å¼ç¥¨ï¼éé¢åæ ¡éª", "upstream": ["åå", "å票"], "downstream": ["æ¶æ¬¾å(å
³è)"], "keywords": "忬¾ æ¶æ¬¾è®¡å receivable"}, |
| | | {"name": "å票", "module": "éå®ç®¡ç", "table": "crm_invoice", "doc": "KPç¼å·ï¼å¯ç空èªå¨çæãç³»ç»å
å¯ä¸ï¼ï¼BPM 审æ¹ï¼ç´¯è®¡å¼ç¥¨â¤ååé¢ï¼éä»¶å¿
ä¼ ï¼å¼ç¥¨ç³è¯·é¡»ç»å® ERP éå®è®¢åä¸ MES éå®åºåºåï¼å®¡æ¹éè¿åè¿å
¥å½å
¥åç¥¨é¶æ®µ(entry_status 0å¾
å½å
¥â10å·²å½å
¥)ï¼å½å
¥æ¶å¡«åå票å·ç /æ¥æ/é件并设置å忬¾/é¢ä»æ¬¾/å°è´§æ¬¾/éªæ¶æ¬¾/è´¨ä¿éæ¶æ¬¾èç¹ï¼æ¯æ Excel 导å
¥ï¼ä»
æ°å¢ä¸æ´æ°ï¼ååé¡»å®¡æ ¸éè¿ä¸æ¬æ¬¡éé¢â¤ååå©ä½å¯å¼ç¥¨é¢ï¼å䏿¹æ°æ®ä¸å¯éå¤å¯¼å
¥ââåååä¸å票å·ç ç¸åãæå票å·ç ç空æ¶å¼ç¥¨éé¢+å票æ¬å¤´+å¼ç¥¨æ¥æç¸åå³å¤éå¤ï¼æä»¶å
éå¤è¡ä¸åºå
å·²æåé½æè¯¥è¡å¹¶åæ¾ç»´åº¦ä¸å®é
å¼ï¼", "upstream": ["åå", "éå®è®¢å", "éå®åºåºå"], "downstream": ["忬¾", "忬¾è®¡å", "è®°è´¦åè¯"], "keywords": "å¼ç¥¨ å票 invoice 导å
¥ å»é å¼ç¥¨ç³è¯· å½å
¥å票 åºåºå"}, |
| | | {"name": "忬¾", "module": "éå®ç®¡ç", "table": "crm_receivable", "doc": "HKç¼å·ï¼å建å³å®¡æ¹ä¸(æå¨å®¡æ ¸)ï¼å¼ºå¶å
å¼ç¥¨ï¼éé¢åæ ¡éªï¼æ°å¢/ç¼è¾å¯å¸¦æ ¸éæç» items(20éå®è®¢å/21éå®åºåº/23å¼ç¥¨)ï¼æç»å计å¿
é¡»çäºå款éé¢ï¼å®¡æ ¸éè¿ååå忬¾è®¡å已忬¾é¢/å®é
忬¾æ¶é´/ç¶æ(0æªå款10é¨å忬¾20已忏
)", "upstream": ["åå", "å票", "éå®è®¢å", "éå®åºåºå"], "downstream": ["æ¶æ¬¾å(å
³è)", "忬¾æ ¸éæç»", "忬¾è®¡å", "è®°è´¦åè¯"], "keywords": "忬¾ æ¶æ¬¾è®¡å receivable æ ¸é"}, |
| | | {"name": "忬¾æ ¸éæç»", "module": "éå®ç®¡ç", "table": "crm_receivable_item", "doc": "æ¯è¡æå款é颿 ¸éå°ä¸å¼ ä¸å¡åæ®ï¼biz_type 20éå®è®¢å/21éå®åºåº/23å¼ç¥¨ï¼biz_noãåæ®éé¢ãå·²æ ¸ééé¢ç±å端æ biz_id åå¡«ï¼æ¯è¡æ ¸éé¢ä¸å¾è¶
è¿è¯¥åæ®å©ä½åºæ¶ï¼ä¸ä¼ items ä¸å¸¦ invoice_id æ¶èªå¨çæä¸æ¡å¼ç¥¨æ ¸éè¡", "upstream": ["忬¾", "éå®è®¢å", "éå®åºåºå", "å票"], "downstream": ["客æ·åºæ¶å¯¹è´¦", "æªæ ¸éåºæ¶æ¥è¡¨"], "keywords": "æ ¸é æ ¸éæç» write off item receivable_item"}, |
| | | {"name": "éå®ç®æ ", "module": "éå®ç®¡ç", "table": "crm_sales_target", "doc": "å¹´/å£/æÃ个人/é¨é¨/产å维度çåå忬¾çç®æ ", "upstream": [], "downstream": ["ä¸ç»©ç»è®¡"], "keywords": "ç®æ target ä¸ç»©"}, |
| | | {"name": "ä¾åºå", "module": "ä¾åºå管ç", "table": "srm_supplier", "doc": "ä¾åºåæ¡£æ¡ï¼æ§ç
§/ç¨å·ï¼å¤ä¸ªè系人(srm_supplier_contact)ä¸å¤ä¸ªé¶è¡è´¦æ·(srm_supplier_bank·å«é¶è¡è¡å·)ï¼ä¸»è¡¨ä¿çé»è®¤è系人/é»è®¤é¶è¡å段ï¼ERP ä¸ MES å
±ç¨", "upstream": ["æå·¥å»ºæ¡£/Excel 导å
¥"], "downstream": ["询价æ¯ä»·", "ææ ä¿è¯é", "éè´è®¢å", "å°è´§éç¥", "ä¾åºåéè´§", "ä¾åºå徿¥"], "keywords": "ä¾åºå supplier vendor è系人 弿·è¡ é¶è¡è¡å·"}, |
| | | {"name": "询价æ¯ä»·", "module": "ä¾åºå管ç", "table": "srm_inquiry", "doc": "XJç¼å·ï¼è稿0â已转订å20â已忶30(10询价ä¸ä¸ºåå²ç¶æ)ï¼æ°å¢/ç¼è¾æ¶ä¸å¹¶å½å
¥äº§åè¡Ãåä¸ä¾åºåæ¥ä»·(srm_inquiry_quote)å¹¶é宿¯ä¸ªäº§åç䏿 ä¾åºåï¼æ éåç¬çæ¥ä»·/æ¯ä»·æ¥éª¤ï¼ç¡®è®¤åæä¸æ ä¾åºåæåçæéè´è®¢åèç¨¿å¹¶è®°å½ srm_inquiry_order", "upstream": ["ä¾åºå", "ä¸»æ°æ®(ç©æ)"], "downstream": ["éè´è®¢å(è稿)"], "keywords": "询价 æ¯ä»· æ¥ä»· 䏿 inquiry quote"}, |
| | | {"name": "ææ ä¿è¯é", "module": "ä¾åºå管ç", "table": "srm_bid_bond", "doc": "BZç¼å·å°è´¦ï¼å
³èä¾åºå/询价å/éè´è®¢åï¼è®°å½ä¿è¯ééé¢ãç¼´çº³æ¥æãæ¯å¦ä¸æ ãéåç¶æ(0æªé1é¨å2å·²é3æ éé)/éåéé¢/é忥æ", "upstream": ["ä¾åºå", "询价æ¯ä»·", "éè´è®¢å"], "downstream": ["ä¾åºå徿¥(åè)"], "keywords": "ææ ä¿è¯é 䏿 éå bid bond"}, |
| | | {"name": "éè´ç³è¯·", "module": "è¿éå", "table": "erp_purchase_request", "doc": "CGSQç¼å·ï¼BPM 审æ¹ï¼éè¿åæä¾åºåèªå¨çæè®¢å", "upstream": ["ç产缺å£(人工)"], "downstream": ["éè´è®¢å"], "keywords": "éè´ç³è¯· è¯·è´ request"}, |
| | | {"name": "éè´è®¢å", "module": "è¿éå", "table": "erp_purchase_order", "doc": "CGDDç¼å·ï¼BPM 审æ¹(è稿0â审æ¹ä¸15âå·²å®¡æ ¸20)ï¼å
¥åºç¶æ:æª0é¨å1å
¨é¨2ï¼æ¥æºå¯ä¸ºéè´ç³è¯·æè¯¢ä»·æ¯ä»·ç¡®è®¤çæçè稿(æ¥æºåå·å溯)ï¼å价为å«ç¨åä»·ï¼ä»·ç¨å计=åä»·Ãæ°éï¼ç¨é¢ä»å«ç¨éé¢ä¸åç®(ä¸åé¢å¤å ç¨)", "upstream": ["éè´ç³è¯·", "询价æ¯ä»·(ç¡®è®¤ä¸æ )"], "downstream": ["å°è´§éç¥", "éè´æ¥ç¥¨", "ä¾åºåéè´§(约æç©æ)", "ä¾åºå徿¥"], "keywords": "éè´è®¢å purchase"}, |
| | | {"name": "éè´æ¥ç¥¨", "module": "è¿éå", "table": "erp_purchase_invoice", "doc": "FPDç¼å·ï¼AI OCR é¢å¡«ï¼ç´¯è®¡â¤è®¢åæ»ä»·ï¼ä»æ¬¾åçåç½®ï¼ä¾åºå徿¥å³ä¾§å±ç¤ºå¼ç¥¨éé¢/å·²ä»/å©ä½åºä»", "upstream": ["éè´è®¢å"], "downstream": ["仿¬¾å", "ä¾åºå徿¥"], "keywords": "æ¥ç¥¨ å票 éè´å票"}, |
| | | {"name": "éè´æ¥ç¥¨", "module": "è¿éå", "table": "erp_purchase_invoice", "doc": "FPDç¼å·ï¼AI OCR é¢å¡«ï¼ç´¯è®¡â¤è®¢åæ»ä»·ï¼ä»æ¬¾åçåç½®ï¼å¿
须忶ç»å®éè´è®¢åä¸ MES éè´å
¥åºå(item_receipt_id)ï¼æè®¢åä¸å
¥åºå两å±å©ä½å¯æ¥ç¥¨é¢åº¦æ ¡éªï¼ä¾åºå徿¥å³ä¾§å±ç¤ºå¼ç¥¨éé¢/å·²ä»/å©ä½åºä»", "upstream": ["éè´è®¢å", "MES éè´å
¥åºå"], "downstream": ["仿¬¾å", "ä¾åºå徿¥", "è®°è´¦åè¯"], "keywords": "æ¥ç¥¨ å票 éè´å票 å
¥åºå"}, |
| | | {"name": "仿¬¾å", "module": "è´¢å¡", "table": "erp_finance_payment", "doc": "FKDç¼å·ï¼å¿
é¡»å
³èæ¥ç¥¨+éä»¶ï¼ç´¯è®¡â¤æ¥ç¥¨éé¢ï¼BPM 审æ¹", "upstream": ["éè´æ¥ç¥¨"], "downstream": ["ç»ç®è´¦æ·", "ä¾åºå徿¥"], "keywords": "仿¬¾ åºä» payment"}, |
| | | {"name": "ä¾åºå徿¥", "module": "è¿éå", "table": "æ ç¬ç«è¡¨(èåè§å¾)", "doc": "æä¾åºå+æ¶é´èå´èåéè´è®¢å/æ¥ç¥¨/仿¬¾ï¼æ±æ»ç´¯è®¡éè´é¢ã累计å¼ç¥¨é¢ãç´¯è®¡ä»æ¬¾é¢ãæªä»ä½é¢ï¼å·¦ä¾§è®¢åè¡å«å·²å¼ç¥¨/æªå¼ç¥¨éé¢ï¼å³ä¾§æ¥ç¥¨è¡å«å¼ç¥¨éé¢/å·²ä»/å©ä½åºä»", "upstream": ["éè´è®¢å", "éè´æ¥ç¥¨", "仿¬¾å"], "downstream": [], "keywords": "ä¾åºå徿¥ 对账 å¼ç¥¨éé¢ åºä» statement"}, |
| | | {"name": "æ¶æ¬¾å", "module": "è´¢å¡", "table": "erp_finance_receipt", "doc": "SKDç¼å·ï¼å
³è CRM å®¢æ·æ ¡éªï¼æ BPM(æå¨å®¡æ ¸)", "upstream": ["éå®(å¼±å
³è)"], "downstream": ["ç»ç®è´¦æ·"], "keywords": "æ¶æ¬¾ åºæ¶ receipt"}, |
| | | {"name": "ä¼è®¡ç§ç®", "module": "ä¼è®¡æ ¸ç®", "table": "fin_account_subject", "doc": "ç§ç®æ ï¼parent_id èªå
³èï¼ç§ç®ç±»å1èµäº§2è´åº3æç4ææ¬5æçï¼ä½é¢æ¹å1å2è´·ï¼ç¶æ0å¯ç¨1ç¦ç¨ï¼è´¦è¡¨ä¸åå½ç»ä¸æ subject_code åæ°", "upstream": ["ä¼è®¡ç§ç®ç§å约68æ¡ä¸çº§ç§ç®"], "downstream": ["è®°è´¦åè¯åå½", "æ»è´¦", "æç»è´¦"], "keywords": "ä¼è®¡ç§ç® ç§ç® subject account èµäº§ç±» è´åºç±» æçç±»"}, |
| | | {"name": "è®°è´¦åè¯", "module": "ä¼è®¡æ ¸ç®", "table": "fin_voucher", "doc": "åè¯åå·å¯ç空ç±å端èªå¨çæï¼ç¶æ æªè¿è´¦0/å·²è¿è´¦10/å·²ä½åº20ï¼å·²è¿è´¦ä¸å¯æ¹ï¼æªè¿è´¦ä¸å·²è¿è´¦åå¯ä½åºï¼æªè¿è´¦ä¸å·²ä½åºå¯å é¤ï¼éä»¶æ recordType=fin_voucher æç³»ç»éä»¶ä¸å¿", "upstream": ["ä¼è®¡ç§ç®"], "downstream": ["æ»è´¦", "æç»è´¦", "è´¢å¡æ¥è¡¨çæ¿"], "keywords": "è®°è´¦åè¯ åè¯ voucher è¿è´¦ ä½åº å贷平衡"}, |
| | | {"name": "è®°è´¦åè¯", "module": "ä¼è®¡æ ¸ç®", "table": "fin_voucher", "doc": "åè¯åå·å¯ç空ç±å端èªå¨çæï¼ç¶æ æªè¿è´¦0/å·²è¿è´¦10/å·²ä½åº20ï¼å·²è¿è´¦ä¸å¯æ¹ï¼æªè¿è´¦ä¸å·²è¿è´¦åå¯ä½åºï¼æªè¿è´¦ä¸å·²ä½åºå¯å é¤ï¼å¯éè¿ source_type/source_id/source_no å
³èå¼ç¥¨/忬¾/æ¥ç¥¨/仿¬¾çæ¥æºåæ®å¹¶æ¯æææ¥æºåå·æ£ç´¢ï¼éä»¶æ recordType=fin_voucher æç³»ç»éä»¶ä¸å¿", "upstream": ["ä¼è®¡ç§ç®", "å¼ç¥¨", "忬¾", "éè´æ¥ç¥¨", "仿¬¾å"], "downstream": ["æ»è´¦", "æç»è´¦", "è´¢å¡æ¥è¡¨çæ¿"], "keywords": "è®°è´¦åè¯ åè¯ voucher è¿è´¦ ä½åº å贷平衡"}, |
| | | {"name": "åè¯åå½", "module": "ä¼è®¡æ ¸ç®", "table": "fin_voucher_entry", "doc": "åè¯ä¸éè¡åå½ï¼ç§ç®ç¼ç +å/è´·éé¢+è¾
婿 ¸ç®(1客æ·2ä¾åºå3é¨é¨4åå·¥5项ç®)ï¼ä¸è¡ä¸å¯åè´·åæ¶å¤§äº0ï¼å
¨è¡¨åè´·å计å¿
é¡»ç¸çä¸å¤§äº0", "upstream": ["è®°è´¦åè¯", "ä¼è®¡ç§ç®"], "downstream": ["æ»è´¦", "æç»è´¦"], "keywords": "åè¯åå½ åå½ entry åæ¹ è´·æ¹ è¾
婿 ¸ç®"}, |
| | | {"name": "åºå®èµäº§", "module": "ä¼è®¡æ ¸ç®", "table": "fin_fixed_asset", "doc": "èµäº§å¡çï¼ç¶æ 1å¨ç¨/2é²ç½®/3ç»´ä¿®ä¸/4å·²æ¥åºï¼æææ§é¢=(åå¼Ã(1-æ®å¼ç))÷(å¹´éÃ12)ï¼ç´¯è®¡ææ§ä¸åå¼ç±è®¡æç´¯å ï¼ä¸æ¥æ¶åç«¯ä¼ å¼", "upstream": [], "downstream": ["è´¢å¡æ¥è¡¨çæ¿", "æ»è´¦"], "keywords": "åºå®èµäº§ ææ§ èµäº§å¡ç fixed asset æ®å¼ç"}, |
| | | {"name": "æ å½¢èµäº§", "module": "ä¼è®¡æ ¸ç®", "table": "fin_intangible_asset", "doc": "æ å½¢èµäº§å¡ç(è¯ä¹¦ç¼å·/æææ)ï¼ç¶æ 1å¨ç¨/2已失æ/3å·²æéå®ï¼ææéé¢=(åå¼Ã(1-æ®å¼ç))÷(æéå¹´éÃ12)ï¼ç´¯è®¡æéä¸åå¼ç±è®¡æç´¯å ", "upstream": [], "downstream": ["è´¢å¡æ¥è¡¨çæ¿", "æ»è´¦"], "keywords": "æ å½¢èµäº§ æé 软件è使 ä¸å© intangible æææ"}, |
| | |
| | | {"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_return_sales", "doc": "è稿âå¾
æ£éª(RQC)âå¾
䏿¶âå¾
å
¥åºâ宿ï¼å®åä¸æå·¥ä¸¤æ¥æº", "upstream": ["å®åéè´§ç³è¯·"], "downstream": ["åºåå°è´¦", "RQC"], "keywords": "éå®éè´§ éè´§å
¥åº"}, |
| | | {"name": "éå®éè´§å", "module": "ä»å¨", "table": "mes_wm_return_sales", "doc": "è稿âå¾
æ£éª(RQC)âå¾
䏿¶âå¾
å
¥åºâ宿ï¼å®åä¸æå·¥ä¸¤æ¥æº", "upstream": ["å®åéè´§(ä»å¨åèµ·)"], "downstream": ["åºåå°è´¦", "RQC"], "keywords": "éå®éè´§ éè´§å
¥åº"}, |
| | | {"name": "ä¾åºåéè´§å", "module": "ä»å¨", "table": "mes_wm_return_vendor", "doc": "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_stock_taking_task", "doc": "éæ/卿çç¹ï¼è¡ç»æ:æ£å¸¸/çç(ADJUST_IN)/çäº(ADJUST_OUT)ï¼å¯å»ç»åºåãç²ç", "upstream": ["åºåå°è´¦"], "downstream": ["åºåå°è´¦(è°æ´)"], "keywords": "çç¹ çç çäº stock taking"}, |
| | |
| | | {"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"}, |
| | | {"name": "å®åå·¥å", "module": "å®å", "table": "after_sale_ticket", "doc": "è稿0âå¤çä¸10âå¾
å
¥åº30âå¾
鿬¾40âå®ç»50âå
³é60/åæ¶99ï¼å¤å®:ä¸è¬/ç»´ä¿®/éè´§", "upstream": ["客æ·åé¦(人工å½å
¥)"], "downstream": ["维修记å½", "éè´§ç³è¯·"], "keywords": "å®å å·¥å ticket ç»´ä¿®"}, |
| | | {"name": "éè´§ç³è¯·", "module": "å®å", "table": "after_sale_return", "doc": "è稿0âå·²å®¡æ ¸20(èªå¨å»ºMESéè´§å)â已质æ£40âå·²å
¥åº50â已鿬¾60âå
³é70ï¼ç±»å:鿬¾éè´§/æ¢è´§/ä»
鿬¾", "upstream": ["å®åå·¥å"], "downstream": ["éå®éè´§å", "鿬¾"], "keywords": "å®åéè´§ return"}, |
| | | {"name": "åå·¥", "module": "人å", "table": "hrm_employee", "doc": "å¨è1/è¯ç¨2/离è3ï¼å
¥èèªå¨å»ºç³»ç»è´¦å·", "upstream": [], "downstream": ["äº¤æ¥æ å°", "èå¤", "èªé
¬"], "keywords": "åå·¥ å
¥è employee"}, |
| | | {"name": "离è交æ¥", "module": "人å", "table": "hrm_user_handover", "doc": "fromâto æ å°ï¼å·²å®æ20 å expandUserIds æ©å±äº¤æ¥äººå¯è§æ°æ®ï¼å½ååä¸å¡æ¨¡åå°æªå®é
æ¥å
¥è°ç¨ï¼", "upstream": ["离èç³è¯·"], "downstream": ["忍¡åæçæ°æ®æ¥è¯¢"], "keywords": "äº¤æ¥ ç¦»è handover expandUserIds"}, |
| | | {"name": "å®åå·¥å", "module": "å®å", "table": "after_sale_ticket", "doc": "è稿0âå¤çä¸10âå¾
å
¥åº30âå¾
鿬¾40âå®ç»50âå
³é60/åæ¶99ï¼å¤å®:ä¸è¬/ç»´ä¿®/éè´§ï¼å®¢æ·è¯æ±åé¦æè¿°+éä»¶ãå¤çç»æ+éä»¶ï¼å建/æ´æ°/å¤å®/å®ç»/彿¡£/åæ¶/å访åå
¥æµè½¬è®°å½", "upstream": ["客æ·åé¦(人工å½å
¥)"], "downstream": ["维修记å½", "ä»å¨éå®éè´§(åéè´§ç³è¯·é¡µé¢å·²ä¸çº¿)"], "keywords": "å®å å·¥å ticket ç»´ä¿® 客æ·è¯æ± å¤çç»æ æµè½¬è®°å½"}, |
| | | {"name": "å·¥åæµè½¬è®°å½", "module": "å®å", "table": "after_sale_ticket_flow", "doc": "å®åå·¥åæ¯æ¬¡å¨ä½ççï¼å¨ä½ç¼ç /åç§°ãåæ´ååç¶æãå
容ãæä½äººãæ¶é´", "upstream": ["å®åå·¥å"], "downstream": [], "keywords": "å®å æµè½¬è®°å½ flow"}, |
| | | {"name": "éè´§ç³è¯·", "module": "å®å", "table": "after_sale_return", "doc": "åå°ä¿çï¼å®å页é¢å·²ä¸çº¿ï¼è稿0âå·²å®¡æ ¸20(èªå¨å»ºMESéè´§å)â已质æ£40âå·²å
¥åº50â已鿬¾60âå
³é70ï¼ç±»å:鿬¾éè´§/æ¢è´§/ä»
鿬¾", "upstream": ["å®åå·¥å"], "downstream": ["éå®éè´§å", "鿬¾"], "keywords": "å®åéè´§ return"}, |
| | | {"name": "åå·¥", "module": "人å", "table": "hrm_employee", "doc": "å¨è1/è¯ç¨2/离è3ï¼å
¥èèªå¨å»ºç³»ç»è´¦å·ï¼ç¦»èç³è¯·å°æèªå¨ç½®ä¸ºç¦»è3å¹¶åç¨ç³»ç»è´¦å·", "upstream": [], "downstream": ["äº¤æ¥æ å°", "èå¤", "èªé
¬"], "keywords": "åå·¥ å
¥è employee 离è"}, |
| | | {"name": "离èç³è¯·", "module": "人å", "table": "hrm_resignation_application", "doc": "è稿0â审æ¹ä¸10âéè¿20/驳å30/æ¤é40ï¼å®¡æ¹éè¿åå¯äº¤æ¥0â10â20ï¼å°æä»»å¡åå®é
ç¦»èæ¥æãæåå·¥ç¶ææ¹ä¸ºç¦»è3å¹¶åç¨ç³»ç»è´¦å·", "upstream": ["åå·¥"], "downstream": ["å工档æ¡ç¶æ", "离è交æ¥"], "keywords": "离è resignation å®¡æ¹ äº¤æ¥ èªå¨ç¦»è"}, |
| | | {"name": "离è交æ¥", "module": "人å", "table": "hrm_user_handover", "doc": "åæ¶è®°å½ç¦»è/交æ¥åæ¹åå·¥IDä¸ç¨æ·IDï¼äº¤æ¥å®æ20 å expandUserIds æ©å±äº¤æ¥äººå¯è§æ°æ®ï¼å®¡æ¹éè¿ä¸å°é¢è®¡ç¦»èæ¥æåèªå¨æåå·¥ç¶ææ¹ä¸ºç¦»è3å¹¶åç¨ç³»ç»è´¦å·", "upstream": ["离èç³è¯·"], "downstream": ["忍¡åæçæ°æ®æ¥è¯¢", "å工档æ¡ç¶æ"], "keywords": "äº¤æ¥ ç¦»è handover expandUserIds èªå¨ç¦»è"}, |
| | | {"name": "æç计å", "module": "设å¤", "table": "mes_cal_plan", "doc": "çç»Ãçæ¬¡Ãæ¥ææçï¼ä¾ç产ä¸èå¤å¼ç¨", "upstream": [], "downstream": ["ç产任å¡", "èå¤"], "keywords": "æç çç» çæ¬¡ æ¥å"}, |
| | | {"name": "æ¥å模æ¿", "module": "è´¨æ£æ¥å", "table": "qc_report_template", "doc": "æºè½è´¨æ£æ¥å模æ¿ï¼å¯ç¨0/åç¨1ï¼ç»å¸å
容åå¨ qc_report_template_versionï¼è稿0/å·²åå¸1/å·²åç¨2ï¼å·²åå¸ä¸å¯è¦çï¼ï¼currentVersion æåå½åå·²åå¸çæ¬ï¼æºæä»¶ç» AI 导å
¥è¯å«æè稿åç±äººå·¥ç¡®è®¤ææä¸ºçæ¬ï¼å䏿¨¡æ¿éå¤å¯¼å
¥æãæ¿æ¢ãå¤çââå
å æ§éä»¶ï¼è¿å¸¦ blob è¡ä¸ç£çæä»¶ï¼åç»æ°çï¼ä¸çå¤å¿æä»¶ï¼å 餿¨¡æ¿ä¼è¿å¸¦æ¸
éä»¶", "upstream": ["人工设计(GrapesJS 设计å¨)", "AI 导å
¥è稿(qc-report/ai-import/draft)"], "downstream": ["模æ¿çæ¬", "æ¥åå®ä¾"], "keywords": "æ¥åæ¨¡æ¿ è´¨æ£æ¥å template è®¾è®¡å¨ çæ¬ AI导å
¥ è¯å« è稿 æºæä»¶æ¿æ¢"}, |
| | | {"name": "æ¥åå®ä¾", "module": "è´¨æ£æ¥å", "table": "qc_report_instance", "doc": "åºä»¶äº§ç©ï¼ç¼å· QR+yyyyMMdd+4使µæ°´æå¤©ç¬ç«ä¸ä¸å¡å¯ä¸ï¼å¯æ¾å¼æå®è¦çï¼æ³¨æ uk_report_no ä¸åºå软å é¤ï¼å æçå·ä¸åæ¶ï¼ï¼ä¸¤æ¡åºä»¶å
¥å£ï¼éç¨ generateï¼è°ç¨æ¹èªå¸¦ contextï¼ä¸ generate-from-qcï¼æ°æ®ä» MES è´¨æ£ååï¼æéç qc-report:instance:generate å·²å
¥ system_menu id=1075416ï¼äºéæ ¡éªæä¸å¡ä¼å
çº§åªæ¥ç¬¬ä¸å¤ï¼105_000 ç±»åéæ³ / 105_001 åæ®ä¸åå¨ / 105_002 æªå®æ / 105_003 æªå¤å® / 105_005 模æ¿ç±»åä¸ç¬¦ / 105_006 æ å¯ç¨æ£éªé¡¹ï¼åå¼ è´¨æ£åå表çè¡æä½ãåºæ¥åãä»
å¨ status=已宿æ¶å¯è§ï¼å¼¹çªåªå reportType ä¸è´ã模æ¿å¯ç¨ãä¸ currentVersion æåççæ¬å·²åå¸ç模æ¿ï¼å端 /qc-report/template/selectable å¤å®ââåç¨çæ¬ä¸æ¸
空 currentVersionï¼å端æ¿åé¡µç»æèªå·±æ¨å¯¼ä¼æ¼ï¼ï¼ç»æå°±å°å±ç¤ºå¹¶è·³æ¬é¡µå表ï¼ï¼å»ç» data_snapshotï¼å¤å®åæ°æ®ï¼å«å端ç®å¥½ç PASS/FAIL ä¸åæ ¼çï¼ä¸ render_htmlï¼regenerate åªé渲æçãæ°æ®ä¸ç¼å·ä¸åï¼business_id/business_type å MES 表åï¼mes_qc_iqc çï¼ä¸åæ® IDï¼å¯åæ¥ãä¸åå¯åºå¤ä»½ï¼æ¥å头å¦å¸¦åæ®åå¤å® qcResult(æ°)/qcResultText(䏿ï¼åæ ¼/ç¹é/ä¸åæ ¼éè´§/ä¸åæ ¼æ¥åº)ï¼ä¸å¼æä¸æå¤å®å¹¶åäºä¸è¦çï¼ååºå¸¦ undecidableCount=å¿«ç
§ä¸ result 为空串ç项æ°ä¸ warningsï¼åç»æ é¢è·³è¿/ææ å·²å /æªå½å®æµå¼/æ ·åè¶
3ï¼ï¼ä¸¤è
é½ä¸è½åºãäºåçä¸å°", "upstream": ["æ¥å模æ¿çæ¬", "è´¨æ£åä¸ä¸æ(éç¨ generate ç±è°ç¨æ¹ä¼ å
¥)", "MES è´¨æ£å IQC/IPQC/OQC/RQC(generate-from-qc ç» MesQcReportApi åæ°)"], "downstream": ["å端å®ä¾é¡µ /qc/report-instance(å表·iframeé¢è§Â·å¿«ç
§é¡µç¾Â·å¯¼åºPDF)", "PDF彿¡£(system_storage_attachment recordType=qc_report_instance)"], "keywords": "æ¥åå®ä¾ åºä»¶ QRç¼å· å¿«ç
§ å¤ç° regenerate PDF彿¡£ æ¥åå®ä¾é¡µ 导åºPDF generate-from-qc è´¨æ£ååºæ¥å åºæ¥åå¼¹çª qcResult undecidableCount warnings å¾
å¤å® 忥 ä¸å¡åæ®çé"} |
| | |
| | | {"stage": "çç¹", "action": "æ¹æ¡âä»»å¡âæç»è¡âç»æï¼çç ADJUST_INãçäº ADJUST_OUTï¼å¯å»ç»ä¸ç²ç", "roles": ["çç¹å"]}, |
| | | {"stage": "追溯", "action": "æ¹æ¬¡/SN(uuid)/æ¡ç (18ç±»)/è£
ç®±åµå¥æ¯ææ£åå追溯", "roles": ["è´¨é", "å®å"]}]}, |
| | | {"id": "aftersales", "name": "å®åæµç¨", "mermaid": "mermaid/07-after-sales-flow.mmd", "color": "#c78bd6", |
| | | "summary": "å·¥å(å
æ+é®é¢å¤å®) â ç»´ä¿®ä¸ç±»åæéè´§ç³è¯· â å®¡æ ¸èªå¨å»º MES éå®éè´§å â RQC è´¨æ£/å
¥åº/鿬¾ä¸åè°é级æ¨è¿ â å·¥åå®ç»å
³éã", |
| | | "summary": "å·¥å(å
æ+é®é¢å¤å®) â 客æ·è¯æ±/å¤çç»æé件䏿µè½¬è®°å½çç â ç»´ä¿®ä¸ç±»åæç±ä»å¨ç©æµåèµ·éå®éè´§ â RQC è´¨æ£/å
¥åº/鿬¾ä¸åè°é级æ¨è¿ â å·¥åå®ç»å
³éã", |
| | | "steps": [ |
| | | {"stage": "åç", "action": "人工å½å
¥å·¥å(å
³è客æ·/订å/åå)ï¼åé
å¤ç人è¿å
¥å¤çä¸", "roles": ["客æ"]}, |
| | | {"stage": "åç", "action": "人工å½å
¥å·¥å(å
³è客æ·/订å/åå)ï¼å¡«å客æ·è¯æ±åé¦æè¿°å¹¶ä¸ä¼ éä»¶ï¼åå»ºæ¶æå®çå¤çäººç´æ¥è¿å
¥å¤çä¸", "roles": ["客æ"]}, |
| | | {"stage": "å¤å®", "action": "é®é¢å¤å®: ä¸è¬/ç»´ä¿®/éè´§ï¼ä¸¥é度 0-3", "roles": ["å®åå·¥ç¨å¸"]}, |
| | | {"stage": "å¤ç", "action": "å¡«åå¤çç»æå¹¶ä¸ä¼ å¤çç»æéä»¶ï¼åå»ºãæ´æ°ãå¤å®ãå®ç»ã彿¡£ãåæ¶ãå访ååå
¥æµè½¬è®°å½", "roles": ["å®åå·¥ç¨å¸"]}, |
| | | {"stage": "ç»´ä¿®", "action": "ç°åº/è¿å/è¿ç¨ç»´ä¿®ï¼è´¹ç¨ä¸ç»æè®°å½ï¼å®æèå¨å·¥åå®ç»", "roles": ["维修工ç¨å¸"]}, |
| | | {"stage": "éè´§", "action": "éè´§ç³è¯·å®¡æ ¸âèªå¨å»º MES éå®éè´§å(RQC)âè´¨æ£/å
¥åºåè°â鿬¾åè°âå
³é", "roles": ["å®å", "è´¨æ£", "è´¢å¡"]}]}, |
| | | {"stage": "éè´§", "action": "å®åä¸ååèµ·éè´§ç³è¯·ï¼ç±ä»å¨ç©æµåèµ·éå®éè´§å(RQC)âè´¨æ£/å
¥åºåè°â鿬¾åè°âå
³é", "roles": ["ä»å¨", "è´¨æ£", "è´¢å¡"]}]}, |
| | | {"id": "finance", "name": "ä¼è®¡æ ¸ç®æµç¨", "mermaid": "mermaid/12-finance-flow.mmd", "color": "#3ec9a7", |
| | | "summary": "ç¬ç«æ ¸ç®æ¨¡å yudao-module-financeï¼ä¼è®¡ç§ç®å»ºè´¦ â è®°è´¦åè¯å½å
¥(åè´·å¹³è¡¡æ ¡éª) â è¿è´¦ â æ»è´¦/æç»è´¦ â èµäº§è®¡æææ§ä¸æé â è´¢å¡æ¥è¡¨çæ¿åæ° ERP å·²å®¡æ ¸åæ®ã", |
| | | "steps": [ |
| | |
| | | {"role": "ä»ç®¡å", "modules": ["MES-WM"], "operations": ["15 ç±»åºå
¥åºåæ®æ§è¡", "è°æ¨", "çç¹", "æ¡ç è£
ç®±"], "data": ["mes_wm_*"], "scope": "ä»åºç»´åº¦ï¼WMS 坿ä»åºé
ç½®åºå
¥åº/è°æ¨/çç¹æ¯å¦èµ° BPM"}, |
| | | {"role": "è´¨æ£å", "modules": ["MES-QC"], "operations": ["IQC/IPQC/OQC/RQC æ£éª", "NCR è¯å®¡å¤ç½®"], "data": ["mes_qc_*"], "scope": "inspectorUserId å½å±"}, |
| | | {"role": "设å¤å/维修工", "modules": ["MES-DV"], "operations": ["ç¹æ£ä¿å
»", "维修工å", "å·¥è£
é¢ç¨"], "data": ["mes_dv_*", "mes_tm_*"], "scope": "chargeUserId å½å±"}, |
| | | {"role": "客æ/å®åå·¥ç¨å¸", "modules": ["å®å"], "operations": ["å·¥ååçæ´¾å·¥", "ç»´ä¿®", "éè´§ç³è¯·"], "data": ["after_sale_*"], "scope": "è¡çº§æ°æ®æéåè§å¾ï¼æè´è´£/æåä¸/ä¸å±è´è´£/å
¨é¨(aftersales:view-all)"}, |
| | | {"role": "客æ/å®åå·¥ç¨å¸", "modules": ["å®å"], "operations": ["å·¥ååçæ´¾å·¥", "客æ·è¯æ±/å¤çç»æéä»¶", "ç»´ä¿®", "é货转ä»å¨åèµ·"], "data": ["after_sale_*"], "scope": "è¡çº§æ°æ®æéåè§å¾ï¼æè´è´£/æåä¸/ä¸å±è´è´£/å
¨é¨(aftersales:view-all)"}, |
| | | {"role": "è´¢å¡", "modules": ["ERP", "CRM", "FIN"], "operations": ["æ¶æ¬¾å", "仿¬¾å", "å¼ç¥¨å®¡æ ¸", "ç»ç®è´¦æ·", "ä¼è®¡ç§ç®ç»´æ¤", "è®°è´¦åè¯å½å
¥ä¸è¿è´¦/ä½åº", "æ»è´¦ä¸æç»è´¦æ¥è¯¢", "åºå®èµäº§ææ§è®¡æ", "æ å½¢èµäº§æé计æ", "ä¼è®¡æ ¸ç®çæ¿"], "data": ["erp_finance_*", "crm_invoice", "crm_receivable", "fin_account_subject", "fin_voucher", "fin_voucher_entry", "fin_fixed_asset", "fin_intangible_asset"], "scope": "financeUserId å½å±ï¼è´¢å¡æ ¸ç®æ¨¡åæ finance:* æ¥å£æé + system_menu ææï¼ææ æ°æ®æéåæ®µ"}, |
| | | {"role": "HR", "modules": ["HRM"], "operations": ["å工档æ¡å
¥è½¬è°ç¦»", "èå¤è§åæç", "èªé
¬æ ¸ç®åæ¾", "离è交æ¥"], "data": ["hrm_*"], "scope": "é¨é¨èå´ dataScope"}, |
| | | {"role": "管çå±", "modules": ["BI"], "operations": ["æ¥çéè´éå®/ä»åº/ç产设å¤/è´¨é/人åäºå¤§ä¸»é¢å¤§å±"], "data": ["bi_dashboard"], "scope": "åªè¯»"} |
| | |
| | | å·¥è£
夹å
· |
| | | çç»çæ¬¡ä¸æç |
| | | å®åæå¡ |
| | | å®åå·¥å |
| | | å®åå·¥å(客æ·è¯æ±/å¤çç»æéä»¶) |
| | | å·¥åæµè½¬è®°å½ |
| | | ç»´ä¿®è®°å½ |
| | | éè´§ç³è¯· |
| | | éè´§æä½(ä»å¨ç©æµåèµ·ï¼åéè´§ç³è¯·é¡µé¢å·²ä¸çº¿) |
| | | æ°æ®æé |
| | | 人åèµæº HRM |
| | | åå·¥æ¡£æ¡ |
| | |
| | | </pre> |
| | | <pre style="display:none" class="mmd-src" data-mmd="07-after-sales-flow"> |
| | | flowchart TD |
| | | F1[客æ·åé¦Â·åå°äººå·¥å½å
¥å·¥å·å
³è客æ·è系人éå®è®¢ååå] --> K1[å®åå·¥å·è稿0] |
| | | K1 -->|assignTicket åé
å¤ç人| K2[å¤çä¸10·é®é¢å¤å®:ä¸è¬1ç»´ä¿®2éè´§3·严é度0-3] |
| | | F1[客æ·åé¦Â·åå°äººå·¥å½å
¥å·¥å·å
³è客æ·è系人éå®è®¢ååå·客æ·è¯æ±åé¦+éä»¶] --> K1[å®åå·¥å·è稿0] |
| | | K1 -->|åå»ºæ¶æå®å¤ç人ï¼ç´æ¥è¿å
¥| K2[å¤çä¸10·é®é¢å¤å®:ä¸è¬1ç»´ä¿®2éè´§3·严é度0-3] |
| | | K2 -->|维修类| R1[维修记å½Â·å¾
å¤ç0âç»´ä¿®ä¸10â已宿20âå·²å
³é30·ç°åºè¿åè¿ç¨] |
| | | R1 -->|completeRepair| K4[å·²å®ç»50] |
| | | K2 -->|éè´§ç±»å建éè´§ç³è¯·| T1[éè´§ç³è¯·Â·è稿0] |
| | | K1 -.->|å建/æ´æ°/å¤å®/å®ç»/彿¡£/åæ¶/å访åçç| FL[å·¥åæµè½¬è®°å½ after_sale_ticket_flow] |
| | | K2 -->|éè´§ç±»âä»å¨ç©æµåèµ·éå®éè´§| T1[éè´§ç³è¯·Â·è稿0·å®å页é¢å·²ä¸çº¿ï¼åå°ä¿ç] |
| | | T1 -->|approveReturn å®¡æ ¸éè¿| T2[å·²å®¡æ ¸20·èªå¨å建MESéå®éè´§å] |
| | | T2 --> T3[MES éå®é货·è稿âå¾
æ£éªRQCâå¾
䏿¶âå¾
å
¥åºâ宿] |
| | | T3 -->|è´¨æ£ç»è®ºåè° onReturnQualityFinished åæ ¼ç¹ééè´§æ¥åº| T4[已质æ£40] |
| | |
| | | T2 -.->|ç¶ææµè½¬ä¸| T8[å®¡æ ¸ä¸10·é¢çæªå¯ç¨] |
| | | K2 -->|éè´§é¾è·¯èå¨å·¥å| K3[å¾
å
¥åº30âå¾
鿬¾40] |
| | | K3 --> K4 |
| | | K2 -->|resolveTicket| K4 |
| | | K2 -->|resolveTicket å¡«åå¤çç»æ+éä»¶| K4 |
| | | K4 -->|closeTicket| K5[å·²å
³é60] |
| | | K1 -->|cancelTicket| K9[已忶99] |
| | | K2 -->|cancelTicket| K9 |
| | |
| | | mes_wm_item_receipt ||--o{ mes_wm_material_stock : "åºåå¢å " |
| | | mes_wm_material_stock ||--o{ mes_wm_transaction : "äºå¡æµæ°´" |
| | | mes_wm_material_stock }o--|| mes_wm_batch : "ææ¹æ¬¡" |
| | | after_sale_ticket ||--o{ after_sale_return : "éè´§ç³è¯·" |
| | | after_sale_ticket ||--o{ after_sale_ticket_flow : "æµè½¬è®°å½" |
| | | after_sale_ticket ||--o{ after_sale_return : "éè´§ç³è¯·(åå°ä¿ç)" |
| | | after_sale_return ||--o| mes_wm_return_sales : "çæMESéè´§å" |
| | | mdm_item ||--o{ erp_sale_order_items : "é宿ç»" |
| | | mdm_item ||--o{ erp_purchase_order_items : "éè´æç»" |
| | |
| | | M --> K |
| | | O --> K |
| | | P[ERP å·²å®¡æ ¸åæ® status=20 æ¶æ¬¾å 仿¬¾å éå®è®¢å éè´è®¢å] -->|ErpFinanceStatisticsApi.getMonthlyStatistics ææ| K |
| | | subgraph éå®éè´è´¢å¡éç¯ |
| | | R1[ERP éå®è®¢å status=20] -->|éæ©è®¢å| R2[MES éå®åºåºå status=4 已宿] |
| | | R2 -->|å¼ç¥¨ç³è¯·Â·ç»å®è®¢å+åºåºå| R3[CRM å¼ç¥¨ crm_invoice entry_status=0 å¾
å½å
¥] |
| | | R3 -->|审æ¹éè¿| R4[å½å
¥å票 invoiceNo/æ¥æ/éä»¶] |
| | | R4 -->|å¡«åæ¶æ¬¾èç¹| R5[忬¾è®¡å crm_receivable_plan stage=1..5] |
| | | R4 -->|entry_status=10 å·²å½å
¥| R6[CRM 忬¾ crm_receivable] |
| | | R6 -->|æ ¸éæç» crm_receivable_item bizType=20/21/23| R7[éå®è®¢å / éå®åºåº / å¼ç¥¨] |
| | | R7 -->|订åéé¢-已忬¾| R8[客æ·åºæ¶å¯¹è´¦å] |
| | | R5 -->|䏿æªåæ¸
èç¹| R8 |
| | | R2 -->|已宿åºåº-å·²å¼ç¥¨| R9[å·²åè´§æªå¼ç¥¨æ¥è¡¨] |
| | | R4 -->|å¼ç¥¨-已忬¾| R10[æªæ ¸éåºæ¶æ¥è¡¨Â·è´¦é¾] |
| | | R8 --> R11[䏿忬¾è®¡å] |
| | | R1 -->|éæ©è®¢å| P1[ERP éè´è®¢å status=20] |
| | | P1 -->|éæ©è®¢å| P2[MES éè´å
¥åºå mes_wm_item_receipt status=4] |
| | | P2 -->|æ¥ç¥¨Â·ç»å®è®¢å+å
¥åºå| P3[ERP æ¥ç¥¨ erp_purchase_invoice item_receipt_id] |
| | | P3 -->|å©ä½å¯æ¥ç¥¨| P1 |
| | | end |
| | | R4 -->|sourceType=CRM_INVOICE| C1[è®°è´¦åè¯ fin_voucher source_type/source_id/source_no] |
| | | R6 -->|sourceType=CRM_RECEIVABLE| C1 |
| | | P3 -->|sourceType=ERP_PURCHASE_INVOICE| C1 |
| | | K -.->|ç§ç®æ° åè¯æ° æªè¿è´¦ å·²è¿è´¦ å·²ä½åº èµäº§åå¼ æåº¦è¶å¿| Q[çæ¿å¡ç+æåº¦è¶å¿å¾] |
| | | V[éä»¶ä¸å¿ recordType=fin_voucher] --- C |
| | | V -.->|ä¸è½ file_url å| C |
| | |
| | | å·¥è£
夹å
· |
| | | çç»çæ¬¡ä¸æç |
| | | å®åæå¡ |
| | | å®åå·¥å |
| | | å®åå·¥å(客æ·è¯æ±/å¤çç»æéä»¶) |
| | | å·¥åæµè½¬è®°å½ |
| | | ç»´ä¿®è®°å½ |
| | | éè´§ç³è¯· |
| | | éè´§æä½(ä»å¨ç©æµåèµ·ï¼åéè´§ç³è¯·é¡µé¢å·²ä¸çº¿) |
| | | æ°æ®æé |
| | | 人åèµæº HRM |
| | | åå·¥æ¡£æ¡ |
| | |
| | | flowchart TD |
| | | F1[客æ·åé¦Â·åå°äººå·¥å½å
¥å·¥å·å
³è客æ·è系人éå®è®¢ååå] --> K1[å®åå·¥å·è稿0] |
| | | K1 -->|assignTicket åé
å¤ç人| K2[å¤çä¸10·é®é¢å¤å®:ä¸è¬1ç»´ä¿®2éè´§3·严é度0-3] |
| | | F1[客æ·åé¦Â·åå°äººå·¥å½å
¥å·¥å·å
³è客æ·è系人éå®è®¢ååå·客æ·è¯æ±åé¦+éä»¶] --> K1[å®åå·¥å·è稿0] |
| | | K1 -->|åå»ºæ¶æå®å¤ç人ï¼ç´æ¥è¿å
¥| K2[å¤çä¸10·é®é¢å¤å®:ä¸è¬1ç»´ä¿®2éè´§3·严é度0-3] |
| | | K2 -->|维修类| R1[维修记å½Â·å¾
å¤ç0âç»´ä¿®ä¸10â已宿20âå·²å
³é30·ç°åºè¿åè¿ç¨] |
| | | R1 -->|completeRepair| K4[å·²å®ç»50] |
| | | K2 -->|éè´§ç±»å建éè´§ç³è¯·| T1[éè´§ç³è¯·Â·è稿0] |
| | | K1 -.->|å建/æ´æ°/å¤å®/å®ç»/彿¡£/åæ¶/å访/ä»å¨éè´§åçç| FL[å·¥åæµè½¬è®°å½ after_sale_ticket_flow] |
| | | K2 -->|éè´§ç±»âä»å¨ç©æµåèµ·éå®éè´§| T1[éè´§ç³è¯·Â·è稿0·å®å页é¢å·²ä¸çº¿ï¼åå°ä¿ç] |
| | | T1 -->|approveReturn å®¡æ ¸éè¿| T2[å·²å®¡æ ¸20·èªå¨å建MESéå®éè´§å] |
| | | T2 --> T3[MES éå®é货·è稿âå¾
æ£éªRQCâå¾
䏿¶âå¾
å
¥åºâ宿] |
| | | T3 -->|è´¨æ£ç»è®ºåè° onReturnQualityFinished åæ ¼ç¹ééè´§æ¥åº| T4[已质æ£40] |
| | |
| | | T5 -->|鿬¾å®æåè° onRefundCompleted è®°å½å®é
鿬¾é¢| T6[已鿬¾60] |
| | | T6 --> T7[å·²å
³é70] |
| | | T2 -.->|ç¶ææµè½¬ä¸| T8[å®¡æ ¸ä¸10·é¢çæªå¯ç¨] |
| | | K2 -->|éè´§é¾è·¯èå¨å·¥å| K3[å¾
å
¥åº30âå¾
鿬¾40] |
| | | K2 -->|éè´§é¾è·¯èå¨å·¥å| K3[å¾
éè´§30âå¾
鿬¾40] |
| | | W1[ä»å¨ç©æµÂ·å建éå®éè´§å·å
³èéå®è®¢å] -.->|onWarehouseReturnCreated åå
¥ä»å¨éè´§è®°å½ RETURN| FL |
| | | W1 -->|å¹é
该订åæè¿ä¸å¼ æªå
³é/æªåæ¶å·¥åï¼è稿æå¤çä¸åæ¨è¿| K3 |
| | | K3 --> K4 |
| | | K2 -->|resolveTicket| K4 |
| | | K2 -->|resolveTicket å¡«åå¤çç»æ+éä»¶| K4 |
| | | K4 -->|closeTicket| K5[å·²å
³é60] |
| | | K1 -->|cancelTicket| K9[已忶99] |
| | | K2 -->|cancelTicket| K9 |
| | |
| | | mes_wm_item_receipt ||--o{ mes_wm_material_stock : "åºåå¢å " |
| | | mes_wm_material_stock ||--o{ mes_wm_transaction : "äºå¡æµæ°´" |
| | | mes_wm_material_stock }o--|| mes_wm_batch : "ææ¹æ¬¡" |
| | | after_sale_ticket ||--o{ after_sale_return : "éè´§ç³è¯·" |
| | | after_sale_ticket ||--o{ after_sale_ticket_flow : "æµè½¬è®°å½" |
| | | after_sale_ticket ||--o{ after_sale_return : "éè´§ç³è¯·(åå°ä¿ç)" |
| | | after_sale_return ||--o| mes_wm_return_sales : "çæMESéè´§å" |
| | | mdm_item ||--o{ erp_sale_order_items : "é宿ç»" |
| | | mdm_item ||--o{ erp_purchase_order_items : "éè´æç»" |
| | |
| | | ## ä¸å¡æµç¨ |
| | | |
| | | ``` |
| | | éè´ç³è¯·å®¡æ¹éè¿ â èªå¨çæéè´è®¢å(å·²å®¡æ ¸) |
| | | éè´ç³è¯·å®¡æ¹éè¿ â èªå¨çæéè´è®¢å(è稿ï¼è¡¥å
仿¬¾æ¥æ/éè´ç±»åçåæ®µåç±éè´å°è´¦æäº¤å®¡æ¹) |
| | | â ç¹å»"确认æ¶è´§" â çæå°è´§éç¥å(å¾
å
¥åº/å¾
è´¨æ£) |
| | | â IQCè´¨æ£(å¦éè¦) â éè´å
¥åº |
| | | ``` |
| | |
| | | `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT 'æ¯å¦å é¤', |
| | | PRIMARY KEY (`id`) USING BTREE |
| | | ) ENGINE=InnoDB AUTO_INCREMENT=71 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES ç¼ç è§å'; |
| | | INSERT INTO `mes_md_auto_code_rule` (`id`, `code`, `name`, `description`, `max_length`, `padded`, `padded_char`, `padded_method`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1,'MD_ITEM_TYPE_CODE','ç©æåç±»ç¼ç ','ç©æåç±»èªå¨ç¼ç ',6,0x01,'0',1,0,NULL,'1','2026-07-16 08:06:12','1','2026-07-16 08:06:12',0x00),(2,'MD_ITEM_CODE','ç©æç¼ç ','ç©æèªå¨ç¼ç ',16,0x01,'0',1,0,NULL,'1','2026-07-16 08:06:12','103','2026-07-16 16:17:45',0x00),(3,'MD_VENDOR_CODE','ä¾åºåç¼ç ','ä¾åºåèªå¨ç¼ç ',15,0x01,'0',1,0,NULL,'1','2026-07-16 08:06:12','1','2026-07-16 08:06:12',0x00),(4,'MD_CLIENT_CODE','客æ·ç¼ç ','客æ·èªå¨ç¼ç ',15,0x01,'0',1,0,NULL,'1','2026-07-16 08:06:12','1','2026-07-16 08:06:12',0x00),(5,'MD_WORKSTATION_CODE','å·¥ä½ç«ç¼ç ','å·¥ä½ç«èªå¨ç¼ç ',6,0x01,'0',1,0,NULL,'1','2026-07-16 08:06:12','1','2026-07-16 08:06:12',0x00),(6,'MD_WORKSHOP_CODE','车é´ç¼ç ','车é´èªå¨ç¼ç ',6,0x01,'0',1,0,NULL,'1','2026-07-16 08:06:12','1','2026-07-16 08:06:12',0x00),(7,'TM_TOOL_TYPE_CODE','å·¥å
·ç±»åç¼ç ','å·¥å
·ç±»åèªå¨ç¼ç ',6,0x01,'0',1,0,NULL,'1','2026-07-16 08:06:12','1','2026-07-16 08:06:12',0x00),(10,'WM_WAREHOUSE_CODE','ä»åºç¼ç ','ä»åºèªå¨ç¼ç ',6,0x01,'0',1,0,NULL,'1','2026-07-16 08:06:12','1','2026-07-16 08:06:12',0x00),(11,'WM_LOCATION_CODE','åºåºç¼ç ','åºåºèªå¨ç¼ç ',6,0x01,'0',1,0,NULL,'1','2026-07-16 08:06:12','1','2026-07-16 08:06:12',0x00),(12,'WM_AREA_CODE','åºä½ç¼ç ','åºä½èªå¨ç¼ç ',6,0x01,'0',1,0,NULL,'1','2026-07-16 08:06:12','1','2026-07-16 08:06:12',0x00),(13,'WM_ARRIVAL_NOTICE_CODE','å°è´§éç¥åç¼ç ','å°è´§éç¥åèªå¨ç¼ç ',14,0x01,'0',1,0,NULL,'1','2026-07-16 08:06:12','1','2026-07-16 08:15:29',0x00),(14,'WM_ITEM_RECEIPT_CODE','éè´å
¥åºåç¼ç ','éè´å
¥åºåèªå¨ç¼ç ',14,0x01,'0',1,0,NULL,'1','2026-07-16 08:06:12','1','2026-07-16 08:15:29',0x00),(15,'WM_RETURN_VENDOR_CODE','éè´éè´§åç¼ç ','éè´éè´§åèªå¨ç¼ç ',14,0x01,'0',1,0,NULL,'1','2026-07-16 08:06:12','1','2026-07-16 08:15:29',0x00),(16,'WM_RETURN_ISSUE_CODE','ç产éæåç¼ç ','ç产éæåèªå¨ç¼ç ',14,0x01,'0',1,0,NULL,'1','2026-07-16 08:06:12','1','2026-07-16 08:15:29',0x00),(17,'WM_SN_CODE','SNç ','SNç èªå¨ç¼ç ',15,0x01,'0',1,0,NULL,'1','2026-07-16 08:06:12','1','2026-07-16 08:15:29',0x00),(18,'WM_PACKAGE_CODE','è£
ç®±åç¼ç ','è£
ç®±åèªå¨ç¼ç ',14,0x01,'0',1,0,NULL,'1','2026-07-16 08:06:12','1','2026-07-16 08:15:29',0x00),(19,'WM_BATCH_CODE','æ¹æ¬¡ç¼ç ','æ¹æ¬¡èªå¨ç¼ç ',14,0x01,'0',1,0,NULL,'1','2026-07-16 08:06:12','1','2026-07-16 08:15:29',0x00),(20,'WM_PRODUCT_SALES_CODE','éå®åºåºåç¼ç ','éå®åºåºåèªå¨ç¼ç ',14,0x01,'0',1,0,NULL,'1','2026-07-16 08:06:12','1','2026-07-16 08:15:29',0x00),(21,'WM_MISC_RECEIPT_CODE','æé¡¹å
¥åºåç¼ç ','æé¡¹å
¥åºåèªå¨ç¼ç ',14,0x01,'0',1,0,NULL,'1','2026-07-16 08:06:12','1','2026-07-16 08:15:29',0x00),(22,'WM_MISC_ISSUE_CODE','æé¡¹åºåºåç¼ç ','æé¡¹åºåºåèªå¨ç¼ç ',14,0x01,'0',1,0,NULL,'1','2026-07-16 08:06:12','1','2026-07-16 08:15:29',0x00),(23,'WM_STOCK_TAKING_PLAN_CODE','çç¹æ¹æ¡ç¼ç ','çç¹æ¹æ¡èªå¨ç¼ç ',14,0x01,'0',1,0,NULL,'1','2026-07-16 08:06:12','1','2026-07-16 08:15:29',0x00),(24,'WM_STOCK_TAKING_CODE','çç¹ä»»å¡ç¼ç ','çç¹ä»»å¡èªå¨ç¼ç ',14,0x01,'0',1,0,NULL,'1','2026-07-16 08:06:12','1','2026-07-16 08:15:29',0x00),(25,'TRANSFER_CODE','è½¬ç§»è°æ¨åç¼ç ','è½¬ç§»è°æ¨åèªå¨ç¼ç ',14,0x01,'0',1,0,NULL,'1','2026-07-16 08:06:12','1','2026-07-16 08:15:29',0x00),(26,'WM_OUTSOURCE_ISSUE_CODE','å¤ååæåç¼ç ','å¤ååæåèªå¨ç¼ç ',14,0x01,'0',1,0,NULL,'1','2026-07-16 08:06:12','1','2026-07-16 08:15:29',0x00),(27,'WM_OUTSOURCE_RECEIPT_CODE','å¤åå
¥åºåç¼ç ','å¤åå
¥åºåèªå¨ç¼ç ',14,0x01,'0',1,0,NULL,'1','2026-07-16 08:06:12','1','2026-07-16 08:15:29',0x00),(28,'WM_SALES_NOTICE_CODE','åè´§éç¥åç¼ç ','åè´§éç¥åèªå¨ç¼ç ',14,0x01,'0',1,0,NULL,'1','2026-07-16 08:06:12','1','2026-07-16 08:15:29',0x00),(29,'WM_RETURN_SALES_CODE','éå®éè´§åç¼ç ','éå®éè´§åèªå¨ç¼ç ',14,0x01,'0',1,0,NULL,'1','2026-07-16 08:06:12','1','2026-07-16 08:15:29',0x00),(30,'PRO_WORK_ORDER_CODE','ç产工åç¼ç ','ç产工åèªå¨ç¼ç ',14,0x01,'0',1,0,NULL,'1','2026-07-16 08:06:12','1','2026-07-16 08:15:29',0x00),(31,'PRO_TASK_CODE','ç产任å¡ç¼ç ','ç产任å¡èªå¨ç¼ç ',14,0x01,'0',1,0,NULL,'1','2026-07-16 08:06:12','1','2026-07-16 08:15:29',0x00),(32,'PRO_ROUTE_CODE','å·¥èºè·¯çº¿ç¼ç ','å·¥èºè·¯çº¿èªå¨ç¼ç ',14,0x01,'0',1,0,NULL,'1','2026-07-16 08:06:12','1','2026-07-16 08:15:29',0x00),(33,'PRO_FEEDBACK_CODE','ç产æ¥å·¥åç¼ç ','ç产æ¥å·¥åèªå¨ç¼ç ',14,0x01,'0',1,0,NULL,'1','2026-07-16 08:06:12','1','2026-07-16 08:15:29',0x00),(40,'QC_IQC_CODE','æ¥ææ£éªåç¼ç ','æ¥ææ£éªåèªå¨ç¼ç ',15,0x01,'0',1,0,NULL,'1','2026-07-16 08:06:12','1','2026-07-16 08:15:29',0x00),(41,'QC_IPQC_CODE','è¿ç¨æ£éªåç¼ç ','è¿ç¨æ£éªåèªå¨ç¼ç ',16,0x01,'0',1,0,NULL,'1','2026-07-16 08:06:12','1','2026-07-16 08:15:29',0x00),(42,'QC_OQC_CODE','åºè´§æ£éªåç¼ç ','åºè´§æ£éªåèªå¨ç¼ç ',15,0x01,'0',1,0,NULL,'1','2026-07-16 08:06:12','1','2026-07-16 08:15:29',0x00),(43,'QC_RQC_CODE','éè´§æ£éªåç¼ç ','éè´§æ£éªåèªå¨ç¼ç ',15,0x01,'0',1,0,NULL,'1','2026-07-16 08:06:12','1','2026-07-16 08:15:29',0x00),(44,'QC_DEFECT_CODE','缺é·ç±»åç¼ç ','缺é·ç±»åèªå¨ç¼ç ',6,0x01,'0',1,0,NULL,'1','2026-07-16 08:06:12','1','2026-07-16 08:06:12',0x00),(45,'QC_INDICATOR_RESULT_CODE','æ ·åæ£éªç»æç¼ç ','æ ·åæ£éªç»æèªå¨ç¼ç ',14,0x01,'0',1,0,NULL,'1','2026-07-16 08:06:12','1','2026-07-16 08:15:29',0x00),(50,'DV_MACHINERY_CODE','设å¤ç¼ç ','设å¤èªå¨ç¼ç ',14,0x01,'0',1,0,NULL,'1','2026-07-16 08:06:12','1','2026-07-16 08:15:29',0x00),(51,'DV_MACHINERY_TYPE_CODE','设å¤ç±»åç¼ç ','设å¤ç±»åèªå¨ç¼ç ',6,0x01,'0',1,0,NULL,'1','2026-07-16 08:06:12','1','2026-07-16 08:06:12',0x00),(52,'DV_SUBJECT_CODE','ç¹æ£ä¿å
»é¡¹ç®ç¼ç ','ç¹æ£ä¿å
»é¡¹ç®èªå¨ç¼ç ',6,0x01,'0',1,0,NULL,'1','2026-07-16 08:06:12','1','2026-07-16 08:06:12',0x00),(53,'DV_REPAIR_CODE','ç»´ä¿®åç¼ç ','ç»´ä¿®åèªå¨ç¼ç ',14,0x01,'0',1,0,NULL,'1','2026-07-16 08:06:12','1','2026-07-16 08:15:29',0x00),(60,'PD_DOCUMENT_AUDIT_CODE','èµæå®¡æ ¸åç¼ç ','èµæå®¡æ ¸åèªå¨ç¼ç ',14,0x01,'0',1,0,NULL,'1','2026-07-16 08:06:12','1','2026-07-16 08:15:29',0x00),(61,'PD_ARCHIVE_CODE','彿¡£å°è´¦ç¼ç ','彿¡£å°è´¦èªå¨ç¼ç ',14,0x01,'0',1,0,NULL,'1','2026-07-16 08:06:12','1','2026-07-16 08:15:29',0x00),(62,'PD_PROCESS_PARAM_CODE','å·¥èºåæ°ç¼ç ','å·¥èºåæ°èªå¨ç¼ç ',14,0x01,'0',1,0,NULL,'1','2026-07-16 08:06:12','1','2026-07-16 08:15:29',0x00),(63,'PD_PROCESS_PARAM_TEMPLATE_CODE','å·¥èºåæ°æ¨¡æ¿ç¼ç ','å·¥èºåæ°æ¨¡æ¿èªå¨ç¼ç ',14,0x01,'0',1,0,NULL,'1','2026-07-16 08:06:12','1','2026-07-16 16:06:38',0x00),(64,'WM_PRODUCT_ISSUE_CODE','颿å',NULL,15,0x01,'0',1,0,NULL,'103','2026-07-16 16:58:14','103','2026-07-16 16:59:03',0x00),(65,'MPS','ç产主计åç¼ç ','ç产主计åèªå¨ç¼ç ',14,0x01,'0',1,0,'','1','2026-07-17 05:17:30','1','2026-07-17 05:17:30',0x00),(66,'QC_INDICATOR_CODE','è´¨æ£ææ ç¼ç ',NULL,12,0x01,'0',1,0,NULL,'1','2026-07-17 14:31:46','1','2026-07-17 14:32:23',0x00),(67,'QC_TEMPLATE_CODE','è´¨æ£æ¹æ¡ç¼ç ',NULL,11,0x01,'0',1,0,NULL,'1','2026-07-17 14:36:35','1','2026-07-17 14:37:05',0x00),(68,'SALESNOTICE_CODE','éå®éç¥ç¼ç ','éå®éç¥èªå¨ç¼ç ',20,0x01,'0',1,0,'','admin','2026-07-17 07:36:53','admin','2026-07-17 07:36:53',0x00),(69,'CAL_TEAM_CODE','çç»ç¼ç è§å','çç»ç¼ç è§å',10,0x01,'0',1,0,NULL,'1','2026-07-31 09:57:04','1','2026-07-31 09:57:36',0x00),(70,'CAL_PLAN_CODE','æç计å',NULL,14,0x01,'0',1,0,NULL,'1','2026-07-31 09:59:32','1','2026-07-31 10:00:17',0x00); |
| | | INSERT INTO `mes_md_auto_code_rule` (`id`, `code`, `name`, `description`, `max_length`, `padded`, `padded_char`, `padded_method`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1,'MD_ITEM_TYPE_CODE','ç©æåç±»ç¼ç ','ç©æåç±»èªå¨ç¼ç ',6,0x01,'0',1,0,NULL,'1','2026-07-16 08:06:12','1','2026-07-16 08:06:12',0x00),(2,'MD_ITEM_CODE','ç©æç¼ç ','ç©æèªå¨ç¼ç ',16,0x01,'0',1,0,NULL,'1','2026-07-16 08:06:12','103','2026-07-16 16:17:45',0x00),(3,'MD_VENDOR_CODE','ä¾åºåç¼ç ','ä¾åºåèªå¨ç¼ç ',15,0x01,'0',1,0,NULL,'1','2026-07-16 08:06:12','1','2026-07-16 08:06:12',0x00),(4,'MD_CLIENT_CODE','客æ·ç¼ç ','客æ·èªå¨ç¼ç ',15,0x01,'0',1,0,NULL,'1','2026-07-16 08:06:12','1','2026-07-16 08:06:12',0x00),(5,'MD_WORKSTATION_CODE','å·¥ä½ç«ç¼ç ','å·¥ä½ç«èªå¨ç¼ç ',6,0x01,'0',1,0,NULL,'1','2026-07-16 08:06:12','1','2026-07-16 08:06:12',0x00),(6,'MD_WORKSHOP_CODE','车é´ç¼ç ','车é´èªå¨ç¼ç ',6,0x01,'0',1,0,NULL,'1','2026-07-16 08:06:12','1','2026-07-16 08:06:12',0x00),(7,'TM_TOOL_TYPE_CODE','å·¥å
·ç±»åç¼ç ','å·¥å
·ç±»åèªå¨ç¼ç ',6,0x01,'0',1,0,NULL,'1','2026-07-16 08:06:12','1','2026-07-16 08:06:12',0x00),(10,'WM_WAREHOUSE_CODE','ä»åºç¼ç ','ä»åºèªå¨ç¼ç ',6,0x01,'0',1,0,NULL,'1','2026-07-16 08:06:12','1','2026-07-16 08:06:12',0x00),(11,'WM_LOCATION_CODE','åºåºç¼ç ','åºåºèªå¨ç¼ç ',6,0x01,'0',1,0,NULL,'1','2026-07-16 08:06:12','1','2026-07-16 08:06:12',0x00),(12,'WM_AREA_CODE','åºä½ç¼ç ','åºä½èªå¨ç¼ç ',6,0x01,'0',1,0,NULL,'1','2026-07-16 08:06:12','1','2026-07-16 08:06:12',0x00),(13,'WM_ARRIVAL_NOTICE_CODE','å°è´§éç¥åç¼ç ','å°è´§éç¥åèªå¨ç¼ç ',14,0x01,'0',1,0,NULL,'1','2026-07-16 08:06:12','1','2026-07-16 08:15:29',0x00),(14,'WM_ITEM_RECEIPT_CODE','éè´å
¥åºåç¼ç ','éè´å
¥åºåèªå¨ç¼ç ',14,0x01,'0',1,0,NULL,'1','2026-07-16 08:06:12','1','2026-07-16 08:15:29',0x00),(15,'WM_RETURN_VENDOR_CODE','éè´éè´§åç¼ç ','éè´éè´§åèªå¨ç¼ç ',14,0x01,'0',1,0,NULL,'1','2026-07-16 08:06:12','1','2026-07-16 08:15:29',0x00),(16,'WM_RETURN_ISSUE_CODE','ç产éæåç¼ç ','ç产éæåèªå¨ç¼ç ',14,0x01,'0',1,0,NULL,'1','2026-07-16 08:06:12','1','2026-07-16 08:15:29',0x00),(17,'WM_SN_CODE','SNç ','SNç èªå¨ç¼ç ',15,0x01,'0',1,0,NULL,'1','2026-07-16 08:06:12','1','2026-07-16 08:15:29',0x00),(18,'WM_PACKAGE_CODE','è£
ç®±åç¼ç ','è£
ç®±åèªå¨ç¼ç ',14,0x01,'0',1,0,NULL,'1','2026-07-16 08:06:12','1','2026-07-16 08:15:29',0x00),(19,'WM_BATCH_CODE','æ¹æ¬¡ç¼ç ','æ¹æ¬¡èªå¨ç¼ç ',14,0x01,'0',1,0,NULL,'1','2026-07-16 08:06:12','1','2026-07-16 08:15:29',0x00),(20,'WM_PRODUCT_SALES_CODE','éå®åºåºåç¼ç ','éå®åºåºåèªå¨ç¼ç ',14,0x01,'0',1,0,NULL,'1','2026-07-16 08:06:12','1','2026-07-16 08:15:29',0x00),(21,'WM_MISC_RECEIPT_CODE','æé¡¹å
¥åºåç¼ç ','æé¡¹å
¥åºåèªå¨ç¼ç ',14,0x01,'0',1,0,NULL,'1','2026-07-16 08:06:12','1','2026-07-16 08:15:29',0x00),(22,'WM_MISC_ISSUE_CODE','æé¡¹åºåºåç¼ç ','æé¡¹åºåºåèªå¨ç¼ç ',14,0x01,'0',1,0,NULL,'1','2026-07-16 08:06:12','1','2026-07-16 08:15:29',0x00),(23,'WM_STOCK_TAKING_PLAN_CODE','çç¹æ¹æ¡ç¼ç ','çç¹æ¹æ¡èªå¨ç¼ç ',14,0x01,'0',1,0,NULL,'1','2026-07-16 08:06:12','1','2026-07-16 08:15:29',0x00),(24,'WM_STOCK_TAKING_CODE','çç¹ä»»å¡ç¼ç ','çç¹ä»»å¡èªå¨ç¼ç ',14,0x01,'0',1,0,NULL,'1','2026-07-16 08:06:12','1','2026-07-16 08:15:29',0x00),(25,'TRANSFER_CODE','è½¬ç§»è°æ¨åç¼ç ','è½¬ç§»è°æ¨åèªå¨ç¼ç ',14,0x01,'0',1,0,NULL,'1','2026-07-16 08:06:12','1','2026-07-16 08:15:29',0x00),(26,'WM_OUTSOURCE_ISSUE_CODE','å¤ååæåç¼ç ','å¤ååæåèªå¨ç¼ç ',14,0x01,'0',1,0,NULL,'1','2026-07-16 08:06:12','1','2026-07-16 08:15:29',0x00),(27,'WM_OUTSOURCE_RECEIPT_CODE','å¤åå
¥åºåç¼ç ','å¤åå
¥åºåèªå¨ç¼ç ',14,0x01,'0',1,0,NULL,'1','2026-07-16 08:06:12','1','2026-07-16 08:15:29',0x00),(28,'WM_SALES_NOTICE_CODE','åè´§éç¥åç¼ç ','åè´§éç¥åèªå¨ç¼ç ',14,0x01,'0',1,0,NULL,'1','2026-07-16 08:06:12','1','2026-07-16 08:15:29',0x00),(29,'WM_RETURN_SALES_CODE','éå®éè´§åç¼ç ','éå®éè´§åèªå¨ç¼ç ',14,0x01,'0',1,0,NULL,'1','2026-07-16 08:06:12','1','2026-07-16 08:15:29',0x00),(30,'PRO_WORK_ORDER_CODE','ç产工åç¼ç ','ç产工åèªå¨ç¼ç ',14,0x01,'0',1,0,NULL,'1','2026-07-16 08:06:12','1','2026-07-16 08:15:29',0x00),(31,'PRO_TASK_CODE','ç产任å¡ç¼ç ','ç产任å¡èªå¨ç¼ç ',14,0x01,'0',1,0,NULL,'1','2026-07-16 08:06:12','1','2026-07-16 08:15:29',0x00),(32,'PRO_ROUTE_CODE','å·¥èºè·¯çº¿ç¼ç ','å·¥èºè·¯çº¿èªå¨ç¼ç ',14,0x01,'0',1,0,NULL,'1','2026-07-16 08:06:12','1','2026-07-16 08:15:29',0x00),(33,'PRO_FEEDBACK_CODE','ç产æ¥å·¥åç¼ç ','ç产æ¥å·¥åèªå¨ç¼ç ',14,0x01,'0',1,0,NULL,'1','2026-07-16 08:06:12','1','2026-07-16 08:15:29',0x00),(40,'QC_IQC_CODE','æ¥ææ£éªåç¼ç ','æ¥ææ£éªåèªå¨ç¼ç ',15,0x01,'0',1,0,NULL,'1','2026-07-16 08:06:12','1','2026-07-16 08:15:29',0x00),(41,'QC_IPQC_CODE','è¿ç¨æ£éªåç¼ç ','è¿ç¨æ£éªåèªå¨ç¼ç ',16,0x01,'0',1,0,NULL,'1','2026-07-16 08:06:12','1','2026-07-16 08:15:29',0x00),(42,'QC_OQC_CODE','åºè´§æ£éªåç¼ç ','åºè´§æ£éªåèªå¨ç¼ç ',15,0x01,'0',1,0,NULL,'1','2026-07-16 08:06:12','1','2026-07-16 08:15:29',0x00),(43,'QC_RQC_CODE','éè´§æ£éªåç¼ç ','éè´§æ£éªåèªå¨ç¼ç ',15,0x01,'0',1,0,NULL,'1','2026-07-16 08:06:12','1','2026-07-16 08:15:29',0x00),(44,'QC_DEFECT_CODE','缺é·ç±»åç¼ç ','缺é·ç±»åèªå¨ç¼ç ',6,0x01,'0',1,0,NULL,'1','2026-07-16 08:06:12','1','2026-07-16 08:06:12',0x00),(45,'QC_INDICATOR_RESULT_CODE','æ ·åæ£éªç»æç¼ç ','æ ·åæ£éªç»æèªå¨ç¼ç ',14,0x01,'0',1,0,NULL,'1','2026-07-16 08:06:12','1','2026-07-16 08:15:29',0x00),(50,'DV_MACHINERY_CODE','设å¤ç¼å·','设å¤èªå¨ç¼å·',14,0x01,'0',1,0,NULL,'1','2026-07-16 08:06:12','1','2026-07-16 08:15:29',0x00),(51,'DV_MACHINERY_TYPE_CODE','设å¤ç±»åç¼ç ','设å¤ç±»åèªå¨ç¼ç ',6,0x01,'0',1,0,NULL,'1','2026-07-16 08:06:12','1','2026-07-16 08:06:12',0x00),(52,'DV_SUBJECT_CODE','ç¹æ£ä¿å
»é¡¹ç®ç¼ç ','ç¹æ£ä¿å
»é¡¹ç®èªå¨ç¼ç ',6,0x01,'0',1,0,NULL,'1','2026-07-16 08:06:12','1','2026-07-16 08:06:12',0x00),(53,'DV_REPAIR_CODE','ç»´ä¿®åç¼ç ','ç»´ä¿®åèªå¨ç¼ç ',14,0x01,'0',1,0,NULL,'1','2026-07-16 08:06:12','1','2026-07-16 08:15:29',0x00),(60,'PD_DOCUMENT_AUDIT_CODE','èµæå®¡æ ¸åç¼ç ','èµæå®¡æ ¸åèªå¨ç¼ç ',14,0x01,'0',1,0,NULL,'1','2026-07-16 08:06:12','1','2026-07-16 08:15:29',0x00),(61,'PD_ARCHIVE_CODE','彿¡£å°è´¦ç¼ç ','彿¡£å°è´¦èªå¨ç¼ç ',14,0x01,'0',1,0,NULL,'1','2026-07-16 08:06:12','1','2026-07-16 08:15:29',0x00),(62,'PD_PROCESS_PARAM_CODE','å·¥èºåæ°ç¼ç ','å·¥èºåæ°èªå¨ç¼ç ',14,0x01,'0',1,0,NULL,'1','2026-07-16 08:06:12','1','2026-07-16 08:15:29',0x00),(63,'PD_PROCESS_PARAM_TEMPLATE_CODE','å·¥èºåæ°æ¨¡æ¿ç¼ç ','å·¥èºåæ°æ¨¡æ¿èªå¨ç¼ç ',14,0x01,'0',1,0,NULL,'1','2026-07-16 08:06:12','1','2026-07-16 16:06:38',0x00),(64,'WM_PRODUCT_ISSUE_CODE','颿å',NULL,15,0x01,'0',1,0,NULL,'103','2026-07-16 16:58:14','103','2026-07-16 16:59:03',0x00),(65,'MPS','ç产主计åç¼ç ','ç产主计åèªå¨ç¼ç ',14,0x01,'0',1,0,'','1','2026-07-17 05:17:30','1','2026-07-17 05:17:30',0x00),(66,'QC_INDICATOR_CODE','è´¨æ£ææ ç¼ç ',NULL,12,0x01,'0',1,0,NULL,'1','2026-07-17 14:31:46','1','2026-07-17 14:32:23',0x00),(67,'QC_TEMPLATE_CODE','è´¨æ£æ¹æ¡ç¼ç ',NULL,11,0x01,'0',1,0,NULL,'1','2026-07-17 14:36:35','1','2026-07-17 14:37:05',0x00),(68,'SALESNOTICE_CODE','éå®éç¥ç¼ç ','éå®éç¥èªå¨ç¼ç ',20,0x01,'0',1,0,'','admin','2026-07-17 07:36:53','admin','2026-07-17 07:36:53',0x00),(69,'CAL_TEAM_CODE','çç»ç¼ç è§å','çç»ç¼ç è§å',10,0x01,'0',1,0,NULL,'1','2026-07-31 09:57:04','1','2026-07-31 09:57:36',0x00),(70,'CAL_PLAN_CODE','æç计å',NULL,14,0x01,'0',1,0,NULL,'1','2026-07-31 09:59:32','1','2026-07-31 10:00:17',0x00); |
| | | |
| | | -- ============ 表ï¼mes_md_auto_code_partï¼å¯¼åº 145 è¡ï¼ ============ |
| | | DROP TABLE IF EXISTS `mes_md_auto_code_part`; |
| | |
| | | `issue_type` tinyint NOT NULL DEFAULT '0' COMMENT 'é®é¢ç±»å: 0-æªå¤å® 1-ä¸è¬é®é¢ 2-ç»´ä¿®é®é¢ 3-éè´§é®é¢', |
| | | `issue_category` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT 'é®é¢åç±»', |
| | | `issue_description` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT 'é®é¢æè¿°', |
| | | `feedback_description` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT '客æ·è¯æ±åé¦æè¿°', |
| | | `result_description` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT 'å¤çç»ææè¿°', |
| | | `severity_level` tinyint DEFAULT '0' COMMENT '严éç¨åº¦: 0-轻微 1-ä¸è¬ 2-严é 3-è´å½', |
| | | `status` tinyint NOT NULL DEFAULT '0' COMMENT 'ç¶æ: 0-è稿 10-å¤çä¸ 30-å¾
éè´§ 40-å¾
鿬¾/æ¢è´§ 50-å·²å®ç» 60-å·²å
³é 99-已忶', |
| | | `visit_status` tinyint NOT NULL DEFAULT '0' COMMENT 'åè®¿ç¶æ: 0-å¾
å访 1-å·²å访éè¿', |
| | |
| | | KEY `idx_ticket_id` (`ticket_id`) USING BTREE, |
| | | KEY `idx_item_id` (`item_id`) USING BTREE |
| | | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='å®åå·¥åæç»è¡è¡¨'; |
| | | |
| | | -- ============ 表ï¼after_sale_ticket_flowï¼ä»
DDLï¼æ æ°æ®ï¼ ============ |
| | | DROP TABLE IF EXISTS `after_sale_ticket_flow`; |
| | | CREATE TABLE `after_sale_ticket_flow` ( |
| | | `id` bigint NOT NULL AUTO_INCREMENT COMMENT 'æµè½¬è®°å½ç¼å·', |
| | | `ticket_id` bigint NOT NULL COMMENT 'å®åå·¥åç¼å·ï¼å
³è after_sale_ticket.id', |
| | | `action` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'å¨ä½ç¼ç ï¼CREATE/UPDATE/ASSIGN/CLASSIFY/RESOLVE/ARCHIVE/CANCEL/VISIT', |
| | | `action_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'å¨ä½åç§°ï¼å¦ï¼å建工åãåé
å¤ç人', |
| | | `from_status` int DEFAULT NULL COMMENT 'åæ´åç¶æï¼å
³è AfterSaleTicketStatusEnum', |
| | | `to_status` int DEFAULT NULL COMMENT 'åæ´åç¶æï¼å
³è AfterSaleTicketStatusEnum', |
| | | `content` varchar(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT 'æµè½¬å
容/说æ', |
| | | `operator_id` bigint DEFAULT NULL COMMENT 'æä½äººç¨æ·ç¼å·', |
| | | `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT 'å建è
', |
| | | `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'å建æ¶é´', |
| | | `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT 'æ´æ°è
', |
| | | `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'æ´æ°æ¶é´', |
| | | `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT 'æ¯å¦å é¤', |
| | | PRIMARY KEY (`id`) USING BTREE, |
| | | KEY `idx_ticket_id` (`ticket_id`) USING BTREE |
| | | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='å®åå·¥åæµè½¬è®°å½'; |
| | | |
| | | -- ============ 表ï¼after_sale_visitï¼ä»
DDLï¼æ æ°æ®ï¼ ============ |
| | | DROP TABLE IF EXISTS `after_sale_visit`; |
| | |
| | | DROP TABLE IF EXISTS `mes_dv_machinery`; |
| | | CREATE TABLE `mes_dv_machinery` ( |
| | | `id` bigint NOT NULL AUTO_INCREMENT COMMENT 'ç¼å·', |
| | | `code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '设å¤ç¼ç ', |
| | | `code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '设å¤ç¼å·', |
| | | `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '设å¤åç§°', |
| | | `brand` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT 'åç', |
| | | `specification` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT 'è§æ ¼åå·', |
| | |
| | | `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT 'åç§°', |
| | | `purchase_order_id` bigint DEFAULT NULL COMMENT 'éè´è®¢åç¼å·', |
| | | `purchase_order_code` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT 'éè´è®¢åç¼ç ï¼åä½å段ï¼', |
| | | `contract_no` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT 'éè´ååå·ï¼å建æ¶ä»éè´è®¢åå¿«ç
§ï¼æ¢è´§å°è´§æ²¿ç¨éè´§åååå·ï¼', |
| | | `vendor_id` bigint DEFAULT NULL COMMENT 'ä¾åºå ID', |
| | | `arrival_date` datetime DEFAULT NULL COMMENT 'é¢è®¡å°è´§æ¥æ', |
| | | `status` int DEFAULT NULL COMMENT 'ç¶æ', |
| | |
| | | (1, 5393, '1', NOW(), '1', NOW(), b'0'); |
| | | |
| | | SET FOREIGN_KEY_CHECKS = 1; |
| | | |
| | | -- ============================================================ |
| | | -- è¡¥å
ï¼2026-11-05ï¼ï¼ç¦»èç³è¯·å¢å¼º |
| | | -- 交æ¥åå·¥/ç¨æ·ä¸ä¸å¡æ°æ®è½¬ç§»ã离è审æ¹åç±»ãå°æèªå¨ç¦»è Job |
| | | -- ============================================================ |
| | | -- å¯é夿§è¡ï¼ä¸å
å« tenant_idã |
| | | |
| | | -- 1. ç¨æ·æ°æ®äº¤æ¥æ å°è¡¨ï¼è¡¥é½åå·¥IDç»´åº¦ï¼ |
| | | CREATE TABLE IF NOT EXISTS `hrm_user_handover` ( |
| | | `id` bigint NOT NULL AUTO_INCREMENT COMMENT 'æ å°ID', |
| | | `from_employee_id` bigint DEFAULT NULL COMMENT '离èåå·¥ID', |
| | | `from_user_id` bigint NOT NULL COMMENT '离èç¨æ·ID', |
| | | `to_employee_id` bigint DEFAULT NULL COMMENT '交æ¥ç®æ åå·¥ID', |
| | | `to_user_id` bigint NOT NULL COMMENT '交æ¥ç®æ ç¨æ·ID', |
| | | `resignation_id` bigint NOT NULL COMMENT 'å
³èç离èç³è¯·ID', |
| | | `handover_status` tinyint NOT NULL DEFAULT 0 COMMENT '交æ¥ç¶æï¼0-è¿è¡ä¸ï¼20-已宿', |
| | | `handover_time` datetime DEFAULT NULL COMMENT '交æ¥å®ææ¶é´', |
| | | `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT 'å建è
', |
| | | `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'å建æ¶é´', |
| | | `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT 'æ´æ°è
', |
| | | `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'æ´æ°æ¶é´', |
| | | `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT 'æ¯å¦å é¤', |
| | | PRIMARY KEY (`id`) USING BTREE, |
| | | UNIQUE KEY `uk_from_to_resignation` (`from_user_id`, `to_user_id`, `resignation_id`), |
| | | KEY `idx_from_user_id` (`from_user_id`), |
| | | KEY `idx_to_user_id` (`to_user_id`) |
| | | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='HRMç¨æ·æ°æ®äº¤æ¥æ å°è¡¨'; |
| | | |
| | | -- 1.1 å·²åå¨çæ§è¡¨è¡¥é½åå·¥IDå |
| | | SET @target_db = DATABASE(); |
| | | SET @ddl = (SELECT IF(COUNT(*) = 0, |
| | | 'ALTER TABLE hrm_user_handover ADD COLUMN from_employee_id BIGINT NULL COMMENT ''离èåå·¥ID'' AFTER id', |
| | | 'SELECT 1') FROM information_schema.columns WHERE table_schema = @target_db AND table_name = 'hrm_user_handover' AND column_name = 'from_employee_id'); |
| | | PREPARE hrm_stmt FROM @ddl; |
| | | EXECUTE hrm_stmt; |
| | | DEALLOCATE PREPARE hrm_stmt; |
| | | SET @ddl = (SELECT IF(COUNT(*) = 0, |
| | | 'ALTER TABLE hrm_user_handover ADD COLUMN to_employee_id BIGINT NULL COMMENT ''交æ¥ç®æ åå·¥ID'' AFTER from_user_id', |
| | | 'SELECT 1') FROM information_schema.columns WHERE table_schema = @target_db AND table_name = 'hrm_user_handover' AND column_name = 'to_employee_id'); |
| | | PREPARE hrm_stmt FROM @ddl; |
| | | EXECUTE hrm_stmt; |
| | | DEALLOCATE PREPARE hrm_stmt; |
| | | |
| | | -- 2. 离è审æ¹åç±»ï¼å端æäº¤ç processDefinitionKey åå²å¼ä¸ºè¯¥åç±»ç¼ç ï¼ |
| | | SET @category_id = (SELECT COALESCE(MAX(id), 0) + 1 FROM bpm_category); |
| | | INSERT INTO `bpm_category` (`id`, `name`, `code`, `description`, `status`, `sort`, `creator`, `updater`) |
| | | SELECT @category_id, '离è审æ¹', 'hrm_resignation_approve', '离èç³è¯·å®¡æ¹æµç¨', 0, 0, '1', '1' |
| | | FROM DUAL |
| | | WHERE NOT EXISTS (SELECT 1 FROM bpm_category WHERE code = 'hrm_resignation_approve' AND deleted = b'0'); |
| | | |
| | | -- 3. å°æèªå¨ç¦»è Jobï¼æ¯å¤© 00:10 æ§è¡ï¼ |
| | | INSERT INTO `infra_job` (`name`, `status`, `handler_name`, `handler_param`, `cron_expression`, |
| | | `retry_count`, `retry_interval`, `monitor_timeout`, `creator`, `updater`) |
| | | SELECT '离èå°æèªå¨åç', 1, 'hrmResignationAutoLeaveJob', '', '0 10 0 * * ?', 0, 0, 0, '1', '1' |
| | | FROM DUAL |
| | | WHERE NOT EXISTS (SELECT 1 FROM infra_job WHERE handler_name = 'hrmResignationAutoLeaveJob' AND deleted = b'0'); |
| | | |
| | | -- 4. 离èç³è¯·äº¤æ¥å段ï¼åå·¥IDãç¨æ·æ°æ®äº¤æ¥ç¶æï¼ |
| | | 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; |
| | | |
| | | -- ============================================================ |
| | | -- è¡¥å
ï¼2026-11-05ï¼ï¼äººåèµæº - 人äºç»è®¡èå |
| | | -- 页é¢ï¼/hrm/statisticsï¼å·¥é¾ãå¹´é¾ãå¦åãæ§å«ãé¨é¨å·¥é¾ã工龿è¡ï¼ |
| | | -- ============================================================ |
| | | INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, |
| | | status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) |
| | | VALUES (1063300, '人äºç»è®¡', '', 2, 0, 6001, 'statistics', 'ep:data-analysis', |
| | | 'hrm/statistics/index', 'HrmHumanStatistics', 0, b'1', b'0', b'1', '1', NOW(), '1', NOW(), b'0') |
| | | ON DUPLICATE KEY UPDATE name = VALUES(name), parent_id = VALUES(parent_id), path = VALUES(path), |
| | | component = VALUES(component), component_name = VALUES(component_name), |
| | | status = VALUES(status), visible = VALUES(visible), deleted = b'0'; |
| | | |
| | | -- å¯è§è§è²ä¸ãå工管çãä¿æä¸è´ï¼å¹çï¼é夿§è¡ä¸äº§çéå¤è¡ï¼ |
| | | INSERT INTO system_role_menu (role_id, menu_id, creator, create_time, updater, update_time, deleted) |
| | | SELECT rm.role_id, 1063300, '1', NOW(), '1', NOW(), b'0' |
| | | FROM system_role_menu rm |
| | | LEFT JOIN system_role_menu ex |
| | | ON ex.role_id = rm.role_id AND ex.menu_id = 1063300 AND ex.deleted = b'0' |
| | | WHERE rm.menu_id = 6006 AND rm.deleted = b'0' AND ex.id IS NULL; |
| | | |
| | | -- ============================================================ |
| | | -- è¡¥å
ï¼2026-11-05ï¼ï¼è´¢å¡ - éå®/éè´éç¯ |
| | | -- æ¥ç¥¨ç»å®éè´è®¢å+å
¥åºåï¼å¼ç¥¨ç»å®éå®è®¢å+åºåºåï¼ |
| | | -- æ¶æ¬¾èç¹ï¼åæ¬¾æ ¸éæç»ï¼åè¯æ¥æºåæ®ã |
| | | -- ============================================================ |
| | | |
| | | -- 1. æ¥ç¥¨ï¼ç»å® MES éè´å
¥åºå |
| | | SET @ddl = (SELECT IF(COUNT(*) = 0, |
| | | 'ALTER TABLE erp_purchase_invoice ADD COLUMN item_receipt_id BIGINT NULL COMMENT ''å
³è MES éè´å
¥åºåID'' AFTER arrival_notice_id', |
| | | 'SELECT 1') FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'erp_purchase_invoice' AND column_name = 'item_receipt_id'); |
| | | PREPARE fin_stmt FROM @ddl; EXECUTE fin_stmt; DEALLOCATE PREPARE fin_stmt; |
| | | SET @ddl = (SELECT IF(COUNT(*) = 0, |
| | | 'ALTER TABLE erp_purchase_invoice ADD COLUMN item_receipt_code VARCHAR(64) NULL COMMENT ''å
³è MES éè´å
¥åºåå·'' AFTER item_receipt_id', |
| | | 'SELECT 1') FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'erp_purchase_invoice' AND column_name = 'item_receipt_code'); |
| | | PREPARE fin_stmt FROM @ddl; EXECUTE fin_stmt; DEALLOCATE PREPARE fin_stmt; |
| | | |
| | | -- 2. å¼ç¥¨ï¼åºåºåå·å¿«ç
§ + å票å½å
¥ç¶æï¼å¼ç¥¨ç³è¯· -> å½å
¥åç¥¨ï¼ |
| | | SET @ddl = (SELECT IF(COUNT(*) = 0, |
| | | 'ALTER TABLE crm_invoice ADD COLUMN sale_out_code VARCHAR(64) NULL COMMENT ''éå®åºåºåå·å¿«ç
§'' AFTER sale_out_id', |
| | | 'SELECT 1') FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'crm_invoice' AND column_name = 'sale_out_code'); |
| | | PREPARE fin_stmt FROM @ddl; EXECUTE fin_stmt; DEALLOCATE PREPARE fin_stmt; |
| | | SET @ddl = (SELECT IF(COUNT(*) = 0, |
| | | 'ALTER TABLE crm_invoice ADD COLUMN entry_status TINYINT NOT NULL DEFAULT 0 COMMENT ''å票å½å
¥ç¶æï¼0å¾
å½å
¥ 10å·²å½å
¥'' AFTER sale_out_code', |
| | | 'SELECT 1') FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'crm_invoice' AND column_name = 'entry_status'); |
| | | PREPARE fin_stmt FROM @ddl; EXECUTE fin_stmt; DEALLOCATE PREPARE fin_stmt; |
| | | SET @ddl = (SELECT IF(COUNT(*) = 0, |
| | | 'ALTER TABLE crm_invoice ADD COLUMN entry_user_id BIGINT NULL COMMENT ''å票å½å
¥äºº'' AFTER entry_status', |
| | | 'SELECT 1') FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'crm_invoice' AND column_name = 'entry_user_id'); |
| | | PREPARE fin_stmt FROM @ddl; EXECUTE fin_stmt; DEALLOCATE PREPARE fin_stmt; |
| | | SET @ddl = (SELECT IF(COUNT(*) = 0, |
| | | 'ALTER TABLE crm_invoice ADD COLUMN entry_time DATETIME NULL COMMENT ''å票å½å
¥æ¶é´'' AFTER entry_user_id', |
| | | 'SELECT 1') FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'crm_invoice' AND column_name = 'entry_time'); |
| | | PREPARE fin_stmt FROM @ddl; EXECUTE fin_stmt; DEALLOCATE PREPARE fin_stmt; |
| | | |
| | | -- 3. 忬¾è®¡åï¼æ¶æ¬¾é¶æ®µ/æ¥æºå¼ç¥¨/æ¥æºè®¢å/å®é
忬¾ |
| | | SET @ddl = (SELECT IF(COUNT(*) = 0, |
| | | 'ALTER TABLE crm_receivable_plan ADD COLUMN stage TINYINT NULL COMMENT ''æ¶æ¬¾é¶æ®µï¼1å忬¾ 2é¢ä»æ¬¾ 3å°è´§æ¬¾ 4éªæ¶æ¬¾ 5è´¨ä¿é''', |
| | | 'SELECT 1') FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'crm_receivable_plan' AND column_name = 'stage'); |
| | | PREPARE fin_stmt FROM @ddl; EXECUTE fin_stmt; DEALLOCATE PREPARE fin_stmt; |
| | | SET @ddl = (SELECT IF(COUNT(*) = 0, |
| | | 'ALTER TABLE crm_receivable_plan ADD COLUMN invoice_id BIGINT NULL COMMENT ''æ¥æºå¼ç¥¨åç¼å·''', |
| | | 'SELECT 1') FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'crm_receivable_plan' AND column_name = 'invoice_id'); |
| | | PREPARE fin_stmt FROM @ddl; EXECUTE fin_stmt; DEALLOCATE PREPARE fin_stmt; |
| | | SET @ddl = (SELECT IF(COUNT(*) = 0, |
| | | 'ALTER TABLE crm_receivable_plan ADD COLUMN sale_order_id BIGINT NULL COMMENT ''æ¥æºéå®è®¢åç¼å·''', |
| | | 'SELECT 1') FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'crm_receivable_plan' AND column_name = 'sale_order_id'); |
| | | PREPARE fin_stmt FROM @ddl; EXECUTE fin_stmt; DEALLOCATE PREPARE fin_stmt; |
| | | SET @ddl = (SELECT IF(COUNT(*) = 0, |
| | | 'ALTER TABLE crm_receivable_plan ADD COLUMN actual_time DATETIME NULL COMMENT ''å®é
忬¾æ¶é´''', |
| | | 'SELECT 1') FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'crm_receivable_plan' AND column_name = 'actual_time'); |
| | | PREPARE fin_stmt FROM @ddl; EXECUTE fin_stmt; DEALLOCATE PREPARE fin_stmt; |
| | | SET @ddl = (SELECT IF(COUNT(*) = 0, |
| | | 'ALTER TABLE crm_receivable_plan ADD COLUMN receipted_price DECIMAL(24,6) NOT NULL DEFAULT 0 COMMENT ''已忬¾éé¢''', |
| | | 'SELECT 1') FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'crm_receivable_plan' AND column_name = 'receipted_price'); |
| | | PREPARE fin_stmt FROM @ddl; EXECUTE fin_stmt; DEALLOCATE PREPARE fin_stmt; |
| | | SET @ddl = (SELECT IF(COUNT(*) = 0, |
| | | 'ALTER TABLE crm_receivable_plan ADD COLUMN status TINYINT NOT NULL DEFAULT 0 COMMENT ''ç¶æï¼0æªå款 10é¨å忬¾ 20已忏
''', |
| | | 'SELECT 1') FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'crm_receivable_plan' AND column_name = 'status'); |
| | | PREPARE fin_stmt FROM @ddl; EXECUTE fin_stmt; DEALLOCATE PREPARE fin_stmt; |
| | | |
| | | -- 4. 忬¾æ ¸éæç» |
| | | CREATE TABLE IF NOT EXISTS `crm_receivable_item` ( |
| | | `id` bigint NOT NULL AUTO_INCREMENT COMMENT 'ç¼å·', |
| | | `receivable_id` bigint NOT NULL COMMENT '忬¾åID', |
| | | `biz_type` int NOT NULL COMMENT 'æ ¸éåæ®ç±»åï¼20éå®è®¢å 21éå®åºåº 23å¼ç¥¨', |
| | | `biz_id` bigint NOT NULL COMMENT 'æ ¸éåæ®ID', |
| | | `biz_no` varchar(64) DEFAULT NULL COMMENT 'æ ¸éåæ®å·', |
| | | `total_price` decimal(24,6) NOT NULL DEFAULT '0.000000' COMMENT 'åæ®éé¢', |
| | | `receipted_price` decimal(24,6) NOT NULL DEFAULT '0.000000' COMMENT 'æ¬æ¬¡æ ¸éå已忬¾éé¢', |
| | | `receipt_price` decimal(24,6) NOT NULL DEFAULT '0.000000' COMMENT 'æ¬æ¬¡æ ¸ééé¢', |
| | | `remark` varchar(500) DEFAULT NULL COMMENT '夿³¨', |
| | | `creator` varchar(64) DEFAULT '' COMMENT 'å建è
', |
| | | `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'å建æ¶é´', |
| | | `updater` varchar(64) DEFAULT '' COMMENT 'æ´æ°è
', |
| | | `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'æ´æ°æ¶é´', |
| | | `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT 'æ¯å¦å é¤', |
| | | PRIMARY KEY (`id`), |
| | | KEY `idx_receivable_id` (`receivable_id`), |
| | | KEY `idx_biz` (`biz_type`,`biz_id`) |
| | | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='CRM 忬¾æ ¸éæç»'; |
| | | |
| | | -- 5. è´¢å¡åè¯ï¼æ¥æºåæ® |
| | | SET @ddl = (SELECT IF(COUNT(*) = 0, |
| | | 'ALTER TABLE fin_voucher ADD COLUMN source_type VARCHAR(32) NULL COMMENT ''æ¥æºåæ®ç±»åï¼CRM_INVOICE/CRM_RECEIVABLE/ERP_PURCHASE_INVOICE/ERP_PAYMENT''', |
| | | 'SELECT 1') FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'fin_voucher' AND column_name = 'source_type'); |
| | | PREPARE fin_stmt FROM @ddl; EXECUTE fin_stmt; DEALLOCATE PREPARE fin_stmt; |
| | | SET @ddl = (SELECT IF(COUNT(*) = 0, |
| | | 'ALTER TABLE fin_voucher ADD COLUMN source_id BIGINT NULL COMMENT ''æ¥æºåæ®ç¼å·''', |
| | | 'SELECT 1') FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'fin_voucher' AND column_name = 'source_id'); |
| | | PREPARE fin_stmt FROM @ddl; EXECUTE fin_stmt; DEALLOCATE PREPARE fin_stmt; |
| | | SET @ddl = (SELECT IF(COUNT(*) = 0, |
| | | 'ALTER TABLE fin_voucher ADD COLUMN source_no VARCHAR(64) NULL COMMENT ''æ¥æºåæ®å·''', |
| | | 'SELECT 1') FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'fin_voucher' AND column_name = 'source_no'); |
| | | PREPARE fin_stmt FROM @ddl; EXECUTE fin_stmt; DEALLOCATE PREPARE fin_stmt; |
| | | |
| | | -- 6. MES åºåº/å
¥åºè¡éé¢å¿«ç
§ï¼å¼ç¥¨ã对账éé¢å£å¾ï¼ |
| | | SET @ddl = (SELECT IF(COUNT(*) = 0, |
| | | 'ALTER TABLE mes_wm_product_sales_line ADD COLUMN price DECIMAL(24,6) NULL COMMENT ''åä»·ï¼éå®è®¢åè¡å¿«ç
§ï¼''', |
| | | 'SELECT 1') FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'mes_wm_product_sales_line' AND column_name = 'price'); |
| | | PREPARE fin_stmt FROM @ddl; EXECUTE fin_stmt; DEALLOCATE PREPARE fin_stmt; |
| | | SET @ddl = (SELECT IF(COUNT(*) = 0, |
| | | 'ALTER TABLE mes_wm_product_sales_line ADD COLUMN total_price DECIMAL(24,6) NULL COMMENT ''éé¢ï¼æ°éÃåä»·ï¼''', |
| | | 'SELECT 1') FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'mes_wm_product_sales_line' AND column_name = 'total_price'); |
| | | PREPARE fin_stmt FROM @ddl; EXECUTE fin_stmt; DEALLOCATE PREPARE fin_stmt; |
| | | SET @ddl = (SELECT IF(COUNT(*) = 0, |
| | | 'ALTER TABLE mes_wm_item_receipt_line ADD COLUMN price DECIMAL(24,6) NULL COMMENT ''åä»·ï¼éè´è®¢åè¡å¿«ç
§ï¼''', |
| | | 'SELECT 1') FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'mes_wm_item_receipt_line' AND column_name = 'price'); |
| | | PREPARE fin_stmt FROM @ddl; EXECUTE fin_stmt; DEALLOCATE PREPARE fin_stmt; |
| | | SET @ddl = (SELECT IF(COUNT(*) = 0, |
| | | 'ALTER TABLE mes_wm_item_receipt_line ADD COLUMN total_price DECIMAL(24,6) NULL COMMENT ''éé¢ï¼æ°éÃåä»·ï¼''', |
| | | 'SELECT 1') FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'mes_wm_item_receipt_line' AND column_name = 'total_price'); |
| | | PREPARE fin_stmt FROM @ddl; EXECUTE fin_stmt; DEALLOCATE PREPARE fin_stmt; |
| | | |
| | | -- 7. åå
¸ï¼æ¶æ¬¾é¶æ®µ |
| | | INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) |
| | | VALUES (1065416, '忬¾é¶æ®µ', 'crm_payment_stage', 0, 'å¼ç¥¨å½å
¥æ¶æéå®è®¢åæåå忬¾ãé¢ä»æ¬¾ãå°è´§æ¬¾ãéªæ¶æ¬¾', '1', NOW(), '1', NOW(), b'0') |
| | | ON DUPLICATE KEY UPDATE `name` = VALUES(`name`), `status` = VALUES(`status`), `remark` = VALUES(`remark`), `deleted` = b'0'; |
| | | |
| | | INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) |
| | | VALUES (1065501, 1, 'å忬¾', '1', 'crm_payment_stage', 0, 'primary', '', '', '1', NOW(), '1', NOW(), b'0'), |
| | | (1065502, 2, 'é¢ä»æ¬¾', '2', 'crm_payment_stage', 0, 'success', '', '', '1', NOW(), '1', NOW(), b'0'), |
| | | (1065503, 3, 'å°è´§æ¬¾', '3', 'crm_payment_stage', 0, 'warning', '', '', '1', NOW(), '1', NOW(), b'0'), |
| | | (1065504, 4, 'éªæ¶æ¬¾', '4', 'crm_payment_stage', 0, 'info', '', '', '1', NOW(), '1', NOW(), b'0'), |
| | | (1065505, 5, 'è´¨ä¿é', '5', 'crm_payment_stage', 0, 'danger', '', '', '1', NOW(), '1', NOW(), b'0') |
| | | ON DUPLICATE KEY UPDATE `sort` = VALUES(`sort`), `label` = VALUES(`label`), `value` = VALUES(`value`), |
| | | `status` = VALUES(`status`), `color_type` = VALUES(`color_type`), `deleted` = b'0'; |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | -- ============================================= |
| | | -- å°è´§éç¥åè¡¥å
éè´ååå· |
| | | -- èæ¯ï¼éè´éè´§éæ©ãæ¢è´§ãåï¼ç³»ç»éæ°çæå°è´§éç¥åå¹¶éæ°è´¨æ£ï¼ |
| | | -- éè¦å¨å°è´§éç¥åä¸éæ°å
³èåéè´ååå·ï¼ä¾¿äºéè´/è´¢å¡è¿½æº¯ã |
| | | -- ç®æ åºï¼mom-ntshï¼MySQL 8.4ï¼ |
| | | -- 说æï¼èæ¬å¯é夿§è¡ï¼ä¸å
å« tenant_idï¼æ¬é¡¹ç®ä¸ä½¿ç¨å¤ç§æ·ï¼ |
| | | -- ============================================= |
| | | |
| | | SET @exists = (SELECT COUNT(*) FROM information_schema.columns |
| | | WHERE table_schema = DATABASE() AND table_name = 'mes_wm_arrival_notice' AND column_name = 'contract_no'); |
| | | SET @sql = IF(@exists = 0, |
| | | 'ALTER TABLE mes_wm_arrival_notice ADD COLUMN contract_no VARCHAR(64) NULL COMMENT ''éè´ååå·ï¼å建æ¶ä»éè´è®¢åå¿«ç
§ï¼æ¢è´§å°è´§æ²¿ç¨éè´§åååå·ï¼'' AFTER purchase_order_code', |
| | | 'SELECT 1'); |
| | | PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt; |
| | | |
| | | -- å岿°æ®åå¡«ï¼ä»éè´è®¢åè¡¥ååå· |
| | | UPDATE mes_wm_arrival_notice n |
| | | JOIN erp_purchase_order o ON o.id = n.purchase_order_id AND o.deleted = 0 |
| | | SET n.contract_no = o.contract_no |
| | | WHERE (n.contract_no IS NULL OR n.contract_no = '') |
| | | AND n.purchase_order_id IS NOT NULL; |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | -- 离èç³è¯·å¢å¼ºï¼äº¤æ¥åå·¥/ç¨æ·ä¸ç¨æ·æ°æ®è½¬ç§»ã离è审æ¹åç±»ãå°æèªå¨ç¦»è Job |
| | | -- å¯é夿§è¡ï¼ä¸å
å« tenant_idã |
| | | |
| | | -- 1. ç¨æ·æ°æ®äº¤æ¥æ å°è¡¨ï¼è¡¥é½åå·¥IDç»´åº¦ï¼ |
| | | CREATE TABLE IF NOT EXISTS `hrm_user_handover` ( |
| | | `id` bigint NOT NULL AUTO_INCREMENT COMMENT 'æ å°ID', |
| | | `from_employee_id` bigint DEFAULT NULL COMMENT '离èåå·¥ID', |
| | | `from_user_id` bigint NOT NULL COMMENT '离èç¨æ·ID', |
| | | `to_employee_id` bigint DEFAULT NULL COMMENT '交æ¥ç®æ åå·¥ID', |
| | | `to_user_id` bigint NOT NULL COMMENT '交æ¥ç®æ ç¨æ·ID', |
| | | `resignation_id` bigint NOT NULL COMMENT 'å
³èç离èç³è¯·ID', |
| | | `handover_status` tinyint NOT NULL DEFAULT 0 COMMENT '交æ¥ç¶æï¼0-è¿è¡ä¸ï¼20-已宿', |
| | | `handover_time` datetime DEFAULT NULL COMMENT '交æ¥å®ææ¶é´', |
| | | `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT 'å建è
', |
| | | `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'å建æ¶é´', |
| | | `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT 'æ´æ°è
', |
| | | `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'æ´æ°æ¶é´', |
| | | `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT 'æ¯å¦å é¤', |
| | | PRIMARY KEY (`id`) USING BTREE, |
| | | UNIQUE KEY `uk_from_to_resignation` (`from_user_id`, `to_user_id`, `resignation_id`), |
| | | KEY `idx_from_user_id` (`from_user_id`), |
| | | KEY `idx_to_user_id` (`to_user_id`) |
| | | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='HRMç¨æ·æ°æ®äº¤æ¥æ å°è¡¨'; |
| | | |
| | | -- 1.1 å·²åå¨çæ§è¡¨è¡¥é½åå·¥IDå |
| | | SET @target_db = DATABASE(); |
| | | SET @ddl = (SELECT IF(COUNT(*) = 0, |
| | | 'ALTER TABLE hrm_user_handover ADD COLUMN from_employee_id BIGINT NULL COMMENT ''离èåå·¥ID'' AFTER id', |
| | | 'SELECT 1') FROM information_schema.columns WHERE table_schema = @target_db AND table_name = 'hrm_user_handover' AND column_name = 'from_employee_id'); |
| | | PREPARE hrm_stmt FROM @ddl; |
| | | EXECUTE hrm_stmt; |
| | | DEALLOCATE PREPARE hrm_stmt; |
| | | SET @ddl = (SELECT IF(COUNT(*) = 0, |
| | | 'ALTER TABLE hrm_user_handover ADD COLUMN to_employee_id BIGINT NULL COMMENT ''交æ¥ç®æ åå·¥ID'' AFTER from_user_id', |
| | | 'SELECT 1') FROM information_schema.columns WHERE table_schema = @target_db AND table_name = 'hrm_user_handover' AND column_name = 'to_employee_id'); |
| | | PREPARE hrm_stmt FROM @ddl; |
| | | EXECUTE hrm_stmt; |
| | | DEALLOCATE PREPARE hrm_stmt; |
| | | |
| | | -- 2. 离è审æ¹åç±»ï¼å端æäº¤ç processDefinitionKey åå²å¼ä¸ºè¯¥åç±»ç¼ç ï¼ |
| | | SET @category_id = (SELECT COALESCE(MAX(id), 0) + 1 FROM bpm_category); |
| | | INSERT INTO `bpm_category` (`id`, `name`, `code`, `description`, `status`, `sort`, `creator`, `updater`) |
| | | SELECT @category_id, '离è审æ¹', 'hrm_resignation_approve', '离èç³è¯·å®¡æ¹æµç¨', 0, 0, '1', '1' |
| | | FROM DUAL |
| | | WHERE NOT EXISTS (SELECT 1 FROM bpm_category WHERE code = 'hrm_resignation_approve' AND deleted = b'0'); |
| | | |
| | | -- 3. å°æèªå¨ç¦»è Jobï¼æ¯å¤© 00:10 æ§è¡ï¼ |
| | | INSERT INTO `infra_job` (`name`, `status`, `handler_name`, `handler_param`, `cron_expression`, |
| | | `retry_count`, `retry_interval`, `monitor_timeout`, `creator`, `updater`) |
| | | SELECT '离èå°æèªå¨åç', 1, 'hrmResignationAutoLeaveJob', '', '0 10 0 * * ?', 0, 0, 0, '1', '1' |
| | | FROM DUAL |
| | | WHERE NOT EXISTS (SELECT 1 FROM infra_job WHERE handler_name = 'hrmResignationAutoLeaveJob' AND deleted = b'0'); |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | -- ============================================================ |
| | | -- å®åå·¥åï¼æµè½¬è®°å½è¡¨ + ä¸çº¿ãéè´§ç³è¯·ãèå |
| | | -- æ¥æï¼2026-11-05 |
| | | -- 说æï¼ä»å¨ç©æµå·²æä¾éè´§æä½ï¼å®å模åä¸åä¿çãéè´§ç³è¯·ãé¡µé¢ |
| | | -- ============================================================ |
| | | |
| | | -- 1. å®åå·¥åæµè½¬è®°å½è¡¨ |
| | | CREATE TABLE IF NOT EXISTS `after_sale_ticket_flow` ( |
| | | `id` bigint NOT NULL AUTO_INCREMENT COMMENT 'æµè½¬è®°å½ç¼å·', |
| | | `ticket_id` bigint NOT NULL COMMENT 'å®åå·¥åç¼å·ï¼å
³è after_sale_ticket.id', |
| | | `action` varchar(32) NOT NULL COMMENT 'å¨ä½ç¼ç ï¼CREATE/UPDATE/ASSIGN/CLASSIFY/RESOLVE/ARCHIVE/CANCEL/VISIT', |
| | | `action_name` varchar(64) NOT NULL COMMENT 'å¨ä½åç§°ï¼å¦ï¼å建工åãåé
å¤ç人', |
| | | `from_status` int DEFAULT NULL COMMENT 'åæ´åç¶æï¼å
³è AfterSaleTicketStatusEnum', |
| | | `to_status` int DEFAULT NULL COMMENT 'åæ´åç¶æï¼å
³è AfterSaleTicketStatusEnum', |
| | | `content` varchar(1000) DEFAULT NULL COMMENT 'æµè½¬å
容/说æ', |
| | | `operator_id` bigint DEFAULT NULL COMMENT 'æä½äººç¨æ·ç¼å·', |
| | | `creator` varchar(64) DEFAULT '' COMMENT 'å建è
', |
| | | `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'å建æ¶é´', |
| | | `updater` varchar(64) DEFAULT '' COMMENT 'æ´æ°è
', |
| | | `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'æ´æ°æ¶é´', |
| | | `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT 'æ¯å¦å é¤', |
| | | PRIMARY KEY (`id`), |
| | | KEY `idx_ticket_id` (`ticket_id`) |
| | | ) ENGINE = InnoDB |
| | | DEFAULT CHARSET = utf8mb4 |
| | | COLLATE = utf8mb4_unicode_ci COMMENT ='å®åå·¥åæµè½¬è®°å½'; |
| | | |
| | | -- 1.1 è¡¥é½å·¥å表缺失ç客æ·è¯æ±/å¤çç»ææè¿°åï¼MySQL 䏿¯æ ADD COLUMN IF NOT EXISTSï¼ |
| | | SET @exists = (SELECT COUNT(*) FROM information_schema.columns |
| | | WHERE table_schema = DATABASE() AND table_name = 'after_sale_ticket' |
| | | AND column_name = 'feedback_description'); |
| | | SET @sql = IF(@exists = 0, |
| | | 'ALTER TABLE `after_sale_ticket` ADD COLUMN `feedback_description` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT ''客æ·è¯æ±åé¦æè¿°'' AFTER `issue_description`', |
| | | 'SELECT 1'); |
| | | PREPARE stmt FROM @sql; |
| | | EXECUTE stmt; |
| | | DEALLOCATE PREPARE stmt; |
| | | |
| | | SET @exists = (SELECT COUNT(*) FROM information_schema.columns |
| | | WHERE table_schema = DATABASE() AND table_name = 'after_sale_ticket' |
| | | AND column_name = 'result_description'); |
| | | SET @sql = IF(@exists = 0, |
| | | 'ALTER TABLE `after_sale_ticket` ADD COLUMN `result_description` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT ''å¤çç»ææè¿°'' AFTER `feedback_description`', |
| | | 'SELECT 1'); |
| | | PREPARE stmt FROM @sql; |
| | | EXECUTE stmt; |
| | | DEALLOCATE PREPARE stmt; |
| | | |
| | | -- 2. ä¸çº¿ãéè´§ç³è¯·ãèåï¼å«æé®æéï¼ |
| | | -- éè´§ç³è¯·èå id = 602589ï¼ç¶èå = å®å管ç 602587ï¼ |
| | | -- å¦å
¶ä»ç¯å¢ id ä¸åï¼æ path = '/aftersales/return/index' å®ä½åæ¿æ¢ã |
| | | DELETE FROM `system_role_menu` |
| | | WHERE `menu_id` IN (SELECT `id` FROM `system_menu` |
| | | WHERE `id` = 602589 OR `parent_id` = 602589); |
| | | |
| | | DELETE FROM `system_menu` |
| | | WHERE `parent_id` = 602589; |
| | | |
| | | DELETE FROM `system_menu` |
| | | WHERE `id` = 602589 |
| | | AND `component` LIKE '%aftersales/return/index%'; |
| | |
| | | -- HRMç¨æ·æ°æ®äº¤æ¥æ å°è¡¨ |
| | | CREATE TABLE IF NOT EXISTS `hrm_user_handover` ( |
| | | `id` bigint NOT NULL AUTO_INCREMENT COMMENT 'æ å°ID', |
| | | `from_employee_id` bigint DEFAULT NULL COMMENT '离èåå·¥ID', |
| | | `from_user_id` bigint NOT NULL COMMENT '离èç¨æ·ID', |
| | | `to_employee_id` bigint DEFAULT NULL COMMENT '交æ¥ç®æ åå·¥ID', |
| | | `to_user_id` bigint NOT NULL COMMENT '交æ¥ç®æ ç¨æ·ID', |
| | | `resignation_id` bigint NOT NULL COMMENT 'å
³èç离èç³è¯·ID', |
| | | `handover_status` tinyint NOT NULL DEFAULT 0 COMMENT '交æ¥ç¶æï¼0-è¿è¡ä¸ï¼20-已宿', |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.framework.excel.core.handler; |
| | | |
| | | import java.lang.annotation.Documented; |
| | | import java.lang.annotation.ElementType; |
| | | import java.lang.annotation.Retention; |
| | | import java.lang.annotation.RetentionPolicy; |
| | | import java.lang.annotation.Target; |
| | | |
| | | /** |
| | | * Excel å¿
å¡«åæ®µæ è®° |
| | | * |
| | | * <p>æ æ³¨å¨å¯¼å
¥ VO çåæ®µä¸ï¼å¯¼åºã模æ¿ãç±» Excel æ¶ï¼ |
| | | * {@link RequiredHeaderWriteHandler} 伿坹åºè¡¨å¤´æ 红并å 䏿å·ï¼æç¤ºç¨æ·è¯¥åå¿
å¡«ã |
| | | * |
| | | * @author è¶
级管çå |
| | | */ |
| | | @Documented |
| | | @Target(ElementType.FIELD) |
| | | @Retention(RetentionPolicy.RUNTIME) |
| | | public @interface ExcelRequired { |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.framework.excel.core.handler; |
| | | |
| | | import cn.idev.excel.metadata.Head; |
| | | import cn.idev.excel.write.handler.CellWriteHandler; |
| | | import cn.idev.excel.write.handler.context.CellWriteHandlerContext; |
| | | import org.apache.poi.ss.usermodel.Cell; |
| | | import org.apache.poi.ss.usermodel.CellStyle; |
| | | import org.apache.poi.ss.usermodel.Font; |
| | | import org.apache.poi.ss.usermodel.IndexedColors; |
| | | import org.apache.poi.ss.usermodel.Workbook; |
| | | |
| | | import java.lang.reflect.Field; |
| | | |
| | | /** |
| | | * å¿
填表头å¤çå¨ |
| | | * |
| | | * <p>å¯¼åºæ¨¡æ¿æ¶ï¼ææ æ³¨äº {@link ExcelRequired} çåæ®µå¯¹åºç表头æåæ 红ï¼å¹¶å¨åé¢å ä¸ä¸ªæå·ï¼ |
| | | * è®©ç¨æ·ä¸ç¼çåºåªäºåå¿
须填åã |
| | | * |
| | | * @author è¶
级管çå |
| | | */ |
| | | public class RequiredHeaderWriteHandler implements CellWriteHandler { |
| | | |
| | | private static final String REQUIRED_MARK = "*"; |
| | | |
| | | @Override |
| | | public void afterCellDispose(CellWriteHandlerContext context) { |
| | | // 1. åªå¤ç表头åå
æ ¼ |
| | | if (!Boolean.TRUE.equals(context.getHead())) { |
| | | return; |
| | | } |
| | | Head head = context.getHeadData(); |
| | | Cell cell = context.getCell(); |
| | | if (head == null || head.getField() == null || cell == null) { |
| | | return; |
| | | } |
| | | // 2. åªå¤çæ æ³¨äº @ExcelRequired çåæ®µ |
| | | Field field = head.getField(); |
| | | if (!field.isAnnotationPresent(ExcelRequired.class)) { |
| | | return; |
| | | } |
| | | // 3. å¤çº§è¡¨å¤´æ¶åªæ è®°æåä¸è¡ï¼é¿å
ç¶çº§è¡¨å¤´éå¤å æå· |
| | | int lastHeadRowIndex = head.getHeadNameList() == null ? 0 : head.getHeadNameList().size() - 1; |
| | | if (context.getRelativeRowIndex() != null && context.getRelativeRowIndex() < lastHeadRowIndex) { |
| | | return; |
| | | } |
| | | |
| | | // 4. è¡¨å¤´å æå· |
| | | String text = cell.getStringCellValue(); |
| | | if (text != null && !text.startsWith(REQUIRED_MARK)) { |
| | | cell.setCellValue(REQUIRED_MARK + text); |
| | | } |
| | | // 5. å使 红ï¼å¹¶ä¿çåæè¡¨å¤´æ ·å¼çå
¶å®å±æ§ |
| | | Workbook workbook = cell.getSheet().getWorkbook(); |
| | | CellStyle oldStyle = cell.getCellStyle(); |
| | | CellStyle style = workbook.createCellStyle(); |
| | | style.cloneStyleFrom(oldStyle); |
| | | Font oldFont = workbook.getFontAt(oldStyle.getFontIndex()); |
| | | Font font = workbook.createFont(); |
| | | font.setFontName(oldFont.getFontName()); |
| | | font.setFontHeightInPoints(oldFont.getFontHeightInPoints()); |
| | | font.setBold(oldFont.getBold()); |
| | | font.setItalic(oldFont.getItalic()); |
| | | font.setColor(IndexedColors.RED.getIndex()); |
| | | style.setFont(font); |
| | | cell.setCellStyle(style); |
| | | } |
| | | |
| | | } |
| | |
| | | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| | | import cn.iocoder.yudao.module.aftersales.api.dto.AfterSaleReturnRespDTO; |
| | | import cn.iocoder.yudao.module.aftersales.api.dto.AfterSaleTicketRespDTO; |
| | | import cn.iocoder.yudao.module.aftersales.api.dto.AfterSaleWarehouseReturnCreateReqDTO; |
| | | |
| | | import java.math.BigDecimal; |
| | | |
| | |
| | | CommonResult<Boolean> onRefundCompleted(Long returnId, BigDecimal actualRefundPrice); |
| | | |
| | | /** |
| | | * ä»å¨ç©æµå建éå®éè´§åååè°ï¼ç¨äºå¨å
³èå®åå·¥åä¸çç |
| | | * |
| | | * @param reqDTO éè´§åä¿¡æ¯ï¼éå®è®¢åç¼å·ãéè´§åå·ãéè´§åå çï¼ |
| | | */ |
| | | CommonResult<Boolean> onWarehouseReturnCreated(AfterSaleWarehouseReturnCreateReqDTO reqDTO); |
| | | |
| | | /** |
| | | * æ¥è¯¢å®åå·¥åï¼ä¾ MES/ERP æ¥è¯¢å
³èä¿¡æ¯ï¼ |
| | | * |
| | | * @param id å·¥åç¼å· |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.aftersales.api.dto; |
| | | |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | |
| | | /** |
| | | * ä»å¨ç©æµå建éå®éè´§åå忥ç»å®åå·¥åç Request DTO |
| | | */ |
| | | @Schema(description = "ä»å¨ç©æµéå®éè´§åå建éç¥ Request DTO") |
| | | @Data |
| | | public class AfterSaleWarehouseReturnCreateReqDTO { |
| | | |
| | | @Schema(description = "éå®è®¢åç¼å·ï¼ç¨äºå¹é
å
³èçå®åå·¥å", example = "1") |
| | | private Long saleOrderId; |
| | | |
| | | @Schema(description = "MES éå®éè´§åç¼å·", example = "1") |
| | | private Long returnSalesId; |
| | | |
| | | @Schema(description = "MES éå®éè´§åå·", example = "XSTH202611050001") |
| | | private String returnSalesCode; |
| | | |
| | | @Schema(description = "éè´§åå ", example = "客æ·åé¦å¤è§ç ´æ") |
| | | private String returnReason; |
| | | |
| | | } |
| | |
| | | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| | | import cn.iocoder.yudao.module.aftersales.api.dto.AfterSaleReturnRespDTO; |
| | | import cn.iocoder.yudao.module.aftersales.api.dto.AfterSaleTicketRespDTO; |
| | | import cn.iocoder.yudao.module.aftersales.api.dto.AfterSaleWarehouseReturnCreateReqDTO; |
| | | import cn.iocoder.yudao.module.aftersales.dal.dataobject.returnobj.AfterSaleReturnDO; |
| | | import cn.iocoder.yudao.module.aftersales.dal.dataobject.ticket.AfterSaleTicketDO; |
| | | import cn.iocoder.yudao.module.aftersales.service.returnobj.AfterSaleReturnService; |
| | |
| | | } |
| | | |
| | | @Override |
| | | public CommonResult<Boolean> onWarehouseReturnCreated(AfterSaleWarehouseReturnCreateReqDTO reqDTO) { |
| | | ticketService.onWarehouseReturnCreated(reqDTO.getSaleOrderId(), reqDTO.getReturnSalesId(), |
| | | reqDTO.getReturnSalesCode(), reqDTO.getReturnReason()); |
| | | return success(true); |
| | | } |
| | | |
| | | @Override |
| | | public CommonResult<AfterSaleTicketRespDTO> getTicket(Long id) { |
| | | AfterSaleTicketDO ticket = ticketService.getTicket(id); |
| | | return success(BeanUtils.toBean(ticket, AfterSaleTicketRespDTO.class)); |
| | |
| | | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| | | import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; |
| | | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| | | import cn.iocoder.yudao.module.aftersales.controller.admin.ticket.vo.ticket.AfterSaleTicketFlowRespVO; |
| | | import cn.iocoder.yudao.module.aftersales.controller.admin.ticket.vo.ticket.AfterSaleTicketPageReqVO; |
| | | import cn.iocoder.yudao.module.aftersales.controller.admin.ticket.vo.ticket.AfterSaleTicketRespVO; |
| | | import cn.iocoder.yudao.module.aftersales.controller.admin.ticket.vo.ticket.AfterSaleTicketSaveReqVO; |
| | | import cn.iocoder.yudao.module.aftersales.dal.dataobject.ticket.AfterSaleTicketDO; |
| | | import cn.iocoder.yudao.module.aftersales.dal.dataobject.ticket.AfterSaleTicketFlowDO; |
| | | import cn.iocoder.yudao.module.aftersales.dal.dataobject.ticket.AfterSaleTicketItemDO; |
| | | import cn.iocoder.yudao.module.aftersales.enums.AfterSaleTicketStatusEnum; |
| | | import cn.iocoder.yudao.module.aftersales.service.ticket.AfterSaleTicketFlowService; |
| | | import cn.iocoder.yudao.module.aftersales.service.ticket.AfterSaleTicketService; |
| | | import cn.iocoder.yudao.module.crm.api.customer.CrmCustomerApi; |
| | | import cn.iocoder.yudao.module.crm.api.customer.dto.CrmCustomerRespDTO; |
| | |
| | | |
| | | @Resource |
| | | private AfterSaleTicketService ticketService; |
| | | @Resource |
| | | private AfterSaleTicketFlowService ticketFlowService; |
| | | |
| | | @Resource |
| | | private CrmCustomerApi customerApi; |
| | |
| | | List<AfterSaleTicketRespVO> enrichedList = buildTicketDetailList(List.of(ticket)); |
| | | AfterSaleTicketRespVO respVO = enrichedList.get(0); |
| | | respVO.setItems(BeanUtils.toBean(items, AfterSaleTicketRespVO.Item.class)); |
| | | respVO.setFeedbackAttachmentList( |
| | | storageAttachmentApi.listAttachments("aftersales_after_sale_ticket_feedback", id)); |
| | | respVO.setResultAttachmentList( |
| | | storageAttachmentApi.listAttachments("aftersales_after_sale_ticket_result", id)); |
| | | respVO.setAttachmentList(storageAttachmentApi.listAttachments("aftersales_after_sale_ticket", id)); |
| | | respVO.setFlowList(buildFlowList(id)); |
| | | return success(respVO); |
| | | } |
| | | |
| | | @GetMapping("/flow-list") |
| | | @Operation(summary = "è·å¾å®åå·¥åæµè½¬è®°å½") |
| | | @Parameter(name = "ticketId", description = "å·¥åç¼å·", required = true, example = "1") |
| | | public CommonResult<List<AfterSaleTicketFlowRespVO>> getTicketFlowList(@RequestParam("ticketId") Long ticketId) { |
| | | return success(buildFlowList(ticketId)); |
| | | } |
| | | |
| | | @GetMapping("/page") |
| | |
| | | PageResult<AfterSaleTicketDO> pageResult = ticketService.getTicketPage(pageReqVO, getLoginUserId()); |
| | | List<AfterSaleTicketRespVO> list = buildTicketDetailList(pageResult.getList()); |
| | | return success(new PageResult<>(list, pageResult.getTotal())); |
| | | } |
| | | |
| | | @PostMapping("/assign") |
| | | @Operation(summary = "åé
å¤ç人") |
| | | @PreAuthorize("@ss.hasPermission('aftersales:ticket:update')") |
| | | public CommonResult<Boolean> assignTicket(@RequestParam("id") Long id, |
| | | @RequestParam("handlerUserId") Long handlerUserId) { |
| | | ticketService.assignTicket(id, handlerUserId); |
| | | return success(true); |
| | | } |
| | | |
| | | @PostMapping("/classify") |
| | |
| | | return success(true); |
| | | } |
| | | |
| | | // ========== å
鍿¹æ³ï¼æ¹éæ¼è£
å
³èåç§° ========== |
| | | // ========== å
鍿¹æ³ï¼æµè½¬è®°å½ / æ¹éæ¼è£
å
³èåç§° ========== |
| | | |
| | | private List<AfterSaleTicketFlowRespVO> buildFlowList(Long ticketId) { |
| | | List<AfterSaleTicketFlowDO> flowList = ticketFlowService.getFlowList(ticketId); |
| | | if (CollUtil.isEmpty(flowList)) { |
| | | return Collections.emptyList(); |
| | | } |
| | | Set<Long> operatorIds = convertSet(flowList, AfterSaleTicketFlowDO::getOperatorId); |
| | | Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(operatorIds); |
| | | return BeanUtils.toBean(flowList, AfterSaleTicketFlowRespVO.class, vo -> { |
| | | vo.setFromStatusName(getStatusName(vo.getFromStatus())); |
| | | vo.setToStatusName(getStatusName(vo.getToStatus())); |
| | | AdminUserRespDTO operator = userMap.get(vo.getOperatorId()); |
| | | if (operator != null) { |
| | | vo.setOperatorName(operator.getNickname()); |
| | | } else if (vo.getOperatorId() != null) { |
| | | vo.setOperatorName("ç¨æ·(ID=" + vo.getOperatorId() + ")"); |
| | | } else { |
| | | vo.setOperatorName("ç³»ç»"); |
| | | } |
| | | }); |
| | | } |
| | | |
| | | private String getStatusName(Integer status) { |
| | | if (status == null) { |
| | | return null; |
| | | } |
| | | for (AfterSaleTicketStatusEnum item : AfterSaleTicketStatusEnum.values()) { |
| | | if (item.getStatus().equals(status)) { |
| | | return item.getName(); |
| | | } |
| | | } |
| | | return "æªç¥ç¶æ(ID=" + status + ")"; |
| | | } |
| | | |
| | | private List<AfterSaleTicketRespVO> buildTicketDetailList(List<AfterSaleTicketDO> ticketList) { |
| | | if (CollUtil.isEmpty(ticketList)) { |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.aftersales.controller.admin.ticket.vo.ticket; |
| | | |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | |
| | | import java.time.LocalDateTime; |
| | | |
| | | /** |
| | | * å®åå·¥åæµè½¬è®°å½ Response VO |
| | | */ |
| | | @Schema(description = "å®åå·¥å - æµè½¬è®°å½ Response VO") |
| | | @Data |
| | | public class AfterSaleTicketFlowRespVO { |
| | | |
| | | @Schema(description = "æµè½¬è®°å½ç¼å·", example = "1") |
| | | private Long id; |
| | | |
| | | @Schema(description = "å·¥åç¼å·", example = "1") |
| | | private Long ticketId; |
| | | |
| | | @Schema(description = "å¨ä½ç¼ç ", example = "ASSIGN") |
| | | private String action; |
| | | |
| | | @Schema(description = "å¨ä½åç§°", example = "åé
å¤ç人") |
| | | private String actionName; |
| | | |
| | | @Schema(description = "åæ´åç¶æ", example = "0") |
| | | private Integer fromStatus; |
| | | |
| | | @Schema(description = "åæ´åç¶æåç§°", example = "è稿") |
| | | private String fromStatusName; |
| | | |
| | | @Schema(description = "åæ´åç¶æ", example = "10") |
| | | private Integer toStatus; |
| | | |
| | | @Schema(description = "åæ´åç¶æåç§°", example = "å¤çä¸") |
| | | private String toStatusName; |
| | | |
| | | @Schema(description = "æµè½¬å
容", example = "åé
å¤ç人ï¼å¼ ä¸") |
| | | private String content; |
| | | |
| | | @Schema(description = "æä½äººç¨æ·ç¼å·", example = "1") |
| | | private Long operatorId; |
| | | |
| | | @Schema(description = "æä½äººåç§°", example = "å¼ ä¸") |
| | | private String operatorName; |
| | | |
| | | @Schema(description = "æä½æ¶é´") |
| | | private LocalDateTime createTime; |
| | | |
| | | } |
| | |
| | | @Schema(description = "客æ·è¯æ±åé¦æè¿°") |
| | | private String feedbackDescription; |
| | | |
| | | @Schema(description = "客æ·è¯æ±éä»¶å表") |
| | | private List<StorageBlobRespDTO> feedbackAttachmentList; |
| | | |
| | | @Schema(description = "å¤çç»ææè¿°") |
| | | private String resultDescription; |
| | | |
| | | @Schema(description = "å¤çç»æéä»¶å表") |
| | | private List<StorageBlobRespDTO> resultAttachmentList; |
| | | |
| | | @Schema(description = "严éç¨åº¦: 0-轻微 1-ä¸è¬ 2-严é 3-è´å½", example = "1") |
| | | private Integer severityLevel; |
| | |
| | | @Schema(description = "æ´æ°æ¶é´") |
| | | private LocalDateTime updateTime; |
| | | |
| | | @Schema(description = "éä»¶å表") |
| | | @Schema(description = "éç¨éä»¶å表ï¼å岿°æ®ï¼") |
| | | private List<StorageBlobRespDTO> attachmentList; |
| | | |
| | | @Schema(description = "æµè½¬è®°å½åè¡¨ï¼ææ¶é´æ£åºï¼") |
| | | private List<AfterSaleTicketFlowRespVO> flowList; |
| | | |
| | | @Schema(description = "æç»è¡å表") |
| | | private List<Item> items; |
| | | |
| | |
| | | @Schema(description = "客æ·è¯æ±åé¦æè¿°") |
| | | private String feedbackDescription; |
| | | |
| | | @Schema(description = "客æ·è¯æ±éä»¶ blobId å表", example = "[1, 2]") |
| | | private List<Long> feedbackBlobIds; |
| | | |
| | | @Schema(description = "å¤çç»ææè¿°") |
| | | private String resultDescription; |
| | | |
| | | @Schema(description = "å¤çç»æéä»¶ blobId å表", example = "[3, 4]") |
| | | private List<Long> resultBlobIds; |
| | | |
| | | @Schema(description = "严éç¨åº¦: 0-轻微 1-ä¸è¬ 2-严é 3-è´å½", example = "1") |
| | | private Integer severityLevel; |
| | |
| | | @Schema(description = "夿³¨", example = "客æ·è¦æ±å°½å¿«å¤ç") |
| | | private String remark; |
| | | |
| | | @Schema(description = "éä»¶ blobId å表", example = "[1, 2, 3]") |
| | | @Schema(description = "éç¨éä»¶ blobId å表ï¼åå²åæ®µï¼æ°æ°æ®è¯·ä½¿ç¨ feedbackBlobIds / resultBlobIdsï¼", example = "[1, 2, 3]") |
| | | private List<Long> blobIds; |
| | | |
| | | @Schema(description = "æç»è¡å表") |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.aftersales.dal.dataobject.ticket; |
| | | |
| | | import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; |
| | | import com.baomidou.mybatisplus.annotation.KeySequence; |
| | | import com.baomidou.mybatisplus.annotation.TableId; |
| | | import com.baomidou.mybatisplus.annotation.TableName; |
| | | import lombok.*; |
| | | |
| | | /** |
| | | * å®åå·¥åæµè½¬è®°å½ DO |
| | | * |
| | | * 工忝䏿¬¡ç¶ææ¨è¿ãå¤çå¨ä½é½ä¼å¨è¿éçä¸ä¸æ¡è®°å½ï¼ä¾è¯¦æ
é¡µææ¶é´çº¿å±ç¤ºã |
| | | */ |
| | | @TableName("after_sale_ticket_flow") |
| | | @KeySequence("after_sale_ticket_flow_seq") |
| | | @Data |
| | | @EqualsAndHashCode(callSuper = true) |
| | | @ToString(callSuper = true) |
| | | @Builder |
| | | @NoArgsConstructor |
| | | @AllArgsConstructor |
| | | public class AfterSaleTicketFlowDO extends BaseDO { |
| | | |
| | | /** |
| | | * æµè½¬è®°å½ç¼å· |
| | | */ |
| | | @TableId |
| | | private Long id; |
| | | /** |
| | | * å·¥åç¼å·ï¼å
³è after_sale_ticket.id |
| | | */ |
| | | private Long ticketId; |
| | | /** |
| | | * å¨ä½ç¼ç ï¼CREATE/UPDATE/ASSIGN/CLASSIFY/RESOLVE/ARCHIVE/CANCEL/VISIT |
| | | */ |
| | | private String action; |
| | | /** |
| | | * å¨ä½åç§°ï¼å¦ãå建工åããåé
å¤ç人ã |
| | | */ |
| | | private String actionName; |
| | | /** |
| | | * åæ´åç¶æï¼å
³è AfterSaleTicketStatusEnum |
| | | */ |
| | | private Integer fromStatus; |
| | | /** |
| | | * åæ´åç¶æï¼å
³è AfterSaleTicketStatusEnum |
| | | */ |
| | | private Integer toStatus; |
| | | /** |
| | | * æµè½¬å
容/说æ |
| | | */ |
| | | private String content; |
| | | /** |
| | | * æä½äººç¨æ·ç¼å· |
| | | */ |
| | | private Long operatorId; |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.aftersales.dal.mysql.ticket; |
| | | |
| | | import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; |
| | | import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; |
| | | import cn.iocoder.yudao.module.aftersales.dal.dataobject.ticket.AfterSaleTicketFlowDO; |
| | | import org.apache.ibatis.annotations.Mapper; |
| | | |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * å®åå·¥åæµè½¬è®°å½ Mapper |
| | | */ |
| | | @Mapper |
| | | public interface AfterSaleTicketFlowMapper extends BaseMapperX<AfterSaleTicketFlowDO> { |
| | | |
| | | default List<AfterSaleTicketFlowDO> selectListByTicketId(Long ticketId) { |
| | | return selectList(new LambdaQueryWrapperX<AfterSaleTicketFlowDO>() |
| | | .eq(AfterSaleTicketFlowDO::getTicketId, ticketId) |
| | | .orderByAsc(AfterSaleTicketFlowDO::getCreateTime) |
| | | .orderByAsc(AfterSaleTicketFlowDO::getId)); |
| | | } |
| | | |
| | | } |
| | |
| | | return selectOne(AfterSaleTicketDO::getSaleOrderId, saleOrderId); |
| | | } |
| | | |
| | | default List<AfterSaleTicketDO> selectListBySaleOrderId(Long saleOrderId) { |
| | | return selectList(new LambdaQueryWrapperX<AfterSaleTicketDO>() |
| | | .eq(AfterSaleTicketDO::getSaleOrderId, saleOrderId) |
| | | .orderByDesc(AfterSaleTicketDO::getId)); |
| | | } |
| | | |
| | | default Long selectCountByOwnerUserId(Long ownerUserId) { |
| | | return selectCount(AfterSaleTicketDO::getOwnerUserId, ownerUserId); |
| | | } |
| | |
| | | ErrorCode TICKET_BPM_PROCESS_DEFINITION_NOT_EXISTS = new ErrorCode(1_022_000_007, "å®åå·¥åå®¡æ¹æµç¨ä¸åå¨ææªæ¿æ´»ï¼è¯·æ£æ¥ BPM é
ç½®"); |
| | | ErrorCode TICKET_STATUS_ERROR = new ErrorCode(1_022_000_008, "å·¥åå½åç¶æä¸å
è®¸æ¤æä½"); |
| | | ErrorCode TICKET_ARCHIVE_FAIL_NOT_VISITED = new ErrorCode(1_022_000_009, "彿¡£å¤±è´¥ï¼åå ï¼å·¥åå°æªå访éè¿ï¼è¯·å
ç»è®°æ»¡æçå访记å½"); |
| | | ErrorCode TICKET_HANDLER_REQUIRED = new ErrorCode(1_022_000_010, "æ°å¢å®åå·¥åå¿
须鿩å¤ç人ï¼è¯·å¨ãå¤ç人ãåæ®µéæ©ä¸åç¨æ·ååä¿å"); |
| | | |
| | | // ========== å®åå·¥åæç»è¡ 1-022-001-000 ========== |
| | | ErrorCode TICKET_ITEM_NOT_EXISTS = new ErrorCode(1_022_001_000, "å·¥åæç»è¡ä¸åå¨"); |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.aftersales.service.ticket; |
| | | |
| | | import cn.iocoder.yudao.module.aftersales.dal.dataobject.ticket.AfterSaleTicketFlowDO; |
| | | |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * å®åå·¥åæµè½¬è®°å½ Service æ¥å£ |
| | | */ |
| | | public interface AfterSaleTicketFlowService { |
| | | |
| | | // ========== å¨ä½ç¼ç ========== |
| | | |
| | | String ACTION_CREATE = "CREATE"; |
| | | String ACTION_UPDATE = "UPDATE"; |
| | | String ACTION_ASSIGN = "ASSIGN"; |
| | | String ACTION_CLASSIFY = "CLASSIFY"; |
| | | String ACTION_RESOLVE = "RESOLVE"; |
| | | String ACTION_ARCHIVE = "ARCHIVE"; |
| | | String ACTION_CANCEL = "CANCEL"; |
| | | String ACTION_VISIT = "VISIT"; |
| | | String ACTION_RETURN = "RETURN"; |
| | | |
| | | /** |
| | | * è®°å½ä¸æ¡æµè½¬æ¥å¿ |
| | | * |
| | | * @param ticketId å·¥åç¼å· |
| | | * @param action å¨ä½ç¼ç |
| | | * @param actionName å¨ä½åç§° |
| | | * @param fromStatus åæ´åç¶æï¼å¯ä¸ºç©º |
| | | * @param toStatus åæ´åç¶æï¼å¯ä¸ºç©º |
| | | * @param content æµè½¬å
容 |
| | | */ |
| | | void record(Long ticketId, String action, String actionName, |
| | | Integer fromStatus, Integer toStatus, String content); |
| | | |
| | | /** |
| | | * è·å¾å·¥åçæµè½¬è®°å½åè¡¨ï¼ææ¶é´æ£åºï¼ |
| | | * |
| | | * @param ticketId å·¥åç¼å· |
| | | * @return æµè½¬è®°å½å表 |
| | | */ |
| | | List<AfterSaleTicketFlowDO> getFlowList(Long ticketId); |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.aftersales.service.ticket; |
| | | |
| | | import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; |
| | | import cn.iocoder.yudao.module.aftersales.dal.dataobject.ticket.AfterSaleTicketFlowDO; |
| | | import cn.iocoder.yudao.module.aftersales.dal.mysql.ticket.AfterSaleTicketFlowMapper; |
| | | import jakarta.annotation.Resource; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.validation.annotation.Validated; |
| | | |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * å®åå·¥åæµè½¬è®°å½ Service å®ç°ç±» |
| | | */ |
| | | @Service |
| | | @Validated |
| | | public class AfterSaleTicketFlowServiceImpl implements AfterSaleTicketFlowService { |
| | | |
| | | @Resource |
| | | private AfterSaleTicketFlowMapper ticketFlowMapper; |
| | | |
| | | @Override |
| | | public void record(Long ticketId, String action, String actionName, |
| | | Integer fromStatus, Integer toStatus, String content) { |
| | | Long operatorId = SecurityFrameworkUtils.getLoginUserId(); |
| | | AfterSaleTicketFlowDO flow = AfterSaleTicketFlowDO.builder() |
| | | .ticketId(ticketId) |
| | | .action(action) |
| | | .actionName(actionName) |
| | | .fromStatus(fromStatus) |
| | | .toStatus(toStatus) |
| | | .content(content) |
| | | .operatorId(operatorId) |
| | | .build(); |
| | | ticketFlowMapper.insert(flow); |
| | | } |
| | | |
| | | @Override |
| | | public List<AfterSaleTicketFlowDO> getFlowList(Long ticketId) { |
| | | return ticketFlowMapper.selectListByTicketId(ticketId); |
| | | } |
| | | |
| | | } |
| | |
| | | List<AfterSaleTicketItemDO> getTicketItemListByTicketId(Long ticketId); |
| | | |
| | | /** |
| | | * åé
å¤ç人 |
| | | * ä»å¨ç©æµå建éå®éè´§ååï¼å¨å
³èéå®è®¢åçå®åå·¥åä¸è®°å½æµè½¬ |
| | | * |
| | | * @param id å·¥åç¼å· |
| | | * @param handlerUserId å¤çäººç¨æ·ç¼å· |
| | | * @param saleOrderId éå®è®¢åç¼å· |
| | | * @param returnSalesId MES éå®éè´§åç¼å· |
| | | * @param returnSalesCode MES éå®éè´§åå· |
| | | * @param returnReason éè´§åå |
| | | */ |
| | | void assignTicket(Long id, Long handlerUserId); |
| | | void onWarehouseReturnCreated(Long saleOrderId, Long returnSalesId, |
| | | String returnSalesCode, String returnReason); |
| | | |
| | | /** |
| | | * é®é¢å¤å®ï¼ç¡®å®é®é¢ç±»åãåç±»ã严éç¨åº¦ï¼ |
| | |
| | | import cn.iocoder.yudao.module.aftersales.dal.mysql.ticket.AfterSaleTicketMapper; |
| | | import cn.iocoder.yudao.module.aftersales.dal.redis.no.AfterSaleNoRedisDAO; |
| | | import cn.iocoder.yudao.module.aftersales.enums.AfterSaleBizTypeEnum; |
| | | import cn.iocoder.yudao.module.aftersales.enums.AfterSaleIssueTypeEnum; |
| | | import cn.iocoder.yudao.module.aftersales.enums.AfterSaleTicketStatusEnum; |
| | | import cn.iocoder.yudao.module.aftersales.enums.AfterSaleVisitStatusEnum; |
| | | import cn.iocoder.yudao.module.aftersales.enums.permission.AfterSalePermissionLevelEnum; |
| | |
| | | import cn.iocoder.yudao.module.aftersales.service.permission.bo.AfterSalePermissionCreateReqBO; |
| | | import cn.iocoder.yudao.module.aftersales.service.problem.AfterSaleProblemService; |
| | | import cn.iocoder.yudao.module.system.api.storage.StorageAttachmentApi; |
| | | import cn.iocoder.yudao.module.system.api.user.AdminUserApi; |
| | | import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; |
| | | import jakarta.annotation.Resource; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.stereotype.Service; |
| | |
| | | |
| | | import java.time.LocalDateTime; |
| | | import java.util.Collection; |
| | | import java.util.Comparator; |
| | | import java.util.List; |
| | | |
| | | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| | |
| | | @Validated |
| | | @Slf4j |
| | | public class AfterSaleTicketServiceImpl implements AfterSaleTicketService { |
| | | |
| | | /** 客æ·è¯æ±éä»¶è®°å½ç±»å */ |
| | | private static final String FEEDBACK_RECORD_TYPE = "aftersales_after_sale_ticket_feedback"; |
| | | /** å¤çç»æéä»¶è®°å½ç±»å */ |
| | | private static final String RESULT_RECORD_TYPE = "aftersales_after_sale_ticket_result"; |
| | | /** éç¨éä»¶è®°å½ç±»åï¼å岿°æ®ï¼ */ |
| | | private static final String LEGACY_RECORD_TYPE = "aftersales_after_sale_ticket"; |
| | | |
| | | @Resource |
| | | private AfterSaleTicketMapper ticketMapper; |
| | |
| | | @Resource |
| | | private StorageAttachmentApi storageAttachmentApi; |
| | | |
| | | @Resource |
| | | private AfterSaleTicketFlowService ticketFlowService; |
| | | |
| | | @Resource |
| | | private AdminUserApi adminUserApi; |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public Long createTicket(AfterSaleTicketSaveReqVO createReqVO, Long userId) { |
| | | // 1. çæåå· |
| | | // 1. æ ¡éªå¤çäººï¼æ°å¢å³åé
ï¼ä¸åæä¾åç¬çåé
å¤ç人å¨ä½ |
| | | if (createReqVO.getHandlerUserId() == null) { |
| | | throw exception(TICKET_HANDLER_REQUIRED); |
| | | } |
| | | |
| | | // 2. çæåå· |
| | | String no = noRedisDAO.generate(AfterSaleNoRedisDAO.TICKET_NO_PREFIX); |
| | | if (ticketMapper.selectByNo(no) != null) { |
| | | throw exception(TICKET_NO_EXISTS); |
| | | } |
| | | |
| | | // 2. æå
¥å·¥å |
| | | // 3. æå
¥å·¥åï¼æ°å¢æ¶å·²æå®å¤ç人ï¼ç´æ¥è¿å
¥å¤çä¸ |
| | | AfterSaleTicketDO ticket = BeanUtils.toBean(createReqVO, AfterSaleTicketDO.class) |
| | | .setNo(no) |
| | | .setStatus(AfterSaleTicketStatusEnum.DRAFT.getStatus()) |
| | | .setStatus(AfterSaleTicketStatusEnum.PROCESSING.getStatus()) |
| | | .setOwnerUserId(userId); |
| | | ticketMapper.insert(ticket); |
| | | |
| | | // 3. æå
¥æç»è¡ |
| | | // 4. æå
¥æç»è¡ |
| | | if (CollUtil.isNotEmpty(createReqVO.getItems())) { |
| | | createReqVO.getItems().forEach(item -> { |
| | | AfterSaleTicketItemDO itemDO = BeanUtils.toBean(item, AfterSaleTicketItemDO.class); |
| | |
| | | }); |
| | | } |
| | | |
| | | // 4. ç»å®éä»¶ |
| | | storageAttachmentApi.bindAttachments("file", "aftersales_after_sale_ticket", |
| | | // 5. ç»å®éä»¶ï¼å®¢æ·è¯æ±éä»¶ãå¤çç»æéä»¶åå¼åå¨ï¼åå²éç¨éä»¶åæ®µç»§ç»å
¼å®¹ |
| | | storageAttachmentApi.bindAttachments("file", FEEDBACK_RECORD_TYPE, |
| | | ticket.getId(), createReqVO.getFeedbackBlobIds()); |
| | | storageAttachmentApi.bindAttachments("file", RESULT_RECORD_TYPE, |
| | | ticket.getId(), createReqVO.getResultBlobIds()); |
| | | storageAttachmentApi.bindAttachments("file", LEGACY_RECORD_TYPE, |
| | | ticket.getId(), createReqVO.getBlobIds()); |
| | | |
| | | // 5. åå»ºæ°æ®æéï¼è´è´£äººï¼ |
| | | // 6. è®°å½æµè½¬ |
| | | String createContent = "å建å®åå·¥åã" + no + "ãï¼å¤ç人ï¼" + getHandlerName(createReqVO.getHandlerUserId()); |
| | | ticketFlowService.record(ticket.getId(), AfterSaleTicketFlowService.ACTION_CREATE, "å建工å", |
| | | null, ticket.getStatus(), createContent); |
| | | |
| | | // 7. åå»ºæ°æ®æéï¼è´è´£äººï¼ |
| | | AfterSalePermissionCreateReqBO permBO = new AfterSalePermissionCreateReqBO(); |
| | | permBO.setBizType(AfterSaleBizTypeEnum.AFTER_SALE_TICKET.getType()); |
| | | permBO.setBizId(ticket.getId()); |
| | |
| | | public void updateTicket(AfterSaleTicketSaveReqVO updateReqVO) { |
| | | // 1. æ ¡éªåå¨ |
| | | AfterSaleTicketDO ticket = validateTicketExists(updateReqVO.getId()); |
| | | validateTicketStatus(ticket, AfterSaleTicketStatusEnum.DRAFT); |
| | | validateTicketStatus(ticket, AfterSaleTicketStatusEnum.DRAFT, AfterSaleTicketStatusEnum.PROCESSING); |
| | | |
| | | // 2. æ´æ°å·¥å |
| | | // 2. æ´æ°å·¥åï¼åå²è稿补å½å¤ç人åç´æ¥è¿å
¥å¤çä¸ï¼é¿å
å åæ¶åé
èç¹èå¡å¨è稿 |
| | | AfterSaleTicketDO updateObj = BeanUtils.toBean(updateReqVO, AfterSaleTicketDO.class); |
| | | Integer targetStatus = ticket.getStatus(); |
| | | if (AfterSaleTicketStatusEnum.DRAFT.getStatus().equals(ticket.getStatus()) |
| | | && updateReqVO.getHandlerUserId() != null) { |
| | | targetStatus = AfterSaleTicketStatusEnum.PROCESSING.getStatus(); |
| | | updateObj.setStatus(targetStatus); |
| | | } |
| | | ticketMapper.updateById(updateObj); |
| | | |
| | | // 3. æ´æ°æç»è¡ï¼å
å åå¢ï¼ |
| | |
| | | }); |
| | | } |
| | | |
| | | // 4. æ´æ°éä»¶ |
| | | storageAttachmentApi.updateAttachments("file", "aftersales_after_sale_ticket", updateReqVO.getId(), updateReqVO.getBlobIds()); |
| | | // 4. æ´æ°éä»¶ï¼å®¢æ·è¯æ±ãå¤çç»æå嫿´æ°ï¼åå²éç¨éä»¶ä¿çåé»è¾ |
| | | storageAttachmentApi.updateAttachments("file", FEEDBACK_RECORD_TYPE, updateReqVO.getId(), |
| | | updateReqVO.getFeedbackBlobIds()); |
| | | storageAttachmentApi.updateAttachments("file", RESULT_RECORD_TYPE, updateReqVO.getId(), |
| | | updateReqVO.getResultBlobIds()); |
| | | storageAttachmentApi.updateAttachments("file", LEGACY_RECORD_TYPE, updateReqVO.getId(), |
| | | updateReqVO.getBlobIds()); |
| | | |
| | | // 5. è®°å½æµè½¬ |
| | | ticketFlowService.record(ticket.getId(), AfterSaleTicketFlowService.ACTION_UPDATE, "æ´æ°å·¥å", |
| | | ticket.getStatus(), targetStatus, buildUpdateFlowContent(updateReqVO, ticket.getHandlerUserId())); |
| | | } |
| | | |
| | | @Override |
| | |
| | | // 软å é¤ |
| | | ticketMapper.deleteById(id); |
| | | ticketItemMapper.deleteByTicketId(id); |
| | | storageAttachmentApi.deleteAttachmentsByRecord("aftersales_after_sale_ticket", id); |
| | | storageAttachmentApi.deleteAttachmentsByRecord(FEEDBACK_RECORD_TYPE, id); |
| | | storageAttachmentApi.deleteAttachmentsByRecord(RESULT_RECORD_TYPE, id); |
| | | storageAttachmentApi.deleteAttachmentsByRecord(LEGACY_RECORD_TYPE, id); |
| | | permissionService.deletePermission(AfterSaleBizTypeEnum.AFTER_SALE_TICKET.getType(), id); |
| | | } |
| | | |
| | |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void assignTicket(Long id, Long handlerUserId) { |
| | | AfterSaleTicketDO ticket = validateTicketExists(id); |
| | | validateTicketStatus(ticket, AfterSaleTicketStatusEnum.DRAFT, AfterSaleTicketStatusEnum.PROCESSING); |
| | | ticketMapper.updateById(new AfterSaleTicketDO().setId(id).setHandlerUserId(handlerUserId) |
| | | .setStatus(AfterSaleTicketStatusEnum.PROCESSING.getStatus())); |
| | | public void onWarehouseReturnCreated(Long saleOrderId, Long returnSalesId, |
| | | String returnSalesCode, String returnReason) { |
| | | if (saleOrderId == null) { |
| | | return; |
| | | } |
| | | // 1. æ¾å°è¯¥éå®è®¢å䏿è¿ä¸å¼ æªå
³éãæªåæ¶çå·¥å |
| | | List<AfterSaleTicketDO> tickets = ticketMapper.selectListBySaleOrderId(saleOrderId); |
| | | AfterSaleTicketDO ticket = tickets.stream() |
| | | .filter(item -> !AfterSaleTicketStatusEnum.CLOSED.getStatus().equals(item.getStatus()) |
| | | && !AfterSaleTicketStatusEnum.CANCELED.getStatus().equals(item.getStatus())) |
| | | .max(Comparator.comparing(AfterSaleTicketDO::getId)) |
| | | .orElse(null); |
| | | if (ticket == null) { |
| | | return; |
| | | } |
| | | // 2. åä¸éè´§ååªè®°å½ä¸æ¬¡ï¼é¿å
åè°éè¯äº§çéå¤è®°å½ |
| | | String returnSalesKey = returnSalesCode != null && !returnSalesCode.isBlank() |
| | | ? returnSalesCode : "ID=" + returnSalesId; |
| | | boolean recorded = ticketFlowService.getFlowList(ticket.getId()).stream() |
| | | .anyMatch(flow -> AfterSaleTicketFlowService.ACTION_RETURN.equals(flow.getAction()) |
| | | && flow.getContent() != null |
| | | && flow.getContent().contains("ã" + returnSalesKey + "ã")); |
| | | if (recorded) { |
| | | return; |
| | | } |
| | | // 3. è稿/å¤çä¸çå·¥åè¿å
¥å¾
éè´§ï¼å
¶ä»ç¶æåªççï¼ä¸æ¹ç¶æ |
| | | Integer targetStatus = ticket.getStatus(); |
| | | if (AfterSaleTicketStatusEnum.DRAFT.getStatus().equals(targetStatus) |
| | | || AfterSaleTicketStatusEnum.PROCESSING.getStatus().equals(targetStatus)) { |
| | | targetStatus = AfterSaleTicketStatusEnum.WAITING_RETURN.getStatus(); |
| | | ticketMapper.updateById(new AfterSaleTicketDO().setId(ticket.getId()).setStatus(targetStatus)); |
| | | } |
| | | // 4. åå
¥æµè½¬è®°å½ |
| | | String content = "ä»å¨ç©æµå建éå®éè´§åã" + returnSalesKey + "ã" |
| | | + (returnReason != null && !returnReason.isBlank() ? "ï¼éè´§åå ï¼" + returnReason : ""); |
| | | ticketFlowService.record(ticket.getId(), AfterSaleTicketFlowService.ACTION_RETURN, "ä»å¨éè´§", |
| | | ticket.getStatus(), targetStatus, content); |
| | | } |
| | | |
| | | private String getHandlerName(Long handlerUserId) { |
| | | AdminUserRespDTO handler = adminUserApi.getUser(handlerUserId); |
| | | return handler != null ? handler.getNickname() : "ç¨æ·(ID=" + handlerUserId + ")"; |
| | | } |
| | | |
| | | @Override |
| | |
| | | validateTicketStatus(ticket, AfterSaleTicketStatusEnum.PROCESSING); |
| | | ticketMapper.updateById(new AfterSaleTicketDO().setId(id) |
| | | .setIssueType(issueType).setIssueCategory(issueCategory).setSeverityLevel(severityLevel)); |
| | | // è®°å½æµè½¬ |
| | | ticketFlowService.record(id, AfterSaleTicketFlowService.ACTION_CLASSIFY, "é®é¢å¤å®", |
| | | ticket.getStatus(), ticket.getStatus(), |
| | | "é®é¢å¤å®ï¼ç±»å=" + getIssueTypeName(issueType) |
| | | + "ï¼åç±»=" + (issueCategory != null && !issueCategory.isBlank() ? issueCategory : "æªå¡«å") |
| | | + "ï¼ä¸¥éç¨åº¦=" + getSeverityName(severityLevel)); |
| | | } |
| | | |
| | | @Override |
| | |
| | | .setStatus(AfterSaleTicketStatusEnum.COMPLETED.getStatus()) |
| | | .setResolvedTime(LocalDateTime.now()) |
| | | .setVisitStatus(AfterSaleVisitStatusEnum.WAITING.getStatus())); |
| | | // è®°å½æµè½¬ |
| | | ticketFlowService.record(id, AfterSaleTicketFlowService.ACTION_RESOLVE, "å®ç»å·¥å", |
| | | ticket.getStatus(), AfterSaleTicketStatusEnum.COMPLETED.getStatus(), |
| | | "å·¥åå¤ç宿ï¼è¿å
¥å¾
å访"); |
| | | } |
| | | |
| | | @Override |
| | |
| | | .setClosedTime(LocalDateTime.now()) |
| | | .setProblemId(problem.getId()) |
| | | .setProblemNo(problem.getNo())); |
| | | // è®°å½æµè½¬ |
| | | ticketFlowService.record(id, AfterSaleTicketFlowService.ACTION_ARCHIVE, "彿¡£å·¥å", |
| | | AfterSaleTicketStatusEnum.COMPLETED.getStatus(), AfterSaleTicketStatusEnum.CLOSED.getStatus(), |
| | | "彿¡£å·¥åï¼æ²æ·é®é¢ã" + problem.getNo() + "ã"); |
| | | } |
| | | |
| | | @Override |
| | |
| | | validateTicketStatus(ticket, AfterSaleTicketStatusEnum.DRAFT, AfterSaleTicketStatusEnum.PROCESSING); |
| | | ticketMapper.updateById(new AfterSaleTicketDO().setId(id) |
| | | .setStatus(AfterSaleTicketStatusEnum.CANCELED.getStatus())); |
| | | // è®°å½æµè½¬ |
| | | ticketFlowService.record(id, AfterSaleTicketFlowService.ACTION_CANCEL, "åæ¶å·¥å", |
| | | ticket.getStatus(), AfterSaleTicketStatusEnum.CANCELED.getStatus(), "åæ¶å·¥å"); |
| | | } |
| | | |
| | | // ========== å
鍿¹æ³ ========== |
| | | |
| | | private String buildUpdateFlowContent(AfterSaleTicketSaveReqVO reqVO, Long originalHandlerUserId) { |
| | | StringBuilder content = new StringBuilder("æ´æ°å·¥åä¿¡æ¯"); |
| | | if (reqVO.getHandlerUserId() != null |
| | | && !reqVO.getHandlerUserId().equals(originalHandlerUserId)) { |
| | | content.append("ï¼å¤çäººåæ´ä¸ºï¼").append(getHandlerName(reqVO.getHandlerUserId())); |
| | | } |
| | | if (reqVO.getFeedbackDescription() != null && !reqVO.getFeedbackDescription().isBlank()) { |
| | | content.append("ï¼å®¢æ·è¯æ±åé¦å·²æ´æ°"); |
| | | } |
| | | if (CollUtil.isNotEmpty(reqVO.getFeedbackBlobIds())) { |
| | | content.append("ï¼å®¢æ·è¯æ±éä»¶ ").append(reqVO.getFeedbackBlobIds().size()).append(" 个"); |
| | | } |
| | | if (reqVO.getResultDescription() != null && !reqVO.getResultDescription().isBlank()) { |
| | | content.append("ï¼å¤çç»æå·²æ´æ°"); |
| | | } |
| | | if (CollUtil.isNotEmpty(reqVO.getResultBlobIds())) { |
| | | content.append("ï¼å¤çç»æéä»¶ ").append(reqVO.getResultBlobIds().size()).append(" 个"); |
| | | } |
| | | return content.toString(); |
| | | } |
| | | |
| | | private String getIssueTypeName(Integer issueType) { |
| | | if (issueType == null) { |
| | | return AfterSaleIssueTypeEnum.UNCLASSIFIED.getName(); |
| | | } |
| | | for (AfterSaleIssueTypeEnum item : AfterSaleIssueTypeEnum.values()) { |
| | | if (item.getType().equals(issueType)) { |
| | | return item.getName(); |
| | | } |
| | | } |
| | | return "æªç¥ç±»å(ID=" + issueType + ")"; |
| | | } |
| | | |
| | | private String getSeverityName(Integer severityLevel) { |
| | | if (severityLevel == null) { |
| | | return "æªå¡«å"; |
| | | } |
| | | return switch (severityLevel) { |
| | | case 0 -> "轻微"; |
| | | case 1 -> "ä¸è¬"; |
| | | case 2 -> "严é"; |
| | | case 3 -> "è´å½"; |
| | | default -> "æªç¥(ID=" + severityLevel + ")"; |
| | | }; |
| | | } |
| | | |
| | | private AfterSaleTicketDO validateTicketExists(Long id) { |
| | | AfterSaleTicketDO ticket = ticketMapper.selectById(id); |
| | | if (ticket == null) { |
| | |
| | | import cn.iocoder.yudao.module.aftersales.dal.mysql.visit.AfterSaleVisitMapper; |
| | | import cn.iocoder.yudao.module.aftersales.enums.AfterSaleTicketStatusEnum; |
| | | import cn.iocoder.yudao.module.aftersales.enums.AfterSaleVisitStatusEnum; |
| | | import cn.iocoder.yudao.module.aftersales.enums.AfterSaleVisitTypeEnum; |
| | | import cn.iocoder.yudao.module.aftersales.service.ticket.AfterSaleTicketFlowService; |
| | | import cn.iocoder.yudao.module.system.api.storage.StorageAttachmentApi; |
| | | import jakarta.annotation.Resource; |
| | | import lombok.extern.slf4j.Slf4j; |
| | |
| | | private AfterSaleTicketMapper ticketMapper; |
| | | @Resource |
| | | private StorageAttachmentApi storageAttachmentApi; |
| | | @Resource |
| | | private AfterSaleTicketFlowService ticketFlowService; |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | |
| | | .setVisitStatus(AfterSaleVisitStatusEnum.WAITING.getStatus()); |
| | | } |
| | | ticketMapper.updateById(update); |
| | | // 5. è®°å½æµè½¬ï¼å访éè¿åä¿æå·²å®ç»ï¼ä¸æ»¡æ/å¤ååéåå¤çä¸ |
| | | Integer toStatus = satisfied && !recurred |
| | | ? AfterSaleTicketStatusEnum.COMPLETED.getStatus() |
| | | : AfterSaleTicketStatusEnum.PROCESSING.getStatus(); |
| | | ticketFlowService.record(ticket.getId(), AfterSaleTicketFlowService.ACTION_VISIT, "ç»è®°å访", |
| | | ticket.getStatus(), toStatus, |
| | | "ç»è®°å访ï¼" + AfterSaleVisitTypeEnum.getNameByType(createReqVO.getVisitType()) |
| | | + "ï¼å®¢æ·" + (satisfied ? "满æ" : "䏿»¡æ") |
| | | + "ï¼é®é¢" + (recurred ? "å¤å" : "æªå¤å")); |
| | | return visitDO.getId(); |
| | | } |
| | | |
| | |
| | | @NotNull(message = "æµç¨å®ä¾ç key ä¸è½ä¸ºç©º") |
| | | private String processDefinitionKey; |
| | | /** |
| | | * æµç¨åç±»ç¼ç ã |
| | | * ä¸å¡çå¬å¨ææµç¨ key æ æ³å¹é
æ¶ï¼å¦èªå®ä¹æµç¨æ¨¡åç key 为 C000_abc. è¿ç±»éæºå¼ï¼ï¼å¯åéæåç±»å¹é
|
| | | */ |
| | | private String processDefinitionCategory; |
| | | /** |
| | | * æµç¨å®ä¾çç»æ |
| | | */ |
| | | @NotNull(message = "æµç¨å®ä¾çç¶æä¸è½ä¸ºç©º") |
| | |
| | | |
| | | @Override |
| | | public final void onApplicationEvent(BpmProcessInstanceStatusEvent event) { |
| | | if (!StrUtil.equals(event.getProcessDefinitionKey(), getProcessDefinitionKey())) { |
| | | if (!StrUtil.equals(event.getProcessDefinitionKey(), getProcessDefinitionKey()) |
| | | // å
åºï¼èªå®ä¹æµç¨æ¨¡åç key å¯è½æ¯éæºå¼ï¼æ¤æ¶ææµç¨åç±»ï¼ä¸å¡åç±»ç¼ç ï¼å¹é
|
| | | && !StrUtil.equals(event.getProcessDefinitionCategory(), getProcessDefinitionKey())) { |
| | | return; |
| | | } |
| | | onEvent(event); |
| | |
| | | }); |
| | | |
| | | // 2. æ¼æ¥ VO è¿å |
| | | // è¡¥å
表åä¿¡æ¯ï¼åå²é¨ç½² / é
置导å
¥çæµç¨å®ä¹å¯è½æ²¡æ formConfãformFieldsï¼æ formId ä» bpm_form å读 |
| | | Map<Long, BpmFormDO> formMap = formService.getFormMap( |
| | | convertSet(processDefinitionMap.values(), BpmProcessDefinitionInfoDO::getFormId)); |
| | | return success(BpmProcessDefinitionConvert.INSTANCE.buildProcessDefinitionList( |
| | | list, null, processDefinitionMap, null, null)); |
| | | list, null, processDefinitionMap, formMap, null)); |
| | | } |
| | | |
| | | @GetMapping("/simple-list") |
| | |
| | | } |
| | | BpmProcessDefinitionInfoDO processDefinitionInfo = processDefinitionService.getProcessDefinitionInfo(processDefinition.getId()); |
| | | BpmnModel bpmnModel = processDefinitionService.getProcessDefinitionBpmnModel(processDefinition.getId()); |
| | | // æ®é表åå
åºï¼æ formId å读 bpm_formï¼é¿å
formConfãformFields 为空导è´åèµ·æµç¨é¡µè¡¨åç©ºç½ |
| | | BpmFormDO form = processDefinitionInfo != null && processDefinitionInfo.getFormId() != null |
| | | ? formService.getForm(processDefinitionInfo.getFormId()) : null; |
| | | return success(BpmProcessDefinitionConvert.INSTANCE.buildProcessDefinition( |
| | | processDefinition, null, processDefinitionInfo, null, null, bpmnModel)); |
| | | processDefinition, null, processDefinitionInfo, form, null, bpmnModel)); |
| | | } |
| | | |
| | | } |
| | |
| | | import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmCategoryDO; |
| | | import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO; |
| | | import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionInfoDO; |
| | | import cn.iocoder.yudao.module.bpm.enums.definition.BpmModelFormTypeEnum; |
| | | import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils; |
| | | import org.flowable.bpmn.model.BpmnModel; |
| | | import org.flowable.common.engine.impl.db.SuspensionState; |
| | |
| | | import java.util.Comparator; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.Objects; |
| | | |
| | | /** |
| | | * Bpm æµç¨å®ä¹ç Convert |
| | |
| | | // Form |
| | | if (form != null) { |
| | | respVO.setFormName(form.getName()); |
| | | // æ®é表åï¼ä»¥ bpm_form çææ°é
置为åï¼é¿å
åå²é¨ç½² / é
置导å
¥çæ°æ®ç¼ºå¤± formConfãformFields |
| | | if (Objects.equals(respVO.getFormType(), BpmModelFormTypeEnum.NORMAL.getType())) { |
| | | respVO.setFormConf(form.getConf()).setFormFields(form.getFields()); |
| | | } |
| | | } |
| | | } |
| | | // Category |
| | |
| | | void copyTo(BpmProcessDefinitionInfoDO from, @MappingTarget BpmProcessDefinitionRespVO to); |
| | | |
| | | default BpmProcessInstanceStatusEvent buildProcessInstanceStatusEvent(Object source, ProcessInstance instance, |
| | | Integer status, String reason) { |
| | | String category, Integer status, String reason) { |
| | | return new BpmProcessInstanceStatusEvent(source).setId(instance.getId()).setStatus(status).setReason(reason) |
| | | .setProcessDefinitionKey(instance.getProcessDefinitionKey()).setBusinessKey(instance.getBusinessKey()); |
| | | .setProcessDefinitionKey(instance.getProcessDefinitionKey()) |
| | | .setProcessDefinitionCategory(category) |
| | | .setBusinessKey(instance.getBusinessKey()); |
| | | } |
| | | |
| | | default BpmMessageSendWhenProcessInstanceApproveReqDTO buildProcessInstanceApproveMessage(ProcessInstance instance) { |
| | |
| | | } |
| | | // æªå½ä¸é
ç½® / é
置被ç¦ç¨ï¼ä¿æåæ · |
| | | BpmBusinessAttachDO attach = getBusinessAttachByProcessDefinitionKey(processDefinitionKey); |
| | | // å
åºï¼èªå®ä¹æµç¨æ¨¡åç keyï¼å¦ C000_abc.ï¼ä¸ä¸å¡åç±»ä¸ä¸è´æ¶ï¼ææµç¨åç±»å¹é
ä¸å¡è¯¦æ
ç»ä»¶ã |
| | | // ä¸å¡éä»¶é
ç½®ç key å®é
åçæ¯ä¸å¡åç±»ç¼ç ï¼purchase_request_approve çï¼ï¼å
ç½®æµç¨ç key æ°å¥½ä¸åç±»ç¸åã |
| | | if (attach == null && StrUtil.isNotBlank(definitionResp.getCategory())) { |
| | | attach = getBusinessAttachByProcessDefinitionKey(definitionResp.getCategory()); |
| | | } |
| | | if (attach == null || !Objects.equals(attach.getStatus(), CommonStatusEnum.ENABLE.getStatus())) { |
| | | return; |
| | | } |
| | |
| | | import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; |
| | | import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.BpmModelMetaInfoVO; |
| | | import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO; |
| | | import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionRespVO; |
| | | import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.*; |
| | | import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmApprovalDetailRespVO.ActivityNodeTask; |
| | | import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskRespVO; |
| | | import cn.iocoder.yudao.module.bpm.convert.task.BpmProcessInstanceConvert; |
| | | import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO; |
| | | import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionInfoDO; |
| | | import cn.iocoder.yudao.module.bpm.dal.redis.BpmProcessIdRedisDAO; |
| | | import cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants; |
| | | import cn.iocoder.yudao.module.bpm.enums.definition.BpmModelFormTypeEnum; |
| | | import cn.iocoder.yudao.module.bpm.enums.definition.BpmModelTypeEnum; |
| | | import cn.iocoder.yudao.module.bpm.enums.definition.BpmSimpleModelNodeTypeEnum; |
| | | import cn.iocoder.yudao.module.bpm.enums.task.BpmAttachmentTypeEnum; |
| | |
| | | import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils; |
| | | import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.SimpleModelUtils; |
| | | import cn.iocoder.yudao.module.bpm.service.attach.BpmBusinessAttachService; |
| | | import cn.iocoder.yudao.module.bpm.service.definition.BpmFormService; |
| | | import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService; |
| | | import cn.iocoder.yudao.module.bpm.service.message.BpmMessageService; |
| | | import cn.iocoder.yudao.module.system.api.dept.DeptApi; |
| | |
| | | |
| | | @Resource |
| | | private BpmBusinessAttachService businessAttachService; |
| | | @Resource |
| | | private BpmFormService formService; |
| | | |
| | | // ========== Query æ¥è¯¢ç¸å
³æ¹æ³ ========== |
| | | |
| | |
| | | processDefinition, processDefinitionInfo, processInstance, |
| | | processInstanceStatus, approveNodes, todoTask, formFieldsPermission, userMap, deptMap); |
| | | |
| | | // 3.1 æ®é表åå
åºï¼åå²é¨ç½² / é
置导å
¥çæ°æ®ï¼bpm_process_definition_info å¯è½æ²¡æ formConfãformFieldsï¼ |
| | | // æ¤æ¶æ formId å读 bpm_formï¼é¿å
审æ¹è¯¦æ
页表ååºåç©ºç½ |
| | | fillNormalForm(detailRespVO.getProcessDefinition(), processDefinitionInfo); |
| | | |
| | | // 4. å¡«å
ä¸å¡éä»¶é
ç½®ï¼å®ç°å®¡æ¹è¯¦æ
èªå¨å±ç¤ºå¤é¨ä¸å¡ä¿¡æ¯ |
| | | businessAttachService.fillBusinessForm(detailRespVO.getProcessDefinition(), processDefinition.getKey(), |
| | | processInstance != null ? processInstance.getBusinessKey() : null); |
| | | return detailRespVO; |
| | | } |
| | | |
| | | /** |
| | | * æ®é表åå
åºå¡«å
ï¼åå²é¨ç½²æé
置导å
¥çæµç¨å®ä¹ï¼å¯è½åªæ formId è缺失 formConfãformFieldsï¼ |
| | | * 导è´å®¡æ¹è¯¦æ
页ç表ååºå空ç½ãè¿éæ formId å读 bpm_form è¡¥é½ã |
| | | */ |
| | | private void fillNormalForm(BpmProcessDefinitionRespVO definition, BpmProcessDefinitionInfoDO processDefinitionInfo) { |
| | | if (definition == null || !Objects.equals(definition.getFormType(), BpmModelFormTypeEnum.NORMAL.getType())) { |
| | | return; |
| | | } |
| | | Long formId = definition.getFormId() != null ? definition.getFormId() |
| | | : (processDefinitionInfo != null ? processDefinitionInfo.getFormId() : null); |
| | | if (formId == null |
| | | || (StrUtil.isNotBlank(definition.getFormConf()) && CollUtil.isNotEmpty(definition.getFormFields()))) { |
| | | return; |
| | | } |
| | | BpmFormDO form = formService.getForm(formId); |
| | | if (form != null) { |
| | | definition.setFormConf(form.getConf()).setFormFields(form.getFields()); |
| | | } |
| | | } |
| | | |
| | | /** |
| | |
| | | } |
| | | |
| | | // 3. åéæµç¨å®ä¾çç¶æäºä»¶ |
| | | // 另䏿µç¨åç±»ï¼èªå®ä¹æµç¨æ¨¡åç key å¯è½æ¯éæºå¼ï¼å¦ C000_abc.ï¼ï¼ä¸å¡çå¬å¨éè¦æåç±»å
åºå¹é
|
| | | ProcessDefinition processDefinition = processDefinitionService.getProcessDefinition(instance.getProcessDefinitionId()); |
| | | processInstanceEventPublisher.sendProcessInstanceResultEvent( |
| | | BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceStatusEvent(this, instance, status, reason)); |
| | | BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceStatusEvent(this, instance, |
| | | processDefinition != null ? processDefinition.getCategory() : null, status, reason)); |
| | | |
| | | // 4. æµç¨åç½®éç¥ |
| | | if (Objects.equals(status, BpmProcessInstanceStatusEnum.APPROVE.getStatus())) { |
| | |
| | | <version>${revision}</version> |
| | | </dependency> |
| | | |
| | | <!-- MES éå®åºåºå APIï¼å¼ç¥¨ç»å®åºåºåãåºæ¶å¯¹è´¦ï¼ --> |
| | | <dependency> |
| | | <groupId>cn.iocoder.boot</groupId> |
| | | <artifactId>yudao-module-mes-api</artifactId> |
| | | <version>${revision}</version> |
| | | </dependency> |
| | | |
| | | <!-- HRM ç¨æ·æ°æ®äº¤æ¥ APIï¼ç¦»è交æ¥å交æ¥äººå¯è§ç¦»èäººæ°æ®ï¼ --> |
| | | <dependency> |
| | | <groupId>cn.iocoder.boot</groupId> |
| | | <artifactId>yudao-module-hrm-api</artifactId> |
| | | <version>${revision}</version> |
| | | </dependency> |
| | | |
| | | <!-- ä¸å¡ç»ä»¶ --> |
| | | <dependency> |
| | | <groupId>cn.iocoder.boot</groupId> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.crm.controller.admin.finance; |
| | | |
| | | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| | | import cn.iocoder.yudao.module.crm.controller.admin.finance.vo.CrmCustomerStatementRespVO; |
| | | import cn.iocoder.yudao.module.crm.controller.admin.finance.vo.CrmFinanceTrendRespVO; |
| | | import cn.iocoder.yudao.module.crm.controller.admin.finance.vo.CrmShippedNotInvoicedRespVO; |
| | | import cn.iocoder.yudao.module.crm.controller.admin.finance.vo.CrmUnwrittenOffRespVO; |
| | | import cn.iocoder.yudao.module.crm.service.finance.CrmFinanceReportService; |
| | | import io.swagger.v3.oas.annotations.Operation; |
| | | import io.swagger.v3.oas.annotations.Parameter; |
| | | import io.swagger.v3.oas.annotations.tags.Tag; |
| | | import jakarta.annotation.Resource; |
| | | import org.springframework.security.access.prepost.PreAuthorize; |
| | | import org.springframework.validation.annotation.Validated; |
| | | import org.springframework.web.bind.annotation.GetMapping; |
| | | import org.springframework.web.bind.annotation.RequestMapping; |
| | | import org.springframework.web.bind.annotation.RequestParam; |
| | | import org.springframework.web.bind.annotation.RestController; |
| | | |
| | | import java.util.List; |
| | | |
| | | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; |
| | | |
| | | /** |
| | | * 管çåå° - CRM è´¢å¡å¯¹è´¦ä¸æ¥è¡¨ |
| | | * |
| | | * @author è¶
级管çå |
| | | */ |
| | | @Tag(name = "管çåå° - CRM è´¢å¡å¯¹è´¦ä¸æ¥è¡¨") |
| | | @RestController |
| | | @RequestMapping("/crm/finance/report") |
| | | @Validated |
| | | public class CrmFinanceReportController { |
| | | |
| | | @Resource |
| | | private CrmFinanceReportService financeReportService; |
| | | |
| | | @GetMapping("/customer-statement") |
| | | @Operation(summary = "è·å¾å®¢æ·åºæ¶å¯¹è´¦å", description = "æå®¢æ·ç»è®¡ææå·²å®¡æ ¸éå®è®¢åç订åéé¢ãåºåºéé¢ãå¼ç¥¨éé¢ã忬¾éé¢ãæªæ ¸éåºæ¶å䏿忬¾è®¡å") |
| | | @Parameter(name = "customerId", description = "客æ·ç¼å·", required = true) |
| | | @PreAuthorize("@ss.hasPermission('crm:receivable:query')") |
| | | public CommonResult<CrmCustomerStatementRespVO> getCustomerStatement(@RequestParam("customerId") Long customerId) { |
| | | return success(financeReportService.getCustomerStatement(customerId)); |
| | | } |
| | | |
| | | @GetMapping("/shipped-not-invoiced") |
| | | @Operation(summary = "è·å¾å·²åè´§æªå¼ç¥¨æç»") |
| | | @Parameter(name = "customerId", description = "客æ·ç¼å·ï¼ä¸ä¼ æ¶ç»è®¡å
¨é¨å®¢æ·") |
| | | @PreAuthorize("@ss.hasPermission('crm:invoice:query')") |
| | | public CommonResult<List<CrmShippedNotInvoicedRespVO>> getShippedNotInvoicedList( |
| | | @RequestParam(value = "customerId", required = false) Long customerId) { |
| | | return success(financeReportService.getShippedNotInvoicedList(customerId)); |
| | | } |
| | | |
| | | @GetMapping("/unwritten-off") |
| | | @Operation(summary = "è·å¾æªæ ¸éåºæ¶æç»", description = "已审æ¹éè¿å¼ç¥¨ä¸ä»ææªå款éé¢çé¨åï¼è¿åè´¦é¾") |
| | | @Parameter(name = "customerId", description = "客æ·ç¼å·ï¼ä¸ä¼ æ¶ç»è®¡å
¨é¨å®¢æ·") |
| | | @PreAuthorize("@ss.hasPermission('crm:receivable:query')") |
| | | public CommonResult<List<CrmUnwrittenOffRespVO>> getUnwrittenOffList( |
| | | @RequestParam(value = "customerId", required = false) Long customerId) { |
| | | return success(financeReportService.getUnwrittenOffList(customerId)); |
| | | } |
| | | |
| | | @GetMapping("/monthly-trend") |
| | | @Operation(summary = "è·å¾è´¢å¡æåº¦è¶å¿", description = "è¿åæè¿ N 个æçå¼ç¥¨éé¢ï¼å®¡æ¹éè¿ï¼ä¸å款éé¢ï¼å®¡æ¹éè¿ï¼") |
| | | @Parameter(name = "months", description = "æä»½æ°éï¼é»è®¤ 6ï¼èå´ 1-36") |
| | | @PreAuthorize("@ss.hasPermission('crm:receivable:query')") |
| | | public CommonResult<List<CrmFinanceTrendRespVO>> getMonthlyTrend( |
| | | @RequestParam(value = "months", required = false, defaultValue = "6") Integer months) { |
| | | return success(financeReportService.getMonthlyTrend(months)); |
| | | } |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.crm.controller.admin.finance.vo; |
| | | |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.time.LocalDateTime; |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * 客æ·åºæ¶å¯¹è´¦å Response VO |
| | | */ |
| | | @Schema(description = "管çåå° - 客æ·åºæ¶å¯¹è´¦å Response VO") |
| | | @Data |
| | | public class CrmCustomerStatementRespVO { |
| | | |
| | | @Schema(description = "客æ·ç¼å·") |
| | | private Long customerId; |
| | | |
| | | @Schema(description = "客æ·åç§°") |
| | | private String customerName; |
| | | |
| | | @Schema(description = "è®¢åæ°é") |
| | | private Integer orderCount; |
| | | |
| | | @Schema(description = "è®¢åæ»éé¢") |
| | | private BigDecimal orderTotalAmount; |
| | | |
| | | @Schema(description = "å·²åºåºéé¢") |
| | | private BigDecimal shippedAmount; |
| | | |
| | | @Schema(description = "å·²å¼ç¥¨éé¢ï¼å®¡æ¹éè¿ï¼") |
| | | private BigDecimal invoicedAmount; |
| | | |
| | | @Schema(description = "已忬¾éé¢ï¼å®¡æ¹éè¿ï¼") |
| | | private BigDecimal collectedAmount; |
| | | |
| | | @Schema(description = "å·²åºåºæªå¼ç¥¨éé¢") |
| | | private BigDecimal shippedNotInvoicedAmount; |
| | | |
| | | @Schema(description = "æªæ ¸éåºæ¶éé¢ï¼è®¢åéé¢ - 已忬¾ï¼") |
| | | private BigDecimal outstandingAmount; |
| | | |
| | | @Schema(description = "ä¸æè®¡å忬¾éé¢") |
| | | private BigDecimal nextMonthPlanAmount; |
| | | |
| | | @Schema(description = "订åæç»") |
| | | private List<OrderRow> orders; |
| | | |
| | | @Schema(description = "订åè¡") |
| | | @Data |
| | | public static class OrderRow { |
| | | |
| | | @Schema(description = "éå®è®¢åç¼å·") |
| | | private Long saleOrderId; |
| | | |
| | | @Schema(description = "éå®è®¢åå·") |
| | | private String saleOrderNo; |
| | | |
| | | @Schema(description = "ååç¼å·") |
| | | private Long contractId; |
| | | |
| | | @Schema(description = "ä¸åæ¶é´") |
| | | private LocalDateTime orderTime; |
| | | |
| | | @Schema(description = "订åéé¢") |
| | | private BigDecimal orderAmount; |
| | | |
| | | @Schema(description = "å·²åºåºéé¢") |
| | | private BigDecimal shippedAmount; |
| | | |
| | | @Schema(description = "å·²å¼ç¥¨éé¢") |
| | | private BigDecimal invoicedAmount; |
| | | |
| | | @Schema(description = "已忬¾éé¢") |
| | | private BigDecimal collectedAmount; |
| | | |
| | | @Schema(description = "å·²åºåºæªå¼ç¥¨éé¢") |
| | | private BigDecimal shippedNotInvoicedAmount; |
| | | |
| | | @Schema(description = "æªæ ¸éåºæ¶éé¢") |
| | | private BigDecimal outstandingAmount; |
| | | |
| | | } |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.crm.controller.admin.finance.vo; |
| | | |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | |
| | | import java.math.BigDecimal; |
| | | |
| | | /** |
| | | * è´¢å¡æåº¦è¶å¿ Response VO |
| | | */ |
| | | @Schema(description = "管çåå° - è´¢å¡æåº¦è¶å¿ Response VO") |
| | | @Data |
| | | public class CrmFinanceTrendRespVO { |
| | | |
| | | @Schema(description = "æä»½ï¼æ ¼å¼ yyyy-MM", example = "2026-11") |
| | | private String month; |
| | | |
| | | @Schema(description = "å¼ç¥¨éé¢ï¼å®¡æ¹éè¿ï¼") |
| | | private BigDecimal invoicedAmount; |
| | | |
| | | @Schema(description = "忬¾éé¢ï¼å®¡æ¹éè¿ï¼") |
| | | private BigDecimal collectedAmount; |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.crm.controller.admin.finance.vo; |
| | | |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.time.LocalDateTime; |
| | | |
| | | /** |
| | | * å·²åè´§æªå¼ç¥¨æç» Response VO |
| | | */ |
| | | @Schema(description = "管çåå° - å·²åè´§æªå¼ç¥¨æç» Response VO") |
| | | @Data |
| | | public class CrmShippedNotInvoicedRespVO { |
| | | |
| | | @Schema(description = "åºåºåç¼å·") |
| | | private Long saleOutId; |
| | | |
| | | @Schema(description = "åºåºåå·") |
| | | private String saleOutCode; |
| | | |
| | | @Schema(description = "åºåºæ¥æ") |
| | | private LocalDateTime salesDate; |
| | | |
| | | @Schema(description = "éå®è®¢åç¼å·") |
| | | private Long saleOrderId; |
| | | |
| | | @Schema(description = "éå®è®¢åå·") |
| | | private String saleOrderNo; |
| | | |
| | | @Schema(description = "客æ·ç¼å·") |
| | | private Long customerId; |
| | | |
| | | @Schema(description = "客æ·åç§°") |
| | | private String customerName; |
| | | |
| | | @Schema(description = "åºåºéé¢") |
| | | private BigDecimal outAmount; |
| | | |
| | | @Schema(description = "å·²å¼ç¥¨éé¢") |
| | | private BigDecimal invoicedAmount; |
| | | |
| | | @Schema(description = "æªå¼ç¥¨éé¢") |
| | | private BigDecimal remainInvoiceAmount; |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.crm.controller.admin.finance.vo; |
| | | |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.time.LocalDateTime; |
| | | |
| | | /** |
| | | * æªæ ¸éåºæ¶æç» Response VO |
| | | */ |
| | | @Schema(description = "管çåå° - æªæ ¸éåºæ¶æç» Response VO") |
| | | @Data |
| | | public class CrmUnwrittenOffRespVO { |
| | | |
| | | @Schema(description = "å¼ç¥¨åç¼å·") |
| | | private Long invoiceId; |
| | | |
| | | @Schema(description = "å¼ç¥¨ç¼å·") |
| | | private String invoiceNo; |
| | | |
| | | @Schema(description = "å票å·ç ") |
| | | private String taxInvoiceNo; |
| | | |
| | | @Schema(description = "客æ·ç¼å·") |
| | | private Long customerId; |
| | | |
| | | @Schema(description = "客æ·åç§°") |
| | | private String customerName; |
| | | |
| | | @Schema(description = "ååç¼å·") |
| | | private Long contractId; |
| | | |
| | | @Schema(description = "éå®è®¢åç¼å·") |
| | | private Long saleOrderId; |
| | | |
| | | @Schema(description = "å¼ç¥¨æ¥æ") |
| | | private LocalDateTime invoiceTime; |
| | | |
| | | @Schema(description = "å¼ç¥¨éé¢") |
| | | private BigDecimal invoiceAmount; |
| | | |
| | | @Schema(description = "已忬¾éé¢") |
| | | private BigDecimal collectedAmount; |
| | | |
| | | @Schema(description = "æªæ ¸ééé¢") |
| | | private BigDecimal remainAmount; |
| | | |
| | | @Schema(description = "è´¦é¾å¤©æ°") |
| | | private Long agingDays; |
| | | |
| | | @Schema(description = "è´¦é¾åºé´ï¼0-30天 31-60天 61-90天 90天以ä¸") |
| | | private String agingBucket; |
| | | |
| | | } |
| | |
| | | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| | | import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; |
| | | import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.contract.CrmContractRespVO; |
| | | import cn.iocoder.yudao.module.crm.controller.admin.invoice.vo.invoice.CrmInvoiceEntryReqVO; |
| | | import cn.iocoder.yudao.module.crm.controller.admin.invoice.vo.invoice.CrmInvoiceImportExcelVO; |
| | | import cn.iocoder.yudao.module.crm.controller.admin.invoice.vo.invoice.CrmInvoiceImportRespVO; |
| | | import cn.iocoder.yudao.module.crm.controller.admin.invoice.vo.invoice.CrmInvoicePageReqVO; |
| | | import cn.iocoder.yudao.module.crm.controller.admin.invoice.vo.invoice.CrmInvoiceRespVO; |
| | | import cn.iocoder.yudao.module.crm.controller.admin.invoice.vo.invoice.CrmInvoiceSaleOutRespVO; |
| | | import cn.iocoder.yudao.module.crm.controller.admin.invoice.vo.invoice.CrmInvoiceSaveReqVO; |
| | | import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractDO; |
| | | import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO; |
| | | import cn.iocoder.yudao.module.crm.dal.dataobject.invoice.CrmInvoiceDO; |
| | | import cn.iocoder.yudao.module.crm.dal.dataobject.receivable.CrmReceivablePlanDO; |
| | | import cn.iocoder.yudao.module.crm.enums.common.CrmAuditStatusEnum; |
| | | import cn.iocoder.yudao.module.crm.service.contract.CrmContractService; |
| | | import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerService; |
| | |
| | | return success(true); |
| | | } |
| | | |
| | | @PutMapping("/entry") |
| | | @Operation(summary = "å¼ç¥¨ç³è¯·å½å
¥å票", description = "å¼ç¥¨ç³è¯·å®¡æ¹éè¿åï¼å½å
¥çå®å票å·ç ãå¼ç¥¨æ¥æãéä»¶ï¼å¹¶å¡«åæ¶æ¬¾èç¹") |
| | | @PreAuthorize("@ss.hasPermission('crm:invoice:update')") |
| | | public CommonResult<Boolean> entryInvoice(@Valid @RequestBody CrmInvoiceEntryReqVO entryReqVO) { |
| | | invoiceService.entryInvoice(entryReqVO); |
| | | return success(true); |
| | | } |
| | | |
| | | @GetMapping("/sale-out-list") |
| | | @Operation(summary = "è·å¾å¼ç¥¨å¯éçéå®åºåºå", description = "æéå®è®¢åæ¥è¯¢ MES 已宿åºåºåï¼è¿åå·²å¼ç¥¨éé¢ä¸å©ä½å¯å¼ç¥¨éé¢") |
| | | @Parameter(name = "saleOrderId", description = "éå®è®¢åç¼å·", required = true) |
| | | @Parameter(name = "id", description = "å¼ç¥¨åç¼å·ï¼ç¼è¾æ¶ä¼ éï¼ç¨äºæé¤èªèº«å·²å ç¨éé¢ï¼") |
| | | public CommonResult<List<CrmInvoiceSaleOutRespVO>> getSaleOutListForInvoice( |
| | | @RequestParam("saleOrderId") Long saleOrderId, |
| | | @RequestParam(value = "id", required = false) Long id) { |
| | | return success(invoiceService.getSaleOutListForInvoice(saleOrderId, id)); |
| | | } |
| | | |
| | | @DeleteMapping("/delete") |
| | | @Operation(summary = "å é¤å¼ç¥¨") |
| | | @Parameter(name = "id", description = "ç¼å·", required = true) |
| | |
| | | if (invoice == null) { |
| | | return null; |
| | | } |
| | | return buildInvoiceDetailList(Collections.singletonList(invoice)).get(0); |
| | | CrmInvoiceRespVO invoiceVO = buildInvoiceDetailList(Collections.singletonList(invoice)).get(0); |
| | | // 详æ
页补å
æ¶æ¬¾èç¹ï¼å表页ä¸è¿åï¼é¿å
N+1 æ¥è¯¢ï¼ |
| | | List<CrmReceivablePlanDO> plans = invoiceService.getPaymentNodeListByInvoiceId(invoice.getId()); |
| | | if (CollUtil.isNotEmpty(plans)) { |
| | | List<CrmInvoiceRespVO.PaymentNode> nodes = new ArrayList<>(plans.size()); |
| | | for (CrmReceivablePlanDO plan : plans) { |
| | | CrmInvoiceRespVO.PaymentNode node = new CrmInvoiceRespVO.PaymentNode(); |
| | | node.setId(plan.getId()); |
| | | node.setStage(plan.getStage()); |
| | | node.setAmount(plan.getPrice()); |
| | | node.setReturnTime(plan.getReturnTime()); |
| | | node.setActualTime(plan.getActualTime()); |
| | | node.setReceiptedPrice(plan.getReceiptedPrice()); |
| | | node.setStatus(plan.getStatus()); |
| | | node.setRemark(plan.getRemark()); |
| | | nodes.add(node); |
| | | } |
| | | invoiceVO.setPaymentNodes(nodes); |
| | | } |
| | | return invoiceVO; |
| | | } |
| | | |
| | | @GetMapping("/page") |
| | |
| | | if (CollUtil.isEmpty(invoices)) { |
| | | return success(Collections.emptyList()); |
| | | } |
| | | // è¿æ»¤ï¼å·²ä¸ä¼ å票éä»¶ |
| | | invoices.removeIf(invoice -> CollUtil.isEmpty(storageAttachmentApi.listAttachments( |
| | | // è¿æ»¤ï¼å¿
é¡»æ¯å·²å½å
¥å票ï¼entryStatus=10ï¼ï¼å岿°æ®æ å½å
¥ç¶ææ¶ï¼ä»¥æ¯å¦åå¨å票éä»¶å
åº |
| | | invoices.removeIf(invoice -> !Integer.valueOf(10).equals(invoice.getEntryStatus()) |
| | | && CollUtil.isEmpty(storageAttachmentApi.listAttachments( |
| | | StorageRecordTypeEnum.CRM_INVOICE.getType(), invoice.getId()))); |
| | | if (CollUtil.isEmpty(invoices)) { |
| | | return success(Collections.emptyList()); |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.crm.controller.admin.invoice.vo.invoice; |
| | | |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import jakarta.validation.constraints.NotBlank; |
| | | import jakarta.validation.constraints.NotNull; |
| | | import lombok.Data; |
| | | |
| | | import java.time.LocalDateTime; |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * å¼ç¥¨ç³è¯·å½å
¥å票 Request VO |
| | | * |
| | | * å¼ç¥¨ç³è¯·å®¡æ¹éè¿åï¼è´¢å¡å¨æ¤ç¯èå½å
¥çå®å票å·ç ãå¼ç¥¨æ¥æãå票éä»¶ï¼ |
| | | * å¹¶æéå®è®¢åå¡«åå忬¾ãé¢ä»æ¬¾ãå°è´§æ¬¾ãéªæ¶æ¬¾çæ¶æ¬¾èç¹ã |
| | | */ |
| | | @Schema(description = "管çåå° - å¼ç¥¨ç³è¯·å½å
¥å票 Request VO") |
| | | @Data |
| | | public class CrmInvoiceEntryReqVO { |
| | | |
| | | @Schema(description = "å¼ç¥¨åç¼å·", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") |
| | | @NotNull(message = "å¼ç¥¨åç¼å·ä¸è½ä¸ºç©º") |
| | | private Long id; |
| | | |
| | | @Schema(description = "å票å·ç ", requiredMode = Schema.RequiredMode.REQUIRED, example = "02564178") |
| | | @NotBlank(message = "å票å·ç ä¸è½ä¸ºç©ºï¼è¯·å¨å½å
¥å票æ¶å¡«åçå®å票å·ç ") |
| | | private String invoiceNo; |
| | | |
| | | @Schema(description = "å票æ¬å¤´", example = "XXç§ææéå
¬å¸") |
| | | private String invoiceTitle; |
| | | |
| | | @Schema(description = "å¼ç¥¨æ¥æ", requiredMode = Schema.RequiredMode.REQUIRED) |
| | | @NotNull(message = "å¼ç¥¨æ¥æä¸è½ä¸ºç©ºï¼è¯·éæ©å票ä¸çå¼ç¥¨æ¥æ") |
| | | private LocalDateTime invoiceTime; |
| | | |
| | | @Schema(description = "å票éä»¶ BlobId å表") |
| | | private List<Long> blobIds; |
| | | |
| | | @Schema(description = "æ¶æ¬¾èç¹ï¼å忬¾/é¢ä»æ¬¾/å°è´§æ¬¾/éªæ¶æ¬¾/è´¨ä¿éï¼") |
| | | private List<CrmInvoiceSaveReqVO.PaymentNode> paymentNodes; |
| | | |
| | | @Schema(description = "夿³¨") |
| | | private String remark; |
| | | |
| | | } |
| | |
| | | private Long saleOrderId; |
| | | @Schema(description = "å
³èåºåºå") |
| | | private Long saleOutId; |
| | | @Schema(description = "åºåºåå·", example = "SL20261029001") |
| | | private String saleOutCode; |
| | | @Schema(description = "å票å½å
¥ç¶æï¼0å¾
å½å
¥ 10å·²å½å
¥", example = "0") |
| | | private Integer entryStatus; |
| | | @Schema(description = "å票å½å
¥äºº") |
| | | private Long entryUserId; |
| | | @Schema(description = "å票å½å
¥æ¶é´") |
| | | private LocalDateTime entryTime; |
| | | |
| | | @Schema(description = "æ¶æ¬¾èç¹") |
| | | private List<PaymentNode> paymentNodes; |
| | | |
| | | @Schema(description = "æ¶æ¬¾èç¹") |
| | | @Data |
| | | public static class PaymentNode { |
| | | |
| | | @Schema(description = "忬¾è®¡åç¼å·") |
| | | private Long id; |
| | | @Schema(description = "é¶æ®µï¼1å忬¾ 2é¢ä»æ¬¾ 3å°è´§æ¬¾ 4éªæ¶æ¬¾ 5è´¨ä¿é") |
| | | private Integer stage; |
| | | @Schema(description = "计å忬¾éé¢") |
| | | private BigDecimal amount; |
| | | @Schema(description = "计å忬¾æ¶é´") |
| | | private LocalDateTime returnTime; |
| | | @Schema(description = "å®é
忬¾æ¶é´") |
| | | private LocalDateTime actualTime; |
| | | @Schema(description = "已忬¾éé¢") |
| | | private BigDecimal receiptedPrice; |
| | | @Schema(description = "ç¶æï¼0æªå款 10é¨å忬¾ 20已忏
") |
| | | private Integer status; |
| | | @Schema(description = "夿³¨") |
| | | private String remark; |
| | | |
| | | } |
| | | |
| | | @Schema(description = "ååä¿¡æ¯") |
| | | private CrmContractRespVO contract; |
| | | |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.crm.controller.admin.invoice.vo.invoice; |
| | | |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.time.LocalDateTime; |
| | | |
| | | /** |
| | | * å¼ç¥¨å¯éåºåºå Response VO |
| | | * |
| | | * æ°æ®æ¥æºï¼MES éå®åºåºåï¼mes_wm_product_salesï¼ |
| | | */ |
| | | @Schema(description = "管çåå° - å¼ç¥¨å¯éåºåºå Response VO") |
| | | @Data |
| | | public class CrmInvoiceSaleOutRespVO { |
| | | |
| | | @Schema(description = "åºåºåç¼å·", example = "1024") |
| | | private Long id; |
| | | |
| | | @Schema(description = "åºåºåå·", example = "SL20261029001") |
| | | private String code; |
| | | |
| | | @Schema(description = "éå®è®¢åç¼å·", example = "2048") |
| | | private Long saleOrderId; |
| | | |
| | | @Schema(description = "éå®è®¢åå·", example = "SO20261029001") |
| | | private String salesOrderCode; |
| | | |
| | | @Schema(description = "åºåºæ¥æ") |
| | | private LocalDateTime salesDate; |
| | | |
| | | @Schema(description = "åºåºåç¶æ", example = "4") |
| | | private Integer status; |
| | | |
| | | @Schema(description = "åºåºåç¶æåç§°", example = "已宿") |
| | | private String statusName; |
| | | |
| | | @Schema(description = "åºåºéé¢ï¼åä½ï¼å
", example = "10000.00") |
| | | private BigDecimal totalPrice; |
| | | |
| | | @Schema(description = "该åºåºåå·²å¼ç¥¨éé¢ï¼åä½ï¼å
", example = "2000.00") |
| | | private BigDecimal invoicedPrice; |
| | | |
| | | @Schema(description = "å©ä½å¯å¼ç¥¨éé¢ï¼åä½ï¼å
", example = "8000.00") |
| | | private BigDecimal remainInvoicePrice; |
| | | |
| | | } |
| | |
| | | @Schema(description = "å
³èåºåºå") |
| | | private Long saleOutId; |
| | | |
| | | @Schema(description = "åºåºåå·ï¼å端æ saleOutId åå¡«ï¼å端æ éä¼ éï¼", hidden = true) |
| | | private String saleOutCode; |
| | | |
| | | @Schema(description = "è´è´£äººç¼å·", example = "25682") |
| | | private Long ownerUserId; |
| | | |
| | |
| | | @Schema(description = "å票éä»¶ BlobId å表") |
| | | private List<Long> blobIds; |
| | | |
| | | @Schema(description = "æ¶æ¬¾èç¹ï¼å忬¾/é¢ä»æ¬¾/å°è´§æ¬¾/éªæ¶æ¬¾/è´¨ä¿éï¼") |
| | | private List<PaymentNode> paymentNodes; |
| | | |
| | | @Schema(description = "æ¶æ¬¾èç¹") |
| | | @Data |
| | | public static class PaymentNode { |
| | | |
| | | @Schema(description = "é¶æ®µï¼1å忬¾ 2é¢ä»æ¬¾ 3å°è´§æ¬¾ 4éªæ¶æ¬¾ 5è´¨ä¿é", requiredMode = Schema.RequiredMode.REQUIRED) |
| | | private Integer stage; |
| | | |
| | | @Schema(description = "éé¢", requiredMode = Schema.RequiredMode.REQUIRED) |
| | | private BigDecimal amount; |
| | | |
| | | @Schema(description = "计å忬¾æ¶é´", requiredMode = Schema.RequiredMode.REQUIRED) |
| | | private LocalDateTime returnTime; |
| | | |
| | | @Schema(description = "夿³¨") |
| | | private String remark; |
| | | |
| | | } |
| | | |
| | | } |
| | |
| | | import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; |
| | | import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.contract.CrmContractRespVO; |
| | | import cn.iocoder.yudao.module.crm.controller.admin.invoice.vo.invoice.CrmInvoiceRespVO; |
| | | import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.receivable.CrmReceivableItemRespVO; |
| | | import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.receivable.CrmReceivablePageReqVO; |
| | | import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.receivable.CrmReceivableRespVO; |
| | | import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.receivable.CrmReceivableSaveReqVO; |
| | |
| | | import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO; |
| | | import cn.iocoder.yudao.module.crm.dal.dataobject.invoice.CrmInvoiceDO; |
| | | import cn.iocoder.yudao.module.crm.dal.dataobject.receivable.CrmReceivableDO; |
| | | import cn.iocoder.yudao.module.crm.dal.dataobject.receivable.CrmReceivableItemDO; |
| | | import cn.iocoder.yudao.module.crm.enums.receivable.CrmReceivableBizTypeEnum; |
| | | import cn.iocoder.yudao.module.crm.service.contract.CrmContractService; |
| | | import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerService; |
| | | import cn.iocoder.yudao.module.crm.service.invoice.CrmInvoiceService; |
| | |
| | | return success(receivableService.getAuditReceivableCount(getLoginUserId())); |
| | | } |
| | | |
| | | @GetMapping("/item-list") |
| | | @Operation(summary = "è·å¾åæ¬¾çæ ¸éæç»") |
| | | @Parameter(name = "receivableId", description = "忬¾ç¼å·", required = true) |
| | | public CommonResult<List<CrmReceivableItemRespVO>> getReceivableItemList(@RequestParam("receivableId") Long receivableId) { |
| | | CrmReceivableDO receivable = receivableService.getReceivable(receivableId); |
| | | return success(buildReceivableItemList(receivableService.getReceivableItemList(receivableId), |
| | | receivable == null ? Collections.emptyList() : Collections.singletonList(receivable))); |
| | | } |
| | | |
| | | @GetMapping("/item-list-by-customer") |
| | | @Operation(summary = "è·å¾å®¢æ·ä¸å
¨é¨åæ¬¾çæ ¸éæç»") |
| | | @Parameter(name = "customerId", description = "客æ·ç¼å·", required = true) |
| | | @PreAuthorize("@ss.hasPermission('crm:receivable:query')") |
| | | public CommonResult<List<CrmReceivableItemRespVO>> getReceivableItemListByCustomerId( |
| | | @RequestParam("customerId") Long customerId) { |
| | | List<CrmReceivableItemDO> items = receivableService.getReceivableItemListByCustomerId(customerId); |
| | | if (CollUtil.isEmpty(items)) { |
| | | return success(Collections.emptyList()); |
| | | } |
| | | Map<Long, CrmReceivableDO> receivableMap = receivableService.getReceivableMap( |
| | | convertSet(items, CrmReceivableItemDO::getReceivableId)); |
| | | return success(buildReceivableItemList(items, receivableMap.values())); |
| | | } |
| | | |
| | | private List<CrmReceivableItemRespVO> buildReceivableItemList(List<CrmReceivableItemDO> items, |
| | | java.util.Collection<CrmReceivableDO> receivables) { |
| | | if (CollUtil.isEmpty(items)) { |
| | | return Collections.emptyList(); |
| | | } |
| | | Map<Long, CrmReceivableDO> receivableMap = receivables.stream() |
| | | .collect(java.util.stream.Collectors.toMap(CrmReceivableDO::getId, item -> item, (a, b) -> a)); |
| | | return BeanUtils.toBean(items, CrmReceivableItemRespVO.class, vo -> { |
| | | vo.setBizTypeName(CrmReceivableBizTypeEnum.getNameByType(vo.getBizType())); |
| | | CrmReceivableDO receivable = receivableMap.get(vo.getReceivableId()); |
| | | if (receivable != null) { |
| | | vo.setReceivableNo(receivable.getNo()); |
| | | vo.setCustomerId(receivable.getCustomerId()); |
| | | vo.setReturnTime(receivable.getReturnTime()); |
| | | } |
| | | }); |
| | | } |
| | | |
| | | } |
| | |
| | | @Schema(description = "夿³¨", example = "夿³¨") |
| | | private String remark; |
| | | |
| | | @Schema(description = "æ¶æ¬¾é¶æ®µï¼1å忬¾ 2é¢ä»æ¬¾ 3å°è´§æ¬¾ 4éªæ¶æ¬¾ 5è´¨ä¿é", example = "2") |
| | | private Integer stage; |
| | | |
| | | @Schema(description = "æ¥æºå¼ç¥¨åç¼å·", example = "1024") |
| | | private Long invoiceId; |
| | | |
| | | @Schema(description = "æ¥æºéå®è®¢åç¼å·", example = "1024") |
| | | private Long saleOrderId; |
| | | |
| | | @Schema(description = "å®é
忬¾æ¶é´") |
| | | private LocalDateTime actualTime; |
| | | |
| | | @Schema(description = "已忬¾éé¢", example = "0") |
| | | private BigDecimal receiptedPrice; |
| | | |
| | | @Schema(description = "ç¶æï¼0æªå款 10é¨å忬¾ 20已忏
", example = "0") |
| | | private Integer status; |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.receivable; |
| | | |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.time.LocalDateTime; |
| | | |
| | | /** |
| | | * CRM 忬¾æ ¸éæç» Response VO |
| | | */ |
| | | @Schema(description = "管çåå° - CRM 忬¾æ ¸éæç» Response VO") |
| | | @Data |
| | | public class CrmReceivableItemRespVO { |
| | | |
| | | @Schema(description = "ç¼å·", example = "1") |
| | | private Long id; |
| | | |
| | | @Schema(description = "忬¾ç¼å·", example = "1") |
| | | private Long receivableId; |
| | | |
| | | @Schema(description = "忬¾åå·", example = "HK20261029001") |
| | | private String receivableNo; |
| | | |
| | | @Schema(description = "客æ·ç¼å·", example = "1") |
| | | private Long customerId; |
| | | |
| | | @Schema(description = "ä¸å¡ç±»åï¼20éå®è®¢å 21éå®åºåº 23å¼ç¥¨", example = "20") |
| | | private Integer bizType; |
| | | |
| | | @Schema(description = "ä¸å¡ç±»ååç§°", example = "éå®è®¢å") |
| | | private String bizTypeName; |
| | | |
| | | @Schema(description = "ä¸å¡ç¼å·", example = "1") |
| | | private Long bizId; |
| | | |
| | | @Schema(description = "ä¸å¡åå·", example = "SO20261029001") |
| | | private String bizNo; |
| | | |
| | | @Schema(description = "åºæ¶éé¢", example = "10000.00") |
| | | private BigDecimal totalPrice; |
| | | |
| | | @Schema(description = "å·²æ ¸ééé¢ï¼ä¸å«æ¬æ¬¡ï¼", example = "2000.00") |
| | | private BigDecimal receiptedPrice; |
| | | |
| | | @Schema(description = "æ¬æ¬¡æ ¸ééé¢", example = "3000.00") |
| | | private BigDecimal receiptPrice; |
| | | |
| | | @Schema(description = "夿³¨") |
| | | private String remark; |
| | | |
| | | @Schema(description = "忬¾æ¥æ") |
| | | private LocalDateTime returnTime; |
| | | |
| | | @Schema(description = "å建æ¶é´") |
| | | private LocalDateTime createTime; |
| | | |
| | | } |
| | |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.time.LocalDateTime; |
| | | import java.util.List; |
| | | |
| | | @Schema(description = "管çåå° - CRM 忬¾æ°å¢/ä¿®æ¹ Request VO") |
| | | @Data |
| | |
| | | @DiffLogField(name = "夿³¨") |
| | | private String remark; |
| | | |
| | | @Schema(description = "æ ¸éæç»ï¼ä¸ä¼ æ¶æå
³èå¼ç¥¨èªå¨çæä¸æ¡ï¼") |
| | | private List<ReceivableItem> items; |
| | | |
| | | @Schema(description = "æ ¸éæç»") |
| | | @Data |
| | | public static class ReceivableItem { |
| | | |
| | | @Schema(description = "ä¸å¡ç±»åï¼20éå®è®¢å 21éå®åºåº 23å¼ç¥¨", requiredMode = Schema.RequiredMode.REQUIRED) |
| | | private Integer bizType; |
| | | |
| | | @Schema(description = "ä¸å¡ç¼å·", requiredMode = Schema.RequiredMode.REQUIRED) |
| | | private Long bizId; |
| | | |
| | | @Schema(description = "ä¸å¡åå·ï¼ä¸ä¼ æ¶å端æ bizId æ¥è¯¢åå¡«ï¼") |
| | | private String bizNo; |
| | | |
| | | @Schema(description = "åºæ¶éé¢") |
| | | private BigDecimal totalPrice; |
| | | |
| | | @Schema(description = "æ¬æ¬¡æ ¸ééé¢", requiredMode = Schema.RequiredMode.REQUIRED) |
| | | private BigDecimal receiptPrice; |
| | | |
| | | @Schema(description = "夿³¨") |
| | | private String remark; |
| | | |
| | | } |
| | | |
| | | } |
| | |
| | | /** å
³èåºåºå */ |
| | | private Long saleOutId; |
| | | /** |
| | | * åºåºåå·ï¼å¿«ç
§ï¼ |
| | | */ |
| | | private String saleOutCode; |
| | | /** |
| | | * å票å½å
¥ç¶æ |
| | | * |
| | | * 0-å¾
å½å
¥ 10-å·²å½å
¥ |
| | | */ |
| | | private Integer entryStatus; |
| | | /** |
| | | * å票å½å
¥äºº |
| | | */ |
| | | private Long entryUserId; |
| | | /** |
| | | * å票å½å
¥æ¶é´ |
| | | */ |
| | | private LocalDateTime entryTime; |
| | | /** |
| | | * è´è´£äººç¼å·ï¼å
³è {@link AdminUserRespDTO#getId()} |
| | | */ |
| | | private Long ownerUserId; |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.crm.dal.dataobject.receivable; |
| | | |
| | | import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; |
| | | import com.baomidou.mybatisplus.annotation.KeySequence; |
| | | import com.baomidou.mybatisplus.annotation.TableId; |
| | | import com.baomidou.mybatisplus.annotation.TableName; |
| | | import lombok.*; |
| | | |
| | | import java.math.BigDecimal; |
| | | |
| | | /** |
| | | * CRM 忬¾æ ¸éæç» DO |
| | | * |
| | | * 䏿¡å款å¯ä»¥æ ¸éå¤ä¸ªéå®è®¢å / éå®åºåºå / å¼ç¥¨ï¼æ¬è¡¨è®°å½æ¯ç¬æ ¸éçéé¢ã |
| | | * |
| | | * @author è¶
级管çå |
| | | */ |
| | | @TableName("crm_receivable_item") |
| | | @KeySequence("crm_receivable_item_seq") |
| | | @Data |
| | | @EqualsAndHashCode(callSuper = true) |
| | | @ToString(callSuper = true) |
| | | @Builder |
| | | @NoArgsConstructor |
| | | @AllArgsConstructor |
| | | public class CrmReceivableItemDO extends BaseDO { |
| | | |
| | | /** |
| | | * ç¼å· |
| | | */ |
| | | @TableId |
| | | private Long id; |
| | | /** |
| | | * 忬¾ç¼å· |
| | | * |
| | | * å
³è {@link CrmReceivableDO#getId()} |
| | | */ |
| | | private Long receivableId; |
| | | /** |
| | | * ä¸å¡ç±»å |
| | | * |
| | | * æä¸¾ {@link cn.iocoder.yudao.module.crm.enums.receivable.CrmReceivableBizTypeEnum} |
| | | */ |
| | | private Integer bizType; |
| | | /** |
| | | * ä¸å¡ç¼å· |
| | | */ |
| | | private Long bizId; |
| | | /** |
| | | * ä¸å¡åå·ï¼å¿«ç
§ï¼ |
| | | */ |
| | | private String bizNo; |
| | | /** |
| | | * åºæ¶éé¢ï¼åä½ï¼å
|
| | | */ |
| | | private BigDecimal totalPrice; |
| | | /** |
| | | * å·²æ ¸ééé¢ï¼åä½ï¼å
ï¼ä¸å«æ¬æ¬¡ï¼ |
| | | */ |
| | | private BigDecimal receiptedPrice; |
| | | /** |
| | | * æ¬æ¬¡æ ¸ééé¢ï¼åä½ï¼å
|
| | | */ |
| | | private BigDecimal receiptPrice; |
| | | /** |
| | | * 夿³¨ |
| | | */ |
| | | private String remark; |
| | | |
| | | } |
| | |
| | | */ |
| | | private String remark; |
| | | |
| | | /** |
| | | * æ¶æ¬¾é¶æ®µ |
| | | * |
| | | * 1-å忬¾ 2-é¢ä»æ¬¾ 3-å°è´§æ¬¾ 4-éªæ¶æ¬¾ 5-è´¨ä¿é |
| | | */ |
| | | private Integer stage; |
| | | |
| | | /** |
| | | * æ¥æºå¼ç¥¨åç¼å·ï¼å
³è {@link cn.iocoder.yudao.module.crm.dal.dataobject.invoice.CrmInvoiceDO#getId()} |
| | | */ |
| | | private Long invoiceId; |
| | | |
| | | /** |
| | | * æ¥æºéå®è®¢åç¼å· |
| | | */ |
| | | private Long saleOrderId; |
| | | |
| | | /** |
| | | * å®é
忬¾æ¶é´ |
| | | */ |
| | | private LocalDateTime actualTime; |
| | | |
| | | /** |
| | | * 已忬¾éé¢ï¼åä½ï¼å
|
| | | */ |
| | | private BigDecimal receiptedPrice; |
| | | |
| | | /** |
| | | * ç¶æ |
| | | * |
| | | * 0-æªå款 10-é¨å忬¾ 20-已忏
|
| | | */ |
| | | private Integer status; |
| | | |
| | | } |
| | |
| | | return selectOne(CrmInvoiceDO::getNo, no); |
| | | } |
| | | |
| | | /** |
| | | * æ¸
空å票å½å
¥äººãå½å
¥æ¶é´ï¼updateById é»è®¤å¿½ç¥ null åæ®µï¼æ¸
ç©ºéæ¾å¼ updateï¼ |
| | | */ |
| | | default void clearEntryInfo(Long id) { |
| | | update(null, new com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper<CrmInvoiceDO>() |
| | | .eq(CrmInvoiceDO::getId, id) |
| | | .set(CrmInvoiceDO::getEntryStatus, 0) |
| | | .set(CrmInvoiceDO::getEntryUserId, null) |
| | | .set(CrmInvoiceDO::getEntryTime, null)); |
| | | } |
| | | |
| | | /** |
| | | * æå票å·ç æ¥è¯¢æªè¢«å é¤çå¼ç¥¨ï¼å票å·ç å
许åä¸å¼ åç¥¨å¤æ¬¡å¼ç¥¨æ¶ï¼è¿åç¬¬ä¸æ¡ï¼ |
| | | */ |
| | | default CrmInvoiceDO selectByInvoiceNo(String invoiceNo) { |
| | | return selectOne(new LambdaQueryWrapperX<CrmInvoiceDO>() |
| | | .eq(CrmInvoiceDO::getInvoiceNo, invoiceNo) |
| | | .orderByAsc(CrmInvoiceDO::getId) |
| | | .last("LIMIT 1")); |
| | | } |
| | | |
| | | default PageResult<CrmInvoiceDO> selectPageByCustomerId(CrmInvoicePageReqVO reqVO) { |
| | | return selectPage(reqVO, new LambdaQueryWrapperX<CrmInvoiceDO>() |
| | | .eq(CrmInvoiceDO::getCustomerId, reqVO.getCustomerId()) // å¿
é¡»ä¼ é |
| | |
| | | } |
| | | |
| | | /** |
| | | * æ¥è¯¢æå®éå®è®¢åä¸ãæå®å®¡æ¹ç¶æçå¼ç¥¨ |
| | | */ |
| | | default List<CrmInvoiceDO> selectListBySaleOrderIdAndStatus(Long saleOrderId, Collection<Integer> auditStatuses) { |
| | | return selectList(new LambdaQueryWrapperX<CrmInvoiceDO>() |
| | | .eq(CrmInvoiceDO::getSaleOrderId, saleOrderId) |
| | | .in(CrmInvoiceDO::getAuditStatus, auditStatuses)); |
| | | } |
| | | |
| | | /** |
| | | * æ¥è¯¢æå®éå®åºåºåä¸ãæå®å®¡æ¹ç¶æçå¼ç¥¨ |
| | | */ |
| | | default List<CrmInvoiceDO> selectListBySaleOutIdAndStatus(Long saleOutId, Collection<Integer> auditStatuses) { |
| | | return selectList(new LambdaQueryWrapperX<CrmInvoiceDO>() |
| | | .eq(CrmInvoiceDO::getSaleOutId, saleOutId) |
| | | .in(CrmInvoiceDO::getAuditStatus, auditStatuses)); |
| | | } |
| | | |
| | | /** |
| | | * æ¥è¯¢ååä¸çå
¨é¨å¼ç¥¨ï¼å¯¼å
¥å»éç¨ï¼ |
| | | */ |
| | | default List<CrmInvoiceDO> selectListByContractId(Long contractId) { |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.crm.dal.mysql.receivable; |
| | | |
| | | import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; |
| | | import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; |
| | | import cn.iocoder.yudao.module.crm.dal.dataobject.receivable.CrmReceivableItemDO; |
| | | import org.apache.ibatis.annotations.Mapper; |
| | | |
| | | import java.util.Collection; |
| | | import java.util.Collections; |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * CRM 忬¾æ ¸éæç» Mapper |
| | | * |
| | | * @author è¶
级管çå |
| | | */ |
| | | @Mapper |
| | | public interface CrmReceivableItemMapper extends BaseMapperX<CrmReceivableItemDO> { |
| | | |
| | | default List<CrmReceivableItemDO> selectListByReceivableId(Long receivableId) { |
| | | return selectList(new LambdaQueryWrapperX<CrmReceivableItemDO>() |
| | | .eq(CrmReceivableItemDO::getReceivableId, receivableId) |
| | | .orderByAsc(CrmReceivableItemDO::getId)); |
| | | } |
| | | |
| | | default List<CrmReceivableItemDO> selectListByReceivableIds(Collection<Long> receivableIds) { |
| | | if (receivableIds == null || receivableIds.isEmpty()) { |
| | | return Collections.emptyList(); |
| | | } |
| | | return selectList(new LambdaQueryWrapperX<CrmReceivableItemDO>() |
| | | .in(CrmReceivableItemDO::getReceivableId, receivableIds) |
| | | .orderByAsc(CrmReceivableItemDO::getId)); |
| | | } |
| | | |
| | | default List<CrmReceivableItemDO> selectListByBiz(Integer bizType, Long bizId) { |
| | | return selectList(new LambdaQueryWrapperX<CrmReceivableItemDO>() |
| | | .eq(CrmReceivableItemDO::getBizType, bizType) |
| | | .eq(CrmReceivableItemDO::getBizId, bizId) |
| | | .orderByAsc(CrmReceivableItemDO::getId)); |
| | | } |
| | | |
| | | default void deleteByReceivableId(Long receivableId) { |
| | | delete(new LambdaQueryWrapperX<CrmReceivableItemDO>() |
| | | .eq(CrmReceivableItemDO::getReceivableId, receivableId)); |
| | | } |
| | | |
| | | } |
| | |
| | | return selectCount(query); |
| | | } |
| | | |
| | | default List<CrmReceivableDO> selectListByCustomerId(Long customerId) { |
| | | return selectList(new cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX<CrmReceivableDO>() |
| | | .eq(CrmReceivableDO::getCustomerId, customerId) |
| | | .orderByDesc(CrmReceivableDO::getId)); |
| | | } |
| | | |
| | | default List<CrmReceivableDO> selectListByContractIdAndStatus(Long contractId, Collection<Integer> auditStatuses) { |
| | | return selectList(new LambdaQueryWrapperX<CrmReceivableDO>() |
| | | .eq(CrmReceivableDO::getContractId, contractId) |
| | |
| | | @Mapper |
| | | public interface CrmReceivablePlanMapper extends BaseMapperX<CrmReceivablePlanDO> { |
| | | |
| | | /** |
| | | * æ¥è¯¢å¼ç¥¨åçæçæ¶æ¬¾èç¹ |
| | | */ |
| | | default java.util.List<CrmReceivablePlanDO> selectListByInvoiceId(Long invoiceId) { |
| | | return selectList(new cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX<CrmReceivablePlanDO>() |
| | | .eq(CrmReceivablePlanDO::getInvoiceId, invoiceId) |
| | | .orderByAsc(CrmReceivablePlanDO::getStage) |
| | | .orderByAsc(CrmReceivablePlanDO::getId)); |
| | | } |
| | | |
| | | default CrmReceivablePlanDO selectMaxPeriodByContractId(Long contractId) { |
| | | return selectOne(new MPJLambdaWrapperX<CrmReceivablePlanDO>() |
| | | .eq(CrmReceivablePlanDO::getContractId, contractId) |
| | |
| | | ErrorCode RECEIVABLE_DELETE_FAIL_IS_APPROVE = new ErrorCode(1_020_004_008, "å é¤å款失败ï¼åå ï¼å款审æ¹å·²éè¿"); |
| | | ErrorCode RECEIVABLE_APPROVE_FAIL = new ErrorCode(1_020_004_009, "å®¡æ ¸å¤±è´¥ï¼åªææªå®¡æ ¸ç忬¾æè½å®¡æ ¸"); |
| | | ErrorCode RECEIVABLE_PROCESS_FAIL = new ErrorCode(1_020_004_010, "åå®¡æ ¸å¤±è´¥ï¼åªæå·²å®¡æ ¸ç忬¾æè½åå®¡æ ¸"); |
| | | ErrorCode RECEIVABLE_ITEM_BIZ_TYPE_INVALID = new ErrorCode(1_020_004_011, "æ ¸éæç»æ ¡éªå¤±è´¥ï¼åå ï¼ç¬¬ {} è¡çä¸å¡ç±»å[{}]䏿£ç¡®ï¼å¯é 20éå®è®¢åã21éå®åºåºã23å¼ç¥¨ãè¯·éæ°éæ©"); |
| | | ErrorCode RECEIVABLE_ITEM_BIZ_NOT_EXISTS = new ErrorCode(1_020_004_012, "æ ¸éæç»æ ¡éªå¤±è´¥ï¼åå ï¼ç¬¬ {} è¡éæ©ç{}[{}]ä¸åå¨ãè¯·éæ°éæ©å
³èåæ®"); |
| | | ErrorCode RECEIVABLE_ITEM_PRICE_INVALID = new ErrorCode(1_020_004_013, "æ ¸éæç»æ ¡éªå¤±è´¥ï¼åå ï¼ç¬¬ {} è¡{}[{}]çæ¬æ¬¡æ ¸ééé¢ä¸º {}ï¼å¿
é¡»å¤§äº 0ã请修æ¹è¯¥è¡æ ¸ééé¢"); |
| | | ErrorCode RECEIVABLE_ITEM_SUM_MISMATCH = new ErrorCode(1_020_004_014, "æ ¸éæç»æ ¡éªå¤±è´¥ï¼åå ï¼æ ¸éæç»å计 {} å
ï¼ä¸å款éé¢ {} å
ä¸ä¸è´ãè¯·è°æ´æç»éé¢ï¼ä½¿ä¸¤è
ç¸ç"); |
| | | ErrorCode RECEIVABLE_ITEM_PRICE_EXCEEDS = new ErrorCode(1_020_004_015, "æ ¸éæç»æ ¡éªå¤±è´¥ï¼åå ï¼ç¬¬ {} è¡{}[{}]æ¬æ¬¡æ ¸é {} å
ï¼è¶
åºè¯¥åæ®å©ä½åºæ¶ {} å
ï¼åºæ¶ {} å
ï¼å·²æ ¸é {} å
ï¼ã请è°å°è¯¥è¡éé¢ï¼ææ¹éå
¶ä»åæ®"); |
| | | |
| | | // ========== 忬¾è®¡å 1-020-005-000 ========== |
| | | ErrorCode RECEIVABLE_PLAN_NOT_EXISTS = new ErrorCode(1_020_005_000, "忬¾è®¡åä¸åå¨"); |
| | |
| | | ErrorCode RECEIVABLE_CREATE_FAIL_INVOICE_NOT_ATTACHMENT = new ErrorCode(1_020_016_010, "åå»ºåæ¬¾å¤±è´¥ï¼åå ï¼å
³èçå¼ç¥¨æªä¸ä¼ å票éä»¶"); |
| | | ErrorCode RECEIVABLE_CREATE_FAIL_INVOICE_CONTRACT_MISMATCH = new ErrorCode(1_020_016_011, "åå»ºåæ¬¾å¤±è´¥ï¼åå ï¼å
³èçå¼ç¥¨ä¸æéååä¸å¹é
"); |
| | | ErrorCode RECEIVABLE_CREATE_FAIL_INVOICE_PRICE_EXCEEDS = new ErrorCode(1_020_016_012, "åå»ºåæ¬¾å¤±è´¥ï¼åå ï¼å款éé¢è¶
åºè¯¥å¼ç¥¨å©ä½å¯å款éé¢ï¼ç®åå¯å款ï¼{} å
"); |
| | | ErrorCode INVOICE_CREATE_FAIL_SALE_ORDER_NOT_EXISTS = new ErrorCode(1_020_016_013, "å建å¼ç¥¨å¤±è´¥ï¼åå ï¼éå®è®¢å[{}]ä¸åå¨ã请å¨å¼ç¥¨åéæ©å·²å®¡æ ¸çéå®è®¢åï¼æå
å°ãéå®è®¢åãä¸åå»ºå¹¶å®¡æ ¸è¯¥è®¢å"); |
| | | ErrorCode INVOICE_CREATE_FAIL_SALE_ORDER_NOT_APPROVE = new ErrorCode(1_020_016_014, "å建å¼ç¥¨å¤±è´¥ï¼åå ï¼éå®è®¢å[{}]å½åç¶æä¸ºã{}ãï¼åªæãå·²å®¡æ ¸ãçéå®è®¢åæè½å¼ç¥¨ã请å
å®æè¯¥è®¢åå®¡æ ¸ï¼ææ¹éå
¶ä»å·²å®¡æ ¸è®¢å"); |
| | | ErrorCode INVOICE_CREATE_FAIL_SALE_ORDER_MISMATCH = new ErrorCode(1_020_016_015, "å建å¼ç¥¨å¤±è´¥ï¼åå ï¼éå®è®¢å[{}]çå®¢æ·æååä¸å½åå¼ç¥¨åä¸ä¸è´ï¼è®¢å客æ·={}ã订ååå={}ï¼å¼ç¥¨å®¢æ·={}ãå¼ç¥¨åå={}ï¼ã请æ¹éä¸å½åååã客æ·ä¸è´çéå®è®¢å"); |
| | | ErrorCode INVOICE_CREATE_FAIL_SALE_OUT_NOT_EXISTS = new ErrorCode(1_020_016_016, "å建å¼ç¥¨å¤±è´¥ï¼åå ï¼åºåºå(ID={})ä¸å卿已å é¤ãè¯·éæ°éæ©è¯¥éå®è®¢åä¸çåºåºå"); |
| | | ErrorCode INVOICE_CREATE_FAIL_SALE_OUT_NOT_FINISHED = new ErrorCode(1_020_016_017, "å建å¼ç¥¨å¤±è´¥ï¼åå ï¼åºåºå[{}]å½åç¶æä¸ºã{}ãï¼åªæã已宿ãçåºåºåæè½å¼ç¥¨ã请çå¾
åºåºå®æååå¼ç¥¨ï¼ææ¹éå
¶ä»å·²å®æåºåºå"); |
| | | ErrorCode INVOICE_CREATE_FAIL_SALE_OUT_MISMATCH_ORDER = new ErrorCode(1_020_016_018, "å建å¼ç¥¨å¤±è´¥ï¼åå ï¼åºåºå[{}]ä¸å±äºæééå®è®¢å[{}]ï¼åºåºåå®é
订å={}ï¼ã请æ¹é该éå®è®¢åä¸çåºåºå"); |
| | | ErrorCode INVOICE_CREATE_FAIL_SALE_OUT_MISMATCH_CUSTOMER = new ErrorCode(1_020_016_019, "å建å¼ç¥¨å¤±è´¥ï¼åå ï¼åºåºå[{}]ç客æ·(ID={})ä¸å¼ç¥¨å®¢æ·(ID={})ä¸ä¸è´ã请æ¹éå½å客æ·åä¸çåºåºå"); |
| | | ErrorCode INVOICE_CREATE_FAIL_PRICE_EXCEEDS_SALE_ORDER = new ErrorCode(1_020_016_020, "å建å¼ç¥¨å¤±è´¥ï¼åå ï¼å¼ç¥¨éé¢è¶
åºéå®è®¢å[{}]å©ä½å¯å¼ç¥¨éé¢ {} å
ï¼è®¢åéé¢ {} å
ï¼å·²å¼ç¥¨ {} å
ï¼ãè¯·è°æ´å¼ç¥¨éé¢ï¼æå
æ ¸å¯¹å·²å¼ç¥¨éé¢"); |
| | | ErrorCode INVOICE_CREATE_FAIL_PRICE_EXCEEDS_SALE_OUT = new ErrorCode(1_020_016_021, "å建å¼ç¥¨å¤±è´¥ï¼åå ï¼å¼ç¥¨éé¢è¶
åºåºåºå[{}]å©ä½å¯å¼ç¥¨éé¢ {} å
ï¼åºåºéé¢ {} å
ï¼å·²å¼ç¥¨ {} å
ï¼ãè¯·è°æ´å¼ç¥¨éé¢ï¼ææ¹éå
¶ä»åºåºå"); |
| | | ErrorCode INVOICE_ENTRY_FAIL_NOT_APPROVE = new ErrorCode(1_020_016_022, "å½å
¥å票失败ï¼åå ï¼å¼ç¥¨å[{}]å½å审æ¹ç¶æä¸ºã{}ãï¼åªæã审æ¹éè¿ãçå¼ç¥¨ç³è¯·æè½å½å
¥å票ã请å
宿å¼ç¥¨ç³è¯·å®¡æ¹"); |
| | | ErrorCode INVOICE_ENTRY_FAIL_INVOICE_NO_EXISTS = new ErrorCode(1_020_016_023, "å½å
¥å票失败ï¼åå ï¼å票å·ç [{}]已被å¼ç¥¨å[{}]使ç¨ãè¯·æ ¸å¯¹å票å·ç ï¼æå°è¯¥å¼ç¥¨å䏿¥ç"); |
| | | ErrorCode INVOICE_PAYMENT_NODE_INVALID = new ErrorCode(1_020_016_024, "æ¶æ¬¾èç¹æ ¡éªå¤±è´¥ï¼åå ï¼ç¬¬ {} è¡é¶æ®µ[{}]çéé¢ä¸º {}ï¼å¿
é¡»å¤§äº 0ã请修æ¹è¯¥èç¹éé¢"); |
| | | ErrorCode INVOICE_PAYMENT_NODE_TIME_REQUIRED = new ErrorCode(1_020_016_025, "æ¶æ¬¾èç¹æ ¡éªå¤±è´¥ï¼åå ï¼é¶æ®µ[{}]æªéæ©è®¡å忬¾æ¶é´ã请为该èç¹éæ©æ¶é´èç¹"); |
| | | ErrorCode INVOICE_PAYMENT_NODE_STAGE_INVALID = new ErrorCode(1_020_016_026, "æ¶æ¬¾èç¹æ ¡éªå¤±è´¥ï¼åå ï¼ç¬¬ {} è¡çé¶æ®µå¼[{}]䏿£ç¡®ï¼å¯é 1å忬¾ã2é¢ä»æ¬¾ã3å°è´§æ¬¾ã4éªæ¶æ¬¾ã5è´¨ä¿éãè¯·éæ°éæ©"); |
| | | ErrorCode INVOICE_PAYMENT_NODE_STAGE_DUPLICATE = new ErrorCode(1_020_016_027, "æ¶æ¬¾èç¹æ ¡éªå¤±è´¥ï¼åå ï¼é¶æ®µ[{}]éå¤åºç°ãåä¸é¶æ®µåªè½å¡«åä¸ä¸ªèç¹ï¼è¯·åå¹¶æå é¤éå¤è¡"); |
| | | ErrorCode INVOICE_PAYMENT_NODE_ALREADY_RECEIPTED = new ErrorCode(1_020_016_028, "ä¿åæ¶æ¬¾èç¹å¤±è´¥ï¼åå ï¼é¶æ®µ[{}]å·²æå款记å½ï¼å·²å款 {} å
ï¼ï¼ä¸è½å é¤æä¿®æ¹ã请å
å¨ã忬¾ç®¡çãä¸å é¤å¯¹åºåæ¬¾ï¼æä¿ç该èç¹"); |
| | | |
| | | ErrorCode CRM_SALES_TARGET_NOT_EXISTS = new ErrorCode(1_020_017_000, "éå®ç®æ ä¸åå¨"); |
| | | ErrorCode CRM_SALES_TARGET_PERIOD_VALUE_INVALID = new ErrorCode(1_020_017_001, "卿å¼ã{}ãæ ¼å¼ä¸æ£ç¡®ï¼åºä¸º {}"); |
| | |
| | | String CRM_INVOICE_SUBMIT_SUCCESS = "æäº¤ç¼å·ä¸ºã{{#invoiceNo}}ãçå¼ç¥¨å®¡æ¹æå"; |
| | | String CRM_INVOICE_IMPORT_SUB_TYPE = "导å
¥å¼ç¥¨"; |
| | | String CRM_INVOICE_IMPORT_SUCCESS = "导å
¥äºå¼ç¥¨ï¼{{#importSummary}}"; |
| | | String CRM_INVOICE_ENTRY_SUB_TYPE = "å½å
¥å票"; |
| | | String CRM_INVOICE_ENTRY_SUCCESS = "为ç¼å·ä¸ºã{{#invoiceNo}}ãçå¼ç¥¨å½å
¥å票ã{{#entryInvoiceNo}}ã"; |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.crm.enums.receivable; |
| | | |
| | | import cn.iocoder.yudao.framework.common.core.ArrayValuable; |
| | | import lombok.Getter; |
| | | import lombok.RequiredArgsConstructor; |
| | | |
| | | import java.util.Arrays; |
| | | |
| | | /** |
| | | * CRM æ¶æ¬¾é¶æ®µæä¸¾ |
| | | * |
| | | * ç¨äºå¼ç¥¨å½å
¥å票æ¶ï¼æéå®è®¢åæåå忬¾ãé¢ä»æ¬¾ãå°è´§æ¬¾ãéªæ¶æ¬¾çæ¶æ¬¾èç¹ã |
| | | * |
| | | * @author è¶
级管çå |
| | | */ |
| | | @RequiredArgsConstructor |
| | | @Getter |
| | | public enum CrmPaymentStageEnum implements ArrayValuable<Integer> { |
| | | |
| | | CONTRACT(1, "å忬¾"), |
| | | PREPAYMENT(2, "é¢ä»æ¬¾"), |
| | | DELIVERY(3, "å°è´§æ¬¾"), |
| | | ACCEPTANCE(4, "éªæ¶æ¬¾"), |
| | | WARRANTY(5, "è´¨ä¿é"); |
| | | |
| | | public static final Integer[] ARRAYS = Arrays.stream(values()).map(CrmPaymentStageEnum::getStage).toArray(Integer[]::new); |
| | | |
| | | /** |
| | | * é¶æ®µ |
| | | */ |
| | | private final Integer stage; |
| | | |
| | | /** |
| | | * åç§° |
| | | */ |
| | | private final String name; |
| | | |
| | | @Override |
| | | public Integer[] array() { |
| | | return ARRAYS; |
| | | } |
| | | |
| | | public static CrmPaymentStageEnum valueOf(Integer stage) { |
| | | return Arrays.stream(values()).filter(item -> item.getStage().equals(stage)).findFirst().orElse(null); |
| | | } |
| | | |
| | | public static String getNameByStage(Integer stage) { |
| | | CrmPaymentStageEnum item = valueOf(stage); |
| | | return item == null ? String.valueOf(stage) : item.getName(); |
| | | } |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.crm.enums.receivable; |
| | | |
| | | import cn.iocoder.yudao.framework.common.core.ArrayValuable; |
| | | import lombok.Getter; |
| | | import lombok.RequiredArgsConstructor; |
| | | |
| | | import java.util.Arrays; |
| | | |
| | | /** |
| | | * CRM 忬¾æ ¸éä¸å¡ç±»åæä¸¾ |
| | | * |
| | | * æ°å¼ä¸ ERP {@code ErpBizTypeEnum} çéå®ä¾§ä¿æä¸è´ï¼å¼ç¥¨ä½¿ç¨ 23ã |
| | | * |
| | | * @author è¶
级管çå |
| | | */ |
| | | @RequiredArgsConstructor |
| | | @Getter |
| | | public enum CrmReceivableBizTypeEnum implements ArrayValuable<Integer> { |
| | | |
| | | SALE_ORDER(20, "éå®è®¢å"), |
| | | SALE_OUT(21, "éå®åºåº"), |
| | | SALE_INVOICE(23, "å¼ç¥¨"); |
| | | |
| | | public static final Integer[] ARRAYS = Arrays.stream(values()).map(CrmReceivableBizTypeEnum::getType).toArray(Integer[]::new); |
| | | |
| | | /** |
| | | * ç±»å |
| | | */ |
| | | private final Integer type; |
| | | |
| | | /** |
| | | * åç§° |
| | | */ |
| | | private final String name; |
| | | |
| | | @Override |
| | | public Integer[] array() { |
| | | return ARRAYS; |
| | | } |
| | | |
| | | public static CrmReceivableBizTypeEnum valueOf(Integer type) { |
| | | return Arrays.stream(values()).filter(item -> item.getType().equals(type)).findFirst().orElse(null); |
| | | } |
| | | |
| | | public static String getNameByType(Integer type) { |
| | | CrmReceivableBizTypeEnum item = valueOf(type); |
| | | return item == null ? String.valueOf(type) : item.getName(); |
| | | } |
| | | |
| | | } |
| | |
| | | } |
| | | } |
| | | |
| | | // 2. åªèèèªèº«çæé |
| | | // 2. åªèèèªèº«çæéï¼ç¦»è交æ¥å®æåï¼äº¤æ¥äººç»§æ¿ç¦»èäººå¯¹è¯¥æ°æ®çæé |
| | | Long userId = getUserId(); |
| | | CrmPermissionDO userPermission = CollUtil.findOne(bizPermissions, permission -> ObjUtil.equal(permission.getUserId(), userId)); |
| | | if (userPermission != null) { |
| | | if (isUserPermissionValid(userPermission, permissionLevel)) { |
| | | CrmPermissionDO userPermission = null; |
| | | for (Long ownerUserId : CrmPermissionUtils.getOwnerUserIds(userId)) { |
| | | CrmPermissionDO candidate = CollUtil.findOne(bizPermissions, |
| | | permission -> ObjUtil.equal(permission.getUserId(), ownerUserId)); |
| | | if (candidate != null && isUserPermissionValid(candidate, permissionLevel)) { |
| | | return; |
| | | } |
| | | userPermission = candidate != null ? candidate : userPermission; |
| | | } |
| | | |
| | | // 3. åæºç¹æ®å¤çï¼æ£æ¥å®¢æ·å¢éæé |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.crm.service.finance; |
| | | |
| | | import cn.iocoder.yudao.module.crm.controller.admin.finance.vo.CrmCustomerStatementRespVO; |
| | | import cn.iocoder.yudao.module.crm.controller.admin.finance.vo.CrmFinanceTrendRespVO; |
| | | import cn.iocoder.yudao.module.crm.controller.admin.finance.vo.CrmShippedNotInvoicedRespVO; |
| | | import cn.iocoder.yudao.module.crm.controller.admin.finance.vo.CrmUnwrittenOffRespVO; |
| | | |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * CRM è´¢å¡å¯¹è´¦ä¸æ¥è¡¨ Service æ¥å£ |
| | | * |
| | | * æ°æ®å£å¾ï¼ |
| | | * - 订åéé¢ï¼ERP éå®è®¢å totalPriceï¼ä»
å·²å®¡æ ¸è®¢åï¼ |
| | | * - åºåºéé¢ï¼MES éå®åºåºå totalPriceï¼ä»
å·²å®æï¼ |
| | | * - å¼ç¥¨éé¢ï¼CRM å¼ç¥¨ priceï¼ä»
审æ¹éè¿ï¼ |
| | | * - 忬¾éé¢ï¼CRM 忬¾ priceï¼ä»
审æ¹éè¿ï¼ |
| | | * |
| | | * @author è¶
级管çå |
| | | */ |
| | | public interface CrmFinanceReportService { |
| | | |
| | | /** |
| | | * è·å¾å®¢æ·åºæ¶å¯¹è´¦å |
| | | * |
| | | * @param customerId 客æ·ç¼å· |
| | | * @return 对账å |
| | | */ |
| | | CrmCustomerStatementRespVO getCustomerStatement(Long customerId); |
| | | |
| | | /** |
| | | * è·å¾å·²åè´§æªå¼ç¥¨æç» |
| | | * |
| | | * @param customerId 客æ·ç¼å·ï¼ä¸ºç©ºæ¶ç»è®¡å
¨é¨å®¢æ· |
| | | * @return æç»å表 |
| | | */ |
| | | List<CrmShippedNotInvoicedRespVO> getShippedNotInvoicedList(Long customerId); |
| | | |
| | | /** |
| | | * è·å¾æªæ ¸éåºæ¶æç» |
| | | * |
| | | * @param customerId 客æ·ç¼å·ï¼ä¸ºç©ºæ¶ç»è®¡å
¨é¨å®¢æ· |
| | | * @return æç»å表 |
| | | */ |
| | | List<CrmUnwrittenOffRespVO> getUnwrittenOffList(Long customerId); |
| | | |
| | | /** |
| | | * è·å¾æè¿è¥å¹²ä¸ªæçå¼ç¥¨ã忬¾è¶å¿ |
| | | * |
| | | * @param months æä»½æ°é |
| | | * @return è¶å¿åè¡¨ï¼ææä»½ååºï¼ |
| | | */ |
| | | List<CrmFinanceTrendRespVO> getMonthlyTrend(Integer months); |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.crm.service.finance; |
| | | |
| | | import cn.hutool.core.collection.CollUtil; |
| | | import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; |
| | | import cn.iocoder.yudao.module.crm.controller.admin.finance.vo.CrmCustomerStatementRespVO; |
| | | import cn.iocoder.yudao.module.crm.controller.admin.finance.vo.CrmFinanceTrendRespVO; |
| | | import cn.iocoder.yudao.module.crm.controller.admin.finance.vo.CrmShippedNotInvoicedRespVO; |
| | | import cn.iocoder.yudao.module.crm.controller.admin.finance.vo.CrmUnwrittenOffRespVO; |
| | | import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO; |
| | | import cn.iocoder.yudao.module.crm.dal.dataobject.invoice.CrmInvoiceDO; |
| | | import cn.iocoder.yudao.module.crm.dal.dataobject.receivable.CrmReceivableDO; |
| | | import cn.iocoder.yudao.module.crm.dal.dataobject.receivable.CrmReceivableItemDO; |
| | | import cn.iocoder.yudao.module.crm.dal.dataobject.receivable.CrmReceivablePlanDO; |
| | | import cn.iocoder.yudao.module.crm.dal.mysql.invoice.CrmInvoiceMapper; |
| | | import cn.iocoder.yudao.module.crm.dal.mysql.receivable.CrmReceivableItemMapper; |
| | | import cn.iocoder.yudao.module.crm.dal.mysql.receivable.CrmReceivableMapper; |
| | | import cn.iocoder.yudao.module.crm.dal.mysql.receivable.CrmReceivablePlanMapper; |
| | | import cn.iocoder.yudao.module.crm.enums.common.CrmAuditStatusEnum; |
| | | import cn.iocoder.yudao.module.crm.enums.receivable.CrmReceivableBizTypeEnum; |
| | | import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerService; |
| | | import cn.iocoder.yudao.module.erp.api.sale.ErpSaleOrderApi; |
| | | import cn.iocoder.yudao.module.erp.api.sale.dto.ErpSaleOrderRespDTO; |
| | | import cn.iocoder.yudao.module.mes.api.productsales.MesWmProductSalesApi; |
| | | import cn.iocoder.yudao.module.mes.api.productsales.dto.MesWmProductSalesRespDTO; |
| | | import jakarta.annotation.Resource; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.validation.annotation.Validated; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.time.LocalDate; |
| | | import java.time.LocalDateTime; |
| | | import java.time.YearMonth; |
| | | import java.time.format.DateTimeFormatter; |
| | | import java.time.temporal.ChronoUnit; |
| | | import java.util.*; |
| | | |
| | | /** |
| | | * CRM è´¢å¡å¯¹è´¦ä¸æ¥è¡¨ Service å®ç°ç±» |
| | | * |
| | | * @author è¶
级管çå |
| | | */ |
| | | @Service |
| | | @Validated |
| | | @Slf4j |
| | | public class CrmFinanceReportServiceImpl implements CrmFinanceReportService { |
| | | |
| | | private static final Integer ERP_STATUS_APPROVE = 20; |
| | | private static final Integer MES_STATUS_FINISHED = 4; |
| | | private static final Integer AUDIT_APPROVE = CrmAuditStatusEnum.APPROVE.getStatus(); |
| | | private static final Integer PLAN_STATUS_RECEIPTED = 20; |
| | | |
| | | @Resource |
| | | private ErpSaleOrderApi saleOrderApi; |
| | | @Resource |
| | | private MesWmProductSalesApi productSalesApi; |
| | | |
| | | @Resource |
| | | private CrmInvoiceMapper invoiceMapper; |
| | | @Resource |
| | | private CrmReceivableMapper receivableMapper; |
| | | @Resource |
| | | private CrmReceivableItemMapper receivableItemMapper; |
| | | @Resource |
| | | private CrmReceivablePlanMapper receivablePlanMapper; |
| | | @Resource |
| | | private CrmCustomerService customerService; |
| | | |
| | | @Override |
| | | public CrmCustomerStatementRespVO getCustomerStatement(Long customerId) { |
| | | List<ErpSaleOrderRespDTO> orders = getApprovedOrders(customerId); |
| | | Map<Long, BigDecimal> collectedByOrder = getCollectedAmountByOrder(orders, customerId); |
| | | |
| | | CrmCustomerStatementRespVO result = new CrmCustomerStatementRespVO(); |
| | | result.setCustomerId(customerId); |
| | | result.setOrderCount(orders.size()); |
| | | result.setOrderTotalAmount(BigDecimal.ZERO); |
| | | result.setShippedAmount(BigDecimal.ZERO); |
| | | result.setInvoicedAmount(BigDecimal.ZERO); |
| | | result.setCollectedAmount(BigDecimal.ZERO); |
| | | result.setShippedNotInvoicedAmount(BigDecimal.ZERO); |
| | | result.setOutstandingAmount(BigDecimal.ZERO); |
| | | result.setNextMonthPlanAmount(getNextMonthPlanAmount(customerId)); |
| | | List<CrmCustomerStatementRespVO.OrderRow> rows = new ArrayList<>(orders.size()); |
| | | for (ErpSaleOrderRespDTO order : orders) { |
| | | CrmCustomerStatementRespVO.OrderRow row = new CrmCustomerStatementRespVO.OrderRow(); |
| | | row.setSaleOrderId(order.getId()); |
| | | row.setSaleOrderNo(order.getNo()); |
| | | row.setContractId(order.getContractId()); |
| | | row.setOrderAmount(zeroIfNull(order.getTotalPrice())); |
| | | row.setShippedAmount(getShippedAmount(order.getId())); |
| | | row.setInvoicedAmount(getInvoicedAmount(order.getId())); |
| | | row.setCollectedAmount(collectedByOrder.getOrDefault(order.getId(), BigDecimal.ZERO)); |
| | | row.setShippedNotInvoicedAmount(maxZero(row.getShippedAmount().subtract(row.getInvoicedAmount()))); |
| | | row.setOutstandingAmount(maxZero(row.getOrderAmount().subtract(row.getCollectedAmount()))); |
| | | rows.add(row); |
| | | |
| | | result.setOrderTotalAmount(result.getOrderTotalAmount().add(row.getOrderAmount())); |
| | | result.setShippedAmount(result.getShippedAmount().add(row.getShippedAmount())); |
| | | result.setInvoicedAmount(result.getInvoicedAmount().add(row.getInvoicedAmount())); |
| | | result.setCollectedAmount(result.getCollectedAmount().add(row.getCollectedAmount())); |
| | | result.setShippedNotInvoicedAmount(result.getShippedNotInvoicedAmount().add(row.getShippedNotInvoicedAmount())); |
| | | result.setOutstandingAmount(result.getOutstandingAmount().add(row.getOutstandingAmount())); |
| | | } |
| | | result.setOrders(rows); |
| | | if (customerId != null) { |
| | | CrmCustomerDO customer = customerService.getCustomer(customerId); |
| | | result.setCustomerName(customer == null ? null : customer.getName()); |
| | | } |
| | | return result; |
| | | } |
| | | |
| | | @Override |
| | | public List<CrmShippedNotInvoicedRespVO> getShippedNotInvoicedList(Long customerId) { |
| | | List<ErpSaleOrderRespDTO> orders = getApprovedOrders(customerId); |
| | | if (CollUtil.isEmpty(orders)) { |
| | | return Collections.emptyList(); |
| | | } |
| | | Map<Long, ErpSaleOrderRespDTO> orderMap = new HashMap<>(); |
| | | orders.forEach(order -> orderMap.put(order.getId(), order)); |
| | | Map<Long, String> customerNameMap = getCustomerNameMap(orders.stream() |
| | | .map(ErpSaleOrderRespDTO::getCustomerId).filter(Objects::nonNull).toList()); |
| | | |
| | | List<CrmShippedNotInvoicedRespVO> result = new ArrayList<>(); |
| | | for (ErpSaleOrderRespDTO order : orders) { |
| | | for (MesWmProductSalesRespDTO saleOut : getFinishedSaleOuts(order.getId())) { |
| | | BigDecimal outAmount = zeroIfNull(saleOut.getTotalPrice()); |
| | | BigDecimal invoicedAmount = sumInvoicePrice(invoiceMapper.selectListBySaleOutIdAndStatus( |
| | | saleOut.getId(), List.of(AUDIT_APPROVE))); |
| | | BigDecimal remainAmount = outAmount.subtract(invoicedAmount); |
| | | if (remainAmount.compareTo(BigDecimal.ZERO) <= 0) { |
| | | continue; |
| | | } |
| | | CrmShippedNotInvoicedRespVO vo = new CrmShippedNotInvoicedRespVO(); |
| | | vo.setSaleOutId(saleOut.getId()); |
| | | vo.setSaleOutCode(saleOut.getCode()); |
| | | vo.setSalesDate(saleOut.getSalesDate()); |
| | | vo.setSaleOrderId(order.getId()); |
| | | vo.setSaleOrderNo(order.getNo()); |
| | | vo.setCustomerId(order.getCustomerId()); |
| | | vo.setCustomerName(customerNameMap.get(order.getCustomerId())); |
| | | vo.setOutAmount(outAmount); |
| | | vo.setInvoicedAmount(invoicedAmount); |
| | | vo.setRemainInvoiceAmount(remainAmount); |
| | | result.add(vo); |
| | | } |
| | | } |
| | | return result; |
| | | } |
| | | |
| | | @Override |
| | | public List<CrmUnwrittenOffRespVO> getUnwrittenOffList(Long customerId) { |
| | | List<CrmInvoiceDO> invoices = invoiceMapper.selectList(new LambdaQueryWrapperX<CrmInvoiceDO>() |
| | | .eq(CrmInvoiceDO::getAuditStatus, AUDIT_APPROVE) |
| | | .eqIfPresent(CrmInvoiceDO::getCustomerId, customerId) |
| | | .orderByAsc(CrmInvoiceDO::getInvoiceTime)); |
| | | if (CollUtil.isEmpty(invoices)) { |
| | | return Collections.emptyList(); |
| | | } |
| | | Map<Long, BigDecimal> collectedMap = getCollectedAmountByInvoice(customerId); |
| | | Map<Long, String> customerNameMap = getCustomerNameMap(invoices.stream() |
| | | .map(CrmInvoiceDO::getCustomerId).filter(Objects::nonNull).toList()); |
| | | |
| | | List<CrmUnwrittenOffRespVO> result = new ArrayList<>(); |
| | | LocalDate today = LocalDate.now(); |
| | | for (CrmInvoiceDO invoice : invoices) { |
| | | BigDecimal invoiceAmount = zeroIfNull(invoice.getPrice()); |
| | | BigDecimal collectedAmount = collectedMap.getOrDefault(invoice.getId(), BigDecimal.ZERO); |
| | | BigDecimal remainAmount = invoiceAmount.subtract(collectedAmount); |
| | | if (remainAmount.compareTo(BigDecimal.ZERO) <= 0) { |
| | | continue; |
| | | } |
| | | CrmUnwrittenOffRespVO vo = new CrmUnwrittenOffRespVO(); |
| | | vo.setInvoiceId(invoice.getId()); |
| | | vo.setInvoiceNo(invoice.getNo()); |
| | | vo.setTaxInvoiceNo(invoice.getInvoiceNo()); |
| | | vo.setCustomerId(invoice.getCustomerId()); |
| | | vo.setCustomerName(customerNameMap.get(invoice.getCustomerId())); |
| | | vo.setContractId(invoice.getContractId()); |
| | | vo.setSaleOrderId(invoice.getSaleOrderId()); |
| | | vo.setInvoiceTime(invoice.getInvoiceTime()); |
| | | vo.setInvoiceAmount(invoiceAmount); |
| | | vo.setCollectedAmount(collectedAmount); |
| | | vo.setRemainAmount(remainAmount); |
| | | long agingDays = invoice.getInvoiceTime() == null ? 0 |
| | | : Math.max(0, ChronoUnit.DAYS.between(invoice.getInvoiceTime().toLocalDate(), today)); |
| | | vo.setAgingDays(agingDays); |
| | | vo.setAgingBucket(agingBucket(agingDays)); |
| | | result.add(vo); |
| | | } |
| | | return result; |
| | | } |
| | | |
| | | @Override |
| | | public List<CrmFinanceTrendRespVO> getMonthlyTrend(Integer months) { |
| | | int monthCount = months == null ? 6 : Math.min(Math.max(months, 1), 36); |
| | | YearMonth startMonth = YearMonth.now().minusMonths(monthCount - 1L); |
| | | LocalDateTime beginTime = startMonth.atDay(1).atStartOfDay(); |
| | | LocalDateTime endTime = YearMonth.now().plusMonths(1).atDay(1).atStartOfDay(); |
| | | |
| | | List<CrmInvoiceDO> invoices = invoiceMapper.selectList(new LambdaQueryWrapperX<CrmInvoiceDO>() |
| | | .eq(CrmInvoiceDO::getAuditStatus, AUDIT_APPROVE) |
| | | .between(CrmInvoiceDO::getInvoiceTime, beginTime, endTime)); |
| | | List<CrmReceivableDO> receivables = receivableMapper.selectList(new LambdaQueryWrapperX<CrmReceivableDO>() |
| | | .eq(CrmReceivableDO::getAuditStatus, AUDIT_APPROVE) |
| | | .between(CrmReceivableDO::getReturnTime, beginTime, endTime)); |
| | | |
| | | Map<String, BigDecimal> invoicedMap = new HashMap<>(); |
| | | Map<String, BigDecimal> collectedMap = new HashMap<>(); |
| | | DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM"); |
| | | invoices.forEach(invoice -> { |
| | | if (invoice.getInvoiceTime() != null) { |
| | | mergeAmount(invoicedMap, invoice.getInvoiceTime().format(formatter), zeroIfNull(invoice.getPrice())); |
| | | } |
| | | }); |
| | | receivables.forEach(receivable -> { |
| | | if (receivable.getReturnTime() != null) { |
| | | mergeAmount(collectedMap, receivable.getReturnTime().format(formatter), zeroIfNull(receivable.getPrice())); |
| | | } |
| | | }); |
| | | |
| | | List<CrmFinanceTrendRespVO> result = new ArrayList<>(monthCount); |
| | | for (int i = 0; i < monthCount; i++) { |
| | | String month = startMonth.plusMonths(i).format(formatter); |
| | | CrmFinanceTrendRespVO vo = new CrmFinanceTrendRespVO(); |
| | | vo.setMonth(month); |
| | | vo.setInvoicedAmount(invoicedMap.getOrDefault(month, BigDecimal.ZERO)); |
| | | vo.setCollectedAmount(collectedMap.getOrDefault(month, BigDecimal.ZERO)); |
| | | result.add(vo); |
| | | } |
| | | return result; |
| | | } |
| | | |
| | | // ==================== æ°æ®æ¥è¯¢ä¸è®¡ç® ==================== |
| | | |
| | | private List<ErpSaleOrderRespDTO> getApprovedOrders(Long customerId) { |
| | | List<ErpSaleOrderRespDTO> orders = customerId == null |
| | | ? saleOrderApi.getSaleOrderList().getCheckedData() |
| | | : saleOrderApi.getSaleOrderListByCustomerId(customerId).getCheckedData(); |
| | | if (CollUtil.isEmpty(orders)) { |
| | | return Collections.emptyList(); |
| | | } |
| | | return orders.stream() |
| | | .filter(order -> ObjectUtilEqual(order.getStatus(), ERP_STATUS_APPROVE)) |
| | | .toList(); |
| | | } |
| | | |
| | | private List<MesWmProductSalesRespDTO> getFinishedSaleOuts(Long saleOrderId) { |
| | | List<MesWmProductSalesRespDTO> saleOuts = productSalesApi.getProductSalesListBySaleOrderId(saleOrderId); |
| | | if (CollUtil.isEmpty(saleOuts)) { |
| | | return Collections.emptyList(); |
| | | } |
| | | return saleOuts.stream().filter(saleOut -> ObjectUtilEqual(saleOut.getStatus(), MES_STATUS_FINISHED)).toList(); |
| | | } |
| | | |
| | | private BigDecimal getShippedAmount(Long saleOrderId) { |
| | | return getFinishedSaleOuts(saleOrderId).stream() |
| | | .map(saleOut -> zeroIfNull(saleOut.getTotalPrice())) |
| | | .reduce(BigDecimal.ZERO, BigDecimal::add); |
| | | } |
| | | |
| | | private BigDecimal getInvoicedAmount(Long saleOrderId) { |
| | | return sumInvoicePrice(invoiceMapper.selectListBySaleOrderIdAndStatus(saleOrderId, List.of(AUDIT_APPROVE))); |
| | | } |
| | | |
| | | /** |
| | | * è®¡ç®æ¯å¼ éå®è®¢å已忬¾éé¢ |
| | | * |
| | | * ä¼å
åæ ¸éæç»ï¼éå®è®¢å / å¼ç¥¨ï¼ï¼åå²åæ¬¾æ²¡ææ ¸éæç»æ¶æå款å
³èçå¼ç¥¨æç®å°è®¢åã |
| | | */ |
| | | private Map<Long, BigDecimal> getCollectedAmountByOrder(List<ErpSaleOrderRespDTO> orders, Long customerId) { |
| | | Map<Long, BigDecimal> result = new HashMap<>(); |
| | | Map<Long, ErpSaleOrderRespDTO> orderMap = new HashMap<>(); |
| | | orders.forEach(order -> orderMap.put(order.getId(), order)); |
| | | if (orderMap.isEmpty()) { |
| | | return result; |
| | | } |
| | | // 1. å·²å®¡æ ¸åæ¬¾ |
| | | List<CrmReceivableDO> receivables = customerId == null |
| | | ? receivableMapper.selectList(new LambdaQueryWrapperX<CrmReceivableDO>() |
| | | .eq(CrmReceivableDO::getAuditStatus, AUDIT_APPROVE)) |
| | | : receivableMapper.selectListByCustomerId(customerId).stream() |
| | | .filter(receivable -> ObjectUtilEqual(receivable.getAuditStatus(), AUDIT_APPROVE)).toList(); |
| | | if (CollUtil.isEmpty(receivables)) { |
| | | return result; |
| | | } |
| | | Map<Long, CrmReceivableDO> receivableMap = new HashMap<>(); |
| | | receivables.forEach(receivable -> receivableMap.put(receivable.getId(), receivable)); |
| | | // 2. æ ¸éæç» |
| | | List<CrmReceivableItemDO> items = receivableItemMapper.selectListByReceivableIds(receivableMap.keySet()); |
| | | Set<Long> receivablesWithItems = new HashSet<>(); |
| | | Set<Long> invoiceIds = new HashSet<>(); |
| | | items.forEach(item -> { |
| | | receivablesWithItems.add(item.getReceivableId()); |
| | | if (CrmReceivableBizTypeEnum.SALE_INVOICE.getType().equals(item.getBizType()) && item.getBizId() != null) { |
| | | invoiceIds.add(item.getBizId()); |
| | | } |
| | | }); |
| | | receivables.forEach(receivable -> { |
| | | if (receivable.getInvoiceId() != null) { |
| | | invoiceIds.add(receivable.getInvoiceId()); |
| | | } |
| | | }); |
| | | Map<Long, Long> invoiceOrderMap = new HashMap<>(); |
| | | if (CollUtil.isNotEmpty(invoiceIds)) { |
| | | invoiceMapper.selectByIds(invoiceIds).forEach(invoice -> { |
| | | if (invoice.getSaleOrderId() != null) { |
| | | invoiceOrderMap.put(invoice.getId(), invoice.getSaleOrderId()); |
| | | } |
| | | }); |
| | | } |
| | | for (CrmReceivableItemDO item : items) { |
| | | if (!receivableMap.containsKey(item.getReceivableId())) { |
| | | continue; |
| | | } |
| | | Long orderId = null; |
| | | if (CrmReceivableBizTypeEnum.SALE_ORDER.getType().equals(item.getBizType())) { |
| | | orderId = item.getBizId(); |
| | | } else if (CrmReceivableBizTypeEnum.SALE_INVOICE.getType().equals(item.getBizType())) { |
| | | orderId = invoiceOrderMap.get(item.getBizId()); |
| | | } |
| | | if (orderId != null && orderMap.containsKey(orderId)) { |
| | | result.merge(orderId, zeroIfNull(item.getReceiptPrice()), BigDecimal::add); |
| | | } |
| | | } |
| | | // 3. åå²åæ¬¾ï¼æ²¡ææ ¸éæç»æ¶ï¼æå款å
³èå¼ç¥¨æç®å°è®¢åï¼åªå¤ç订åèå´å
çå¼ç¥¨ï¼ |
| | | for (CrmReceivableDO receivable : receivables) { |
| | | if (receivablesWithItems.contains(receivable.getId()) || receivable.getInvoiceId() == null) { |
| | | continue; |
| | | } |
| | | Long orderId = invoiceOrderMap.get(receivable.getInvoiceId()); |
| | | if (orderId != null && orderMap.containsKey(orderId)) { |
| | | result.merge(orderId, zeroIfNull(receivable.getPrice()), BigDecimal::add); |
| | | } |
| | | } |
| | | return result; |
| | | } |
| | | |
| | | /** |
| | | * è®¡ç®æ¯å¼ å¼ç¥¨å·²å款éé¢ï¼ä»
å·²å®¡æ ¸åæ¬¾ï¼ |
| | | * |
| | | * ææ ¸éæç»æ¶ææç»å½éå°å¼ç¥¨ï¼åå²å款æ invoiceId ç´æ¥å½éã |
| | | */ |
| | | private Map<Long, BigDecimal> getCollectedAmountByInvoice(Long customerId) { |
| | | Map<Long, BigDecimal> result = new HashMap<>(); |
| | | List<CrmReceivableDO> receivables = customerId == null |
| | | ? receivableMapper.selectList(new LambdaQueryWrapperX<CrmReceivableDO>() |
| | | .eq(CrmReceivableDO::getAuditStatus, AUDIT_APPROVE)) |
| | | : receivableMapper.selectListByCustomerId(customerId).stream() |
| | | .filter(receivable -> ObjectUtilEqual(receivable.getAuditStatus(), AUDIT_APPROVE)).toList(); |
| | | if (CollUtil.isEmpty(receivables)) { |
| | | return result; |
| | | } |
| | | Map<Long, CrmReceivableDO> receivableMap = new HashMap<>(); |
| | | receivables.forEach(receivable -> receivableMap.put(receivable.getId(), receivable)); |
| | | List<CrmReceivableItemDO> items = receivableItemMapper.selectListByReceivableIds(receivableMap.keySet()); |
| | | Set<Long> receivablesWithItems = new HashSet<>(); |
| | | for (CrmReceivableItemDO item : items) { |
| | | receivablesWithItems.add(item.getReceivableId()); |
| | | if (CrmReceivableBizTypeEnum.SALE_INVOICE.getType().equals(item.getBizType()) && item.getBizId() != null) { |
| | | result.merge(item.getBizId(), zeroIfNull(item.getReceiptPrice()), BigDecimal::add); |
| | | } |
| | | } |
| | | for (CrmReceivableDO receivable : receivables) { |
| | | if (receivablesWithItems.contains(receivable.getId()) || receivable.getInvoiceId() == null) { |
| | | continue; |
| | | } |
| | | result.merge(receivable.getInvoiceId(), zeroIfNull(receivable.getPrice()), BigDecimal::add); |
| | | } |
| | | return result; |
| | | } |
| | | |
| | | private BigDecimal getNextMonthPlanAmount(Long customerId) { |
| | | YearMonth nextMonth = YearMonth.now().plusMonths(1); |
| | | LocalDateTime beginTime = nextMonth.atDay(1).atStartOfDay(); |
| | | LocalDateTime endTime = nextMonth.plusMonths(1).atDay(1).atStartOfDay(); |
| | | List<CrmReceivablePlanDO> plans = receivablePlanMapper.selectList( |
| | | new LambdaQueryWrapperX<CrmReceivablePlanDO>() |
| | | .eqIfPresent(CrmReceivablePlanDO::getCustomerId, customerId) |
| | | .ge(CrmReceivablePlanDO::getReturnTime, beginTime) |
| | | .lt(CrmReceivablePlanDO::getReturnTime, endTime)); |
| | | return plans.stream() |
| | | .filter(plan -> !PLAN_STATUS_RECEIPTED.equals(plan.getStatus())) |
| | | .map(plan -> zeroIfNull(plan.getPrice())) |
| | | .reduce(BigDecimal.ZERO, BigDecimal::add); |
| | | } |
| | | |
| | | private Map<Long, String> getCustomerNameMap(Collection<Long> customerIds) { |
| | | if (CollUtil.isEmpty(customerIds)) { |
| | | return Collections.emptyMap(); |
| | | } |
| | | Map<Long, CrmCustomerDO> customerMap = customerService.getCustomerMap(customerIds); |
| | | Map<Long, String> result = new HashMap<>(); |
| | | customerMap.forEach((id, customer) -> result.put(id, customer.getName())); |
| | | return result; |
| | | } |
| | | |
| | | private static BigDecimal sumInvoicePrice(List<CrmInvoiceDO> invoices) { |
| | | if (CollUtil.isEmpty(invoices)) { |
| | | return BigDecimal.ZERO; |
| | | } |
| | | return invoices.stream().map(invoice -> zeroIfNull(invoice.getPrice())).reduce(BigDecimal.ZERO, BigDecimal::add); |
| | | } |
| | | |
| | | private static void mergeAmount(Map<String, BigDecimal> map, String key, BigDecimal amount) { |
| | | map.merge(key, amount, BigDecimal::add); |
| | | } |
| | | |
| | | private static String agingBucket(long days) { |
| | | if (days <= 30) { |
| | | return "0-30天"; |
| | | } |
| | | if (days <= 60) { |
| | | return "31-60天"; |
| | | } |
| | | if (days <= 90) { |
| | | return "61-90天"; |
| | | } |
| | | return "90天以ä¸"; |
| | | } |
| | | |
| | | private static boolean ObjectUtilEqual(Object left, Object right) { |
| | | return Objects.equals(left, right); |
| | | } |
| | | |
| | | private static BigDecimal zeroIfNull(BigDecimal value) { |
| | | return value == null ? BigDecimal.ZERO : value; |
| | | } |
| | | |
| | | private static BigDecimal maxZero(BigDecimal value) { |
| | | return value.compareTo(BigDecimal.ZERO) < 0 ? BigDecimal.ZERO : value; |
| | | } |
| | | |
| | | } |
| | |
| | | package cn.iocoder.yudao.module.crm.service.invoice; |
| | | |
| | | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| | | import cn.iocoder.yudao.module.crm.controller.admin.invoice.vo.invoice.CrmInvoiceEntryReqVO; |
| | | import cn.iocoder.yudao.module.crm.controller.admin.invoice.vo.invoice.CrmInvoiceImportExcelVO; |
| | | import cn.iocoder.yudao.module.crm.controller.admin.invoice.vo.invoice.CrmInvoiceImportRespVO; |
| | | import cn.iocoder.yudao.module.crm.controller.admin.invoice.vo.invoice.CrmInvoicePageReqVO; |
| | | import cn.iocoder.yudao.module.crm.controller.admin.invoice.vo.invoice.CrmInvoiceSaleOutRespVO; |
| | | import cn.iocoder.yudao.module.crm.controller.admin.invoice.vo.invoice.CrmInvoiceSaveReqVO; |
| | | import cn.iocoder.yudao.module.crm.dal.dataobject.invoice.CrmInvoiceDO; |
| | | import cn.iocoder.yudao.module.crm.dal.dataobject.receivable.CrmReceivablePlanDO; |
| | | import jakarta.validation.Valid; |
| | | |
| | | import java.math.BigDecimal; |
| | |
| | | void updateInvoice(@Valid CrmInvoiceSaveReqVO updateReqVO); |
| | | |
| | | /** |
| | | * å¼ç¥¨ç³è¯·å½å
¥å票 |
| | | * |
| | | * ä»
审æ¹éè¿çå¼ç¥¨ç³è¯·å¯å½å
¥ï¼å½å
¥åå¼ç¥¨è¿å
¥ãå·²å½å
¥ãç¶æï¼å¯è¢«å款åå
³èã |
| | | * |
| | | * @param reqVO å½å
¥ä¿¡æ¯ |
| | | */ |
| | | void entryInvoice(@Valid CrmInvoiceEntryReqVO reqVO); |
| | | |
| | | /** |
| | | * è·å¾å¼ç¥¨å¯éçéå®åºåºå |
| | | * |
| | | * @param saleOrderId éå®è®¢åç¼å· |
| | | * @param excludeInvoiceId éæé¤çå¼ç¥¨ç¼å·ï¼å¯ä¸ºç©º |
| | | * @return åºåºåå表ï¼å«å·²å¼ç¥¨ãå©ä½å¯å¼ç¥¨éé¢ï¼ |
| | | */ |
| | | List<CrmInvoiceSaleOutRespVO> getSaleOutListForInvoice(Long saleOrderId, Long excludeInvoiceId); |
| | | |
| | | /** |
| | | * è·å¾å¼ç¥¨å对åºçæ¶æ¬¾èç¹ |
| | | * |
| | | * @param invoiceId å¼ç¥¨ç¼å· |
| | | * @return æ¶æ¬¾èç¹å表 |
| | | */ |
| | | List<CrmReceivablePlanDO> getPaymentNodeListByInvoiceId(Long invoiceId); |
| | | |
| | | /** |
| | | * æ´æ°å¼ç¥¨æµç¨å®¡æ¹ç»æ |
| | | * |
| | | * @param id å¼ç¥¨ç¼å· |
| | |
| | | import cn.iocoder.yudao.framework.operatelog.core.util.OperateLogUtils; |
| | | import cn.iocoder.yudao.module.bpm.api.task.BpmProcessInstanceApi; |
| | | import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; |
| | | import cn.iocoder.yudao.module.crm.controller.admin.invoice.vo.invoice.CrmInvoiceEntryReqVO; |
| | | import cn.iocoder.yudao.module.crm.controller.admin.invoice.vo.invoice.CrmInvoiceImportExcelVO; |
| | | import cn.iocoder.yudao.module.crm.controller.admin.invoice.vo.invoice.CrmInvoiceImportRespVO; |
| | | import cn.iocoder.yudao.module.crm.controller.admin.invoice.vo.invoice.CrmInvoicePageReqVO; |
| | | import cn.iocoder.yudao.module.crm.controller.admin.invoice.vo.invoice.CrmInvoiceSaleOutRespVO; |
| | | import cn.iocoder.yudao.module.crm.controller.admin.invoice.vo.invoice.CrmInvoiceSaveReqVO; |
| | | import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractDO; |
| | | import cn.iocoder.yudao.module.crm.dal.dataobject.invoice.CrmInvoiceDO; |
| | | import cn.iocoder.yudao.module.crm.dal.dataobject.receivable.CrmReceivablePlanDO; |
| | | import cn.iocoder.yudao.module.crm.dal.mysql.invoice.CrmInvoiceMapper; |
| | | import cn.iocoder.yudao.module.crm.dal.mysql.receivable.CrmReceivablePlanMapper; |
| | | import cn.iocoder.yudao.module.crm.dal.redis.no.CrmNoRedisDAO; |
| | | import cn.iocoder.yudao.module.crm.enums.common.CrmAuditStatusEnum; |
| | | import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; |
| | | import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum; |
| | | import cn.iocoder.yudao.module.crm.enums.receivable.CrmPaymentStageEnum; |
| | | import cn.iocoder.yudao.module.erp.api.sale.ErpSaleOrderApi; |
| | | import cn.iocoder.yudao.module.erp.api.sale.dto.ErpSaleOrderRespDTO; |
| | | import cn.iocoder.yudao.module.mes.api.productsales.MesWmProductSalesApi; |
| | | import cn.iocoder.yudao.module.mes.api.productsales.dto.MesWmProductSalesRespDTO; |
| | | import cn.iocoder.yudao.module.crm.framework.permission.core.annotations.CrmPermission; |
| | | import cn.iocoder.yudao.module.crm.service.contract.CrmContractService; |
| | | import cn.iocoder.yudao.module.crm.service.permission.CrmPermissionService; |
| | |
| | | import java.util.ArrayList; |
| | | import java.util.Collection; |
| | | import java.util.HashMap; |
| | | import java.util.HashSet; |
| | | import java.util.LinkedHashMap; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.Objects; |
| | | import java.util.Set; |
| | | |
| | | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| | | import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; |
| | |
| | | */ |
| | | private static final String INVOICE_RECORD_TYPE = "crm_invoice"; |
| | | |
| | | /** |
| | | * ERP éå®è®¢åå®¡æ ¸éè¿ç¶æï¼å¯¹åº cn.iocoder.yudao.module.erp.enums.ErpAuditStatus#APPROVE |
| | | */ |
| | | private static final Integer ERP_SALE_ORDER_STATUS_APPROVE = 20; |
| | | |
| | | /** |
| | | * MES éå®åºåºåå·²å®æç¶æï¼å¯¹åº cn.iocoder.yudao.module.mes.enums.wm.MesWmProductSalesStatusEnum#FINISHED |
| | | */ |
| | | private static final Integer MES_PRODUCT_SALES_STATUS_FINISHED = 4; |
| | | |
| | | /** |
| | | * MES éå®åºåºåå·²åæ¶ç¶æ |
| | | */ |
| | | private static final Integer MES_PRODUCT_SALES_STATUS_CANCELED = 5; |
| | | |
| | | /** |
| | | * å¼ç¥¨å ç¨é¢åº¦ç审æ¹ç¶æï¼å®¡æ¹ä¸ + 审æ¹éè¿ |
| | | */ |
| | | private static final List<Integer> INVOICE_OCCUPY_STATUSES = List.of( |
| | | CrmAuditStatusEnum.PROCESS.getStatus(), CrmAuditStatusEnum.APPROVE.getStatus()); |
| | | |
| | | @Resource |
| | | private CrmInvoiceMapper invoiceMapper; |
| | | @Resource |
| | | private CrmReceivablePlanMapper receivablePlanMapper; |
| | | |
| | | @Resource |
| | | private ErpSaleOrderApi saleOrderApi; |
| | | @Resource |
| | | private MesWmProductSalesApi productSalesApi; |
| | | |
| | | @Resource |
| | | private CrmNoRedisDAO noRedisDAO; |
| | |
| | | @LogRecord(type = CRM_INVOICE_TYPE, subType = CRM_INVOICE_CREATE_SUB_TYPE, bizNo = "{{#invoice.id}}", |
| | | success = CRM_INVOICE_CREATE_SUCCESS) |
| | | public Long createInvoice(CrmInvoiceSaveReqVO createReqVO) { |
| | | // 1.1 æ ¡éªå¯å¼ç¥¨éé¢è¶
è¿ä¸é |
| | | validateInvoicePriceExceedsLimit(createReqVO); |
| | | // 1.2 æ ¡éªå
³èæ°æ®åå¨ |
| | | // 1.1 æ ¡éªå
³èæ°æ®åå¨ï¼åå -> 客æ·ï¼ |
| | | validateRelationDataExists(createReqVO); |
| | | // 1.3 çæå¼ç¥¨ç¼å· |
| | | // 1.2 æ ¡éªéå®è®¢åãéå®åºåºåï¼å¹¶åå¡«åºåºåå· |
| | | validateSaleOrderAndOut(createReqVO); |
| | | // 1.3 æ ¡éªå¯å¼ç¥¨éé¢è¶
è¿ä¸é |
| | | validateInvoicePriceExceedsLimit(createReqVO); |
| | | // 1.4 çæå¼ç¥¨ç¼å· |
| | | String no = noRedisDAO.generate(CrmNoRedisDAO.INVOICE_PREFIX); |
| | | if (invoiceMapper.selectByNo(no) != null) { |
| | | throw exception(INVOICE_NO_EXISTS); |
| | | } |
| | | |
| | | // 2.1 æå
¥å¼ç¥¨ |
| | | // 2.1 æå
¥å¼ç¥¨ï¼å·²å¡«åå票å·ç è§ä¸ºå·²å½å
¥å票 |
| | | CrmInvoiceDO invoice = BeanUtils.toBean(createReqVO, CrmInvoiceDO.class) |
| | | .setNo(no).setAuditStatus(CrmAuditStatusEnum.DRAFT.getStatus()); |
| | | applyEntryStatus(invoice, createReqVO.getInvoiceNo(), null); |
| | | invoiceMapper.insert(invoice); |
| | | |
| | | // 2.2 ç»å®å票éä»¶ |
| | | if (CollUtil.isNotEmpty(createReqVO.getBlobIds())) { |
| | | storageAttachmentApi.bindAttachments("file", INVOICE_RECORD_TYPE, invoice.getId(), createReqVO.getBlobIds()); |
| | | } |
| | | |
| | | // 2.3 åæ¥æ¶æ¬¾èç¹ï¼å忬¾/é¢ä»æ¬¾/å°è´§æ¬¾/éªæ¶æ¬¾ï¼ |
| | | syncPaymentNodes(invoice, createReqVO.getPaymentNodes()); |
| | | |
| | | // 3. åå»ºæ°æ®æé |
| | | permissionService.createPermission(new CrmPermissionCreateReqBO().setBizType(CrmBizTypeEnum.CRM_INVOICE.getType()) |
| | |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * æ ¡éªéå®è®¢åãéå®åºåºåï¼å¹¶åå¡«åºåºåå· |
| | | * |
| | | * æ ¡éªé¡ºåºï¼éå®è®¢ååå¨ -> å·²å®¡æ ¸ -> 客æ·/ååä¸è´ -> 订åå©ä½å¯å¼ç¥¨ï¼ |
| | | * åæ ¡éªåºåºååå¨ -> 已宿 -> å±äºè¯¥è®¢å -> 客æ·ä¸è´ -> åºåºåå©ä½å¯å¼ç¥¨ã |
| | | */ |
| | | private void validateSaleOrderAndOut(CrmInvoiceSaveReqVO reqVO) { |
| | | if (reqVO.getSaleOrderId() == null) { |
| | | return; |
| | | } |
| | | // 1. éå®è®¢å |
| | | ErpSaleOrderRespDTO saleOrder = saleOrderApi.getSaleOrder(reqVO.getSaleOrderId()).getCheckedData(); |
| | | if (saleOrder == null) { |
| | | throw exception(INVOICE_CREATE_FAIL_SALE_ORDER_NOT_EXISTS, reqVO.getSaleOrderId()); |
| | | } |
| | | if (ObjectUtil.notEqual(saleOrder.getStatus(), ERP_SALE_ORDER_STATUS_APPROVE)) { |
| | | throw exception(INVOICE_CREATE_FAIL_SALE_ORDER_NOT_APPROVE, saleOrder.getNo(), |
| | | erpAuditStatusName(saleOrder.getStatus())); |
| | | } |
| | | if (ObjectUtil.notEqual(saleOrder.getCustomerId(), reqVO.getCustomerId()) |
| | | || (saleOrder.getContractId() != null |
| | | && ObjectUtil.notEqual(saleOrder.getContractId(), reqVO.getContractId()))) { |
| | | throw exception(INVOICE_CREATE_FAIL_SALE_ORDER_MISMATCH, saleOrder.getNo(), |
| | | saleOrder.getCustomerId(), saleOrder.getContractId(), reqVO.getCustomerId(), reqVO.getContractId()); |
| | | } |
| | | // 1.1 订åå©ä½å¯å¼ç¥¨éé¢ = 订åéé¢ - 该订åå·²å ç¨å¼ç¥¨éé¢ï¼å®¡æ¹ä¸ + 审æ¹éè¿ï¼ |
| | | BigDecimal orderTotalPrice = zeroIfNull(saleOrder.getTotalPrice()); |
| | | BigDecimal orderInvoicedPrice = sumInvoicePrice(invoiceMapper.selectListBySaleOrderIdAndStatus( |
| | | reqVO.getSaleOrderId(), INVOICE_OCCUPY_STATUSES), reqVO.getId()); |
| | | BigDecimal orderRemainPrice = orderTotalPrice.subtract(orderInvoicedPrice); |
| | | if (reqVO.getPrice() != null && reqVO.getPrice().compareTo(orderRemainPrice) > 0) { |
| | | throw exception(INVOICE_CREATE_FAIL_PRICE_EXCEEDS_SALE_ORDER, saleOrder.getNo(), |
| | | formatPrice(orderRemainPrice), formatPrice(orderTotalPrice), formatPrice(orderInvoicedPrice)); |
| | | } |
| | | |
| | | // 2. éå®åºåºåï¼å¯éï¼ |
| | | if (reqVO.getSaleOutId() == null) { |
| | | return; |
| | | } |
| | | MesWmProductSalesRespDTO saleOut = productSalesApi.getProductSales(reqVO.getSaleOutId()); |
| | | if (saleOut == null) { |
| | | throw exception(INVOICE_CREATE_FAIL_SALE_OUT_NOT_EXISTS, reqVO.getSaleOutId()); |
| | | } |
| | | if (ObjectUtil.notEqual(saleOut.getStatus(), MES_PRODUCT_SALES_STATUS_FINISHED)) { |
| | | throw exception(INVOICE_CREATE_FAIL_SALE_OUT_NOT_FINISHED, saleOut.getCode(), |
| | | productSalesStatusName(saleOut.getStatus())); |
| | | } |
| | | if (saleOut.getSaleOrderId() != null && ObjectUtil.notEqual(saleOut.getSaleOrderId(), reqVO.getSaleOrderId())) { |
| | | throw exception(INVOICE_CREATE_FAIL_SALE_OUT_MISMATCH_ORDER, saleOut.getCode(), |
| | | saleOrder.getNo(), saleOut.getSaleOrderId()); |
| | | } |
| | | if (saleOut.getClientId() != null && ObjectUtil.notEqual(saleOut.getClientId(), reqVO.getCustomerId())) { |
| | | throw exception(INVOICE_CREATE_FAIL_SALE_OUT_MISMATCH_CUSTOMER, saleOut.getCode(), |
| | | saleOut.getClientId(), reqVO.getCustomerId()); |
| | | } |
| | | // 2.1 åºåºåå©ä½å¯å¼ç¥¨éé¢ = åºåºéé¢ - 该åºåºåå·²å ç¨å¼ç¥¨éé¢ï¼å®¡æ¹ä¸ + 审æ¹éè¿ï¼ |
| | | BigDecimal saleOutTotalPrice = zeroIfNull(saleOut.getTotalPrice()); |
| | | BigDecimal saleOutInvoicedPrice = sumInvoicePrice(invoiceMapper.selectListBySaleOutIdAndStatus( |
| | | reqVO.getSaleOutId(), INVOICE_OCCUPY_STATUSES), reqVO.getId()); |
| | | BigDecimal saleOutRemainPrice = saleOutTotalPrice.subtract(saleOutInvoicedPrice); |
| | | if (reqVO.getPrice() != null && reqVO.getPrice().compareTo(saleOutRemainPrice) > 0) { |
| | | throw exception(INVOICE_CREATE_FAIL_PRICE_EXCEEDS_SALE_OUT, saleOut.getCode(), |
| | | formatPrice(saleOutRemainPrice), formatPrice(saleOutTotalPrice), formatPrice(saleOutInvoicedPrice)); |
| | | } |
| | | reqVO.setSaleOutCode(saleOut.getCode()); |
| | | } |
| | | |
| | | private BigDecimal sumInvoicePrice(List<CrmInvoiceDO> invoices, Long excludeInvoiceId) { |
| | | if (CollUtil.isEmpty(invoices)) { |
| | | return BigDecimal.ZERO; |
| | | } |
| | | return invoices.stream() |
| | | .filter(invoice -> excludeInvoiceId == null || ObjectUtil.notEqual(invoice.getId(), excludeInvoiceId)) |
| | | .map(invoice -> zeroIfNull(invoice.getPrice())) |
| | | .reduce(BigDecimal.ZERO, BigDecimal::add); |
| | | } |
| | | |
| | | /** |
| | | * æ ¹æ®å票å·ç æ¯å¦å¡«åï¼è®¾ç½®å票å½å
¥ç¶æ |
| | | */ |
| | | private void applyEntryStatus(CrmInvoiceDO invoice, String invoiceNo, CrmInvoiceDO oldInvoice) { |
| | | if (StrUtil.isBlank(invoiceNo)) { |
| | | invoice.setEntryStatus(0); |
| | | return; |
| | | } |
| | | invoice.setEntryStatus(10); |
| | | boolean changed = oldInvoice == null || !StrUtil.equals(invoiceNo, oldInvoice.getInvoiceNo()) |
| | | || !Integer.valueOf(10).equals(oldInvoice.getEntryStatus()); |
| | | if (changed) { |
| | | invoice.setEntryUserId(getLoginUserId()).setEntryTime(LocalDateTime.now()); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 忥å¼ç¥¨åçæ¶æ¬¾èç¹å°å款计åï¼crm_receivable_planï¼ |
| | | * |
| | | * ä¼ null è¡¨ç¤ºæ¬æ¬¡ä¸ä¿®æ¹èç¹ï¼ä¼ 空å表表示æ¸
空èç¹ã |
| | | */ |
| | | private void syncPaymentNodes(CrmInvoiceDO invoice, List<CrmInvoiceSaveReqVO.PaymentNode> nodes) { |
| | | if (nodes == null) { |
| | | return; |
| | | } |
| | | validatePaymentNodes(nodes); |
| | | // 已产ç忬¾çèç¹ä¸å
许被è¦ç |
| | | for (CrmReceivablePlanDO oldPlan : receivablePlanMapper.selectListByInvoiceId(invoice.getId())) { |
| | | if (oldPlan.getReceivableId() != null || zeroIfNull(oldPlan.getReceiptedPrice()).compareTo(BigDecimal.ZERO) > 0) { |
| | | throw exception(INVOICE_PAYMENT_NODE_ALREADY_RECEIPTED, |
| | | CrmPaymentStageEnum.getNameByStage(oldPlan.getStage()), |
| | | formatPrice(zeroIfNull(oldPlan.getReceiptedPrice()))); |
| | | } |
| | | } |
| | | deletePaymentNodesByInvoiceId(invoice.getId()); |
| | | |
| | | Long ownerUserId = invoice.getOwnerUserId() != null ? invoice.getOwnerUserId() : getLoginUserId(); |
| | | for (CrmInvoiceSaveReqVO.PaymentNode node : nodes) { |
| | | CrmReceivablePlanDO maxPeriodPlan = receivablePlanMapper.selectMaxPeriodByContractId(invoice.getContractId()); |
| | | int period = maxPeriodPlan == null ? 1 : maxPeriodPlan.getPeriod() + 1; |
| | | int remindDays = 3; |
| | | CrmReceivablePlanDO plan = CrmReceivablePlanDO.builder() |
| | | .period(period).customerId(invoice.getCustomerId()).contractId(invoice.getContractId()) |
| | | .ownerUserId(ownerUserId).returnTime(node.getReturnTime()) |
| | | .remindDays(remindDays).remindTime(node.getReturnTime().minusDays(remindDays)) |
| | | .price(node.getAmount()).stage(node.getStage()).invoiceId(invoice.getId()) |
| | | .saleOrderId(invoice.getSaleOrderId()) |
| | | .receiptedPrice(BigDecimal.ZERO).status(0).remark(node.getRemark()) |
| | | .build(); |
| | | receivablePlanMapper.insert(plan); |
| | | permissionService.createPermission(new CrmPermissionCreateReqBO() |
| | | .setBizType(CrmBizTypeEnum.CRM_RECEIVABLE_PLAN.getType()).setBizId(plan.getId()) |
| | | .setUserId(ownerUserId).setLevel(CrmPermissionLevelEnum.OWNER.getLevel())); |
| | | } |
| | | } |
| | | |
| | | private void validatePaymentNodes(List<CrmInvoiceSaveReqVO.PaymentNode> nodes) { |
| | | if (CollUtil.isEmpty(nodes)) { |
| | | return; |
| | | } |
| | | Set<Integer> stages = new HashSet<>(); |
| | | for (int i = 0; i < nodes.size(); i++) { |
| | | CrmInvoiceSaveReqVO.PaymentNode node = nodes.get(i); |
| | | int row = i + 1; |
| | | CrmPaymentStageEnum stageEnum = node == null ? null : CrmPaymentStageEnum.valueOf(node.getStage()); |
| | | if (stageEnum == null) { |
| | | throw exception(INVOICE_PAYMENT_NODE_STAGE_INVALID, row, node == null ? "æªå¡«å" : node.getStage()); |
| | | } |
| | | if (!stages.add(stageEnum.getStage())) { |
| | | throw exception(INVOICE_PAYMENT_NODE_STAGE_DUPLICATE, stageEnum.getName()); |
| | | } |
| | | if (node.getAmount() == null || node.getAmount().compareTo(BigDecimal.ZERO) <= 0) { |
| | | throw exception(INVOICE_PAYMENT_NODE_INVALID, row, stageEnum.getName(), |
| | | node.getAmount() == null ? "æªå¡«å" : formatPrice(node.getAmount())); |
| | | } |
| | | if (node.getReturnTime() == null) { |
| | | throw exception(INVOICE_PAYMENT_NODE_TIME_REQUIRED, stageEnum.getName()); |
| | | } |
| | | } |
| | | } |
| | | |
| | | private void deletePaymentNodesByInvoiceId(Long invoiceId) { |
| | | for (CrmReceivablePlanDO plan : receivablePlanMapper.selectListByInvoiceId(invoiceId)) { |
| | | receivablePlanMapper.deleteById(plan.getId()); |
| | | permissionService.deletePermission(CrmBizTypeEnum.CRM_RECEIVABLE_PLAN.getType(), plan.getId()); |
| | | } |
| | | } |
| | | |
| | | private String erpAuditStatusName(Integer status) { |
| | | if (Objects.equals(status, ERP_SALE_ORDER_STATUS_APPROVE)) { |
| | | return "å·²å®¡æ ¸"; |
| | | } |
| | | if (status == null) { |
| | | return "æªç¥ç¶æ"; |
| | | } |
| | | return switch (status) { |
| | | case 0 -> "æªæäº¤"; |
| | | case 10 -> "æªå®¡æ ¸"; |
| | | case 15 -> "审æ¹ä¸"; |
| | | case 30 -> "å·²ä½åº"; |
| | | case 35 -> "已驳å"; |
| | | default -> "ç¶æå¼ " + status; |
| | | }; |
| | | } |
| | | |
| | | private String productSalesStatusName(Integer status) { |
| | | if (status == null) { |
| | | return "æªç¥ç¶æ"; |
| | | } |
| | | return switch (status) { |
| | | case 0 -> "è稿"; |
| | | case 1 -> "å¾
æ£æµ"; |
| | | case 2 -> "å¾
æ£è´§"; |
| | | case 3 -> "å¾
æ§è¡åºåº"; |
| | | case 4 -> "已宿"; |
| | | case 5 -> "已忶"; |
| | | case 10 -> "å¾
å¡«åè¿å"; |
| | | default -> "ç¶æå¼ " + status; |
| | | }; |
| | | } |
| | | |
| | | private static BigDecimal zeroIfNull(BigDecimal value) { |
| | | return value == null ? BigDecimal.ZERO : value; |
| | | } |
| | | |
| | | private static String formatPrice(BigDecimal value) { |
| | | return (value == null ? BigDecimal.ZERO : value).stripTrailingZeros().toPlainString(); |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | @LogRecord(type = CRM_INVOICE_TYPE, subType = CRM_INVOICE_UPDATE_SUB_TYPE, bizNo = "{{#updateReqVO.id}}", |
| | |
| | | StrUtil.blankToDefault(CrmAuditStatusEnum.getNameByStatus(oldInvoice.getAuditStatus()), "æªç¥ç¶æ")); |
| | | } |
| | | |
| | | // 1.3 æ ¡éªå¯å¼ç¥¨éé¢è¶
è¿ä¸é |
| | | // 1.3 æ ¡éªéå®è®¢åãéå®åºåºåï¼å¹¶åå¡«åºåºåå· |
| | | validateSaleOrderAndOut(updateReqVO); |
| | | // 1.4 æ ¡éªå¯å¼ç¥¨éé¢è¶
è¿ä¸é |
| | | validateInvoicePriceExceedsLimit(updateReqVO); |
| | | |
| | | // 2. æ´æ°å¼ç¥¨ |
| | | CrmInvoiceDO updateObj = BeanUtils.toBean(updateReqVO, CrmInvoiceDO.class); |
| | | applyEntryStatus(updateObj, updateReqVO.getInvoiceNo(), oldInvoice); |
| | | invoiceMapper.updateById(updateObj); |
| | | // å票å·ç 被æ¸
空æ¶ï¼ä¸å¹¶æ¸
空å½å
¥äººãå½å
¥æ¶é´ï¼updateById ä¼å¿½ç¥ null åæ®µï¼éæ¾å¼æ¸
ç©ºï¼ |
| | | if (StrUtil.isBlank(updateReqVO.getInvoiceNo())) { |
| | | invoiceMapper.clearEntryInfo(updateReqVO.getId()); |
| | | } |
| | | |
| | | // 3. å¢éæ´æ°å票éä»¶ |
| | | storageAttachmentApi.updateAttachments("file", INVOICE_RECORD_TYPE, updateReqVO.getId(), updateReqVO.getBlobIds()); |
| | | |
| | | // 3.1 åæ¥æ¶æ¬¾èç¹ï¼ä»
åç«¯ä¼ äº paymentNodes æè¦çï¼é¿å
ä¸ä¼ æ¶è¯¯å ï¼ |
| | | syncPaymentNodes(oldInvoice, updateReqVO.getPaymentNodes()); |
| | | |
| | | // 4. è®°å½æä½æ¥å¿ä¸ä¸æ |
| | | updateReqVO.setOwnerUserId(oldInvoice.getOwnerUserId()); // é¿å
æä½æ¥å¿åºç°âå é¤è´è´£äººâçæ
åµ |
| | |
| | | invoiceMapper.deleteById(id); |
| | | // 2.3 å 餿°æ®æé |
| | | permissionService.deletePermission(CrmBizTypeEnum.CRM_INVOICE.getType(), id); |
| | | // 2.4 å é¤å¼ç¥¨çæçæ¶æ¬¾èç¹ï¼å®¡æ¹éè¿çå¼ç¥¨ä¸å
许å é¤ï¼æ
æ¤å¤èç¹å¿
ç¶æªäº§ç忬¾ï¼ |
| | | deletePaymentNodesByInvoiceId(id); |
| | | |
| | | // 3. è®°å½æä½æ¥å¿ä¸ä¸æ |
| | | LogRecordContext.putVariable("invoice", invoice); |
| | |
| | | return invoiceMapper.selectCountByContractId(contractId); |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | @LogRecord(type = CRM_INVOICE_TYPE, subType = CRM_INVOICE_ENTRY_SUB_TYPE, bizNo = "{{#reqVO.id}}", |
| | | success = CRM_INVOICE_ENTRY_SUCCESS) |
| | | @CrmPermission(bizType = CrmBizTypeEnum.CRM_INVOICE, bizId = "#reqVO.id", level = CrmPermissionLevelEnum.WRITE) |
| | | public void entryInvoice(CrmInvoiceEntryReqVO reqVO) { |
| | | // 1.1 æ ¡éªåå¨ |
| | | CrmInvoiceDO invoice = validateInvoiceExists(reqVO.getId()); |
| | | // 1.2 åªæå®¡æ¹éè¿çå¼ç¥¨ç³è¯·æè½å½å
¥å票 |
| | | if (ObjectUtil.notEqual(invoice.getAuditStatus(), CrmAuditStatusEnum.APPROVE.getStatus())) { |
| | | throw exception(INVOICE_ENTRY_FAIL_NOT_APPROVE, invoice.getNo(), |
| | | StrUtil.blankToDefault(CrmAuditStatusEnum.getNameByStatus(invoice.getAuditStatus()), "æªç¥ç¶æ")); |
| | | } |
| | | // 1.3 å票å·ç ä¸å¯ä¸å
¶ä»å¼ç¥¨åéå¤ |
| | | String invoiceNo = reqVO.getInvoiceNo().trim(); |
| | | CrmInvoiceDO invoiceNoExists = invoiceMapper.selectByInvoiceNo(invoiceNo); |
| | | if (invoiceNoExists != null && ObjectUtil.notEqual(invoiceNoExists.getId(), invoice.getId())) { |
| | | throw exception(INVOICE_ENTRY_FAIL_INVOICE_NO_EXISTS, invoiceNo, invoiceNoExists.getNo()); |
| | | } |
| | | |
| | | // 2. å½å
¥å票信æ¯ï¼ç¶æç½®ä¸ºå·²å½å
¥ |
| | | invoiceMapper.updateById(new CrmInvoiceDO().setId(invoice.getId()) |
| | | .setInvoiceNo(invoiceNo).setInvoiceTitle(reqVO.getInvoiceTitle()) |
| | | .setInvoiceTime(reqVO.getInvoiceTime()).setRemark(reqVO.getRemark()) |
| | | .setEntryStatus(10).setEntryUserId(getLoginUserId()).setEntryTime(LocalDateTime.now())); |
| | | // 3. æ´æ°å票éä»¶ |
| | | if (reqVO.getBlobIds() != null) { |
| | | storageAttachmentApi.updateAttachments("file", INVOICE_RECORD_TYPE, invoice.getId(), reqVO.getBlobIds()); |
| | | } |
| | | // 4. åæ¥æ¶æ¬¾èç¹ |
| | | syncPaymentNodes(invoice, reqVO.getPaymentNodes()); |
| | | |
| | | // 5. è®°å½æä½æ¥å¿ä¸ä¸æ |
| | | LogRecordContext.putVariable("invoiceNo", invoice.getNo()); |
| | | LogRecordContext.putVariable("entryInvoiceNo", invoiceNo); |
| | | } |
| | | |
| | | @Override |
| | | public List<CrmInvoiceSaleOutRespVO> getSaleOutListForInvoice(Long saleOrderId, Long excludeInvoiceId) { |
| | | if (saleOrderId == null) { |
| | | return ListUtil.empty(); |
| | | } |
| | | List<MesWmProductSalesRespDTO> saleOutList = productSalesApi.getProductSalesListBySaleOrderId(saleOrderId); |
| | | if (CollUtil.isEmpty(saleOutList)) { |
| | | return ListUtil.empty(); |
| | | } |
| | | List<CrmInvoiceSaleOutRespVO> result = new ArrayList<>(); |
| | | for (MesWmProductSalesRespDTO saleOut : saleOutList) { |
| | | // 已忶çåºåºåä¸å¯å¼ç¥¨ |
| | | if (ObjectUtil.equal(saleOut.getStatus(), MES_PRODUCT_SALES_STATUS_CANCELED)) { |
| | | continue; |
| | | } |
| | | BigDecimal totalPrice = zeroIfNull(saleOut.getTotalPrice()); |
| | | BigDecimal invoicedPrice = sumInvoicePrice(invoiceMapper.selectListBySaleOutIdAndStatus( |
| | | saleOut.getId(), INVOICE_OCCUPY_STATUSES), excludeInvoiceId); |
| | | CrmInvoiceSaleOutRespVO vo = new CrmInvoiceSaleOutRespVO(); |
| | | vo.setId(saleOut.getId()); |
| | | vo.setCode(saleOut.getCode()); |
| | | vo.setSaleOrderId(saleOut.getSaleOrderId()); |
| | | vo.setSalesOrderCode(saleOut.getSalesOrderCode()); |
| | | vo.setSalesDate(saleOut.getSalesDate()); |
| | | vo.setStatus(saleOut.getStatus()); |
| | | vo.setStatusName(productSalesStatusName(saleOut.getStatus())); |
| | | vo.setTotalPrice(totalPrice); |
| | | vo.setInvoicedPrice(invoicedPrice); |
| | | vo.setRemainInvoicePrice(totalPrice.subtract(invoicedPrice)); |
| | | result.add(vo); |
| | | } |
| | | return result; |
| | | } |
| | | |
| | | @Override |
| | | public List<CrmReceivablePlanDO> getPaymentNodeListByInvoiceId(Long invoiceId) { |
| | | return receivablePlanMapper.selectListByInvoiceId(invoiceId); |
| | | } |
| | | |
| | | } |
| | |
| | | void updateReceivablePlanReceivableId(Long id, Long receivableId); |
| | | |
| | | /** |
| | | * åå忬¾è®¡åçå®é
忬¾éé¢ãå®é
忬¾æ¶é´ä¸ç¶æ |
| | | * |
| | | * @param id 忬¾è®¡åç¼å· |
| | | * @param receiptPrice 忬¾éé¢ |
| | | * @param actualTime å®é
忬¾æ¶é´ |
| | | */ |
| | | void updateReceivablePlanReceipted(Long id, java.math.BigDecimal receiptPrice, java.time.LocalDateTime actualTime); |
| | | |
| | | /** |
| | | * åå®¡æ ¸åæ¬¾æ¶ï¼æ¸
ç©ºåæ¬¾è®¡åçå®é
忬¾ä¿¡æ¯ |
| | | * |
| | | * @param id 忬¾è®¡åç¼å· |
| | | */ |
| | | void resetReceivablePlanReceipted(Long id); |
| | | |
| | | /** |
| | | * å é¤å款计å |
| | | * |
| | | * @param id ç¼å· |
| | |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | import org.springframework.validation.annotation.Validated; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.util.Collection; |
| | | import java.util.List; |
| | | import java.util.Objects; |
| | |
| | | } |
| | | |
| | | @Override |
| | | public void updateReceivablePlanReceipted(Long id, java.math.BigDecimal receiptPrice, |
| | | java.time.LocalDateTime actualTime) { |
| | | CrmReceivablePlanDO plan = validateReceivablePlanExists(id); |
| | | BigDecimal receiptedPrice = plan.getReceiptedPrice() == null ? java.math.BigDecimal.ZERO : plan.getReceiptedPrice(); |
| | | receiptedPrice = receiptedPrice.add(receiptPrice == null ? java.math.BigDecimal.ZERO : receiptPrice); |
| | | // ç¶æï¼0æªå款 10é¨å忬¾ 20已忏
|
| | | int status = receiptedPrice.compareTo(plan.getPrice()) >= 0 ? 20 : (receiptedPrice.signum() > 0 ? 10 : 0); |
| | | receivablePlanMapper.updateById(new CrmReceivablePlanDO().setId(id) |
| | | .setReceiptedPrice(receiptedPrice).setStatus(status) |
| | | .setActualTime(actualTime != null ? actualTime : java.time.LocalDateTime.now())); |
| | | } |
| | | |
| | | @Override |
| | | public void resetReceivablePlanReceipted(Long id) { |
| | | validateReceivablePlanExists(id); |
| | | // updateById ä¼å¿½ç¥ nullï¼éæ¾å¼æ¸
空å®é
忬¾æ¶é´ |
| | | receivablePlanMapper.update(null, |
| | | new com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper<CrmReceivablePlanDO>() |
| | | .eq(CrmReceivablePlanDO::getId, id) |
| | | .set(CrmReceivablePlanDO::getReceiptedPrice, java.math.BigDecimal.ZERO) |
| | | .set(CrmReceivablePlanDO::getStatus, 0) |
| | | .set(CrmReceivablePlanDO::getActualTime, null)); |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | @LogRecord(type = CRM_RECEIVABLE_PLAN_TYPE, subType = CRM_RECEIVABLE_PLAN_DELETE_SUB_TYPE, bizNo = "{{#id}}", |
| | | success = CRM_RECEIVABLE_PLAN_DELETE_SUCCESS) |
| | |
| | | import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.receivable.CrmReceivableSaveReqVO; |
| | | import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO; |
| | | import cn.iocoder.yudao.module.crm.dal.dataobject.receivable.CrmReceivableDO; |
| | | import cn.iocoder.yudao.module.crm.dal.dataobject.receivable.CrmReceivableItemDO; |
| | | import jakarta.validation.Valid; |
| | | |
| | | import java.math.BigDecimal; |
| | |
| | | List<CrmReceivableDO> getReceivableList(Collection<Long> ids); |
| | | |
| | | /** |
| | | * è·å¾åæ¬¾çæ ¸éæç» |
| | | * |
| | | * @param receivableId 忬¾ç¼å· |
| | | * @return æ ¸éæç»å表 |
| | | */ |
| | | List<CrmReceivableItemDO> getReceivableItemList(Long receivableId); |
| | | |
| | | /** |
| | | * è·å¾å®¢æ·ä¸å
¨é¨åæ¬¾çæ ¸éæç» |
| | | * |
| | | * @param customerId 客æ·ç¼å· |
| | | * @return æ ¸éæç»åè¡¨ï¼æåæ¬¾ååºï¼ |
| | | */ |
| | | List<CrmReceivableItemDO> getReceivableItemListByCustomerId(Long customerId); |
| | | |
| | | /** |
| | | * è·å¾å款 Map |
| | | * |
| | | * @param ids ç¼å· |
| | |
| | | import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractDO; |
| | | import cn.iocoder.yudao.module.crm.dal.dataobject.invoice.CrmInvoiceDO; |
| | | import cn.iocoder.yudao.module.crm.dal.dataobject.receivable.CrmReceivableDO; |
| | | import cn.iocoder.yudao.module.crm.dal.dataobject.receivable.CrmReceivableItemDO; |
| | | import cn.iocoder.yudao.module.crm.dal.dataobject.receivable.CrmReceivablePlanDO; |
| | | import cn.iocoder.yudao.module.crm.dal.mysql.receivable.CrmReceivableItemMapper; |
| | | import cn.iocoder.yudao.module.crm.dal.mysql.receivable.CrmReceivableMapper; |
| | | import cn.iocoder.yudao.module.crm.dal.redis.no.CrmNoRedisDAO; |
| | | import cn.iocoder.yudao.module.crm.enums.common.CrmAuditStatusEnum; |
| | | import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; |
| | | import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum; |
| | | import cn.iocoder.yudao.module.crm.enums.receivable.CrmReceivableBizTypeEnum; |
| | | import cn.iocoder.yudao.module.erp.api.sale.ErpSaleOrderApi; |
| | | import cn.iocoder.yudao.module.erp.api.sale.dto.ErpSaleOrderRespDTO; |
| | | import cn.iocoder.yudao.module.mes.api.productsales.MesWmProductSalesApi; |
| | | import cn.iocoder.yudao.module.mes.api.productsales.dto.MesWmProductSalesRespDTO; |
| | | import cn.iocoder.yudao.module.crm.framework.permission.core.annotations.CrmPermission; |
| | | import cn.iocoder.yudao.module.crm.service.contract.CrmContractService; |
| | | import cn.iocoder.yudao.module.crm.service.invoice.CrmInvoiceService; |
| | |
| | | |
| | | @Resource |
| | | private CrmReceivableMapper receivableMapper; |
| | | @Resource |
| | | private CrmReceivableItemMapper receivableItemMapper; |
| | | |
| | | @Resource |
| | | private ErpSaleOrderApi saleOrderApi; |
| | | @Resource |
| | | private MesWmProductSalesApi productSalesApi; |
| | | |
| | | @Resource |
| | | private CrmNoRedisDAO noRedisDAO; |
| | |
| | | CrmReceivableDO receivable = BeanUtils.toBean(createReqVO, CrmReceivableDO.class) |
| | | .setNo(no).setAuditStatus(CrmAuditStatusEnum.PROCESS.getStatus()); |
| | | receivableMapper.insert(receivable); |
| | | // 2.2 |
| | | // 2.2 ä¿åæ ¸éæç»ï¼æªä¼ æ¶æå
³èå¼ç¥¨èªå¨çæä¸æ¡ï¼ |
| | | syncReceivableItems(receivable, createReqVO.getItems()); |
| | | |
| | | // 3. åå»ºæ°æ®æé |
| | | permissionService.createPermission(new CrmPermissionCreateReqBO().setBizType(CrmBizTypeEnum.CRM_RECEIVABLE.getType()) |
| | |
| | | LogRecordContext.putVariable("receivable", receivable); |
| | | LogRecordContext.putVariable("period", getReceivablePeriod(receivable.getPlanId())); |
| | | return receivable.getId(); |
| | | } |
| | | |
| | | /** |
| | | * ä¿åæ ¸éæç» |
| | | * |
| | | * ä¼ null æ¶ï¼è¥å
³èå¼ç¥¨ï¼èªå¨çæä¸æ¡ãå¼ç¥¨ãæ ¸éæç»ï¼å¦åä¸çæã |
| | | */ |
| | | private void syncReceivableItems(CrmReceivableDO receivable, |
| | | List<CrmReceivableSaveReqVO.ReceivableItem> items) { |
| | | if (items == null) { |
| | | if (receivable.getInvoiceId() == null) { |
| | | return; |
| | | } |
| | | CrmReceivableSaveReqVO.ReceivableItem autoItem = new CrmReceivableSaveReqVO.ReceivableItem(); |
| | | autoItem.setBizType(CrmReceivableBizTypeEnum.SALE_INVOICE.getType()); |
| | | autoItem.setBizId(receivable.getInvoiceId()); |
| | | autoItem.setReceiptPrice(receivable.getPrice()); |
| | | items = List.of(autoItem); |
| | | } |
| | | // 1. æ ¡éªå¹¶è§£ææ¯è¡å
³èåæ® |
| | | List<ResolvedReceivableItem> resolvedItems = new ArrayList<>(items.size()); |
| | | BigDecimal itemPriceSum = BigDecimal.ZERO; |
| | | for (int i = 0; i < items.size(); i++) { |
| | | CrmReceivableSaveReqVO.ReceivableItem item = items.get(i); |
| | | int row = i + 1; |
| | | CrmReceivableBizTypeEnum bizType = item == null ? null |
| | | : CrmReceivableBizTypeEnum.valueOf(item.getBizType()); |
| | | if (bizType == null) { |
| | | throw exception(RECEIVABLE_ITEM_BIZ_TYPE_INVALID, row, |
| | | item == null ? "æªå¡«å" : item.getBizType()); |
| | | } |
| | | if (item.getReceiptPrice() == null || item.getReceiptPrice().compareTo(BigDecimal.ZERO) <= 0) { |
| | | throw exception(RECEIVABLE_ITEM_PRICE_INVALID, row, bizType.getName(), |
| | | item.getBizId(), item.getReceiptPrice() == null ? "æªå¡«å" |
| | | : item.getReceiptPrice().stripTrailingZeros().toPlainString()); |
| | | } |
| | | ResolvedReceivableItem resolved = resolveReceivableItem(row, bizType, item.getBizId()); |
| | | // 1.1 å·²æ ¸ééé¢ï¼ä¸å«æ¬å款åï¼é¿å
ç¼è¾æ¶æèªå·±ç®è¿å»ï¼ |
| | | BigDecimal receiptedPrice = receivableItemMapper.selectListByBiz(bizType.getType(), item.getBizId()).stream() |
| | | .filter(old -> ObjectUtil.notEqual(old.getReceivableId(), receivable.getId())) |
| | | .map(old -> old.getReceiptPrice() == null ? BigDecimal.ZERO : old.getReceiptPrice()) |
| | | .reduce(BigDecimal.ZERO, BigDecimal::add); |
| | | BigDecimal remainPrice = resolved.totalPrice.subtract(receiptedPrice); |
| | | if (item.getReceiptPrice().compareTo(remainPrice) > 0) { |
| | | throw exception(RECEIVABLE_ITEM_PRICE_EXCEEDS, row, bizType.getName(), resolved.bizNo, |
| | | item.getReceiptPrice().stripTrailingZeros().toPlainString(), |
| | | remainPrice.stripTrailingZeros().toPlainString(), |
| | | resolved.totalPrice.stripTrailingZeros().toPlainString(), |
| | | receiptedPrice.stripTrailingZeros().toPlainString()); |
| | | } |
| | | resolved.receiptedPrice = receiptedPrice; |
| | | resolved.receiptPrice = item.getReceiptPrice(); |
| | | resolved.remark = item.getRemark(); |
| | | resolvedItems.add(resolved); |
| | | itemPriceSum = itemPriceSum.add(item.getReceiptPrice()); |
| | | } |
| | | // 2. æç»å计å¿
é¡»çäºå款éé¢ |
| | | if (itemPriceSum.compareTo(receivable.getPrice()) != 0) { |
| | | throw exception(RECEIVABLE_ITEM_SUM_MISMATCH, |
| | | itemPriceSum.stripTrailingZeros().toPlainString(), |
| | | receivable.getPrice().stripTrailingZeros().toPlainString()); |
| | | } |
| | | // 3. é建æç» |
| | | receivableItemMapper.deleteByReceivableId(receivable.getId()); |
| | | for (ResolvedReceivableItem resolved : resolvedItems) { |
| | | receivableItemMapper.insert(CrmReceivableItemDO.builder() |
| | | .receivableId(receivable.getId()).bizType(resolved.bizType.getType()) |
| | | .bizId(resolved.bizId).bizNo(resolved.bizNo).totalPrice(resolved.totalPrice) |
| | | .receiptedPrice(resolved.receiptedPrice).receiptPrice(resolved.receiptPrice) |
| | | .remark(resolved.remark).build()); |
| | | } |
| | | } |
| | | |
| | | private ResolvedReceivableItem resolveReceivableItem(int row, CrmReceivableBizTypeEnum bizType, Long bizId) { |
| | | ResolvedReceivableItem resolved = new ResolvedReceivableItem(); |
| | | resolved.bizType = bizType; |
| | | resolved.bizId = bizId; |
| | | switch (bizType) { |
| | | case SALE_ORDER -> { |
| | | ErpSaleOrderRespDTO saleOrder = bizId == null ? null : saleOrderApi.getSaleOrder(bizId).getCheckedData(); |
| | | if (saleOrder == null) { |
| | | throw exception(RECEIVABLE_ITEM_BIZ_NOT_EXISTS, row, bizType.getName(), bizId); |
| | | } |
| | | resolved.bizNo = saleOrder.getNo(); |
| | | resolved.totalPrice = saleOrder.getTotalPrice() == null ? BigDecimal.ZERO : saleOrder.getTotalPrice(); |
| | | } |
| | | case SALE_OUT -> { |
| | | MesWmProductSalesRespDTO saleOut = bizId == null ? null : productSalesApi.getProductSales(bizId); |
| | | if (saleOut == null) { |
| | | throw exception(RECEIVABLE_ITEM_BIZ_NOT_EXISTS, row, bizType.getName(), bizId); |
| | | } |
| | | resolved.bizNo = saleOut.getCode(); |
| | | resolved.totalPrice = saleOut.getTotalPrice() == null ? BigDecimal.ZERO : saleOut.getTotalPrice(); |
| | | } |
| | | case SALE_INVOICE -> { |
| | | CrmInvoiceDO invoice = bizId == null ? null : invoiceService.getInvoice(bizId); |
| | | if (invoice == null) { |
| | | throw exception(RECEIVABLE_ITEM_BIZ_NOT_EXISTS, row, bizType.getName(), bizId); |
| | | } |
| | | resolved.bizNo = invoice.getNo(); |
| | | resolved.totalPrice = invoice.getPrice() == null ? BigDecimal.ZERO : invoice.getPrice(); |
| | | } |
| | | default -> throw exception(RECEIVABLE_ITEM_BIZ_TYPE_INVALID, row, bizType.getType()); |
| | | } |
| | | return resolved; |
| | | } |
| | | |
| | | private static class ResolvedReceivableItem { |
| | | private CrmReceivableBizTypeEnum bizType; |
| | | private Long bizId; |
| | | private String bizNo; |
| | | private BigDecimal totalPrice; |
| | | private BigDecimal receiptedPrice; |
| | | private BigDecimal receiptPrice; |
| | | private String remark; |
| | | } |
| | | |
| | | private void validateReceivablePriceExceedsLimit(CrmReceivableSaveReqVO reqVO) { |
| | |
| | | // 2. æ´æ°å款 |
| | | CrmReceivableDO updateObj = BeanUtils.toBean(updateReqVO, CrmReceivableDO.class); |
| | | receivableMapper.updateById(updateObj); |
| | | // 2.1 æ´æ°æ ¸éæç»ï¼ä¼ äº items 以 items 为åï¼æªä¼ ä¸å
³èå¼ç¥¨æ¶æå¼ç¥¨é建ï¼å¦åä¿æä¸å |
| | | if (updateReqVO.getItems() != null |
| | | || (updateReqVO.getInvoiceId() != null && ObjectUtil.notEqual(updateReqVO.getInvoiceId(), oldReceivable.getInvoiceId()))) { |
| | | syncReceivableItems(updateObj, updateReqVO.getItems()); |
| | | } |
| | | |
| | | // 3. è®°å½æä½æ¥å¿ä¸ä¸æ |
| | | updateReqVO.setOwnerUserId(oldReceivable.getOwnerUserId()); // é¿å
æä½æ¥å¿åºç°âå é¤è´è´£äººâçæ
åµ |
| | |
| | | if (updateCount == 0) { |
| | | throw exception(approve ? RECEIVABLE_APPROVE_FAIL : RECEIVABLE_PROCESS_FAIL); |
| | | } |
| | | |
| | | // 3. 忬¾è®¡åååå®é
忬¾éé¢ä¸ç¶æ |
| | | if (receivable.getPlanId() != null) { |
| | | if (approve) { |
| | | receivablePlanService.updateReceivablePlanReceipted(receivable.getPlanId(), |
| | | receivable.getPrice(), receivable.getReturnTime()); |
| | | } else { |
| | | receivablePlanService.resetReceivablePlanReceipted(receivable.getPlanId()); |
| | | } |
| | | } |
| | | } |
| | | |
| | | @Override |
| | |
| | | |
| | | // 2.1 å é¤å款 |
| | | receivableMapper.deleteById(id); |
| | | // 2.2 å 餿°æ®æé |
| | | // 2.2 å 餿 ¸éæç» |
| | | receivableItemMapper.deleteByReceivableId(id); |
| | | // 2.3 å 餿°æ®æé |
| | | permissionService.deletePermission(CrmBizTypeEnum.CRM_RECEIVABLE.getType(), id); |
| | | |
| | | // 3. è®°å½æä½æ¥å¿ä¸ä¸æ |
| | |
| | | } |
| | | |
| | | @Override |
| | | public List<CrmReceivableItemDO> getReceivableItemList(Long receivableId) { |
| | | return receivableItemMapper.selectListByReceivableId(receivableId); |
| | | } |
| | | |
| | | @Override |
| | | public List<CrmReceivableItemDO> getReceivableItemListByCustomerId(Long customerId) { |
| | | List<CrmReceivableDO> receivables = receivableMapper.selectListByCustomerId(customerId); |
| | | if (CollUtil.isEmpty(receivables)) { |
| | | return ListUtil.empty(); |
| | | } |
| | | return receivableItemMapper.selectListByReceivableIds( |
| | | receivables.stream().map(CrmReceivableDO::getId).toList()); |
| | | } |
| | | |
| | | @Override |
| | | @CrmPermission(bizType = CrmBizTypeEnum.CRM_CUSTOMER, bizId = "#pageReqVO.customerId", level = CrmPermissionLevelEnum.READ) |
| | | public PageResult<CrmReceivableDO> getReceivablePageByCustomerId(CrmReceivablePageReqVO pageReqVO) { |
| | | return receivableMapper.selectPageByCustomerId(pageReqVO); |
| | |
| | | import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; |
| | | import cn.iocoder.yudao.module.crm.enums.common.CrmSceneTypeEnum; |
| | | import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum; |
| | | import cn.iocoder.yudao.module.hrm.api.handover.HrmUserHandoverApi; |
| | | import cn.iocoder.yudao.module.system.api.user.AdminUserApi; |
| | | import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; |
| | | import cn.iocoder.yudao.module.system.enums.permission.RoleCodeEnum; |
| | | import com.baomidou.mybatisplus.core.toolkit.support.SFunction; |
| | | import com.github.yulichang.autoconfigure.MybatisPlusJoinProperties; |
| | | import com.github.yulichang.wrapper.MPJLambdaWrapper; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | |
| | | import java.util.HashSet; |
| | | import java.util.LinkedHashSet; |
| | | import java.util.List; |
| | | import java.util.Set; |
| | | |
| | | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; |
| | | import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; |
| | |
| | | * |
| | | * @author HUIHUI |
| | | */ |
| | | @Slf4j |
| | | public class CrmPermissionUtils { |
| | | |
| | | /** è¶
级管ç忥çå®¢æ·æ¶ä¸åå
¬æµ·å¯è§åº¦å¼å
³å½±åã */ |
| | |
| | | } |
| | | |
| | | /** |
| | | * è·å¾"æè´è´£çæ°æ®"对åºçç¨æ·ç¼å·éåï¼æ¬äºº + 已尿°æ®äº¤æ¥ç»æç离èç¨æ· |
| | | * |
| | | * 离è交æ¥å®æåï¼äº¤æ¥äººéè¦è½çå°ç¦»è人åä¸çæ°æ®ï¼å æ¤è¿ééè¿ HrmUserHandoverApi æ©å±ã |
| | | * |
| | | * @param userId å½åç¨æ·ç¼å· |
| | | * @return ç¨æ·ç¼å·éåï¼è³å°å
嫿¬äºº |
| | | */ |
| | | public static Set<Long> getOwnerUserIds(Long userId) { |
| | | Set<Long> ownerUserIds = new LinkedHashSet<>(); |
| | | if (userId == null) { |
| | | return ownerUserIds; |
| | | } |
| | | ownerUserIds.add(userId); |
| | | try { |
| | | HrmUserHandoverApi handoverApi = SpringUtil.getBean(HrmUserHandoverApi.class); |
| | | Set<Long> handoverUserIds = handoverApi.expandUserIds(new HashSet<>(ownerUserIds)); |
| | | if (CollUtil.isNotEmpty(handoverUserIds)) { |
| | | ownerUserIds.addAll(handoverUserIds); |
| | | } |
| | | } catch (Exception ex) { |
| | | // HRM æ¨¡åæªé¨ç½²æ¶é级为åªçæ¬äººæ°æ®ï¼ä¸å½±å CRM æ£å¸¸ä½¿ç¨ |
| | | log.warn("[getOwnerUserIds][æ©å±äº¤æ¥ç¨æ·å¤±è´¥ï¼userIds({}) ä»
ææ¬äººæ°æ®æ¥è¯¢]", userId, ex); |
| | | } |
| | | return ownerUserIds; |
| | | } |
| | | |
| | | /** |
| | | * 追å "æè´è´£çæ°æ®"çè¿æ»¤æ¡ä»¶ï¼æ¯æç¦»è交æ¥åçæ°æ®å¯è§æ§æ©å± |
| | | */ |
| | | private static <T extends MPJLambdaWrapper<?>> void appendOwnerUserCondition(T query, String ownerUserIdField, Long userId) { |
| | | Set<Long> ownerUserIds = getOwnerUserIds(userId); |
| | | if (ownerUserIds.size() <= 1) { |
| | | query.eq(ownerUserIdField, userId); |
| | | } else { |
| | | query.in(ownerUserIdField, ownerUserIds); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * æé CRM æ°æ®ç±»åæ°æ®ãåé¡µãæ¥è¯¢æ¡ä»¶ |
| | | * |
| | | * @param query è¿è¡¨æ¥è¯¢å¯¹è±¡ |
| | |
| | | Long userId, Integer sceneType) { |
| | | MybatisPlusJoinProperties mybatisPlusJoinProperties = SpringUtil.getBean(MybatisPlusJoinProperties.class); |
| | | final String ownerUserIdField = mybatisPlusJoinProperties.getTableAlias() + ".owner_user_id"; |
| | | // åºæ¯ä¸ï¼æè´è´£çæ°æ® |
| | | // åºæ¯ä¸ï¼æè´è´£çæ°æ®ï¼å«ç¦»è交æ¥ç»æçæ°æ®ï¼ |
| | | if (CrmSceneTypeEnum.isOwner(sceneType)) { |
| | | query.eq(ownerUserIdField, userId); |
| | | appendOwnerUserCondition(query, ownerUserIdField, userId); |
| | | } |
| | | // åºæ¯äºï¼æåä¸çæ°æ®ï¼ææè¯»æåæéï¼å¹¶ä¸ä¸æ¯è´è´£äººï¼ |
| | | if (CrmSceneTypeEnum.isInvolved(sceneType)) { |
| | |
| | | if (isCrmAdmin() || hasCustomerViewAllPermission()) { |
| | | return; // è·³è¿è¿æ»¤ï¼æ¥çå
¨é¨ |
| | | } |
| | | // æ æéåé级为"æè´è´£ç" |
| | | query.eq(ownerUserIdField, userId); |
| | | // æ æéåé级为"æè´è´£ç"ï¼å«ç¦»è交æ¥ç»æçæ°æ®ï¼ |
| | | appendOwnerUserCondition(query, ownerUserIdField, userId); |
| | | } |
| | | } |
| | | |
| | |
| | | CommonResult<ErpSaleOrderRespDTO> getSaleOrderByContractId(Long contractId); |
| | | |
| | | /** |
| | | * æ ¹æ®å®¢æ·ç¼å·è·åéå®è®¢åå表 |
| | | * |
| | | * @param customerId 客æ·ç¼å· |
| | | * @return éå®è®¢åå表 |
| | | */ |
| | | CommonResult<List<ErpSaleOrderRespDTO>> getSaleOrderListByCustomerId(Long customerId); |
| | | |
| | | /** |
| | | * è·åå
¨é¨éå®è®¢åå表ï¼è´¢å¡å¯¹è´¦ãæ¥è¡¨ä½¿ç¨ï¼ |
| | | * |
| | | * @return éå®è®¢åå表 |
| | | */ |
| | | CommonResult<List<ErpSaleOrderRespDTO>> getSaleOrderList(); |
| | | |
| | | /** |
| | | * è·åéå®è®¢åæç»å表 |
| | | * |
| | | * @param orderId 订åç¼å· |
| | |
| | | } |
| | | |
| | | @Override |
| | | public CommonResult<List<ErpSaleOrderRespDTO>> getSaleOrderListByCustomerId(Long customerId) { |
| | | if (customerId == null) { |
| | | return success(Collections.emptyList()); |
| | | } |
| | | List<ErpSaleOrderDO> orders = saleOrderMapper.selectList(ErpSaleOrderDO::getCustomerId, customerId); |
| | | return success(BeanUtils.toBean(orders, ErpSaleOrderRespDTO.class)); |
| | | } |
| | | |
| | | @Override |
| | | public CommonResult<List<ErpSaleOrderRespDTO>> getSaleOrderList() { |
| | | return success(BeanUtils.toBean(saleOrderMapper.selectList(), ErpSaleOrderRespDTO.class)); |
| | | } |
| | | |
| | | @Override |
| | | public CommonResult<List<ErpSaleOrderItemRespDTO>> getSaleOrderItemList(Long orderId) { |
| | | if (orderId == null) { |
| | | return success(Collections.emptyList()); |
| | |
| | | import cn.iocoder.yudao.framework.common.util.number.NumberUtils; |
| | | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| | | import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; |
| | | import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.invoice.ErpPurchaseInvoiceItemReceiptRespVO; |
| | | import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.invoice.ErpPurchaseInvoicePageReqVO; |
| | | import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.invoice.ErpPurchaseInvoiceRespVO; |
| | | import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.invoice.ErpPurchaseInvoiceSaveReqVO; |
| | |
| | | }); |
| | | } |
| | | |
| | | @GetMapping("/item-receipt-list") |
| | | @Operation(summary = "è·å¾æ¥ç¥¨å¯éå
¥åºåå表", description = "æéè´è®¢åè¿æ»¤ MES å
¥åºåï¼ä»
è¿åæªåæ¶çå
¥åºåï¼å¹¶å¸¦åºå¯æ¥ç¥¨éé¢") |
| | | @Parameter(name = "purchaseOrderId", description = "éè´è®¢åç¼å·", required = true) |
| | | @Parameter(name = "id", description = "æ¥ç¥¨ç¼å·ï¼ç¼è¾æ¶ä¼ å
¥ï¼ç¨äºæé¤èªèº«å·²å ç¨éé¢ï¼") |
| | | public CommonResult<List<ErpPurchaseInvoiceItemReceiptRespVO>> getItemReceiptList( |
| | | @RequestParam("purchaseOrderId") Long purchaseOrderId, |
| | | @RequestParam(value = "id", required = false) Long id) { |
| | | return success(invoiceService.getItemReceiptListForInvoice(purchaseOrderId, id)); |
| | | } |
| | | |
| | | @GetMapping("/simple-list") |
| | | @Operation(summary = "è·å¾æ¥ç¥¨ç²¾ç®å表", description = "åªå
å«å·²ä¸ä¼ å票éä»¶çæ¥ç¥¨ï¼ä¸»è¦ç¨äºä»æ¬¾å建æ¶éæ©å
³èæ¥ç¥¨") |
| | | @Parameter(name = "supplierId", description = "ä¾åºåç¼å·", required = true) |
| | |
| | | convertSet(purchaseRequestItemList, ErpPurchaseRequestItemDO::getProductId)); |
| | | Map<Long, MdmUnitMeasureRespDTO> unitMeasureMap = mdmUnitMeasureApi.getUnitMeasureMap( |
| | | convertSet(purchaseRequestItemList, ErpPurchaseRequestItemDO::getProductUnitId)); |
| | | return success(BeanUtils.toBean(purchaseRequest, ErpPurchaseRequestRespVO.class, purchaseRequestVO -> |
| | | purchaseRequestVO.setItems(BeanUtils.toBean(purchaseRequestItemList, ErpPurchaseRequestRespVO.Item.class, item -> { |
| | | MapUtils.findAndThen(itemMap, item.getProductId(), mdmItem -> item.setProductName(mdmItem.getName()) |
| | | .setProductBarCode(mdmItem.getBarCode())); |
| | | MapUtils.findAndThen(unitMeasureMap, item.getProductUnitId(), unit -> |
| | | item.setProductUnitName(unit.getName())); |
| | | })).setAttachmentList(storageAttachmentApi.listAttachments("erp_purchase_request", id)))); |
| | | // ä¾åºå / ç³è¯·äºº / ç³è¯·é¨é¨åç§°ï¼å®¡æ¹è¯¦æ
é¡µç´æ¥å±ç¤ºè¯¥æ¥å£çæ°æ®ï¼ç¼ºå¤±ä¼æ¾ç¤ºä¸ºâ-â |
| | | List<ErpPurchaseRequestDO> singleList = java.util.Collections.singletonList(purchaseRequest); |
| | | Map<Long, SrmSupplierRespDTO> supplierMap = srmSupplierApi.getSupplierList( |
| | | convertSet(singleList, ErpPurchaseRequestDO::getSupplierId)).getCheckedData().stream() |
| | | .collect(java.util.stream.Collectors.toMap(SrmSupplierRespDTO::getId, v -> v, (a, b) -> a)); |
| | | Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap( |
| | | convertSet(singleList, ErpPurchaseRequestDO::getRequestUserId)); |
| | | Map<Long, DeptRespDTO> deptMap = deptApi.getDeptMap( |
| | | convertSet(singleList, ErpPurchaseRequestDO::getRequestDeptId)); |
| | | return success(BeanUtils.toBean(purchaseRequest, ErpPurchaseRequestRespVO.class, purchaseRequestVO -> { |
| | | purchaseRequestVO.setItems(BeanUtils.toBean(purchaseRequestItemList, ErpPurchaseRequestRespVO.Item.class, item -> { |
| | | MapUtils.findAndThen(itemMap, item.getProductId(), mdmItem -> item.setProductName(mdmItem.getName()) |
| | | .setProductBarCode(mdmItem.getBarCode())); |
| | | MapUtils.findAndThen(unitMeasureMap, item.getProductUnitId(), unit -> |
| | | item.setProductUnitName(unit.getName())); |
| | | })).setAttachmentList(storageAttachmentApi.listAttachments("erp_purchase_request", id)); |
| | | MapUtils.findAndThen(supplierMap, purchaseRequestVO.getSupplierId(), |
| | | supplier -> purchaseRequestVO.setSupplierName(supplier.getName())); |
| | | MapUtils.findAndThen(userMap, purchaseRequestVO.getRequestUserId(), |
| | | user -> purchaseRequestVO.setRequestUserName(user.getNickname())); |
| | | MapUtils.findAndThen(deptMap, purchaseRequestVO.getRequestDeptId(), |
| | | dept -> purchaseRequestVO.setRequestDeptName(dept.getName())); |
| | | })); |
| | | } |
| | | |
| | | @GetMapping("/page") |
| | |
| | | @Operation(summary = "çæéè´è®¢å") |
| | | @PreAuthorize("@ss.hasPermission('erp:purchase-request:generate-order')") |
| | | public CommonResult<Long> generatePurchaseOrder(@RequestParam("id") Long id, |
| | | @RequestParam("supplierId") Long supplierId) { |
| | | @RequestParam(value = "supplierId", required = false) Long supplierId) { |
| | | return success(purchaseRequestService.generatePurchaseOrder(id, supplierId)); |
| | | } |
| | | |
| | |
| | | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| | | import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.statement.ErpSupplierStatementReqVO; |
| | | import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.statement.ErpSupplierStatementRespVO; |
| | | import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.statement.ErpSupplierStatementSummaryReqVO; |
| | | import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.statement.ErpSupplierStatementSummaryRespVO; |
| | | import cn.iocoder.yudao.module.erp.service.purchase.ErpSupplierStatementService; |
| | | import io.swagger.v3.oas.annotations.Operation; |
| | | import io.swagger.v3.oas.annotations.tags.Tag; |
| | |
| | | import org.springframework.web.bind.annotation.GetMapping; |
| | | import org.springframework.web.bind.annotation.RequestMapping; |
| | | import org.springframework.web.bind.annotation.RestController; |
| | | |
| | | import java.util.List; |
| | | |
| | | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; |
| | | |
| | |
| | | return success(supplierStatementService.getSupplierStatement(reqVO)); |
| | | } |
| | | |
| | | @GetMapping("/summary-list") |
| | | @Operation(summary = "è·ååä¾åºå徿¥æ±æ»å表ï¼å·¦ä¾§ä¾åºåæ»è§ï¼") |
| | | @PreAuthorize("@ss.hasPermission('erp:supplier-statement:query')") |
| | | public CommonResult<List<ErpSupplierStatementSummaryRespVO>> getSupplierSummaryList( |
| | | @Valid ErpSupplierStatementSummaryReqVO reqVO) { |
| | | return success(supplierStatementService.getSupplierSummaryList(reqVO)); |
| | | } |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.invoice; |
| | | |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | import lombok.experimental.Accessors; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.time.LocalDateTime; |
| | | |
| | | @Schema(description = "管çåå° - æ¥ç¥¨å¯éå
¥åºå Response VO") |
| | | @Data |
| | | @Accessors(chain = true) |
| | | public class ErpPurchaseInvoiceItemReceiptRespVO { |
| | | |
| | | @Schema(description = "å
¥åºåç¼å·", example = "1024") |
| | | private Long id; |
| | | |
| | | @Schema(description = "å
¥åºåå·", example = "IR202611050001") |
| | | private String code; |
| | | |
| | | @Schema(description = "å
¥åºååç§°") |
| | | private String name; |
| | | |
| | | @Schema(description = "å
¥åºæ¥æ") |
| | | private LocalDateTime receiptDate; |
| | | |
| | | @Schema(description = "å
¥åºåç¶æ", example = "4") |
| | | private Integer status; |
| | | |
| | | @Schema(description = "å
¥åºéé¢", example = "1000.00") |
| | | private BigDecimal totalPrice; |
| | | |
| | | @Schema(description = "å·²æ¥ç¥¨éé¢", example = "200.00") |
| | | private BigDecimal invoicedPrice; |
| | | |
| | | @Schema(description = "坿¥ç¥¨éé¢", example = "800.00") |
| | | private BigDecimal remainInvoicePrice; |
| | | |
| | | } |
| | |
| | | @Schema(description = "éè´è®¢åä¿¡æ¯") |
| | | private ErpPurchaseOrderRespVO order; |
| | | |
| | | @Schema(description = "å
³èå
¥åºåç¼å·") |
| | | private Long itemReceiptId; |
| | | |
| | | @Schema(description = "å
³èå
¥åºåå·") |
| | | @ExcelProperty("å
¥åºåå·") |
| | | private String itemReceiptCode; |
| | | |
| | | @Schema(description = "å票å·ç ", example = "02564178") |
| | | @ExcelProperty("å票å·ç ") |
| | | private String invoiceNo; |
| | |
| | | @NotNull(message = "éè´è®¢åç¼å·ä¸è½ä¸ºç©º") |
| | | private Long purchaseOrderId; |
| | | |
| | | @Schema(description = "å
³èå
¥åºå") |
| | | @Schema(description = "å
³èå°è´§éç¥å") |
| | | private Long arrivalNoticeId; |
| | | |
| | | @Schema(description = "å
³èå
¥åºåç¼å·") |
| | | private Long itemReceiptId; |
| | | |
| | | @Schema(description = "å票å·ç ", example = "02564178") |
| | | private String invoiceNo; |
| | | |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.statement; |
| | | |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | import org.springframework.format.annotation.DateTimeFormat; |
| | | |
| | | import java.time.LocalDateTime; |
| | | |
| | | import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; |
| | | |
| | | @Schema(description = "管çåå° - ä¾åºå徿¥æ±æ»å表æ¥è¯¢ Request VO") |
| | | @Data |
| | | public class ErpSupplierStatementSummaryReqVO { |
| | | |
| | | @Schema(description = "å¼å§æ¶é´") |
| | | @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) |
| | | private LocalDateTime beginTime; |
| | | |
| | | @Schema(description = "ç»ææ¶é´") |
| | | @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) |
| | | private LocalDateTime endTime; |
| | | |
| | | @Schema(description = "æ¯å¦å
嫿ªå®¡æ ¸éè´è®¢å") |
| | | private Boolean includeUnapprovedOrder; |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.statement; |
| | | |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | |
| | | import java.math.BigDecimal; |
| | | |
| | | @Schema(description = "管çåå° - ä¾åºå徿¥æ±æ»ï¼å·¦ä¾§æ»è§è¡ï¼ Response VO") |
| | | @Data |
| | | public class ErpSupplierStatementSummaryRespVO { |
| | | |
| | | @Schema(description = "ä¾åºåç¼å·") |
| | | private Long supplierId; |
| | | |
| | | @Schema(description = "ä¾åºåç¼ç ") |
| | | private String supplierCode; |
| | | |
| | | @Schema(description = "ä¾åºååç§°") |
| | | private String supplierName; |
| | | |
| | | @Schema(description = "éè´è®¢åæ°é") |
| | | private Integer orderCount; |
| | | |
| | | @Schema(description = "æ¥ç¥¨æ°é") |
| | | private Integer invoiceCount; |
| | | |
| | | @Schema(description = "仿¬¾åæ°é") |
| | | private Integer paymentCount; |
| | | |
| | | @Schema(description = "累计éè´é¢") |
| | | private BigDecimal totalPurchaseAmount; |
| | | |
| | | @Schema(description = "累计å¼ç¥¨é¢") |
| | | private BigDecimal totalInvoiceAmount; |
| | | |
| | | @Schema(description = "ç´¯è®¡ä»æ¬¾é¢") |
| | | private BigDecimal totalPaymentAmount; |
| | | |
| | | @Schema(description = "æªä»ä½é¢ï¼å¼ç¥¨ - 仿¬¾ï¼") |
| | | private BigDecimal unpaidAmount; |
| | | |
| | | } |
| | |
| | | */ |
| | | private Long purchaseOrderId; |
| | | |
| | | /** å
³èå
¥åºå */ |
| | | /** å
³èå°è´§éç¥å */ |
| | | private Long arrivalNoticeId; |
| | | /** |
| | | * å
³èå
¥åºåç¼å· |
| | | * |
| | | * å
³è MES éè´å
¥åºå mes_wm_item_receipt |
| | | */ |
| | | private Long itemReceiptId; |
| | | /** |
| | | * å
³èå
¥åºåå·ï¼å¿«ç
§ï¼åè¡¨ç´æ¥å±ç¤ºï¼ |
| | | */ |
| | | private String itemReceiptCode; |
| | | /** |
| | | * å票å·ç |
| | | */ |
| | | private String invoiceNo; |
| | |
| | | .orderByAsc(ErpFinancePaymentDO::getId)); |
| | | } |
| | | |
| | | /** |
| | | * æä»æ¬¾æ¶é´èå´æ¥è¯¢å
¨é¨ä¾åºåç仿¬¾åï¼ä¾åºå徿¥æ±æ»ï¼ |
| | | */ |
| | | default List<ErpFinancePaymentDO> selectListByPaymentTimeBetween(LocalDateTime beginTime, |
| | | LocalDateTime endTime, |
| | | Collection<Integer> statuses) { |
| | | return selectList(new LambdaQueryWrapperX<ErpFinancePaymentDO>() |
| | | .geIfPresent(ErpFinancePaymentDO::getPaymentTime, beginTime) |
| | | .leIfPresent(ErpFinancePaymentDO::getPaymentTime, endTime) |
| | | .inIfPresent(ErpFinancePaymentDO::getStatus, statuses)); |
| | | } |
| | | |
| | | } |
| | |
| | | .in(ErpPurchaseInvoiceDO::getPurchaseOrderId, orderIds)); |
| | | } |
| | | |
| | | default List<ErpPurchaseInvoiceDO> selectListByItemReceiptId(Long itemReceiptId) { |
| | | return selectList(new LambdaQueryWrapperX<ErpPurchaseInvoiceDO>() |
| | | .eq(ErpPurchaseInvoiceDO::getItemReceiptId, itemReceiptId)); |
| | | } |
| | | |
| | | /** |
| | | * æä¾åºåä¸å¼ç¥¨æ¶é´èå´æ¥è¯¢æ¥ç¥¨ï¼ä¾åºå徿¥ï¼ |
| | | */ |
| | |
| | | .orderByAsc(ErpPurchaseInvoiceDO::getId)); |
| | | } |
| | | |
| | | /** |
| | | * æå¼ç¥¨æ¶é´èå´æ¥è¯¢å
¨é¨ä¾åºåçæ¥ç¥¨ï¼ä¾åºå徿¥æ±æ»ï¼ |
| | | */ |
| | | default List<ErpPurchaseInvoiceDO> selectListByInvoiceTimeBetween(LocalDateTime beginTime, |
| | | LocalDateTime endTime) { |
| | | return selectList(new LambdaQueryWrapperX<ErpPurchaseInvoiceDO>() |
| | | .geIfPresent(ErpPurchaseInvoiceDO::getInvoiceTime, beginTime) |
| | | .leIfPresent(ErpPurchaseInvoiceDO::getInvoiceTime, endTime)); |
| | | } |
| | | |
| | | } |
| | |
| | | .orderByAsc(ErpPurchaseOrderDO::getId)); |
| | | } |
| | | |
| | | /** |
| | | * æä¸åæ¶é´èå´æ¥è¯¢å
¨é¨ä¾åºåçéè´è®¢åï¼ä¾åºå徿¥æ±æ»ï¼ |
| | | */ |
| | | default List<ErpPurchaseOrderDO> selectListByOrderTimeBetween(LocalDateTime beginTime, |
| | | LocalDateTime endTime, |
| | | Collection<Integer> statuses) { |
| | | return selectList(new LambdaQueryWrapperX<ErpPurchaseOrderDO>() |
| | | .geIfPresent(ErpPurchaseOrderDO::getOrderTime, beginTime) |
| | | .leIfPresent(ErpPurchaseOrderDO::getOrderTime, endTime) |
| | | .inIfPresent(ErpPurchaseOrderDO::getStatus, statuses)); |
| | | } |
| | | |
| | | } |
| | |
| | | ErrorCode PURCHASE_ORDER_BPM_PROCESS_DEFINITION_NOT_EXISTS = new ErrorCode(1_030_101_012, "éè´å®¡æ ¸åç±»ä¸æ²¡æå¯ç¨çæµç¨æ¨¡åï¼è¯·å
å建并å叿µç¨"); |
| | | ErrorCode PURCHASE_ORDER_SUBMIT_FAIL_STATUS = new ErrorCode(1_030_101_013, "æäº¤å®¡æ¹å¤±è´¥ï¼åªææªå®¡æ ¸ç¶æçéè´è®¢åæè½æäº¤"); |
| | | ErrorCode PURCHASE_ORDER_ALL_IN = new ErrorCode(1_030_101_014, "éè´è®¢åå·²å
¨é¨å
¥åºï¼æ é确认æ¶è´§"); |
| | | ErrorCode PURCHASE_ORDER_PAYMENT_DATE_REQUIRED = new ErrorCode(1_030_101_015, "仿¬¾æ¥æä¸è½ä¸ºç©ºï¼è¯·éæ©ä»æ¬¾æ¥æååä¿å"); |
| | | ErrorCode PURCHASE_ORDER_PAYMENT_DATE_REQUIRED = new ErrorCode(1_030_101_015, "仿¬¾æ¥æä¸è½ä¸ºç©ºï¼è¯·å
ç¼è¾éè´å°è´¦éæ©ä»æ¬¾æ¥æï¼åæäº¤"); |
| | | ErrorCode PURCHASE_ORDER_PURCHASE_TYPE_INVALID = new ErrorCode(1_030_101_016, "éè´ç±»å({})ä¸åæ³ï¼åªè½éæ©ï¼1ç产ã2åå
¬ç¨åã3å
¶ä»"); |
| | | ErrorCode PURCHASE_ORDER_PAYMENT_METHOD_INVALID = new ErrorCode(1_030_101_017, "仿¬¾æ¹å¼({})ä¸åæ³ï¼åªè½éæ©ï¼1çµæ±ã2æ±ç¥¨ã3ç°éã4ææºæ¯ä»"); |
| | | ErrorCode PURCHASE_ORDER_ITEM_PRODUCT_CODE_MISSING = new ErrorCode(1_030_101_018, "ç©æ[{}]æªç»´æ¤ MDM ç©æç¼ç ï¼è¯·å
å¨ MDM ç©ææ¡£æ¡è¡¥å
ç¼ç ååä¿å"); |
| | |
| | | ErrorCode PURCHASE_REQUEST_BPM_CATEGORY_NOT_EXISTS = new ErrorCode(1_030_104_008, "éè´ç³è¯·å®¡æ¹åç±»ä¸åå¨ï¼è¯·å
å¨BPM模åå建éè´ç³è¯·å®¡æ¹æµç¨åç±»"); |
| | | ErrorCode PURCHASE_REQUEST_BPM_PROCESS_DEFINITION_NOT_EXISTS = new ErrorCode(1_030_104_009, "éè´ç³è¯·å®¡æ¹åç±»ä¸æ²¡æå¯ç¨çæµç¨æ¨¡åï¼è¯·å
å建并å叿µç¨"); |
| | | ErrorCode PURCHASE_REQUEST_RESET_FAIL_NOT_REJECT = new ErrorCode(1_030_104_010, "é置失败ï¼åªæé©³åç¶æçéè´ç³è¯·åæè½éç½®"); |
| | | ErrorCode PURCHASE_REQUEST_SUPPLIER_REQUIRED = new ErrorCode(1_030_104_011, "éè´ç³è¯·åæªæå®ä¾åºåï¼æ æ³çæéè´è®¢åï¼è¯·å
ç¼è¾ç³è¯·åè¡¥å
ä¾åºå"); |
| | | |
| | | // ========== ERP éè´æ¥ç¥¨ï¼1-030-105-000ï¼ ========== |
| | | ErrorCode PURCHASE_INVOICE_NOT_EXISTS = new ErrorCode(1_030_105_000, "æ¥ç¥¨ä¸åå¨"); |
| | |
| | | ErrorCode PURCHASE_INVOICE_CREATE_FAIL_ORDER_NOT_APPROVE = new ErrorCode(1_030_105_006, "å建æ¥ç¥¨å¤±è´¥ï¼åå ï¼éè´è®¢å䏿¯å®¡æ ¸éè¿ç¶æ"); |
| | | ErrorCode PURCHASE_INVOICE_CREATE_FAIL_SUPPLIER_MISMATCH = new ErrorCode(1_030_105_007, "å建æ¥ç¥¨å¤±è´¥ï¼åå ï¼æ¥ç¥¨ä¾åºåä¸éè´è®¢åä¸ä¸è´"); |
| | | ErrorCode PURCHASE_INVOICE_CREATE_FAIL_PRICE_EXCEEDS_LIMIT = new ErrorCode(1_030_105_008, "å建æ¥ç¥¨å¤±è´¥ï¼åå ï¼æ¥ç¥¨éé¢è¶
åºéè´è®¢åéé¢ï¼ç®åå¯å¼ç¥¨ï¼{} å
"); |
| | | ErrorCode PURCHASE_INVOICE_CREATE_FAIL_RECEIPT_NOT_EXISTS = new ErrorCode(1_030_105_009, "æ¥ç¥¨å
³èçå
¥åºåä¸åå¨"); |
| | | ErrorCode PURCHASE_INVOICE_CREATE_FAIL_RECEIPT_NOT_FINISHED = new ErrorCode(1_030_105_010, "æ¥ç¥¨å
³èçå
¥åºåæªå®æå
¥åº"); |
| | | ErrorCode PURCHASE_INVOICE_CREATE_FAIL_RECEIPT_ORDER_MISMATCH = new ErrorCode(1_030_105_011, "æ¥ç¥¨å
³èçå
¥åºåä¸éè´è®¢åä¸ä¸è´"); |
| | | ErrorCode PURCHASE_INVOICE_CREATE_FAIL_RECEIPT_SUPPLIER_MISMATCH = new ErrorCode(1_030_105_012, "æ¥ç¥¨å
³èçå
¥åºåä¸ä¾åºåä¸ä¸è´"); |
| | | ErrorCode PURCHASE_INVOICE_CREATE_FAIL_RECEIPT_PRICE_EXCEEDS_LIMIT = new ErrorCode(1_030_105_013, "æ¥ç¥¨éé¢è¶
åºè¯¥å
¥åºåå¯å¼ç¥¨éé¢"); |
| | | |
| | | // ========== ERP éè´éè´§ï¼1-030-103-000ï¼ ========== |
| | | ErrorCode PURCHASE_RETURN_NOT_EXISTS = new ErrorCode(1_030_103_000, "éè´éè´§åä¸åå¨"); |
| | |
| | | package cn.iocoder.yudao.module.erp.service.purchase; |
| | | |
| | | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| | | import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.invoice.ErpPurchaseInvoiceItemReceiptRespVO; |
| | | import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.invoice.ErpPurchaseInvoicePageReqVO; |
| | | import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.invoice.ErpPurchaseInvoiceSaveReqVO; |
| | | import cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpPurchaseInvoiceDO; |
| | |
| | | */ |
| | | Map<Long, BigDecimal> getPurchaseInvoicePriceSumMapByOrderIds(Collection<Long> orderIds); |
| | | |
| | | /** |
| | | * è·å¾æ¥ç¥¨å¯éçå
¥åºååè¡¨ï¼æéè´è®¢åè¿æ»¤ï¼å«å
¥åºéé¢ãå·²æ¥ç¥¨éé¢ã坿¥ç¥¨éé¢ï¼ |
| | | * |
| | | * @param purchaseOrderId éè´è®¢åç¼å· |
| | | * @param excludeInvoiceId éæé¤çæ¥ç¥¨ç¼å·ï¼ç¼è¾æ¶æé¤èªèº«ï¼ï¼å¯ä¸ºç©º |
| | | * @return å
¥åºåå表 |
| | | */ |
| | | List<ErpPurchaseInvoiceItemReceiptRespVO> getItemReceiptListForInvoice(Long purchaseOrderId, Long excludeInvoiceId); |
| | | |
| | | } |
| | |
| | | import cn.hutool.core.collection.CollUtil; |
| | | import cn.hutool.core.lang.Assert; |
| | | import cn.hutool.core.util.ObjectUtil; |
| | | import cn.hutool.core.util.StrUtil; |
| | | import cn.iocoder.yudao.framework.common.exception.ServiceException; |
| | | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| | | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| | | import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.invoice.ErpPurchaseInvoiceItemReceiptRespVO; |
| | | import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.invoice.ErpPurchaseInvoicePageReqVO; |
| | | import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.invoice.ErpPurchaseInvoiceSaveReqVO; |
| | | import cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpPurchaseInvoiceDO; |
| | | import cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpPurchaseOrderDO; |
| | | import cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpPurchaseOrderItemDO; |
| | | import cn.iocoder.yudao.module.mes.api.itemreceipt.MesWmItemReceiptApi; |
| | | import cn.iocoder.yudao.module.mes.api.itemreceipt.dto.MesWmItemReceiptLineRespDTO; |
| | | import cn.iocoder.yudao.module.mes.api.itemreceipt.dto.MesWmItemReceiptRespDTO; |
| | | import cn.iocoder.yudao.module.erp.dal.mysql.finance.ErpFinancePaymentMapper; |
| | | import cn.iocoder.yudao.module.erp.dal.mysql.purchase.ErpPurchaseInvoiceMapper; |
| | | import cn.iocoder.yudao.module.erp.dal.redis.no.ErpNoRedisDAO; |
| | |
| | | import java.util.Collections; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.Objects; |
| | | import java.util.stream.Collectors; |
| | | |
| | | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| | |
| | | private ErpPurchaseOrderService purchaseOrderService; |
| | | |
| | | @Resource |
| | | private MesWmItemReceiptApi mesWmItemReceiptApi; |
| | | |
| | | @Resource |
| | | private StorageAttachmentApi storageAttachmentApi; |
| | | |
| | | /** |
| | | * MES å
¥åºåå·²å®æç¶æï¼è§ MesWmItemReceiptStatusEnum.FINISHED |
| | | */ |
| | | private static final Integer ITEM_RECEIPT_STATUS_FINISHED = 4; |
| | | |
| | | /** |
| | | * MES å
¥åºåå·²åæ¶ç¶æï¼è§ MesWmItemReceiptStatusEnum.CANCELED |
| | | */ |
| | | private static final Integer ITEM_RECEIPT_STATUS_CANCELED = 5; |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | |
| | | |
| | | // 2.1 æå
¥æ¥ç¥¨ï¼å建åå³ä¸ºææç¶æï¼æ éå®¡æ ¸ï¼ |
| | | ErpPurchaseInvoiceDO invoice = BeanUtils.toBean(createReqVO, ErpPurchaseInvoiceDO.class).setNo(no); |
| | | applyItemReceiptCode(invoice); |
| | | invoiceMapper.insert(invoice); |
| | | |
| | | // 2.2 ç»å®å票éä»¶ |
| | |
| | | throw exception(PURCHASE_INVOICE_CREATE_FAIL_SUPPLIER_MISMATCH); |
| | | } |
| | | reqVO.setSupplierId(purchaseOrder.getSupplierId()); // ä¾åºå以éè´è®¢å为å |
| | | // æ ¡éªå
¥åºåï¼å¹¶åå¡«å
¥åºåå·å¿«ç
§ |
| | | validateItemReceipt(reqVO, purchaseOrder); |
| | | } |
| | | |
| | | /** |
| | | * æ ¡éªæ¥ç¥¨ç»å®çå
¥åºåï¼å¿
é¡»åå¨ã已宿å
¥åºãå±äºå½åéè´è®¢ååä¾åºå |
| | | */ |
| | | private void validateItemReceipt(ErpPurchaseInvoiceSaveReqVO reqVO, ErpPurchaseOrderDO purchaseOrder) { |
| | | if (reqVO.getItemReceiptId() == null) { |
| | | return; // åé/æªç»å®æ¶å
许为空 |
| | | } |
| | | MesWmItemReceiptRespDTO receipt = mesWmItemReceiptApi.getItemReceipt(reqVO.getItemReceiptId()); |
| | | if (receipt == null) { |
| | | throw new ServiceException(PURCHASE_INVOICE_CREATE_FAIL_RECEIPT_NOT_EXISTS.getCode(), |
| | | "æ¥ç¥¨å
³èçå
¥åºåä¸åå¨ï¼å
¥åºå ID=" + reqVO.getItemReceiptId() |
| | | + "ãè¯·éæ°éæ©è¯¥éè´è®¢åä¸çå
¥åºåï¼è¥åè¡¨ä¸æ²¡æå¯é项ï¼è¯·å
å¨ MES 宿å
¥åºã"); |
| | | } |
| | | if (!ITEM_RECEIPT_STATUS_FINISHED.equals(receipt.getStatus())) { |
| | | throw new ServiceException(PURCHASE_INVOICE_CREATE_FAIL_RECEIPT_NOT_FINISHED.getCode(), |
| | | "æ¥ç¥¨å
³èçå
¥åºå[" + receipt.getCode() + "]å½åç¶æä¸ºã" + itemReceiptStatusName(receipt.getStatus()) |
| | | + "ãï¼åªæã已宿ãçå
¥åºåæè½æ¥ç¥¨ã请å
å¨ MES 宿å
¥åºååéæ©è¯¥å
¥åºåã"); |
| | | } |
| | | if (ObjectUtil.notEqual(receipt.getPurchaseOrderId(), reqVO.getPurchaseOrderId())) { |
| | | throw new ServiceException(PURCHASE_INVOICE_CREATE_FAIL_RECEIPT_ORDER_MISMATCH.getCode(), |
| | | "æéå
¥åºå[" + receipt.getCode() + "]å±äºéè´è®¢å[" + StrUtil.blankToDefault(receipt.getPurchaseOrderCode(), "ID=" + receipt.getPurchaseOrderId()) |
| | | + "]ï¼ä¸å½åéæ©çéè´è®¢å[" + purchaseOrder.getNo() + "]ä¸ä¸è´ãè¯·éæ°éæ©è¯¥éè´è®¢åä¸çå
¥åºåï¼æå
æ ¸å¯¹éè´è®¢åå·ã"); |
| | | } |
| | | if (ObjectUtil.notEqual(receipt.getVendorId(), purchaseOrder.getSupplierId())) { |
| | | throw new ServiceException(PURCHASE_INVOICE_CREATE_FAIL_RECEIPT_SUPPLIER_MISMATCH.getCode(), |
| | | "æéå
¥åºå[" + receipt.getCode() + "]çä¾åºå(ID=" + receipt.getVendorId() |
| | | + ")ä¸éè´è®¢å[" + purchaseOrder.getNo() + "]çä¾åºå(ID=" + purchaseOrder.getSupplierId() |
| | | + ")ä¸ä¸è´ãè¯·æ ¸å¯¹å
¥åºåæ¥æºï¼ææ¹é该éè´è®¢åä¸çå
¥åºåã"); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * ä¿åå
¥åºåå·å¿«ç
§ï¼å表ä¸å¯¼åºç´æ¥å±ç¤ºï¼é¿å
è表 |
| | | */ |
| | | private void applyItemReceiptCode(ErpPurchaseInvoiceDO invoice) { |
| | | if (invoice.getItemReceiptId() == null) { |
| | | invoice.setItemReceiptCode(null); |
| | | return; |
| | | } |
| | | MesWmItemReceiptRespDTO receipt = mesWmItemReceiptApi.getItemReceipt(invoice.getItemReceiptId()); |
| | | invoice.setItemReceiptCode(receipt != null ? receipt.getCode() : null); |
| | | } |
| | | |
| | | private String itemReceiptStatusName(Integer status) { |
| | | if (status == null) { |
| | | return "æªç¥"; |
| | | } |
| | | return switch (status) { |
| | | case 0 -> "è稿"; |
| | | case 2 -> "å¾
䏿¶"; |
| | | case 3 -> "å¾
æ§è¡å
¥åº"; |
| | | case 4 -> "已宿"; |
| | | case 5 -> "已忶"; |
| | | default -> "ç¶æ" + status; |
| | | }; |
| | | } |
| | | |
| | | private void validatePurchaseInvoicePriceExceedsLimit(ErpPurchaseInvoiceSaveReqVO reqVO) { |
| | |
| | | } |
| | | BigDecimal remainPrice = purchaseOrder.getTotalPrice().subtract( |
| | | getSumValue(invoices, ErpPurchaseInvoiceDO::getPrice, BigDecimal::add, BigDecimal.ZERO)); |
| | | // 2. æ ¡éªé颿¯å¦è¶
è¿ |
| | | // 2. æ ¡éªé颿¯å¦è¶
è¿éè´è®¢åå¯å¼ç¥¨éé¢ |
| | | if (reqVO.getPrice().compareTo(remainPrice) > 0) { |
| | | throw exception(PURCHASE_INVOICE_CREATE_FAIL_PRICE_EXCEEDS_LIMIT, remainPrice); |
| | | } |
| | | // 3. ç»å®äºå
¥åºåæ¶ï¼è¿è¦æ ¡éªä¸è¶
è¿å
¥åºåå¯å¼ç¥¨éé¢ï¼å
¥åºéé¢ - 该å
¥åºåå·²æ¥ç¥¨éé¢ï¼ |
| | | if (reqVO.getItemReceiptId() != null) { |
| | | MesWmItemReceiptRespDTO receipt = mesWmItemReceiptApi.getItemReceipt(reqVO.getItemReceiptId()); |
| | | BigDecimal receiptTotalPrice = calcItemReceiptTotalPrice(receipt); |
| | | BigDecimal invoicedPrice = getItemReceiptInvoicedPrice(reqVO.getItemReceiptId(), reqVO.getId()); |
| | | BigDecimal receiptRemainPrice = receiptTotalPrice.subtract(invoicedPrice); |
| | | if (reqVO.getPrice().compareTo(receiptRemainPrice) > 0) { |
| | | throw new ServiceException(PURCHASE_INVOICE_CREATE_FAIL_RECEIPT_PRICE_EXCEEDS_LIMIT.getCode(), |
| | | "æ¬æ¬¡æ¥ç¥¨éé¢ " + reqVO.getPrice().stripTrailingZeros().toPlainString() + " å
ï¼è¶
è¿æéå
¥åºå[" |
| | | + (receipt != null ? receipt.getCode() : "ID=" + reqVO.getItemReceiptId()) + "]çå¯å¼ç¥¨éé¢ " |
| | | + receiptRemainPrice.stripTrailingZeros().toPlainString() + " å
ï¼å
¥åºéé¢ " |
| | | + receiptTotalPrice.stripTrailingZeros().toPlainString() + " å
ï¼å·²æ¥ç¥¨ " |
| | | + invoicedPrice.stripTrailingZeros().toPlainString() |
| | | + " å
ï¼ãè¯·è°æ´æ¥ç¥¨éé¢ï¼ææ¹éå
¶ä»å
¥åºåï¼å¦éææ´åå¼ç¥¨ï¼è¯·å
æ ¸å¯¹å
¥åºéé¢ã"); |
| | | } |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 计ç®å
¥åºåéé¢ï¼ä¼å
åå
¥åºè¡éé¢å¿«ç
§ï¼å
¶æ¬¡æè¡åä»· à å
¥åºæ°éï¼æåæéè´è®¢åè¡åä»·å
åº |
| | | */ |
| | | private BigDecimal calcItemReceiptTotalPrice(MesWmItemReceiptRespDTO receipt) { |
| | | if (receipt == null || CollUtil.isEmpty(receipt.getLines())) { |
| | | return BigDecimal.ZERO; |
| | | } |
| | | Map<Long, BigDecimal> orderItemPriceMap = purchaseOrderService |
| | | .getPurchaseOrderItemListByOrderId(receipt.getPurchaseOrderId()).stream() |
| | | .filter(item -> item.getProductPrice() != null) |
| | | .collect(Collectors.toMap(ErpPurchaseOrderItemDO::getId, ErpPurchaseOrderItemDO::getProductPrice, (a, b) -> a)); |
| | | BigDecimal total = BigDecimal.ZERO; |
| | | for (MesWmItemReceiptLineRespDTO line : receipt.getLines()) { |
| | | BigDecimal amount = line.getTotalPrice(); |
| | | if (amount == null && line.getPrice() != null && line.getReceivedQuantity() != null) { |
| | | amount = line.getPrice().multiply(line.getReceivedQuantity()); |
| | | } |
| | | if (amount == null && line.getPurchaseOrderItemId() != null && line.getReceivedQuantity() != null) { |
| | | BigDecimal orderItemPrice = orderItemPriceMap.get(line.getPurchaseOrderItemId()); |
| | | if (orderItemPrice != null) { |
| | | amount = orderItemPrice.multiply(line.getReceivedQuantity()); |
| | | } |
| | | } |
| | | if (amount != null) { |
| | | total = total.add(amount); |
| | | } |
| | | } |
| | | return total; |
| | | } |
| | | |
| | | /** |
| | | * è®¡ç®æå
¥åºåå·²æ¥ç¥¨éé¢ï¼å¯ææ¥ç¥¨ç¼å·æé¤èªèº«ï¼ |
| | | */ |
| | | private BigDecimal getItemReceiptInvoicedPrice(Long itemReceiptId, Long excludeInvoiceId) { |
| | | List<ErpPurchaseInvoiceDO> invoices = invoiceMapper.selectListByItemReceiptId(itemReceiptId); |
| | | if (excludeInvoiceId != null) { |
| | | invoices.removeIf(invoice -> Objects.equals(invoice.getId(), excludeInvoiceId)); |
| | | } |
| | | return getSumValue(invoices, ErpPurchaseInvoiceDO::getPrice, BigDecimal::add, BigDecimal.ZERO); |
| | | } |
| | | |
| | | @Override |
| | |
| | | |
| | | // 2. æ´æ°æ¥ç¥¨ |
| | | ErpPurchaseInvoiceDO updateObj = BeanUtils.toBean(updateReqVO, ErpPurchaseInvoiceDO.class); |
| | | applyItemReceiptCode(updateObj); |
| | | invoiceMapper.updateById(updateObj); |
| | | |
| | | // 3. å¢éæ´æ°å票éä»¶ |
| | |
| | | Collectors.mapping(ErpPurchaseInvoiceDO::getPrice, Collectors.reducing(BigDecimal.ZERO, BigDecimal::add)))); |
| | | } |
| | | |
| | | @Override |
| | | public List<ErpPurchaseInvoiceItemReceiptRespVO> getItemReceiptListForInvoice(Long purchaseOrderId, Long excludeInvoiceId) { |
| | | if (purchaseOrderId == null) { |
| | | return List.of(); |
| | | } |
| | | List<MesWmItemReceiptRespDTO> receipts = mesWmItemReceiptApi.getItemReceiptListByPurchaseOrderId(purchaseOrderId); |
| | | return receipts.stream() |
| | | .filter(receipt -> !ITEM_RECEIPT_STATUS_CANCELED.equals(receipt.getStatus())) |
| | | .map(receipt -> { |
| | | BigDecimal totalPrice = calcItemReceiptTotalPrice(receipt); |
| | | BigDecimal invoicedPrice = getItemReceiptInvoicedPrice(receipt.getId(), excludeInvoiceId); |
| | | return new ErpPurchaseInvoiceItemReceiptRespVO() |
| | | .setId(receipt.getId()) |
| | | .setCode(receipt.getCode()) |
| | | .setName(receipt.getName()) |
| | | .setReceiptDate(receipt.getReceiptDate()) |
| | | .setStatus(receipt.getStatus()) |
| | | .setTotalPrice(totalPrice) |
| | | .setInvoicedPrice(invoicedPrice) |
| | | .setRemainInvoicePrice(totalPrice.subtract(invoicedPrice)); |
| | | }) |
| | | .toList(); |
| | | } |
| | | |
| | | } |
| | |
| | | if (!submitable) { |
| | | throw exception(PURCHASE_ORDER_SUBMIT_FAIL_STATUS); |
| | | } |
| | | // 2. 仿¬¾æ¥æå¿
éï¼éè´ç³è¯·èªå¨çæçèç¨¿è®¢åæ²¡æä»æ¬¾æ¥æï¼æäº¤åå¿
é¡»å
ç¼è¾è¡¥é½ |
| | | if (purchaseOrder.getPaymentDate() == null) { |
| | | throw exception(PURCHASE_ORDER_PAYMENT_DATE_REQUIRED); |
| | | } |
| | | |
| | | // 2. å建 BPM æµç¨å®ä¾ |
| | | // 3. å建 BPM æµç¨å®ä¾ |
| | | // å
¨å±å
审æ¹ï¼ä¸å¡æ ¡éªéè¿åç´æ¥æ§è¡å®¡æ¹éè¿é»è¾ï¼æ éæµç¨æ¨¡åã |
| | | if (processInstanceApi.isGlobalAutoApprove()) { |
| | | purchaseOrderMapper.updateById(new ErpPurchaseOrderDO() |
| | |
| | | if (purchaseRequest.getOrderId() != null) { |
| | | throw exception(PURCHASE_REQUEST_ORDER_EXISTS); |
| | | } |
| | | // 3. æ ¡éªä¾åºå |
| | | supplierService.validateSupplier(supplierId); |
| | | // 3. ä¾åºå以éè´ç³è¯·å为åï¼ç³è¯·æäº¤æ¶å·²ç»éè¿ä¾åºåï¼çæè®¢åä¸åè¦æ±éæ°éæ© |
| | | // å
¼å®¹æ§è°ç¨æ¹ä»æ¾å¼ä¼ supplierId çæ
åµï¼ä¼ äºåä»¥ä¼ å
¥å¼ä¸ºå |
| | | Long targetSupplierId = supplierId != null ? supplierId : purchaseRequest.getSupplierId(); |
| | | if (targetSupplierId == null) { |
| | | throw exception(PURCHASE_REQUEST_SUPPLIER_REQUIRED); |
| | | } |
| | | supplierService.validateSupplier(targetSupplierId); |
| | | |
| | | // 4. 设置ä¾åºåå¹¶çæè®¢å |
| | | purchaseRequest.setSupplierId(supplierId); |
| | | purchaseRequest.setSupplierId(targetSupplierId); |
| | | return doGeneratePurchaseOrder(purchaseRequest); |
| | | } |
| | | |
| | |
| | | // 3. å建éè´è®¢å |
| | | ErpPurchaseOrderDO purchaseOrder = new ErpPurchaseOrderDO(); |
| | | purchaseOrder.setNo(orderNo); |
| | | purchaseOrder.setStatus(ErpAuditStatus.APPROVE.getStatus()); // éè´è®¢åç´æ¥ä¸ºå·²å®¡æ ¸ç¶æ |
| | | // çæå为è稿ï¼éè´ç³è¯·ä¸éè´å°è´¦å段ä¸å®å
¨ä¸è´ï¼ä»æ¬¾æ¥æãéè´ç±»åã仿¬¾æ¹å¼çï¼ï¼ |
| | | // éè¦ä¸å¡å¨éè´å°è´¦éè¡¥å
宿´ååæäº¤å®¡æ¹ |
| | | purchaseOrder.setStatus(ErpAuditStatus.DRAFT.getStatus()); |
| | | purchaseOrder.setSupplierId(purchaseRequest.getSupplierId()); |
| | | purchaseOrder.setOrderTime(purchaseRequest.getRequestTime()); |
| | | purchaseOrder.setTotalCount(purchaseRequest.getTotalCount()); |
| | |
| | | orderItem.setTaxPrice(item.getTaxPrice()); |
| | | orderItem.setRemark(item.getRemark()); |
| | | orderItem.setInCount(BigDecimal.ZERO); |
| | | orderItem.setQcCheckFlag(item.getQcCheckFlag() != null ? item.getQcCheckFlag() : false); |
| | | // æ¯å¦è´¨æ£ä¸éè´ç³è¯·ä¿æä¸è´ï¼æç»æªæç¡®æ è®°æ¶é»è®¤ä¸ºãæ¯ãï¼åå²ç³è¯·åå¯è½ä¸º nullï¼ |
| | | orderItem.setQcCheckFlag(item.getQcCheckFlag() != null ? item.getQcCheckFlag() : true); |
| | | return orderItem; |
| | | }); |
| | | purchaseOrderItemMapper.insertBatch(orderItems); |
| | |
| | | // 5. æ´æ°éè´ç³è¯·ç订åä¿¡æ¯ |
| | | purchaseRequestMapper.updateById(new ErpPurchaseRequestDO() |
| | | .setId(id) |
| | | .setSupplierId(purchaseRequest.getSupplierId()) |
| | | .setOrderId(purchaseOrder.getId()) |
| | | .setOrderNo(orderNo)); |
| | | |
| | |
| | | |
| | | import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.statement.ErpSupplierStatementReqVO; |
| | | import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.statement.ErpSupplierStatementRespVO; |
| | | import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.statement.ErpSupplierStatementSummaryReqVO; |
| | | import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.statement.ErpSupplierStatementSummaryRespVO; |
| | | import jakarta.validation.Valid; |
| | | |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * ERP ä¾åºå徿¥ Service æ¥å£ |
| | |
| | | */ |
| | | ErpSupplierStatementRespVO getSupplierStatement(@Valid ErpSupplierStatementReqVO reqVO); |
| | | |
| | | /** |
| | | * è·ååä¾åºå徿¥æ±æ»å表ï¼å·¦ä¾§ä¾åºåæ»è§ï¼ï¼å£å¾ä¸å个ä¾åºå详æ
ä¸è´ |
| | | */ |
| | | List<ErpSupplierStatementSummaryRespVO> getSupplierSummaryList(@Valid ErpSupplierStatementSummaryReqVO reqVO); |
| | | |
| | | } |
| | |
| | | package cn.iocoder.yudao.module.erp.service.purchase; |
| | | |
| | | import cn.hutool.core.collection.CollUtil; |
| | | import cn.hutool.core.util.StrUtil; |
| | | import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil; |
| | | import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.statement.ErpSupplierStatementReqVO; |
| | | import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.statement.ErpSupplierStatementRespVO; |
| | | import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.statement.ErpSupplierStatementSummaryReqVO; |
| | | import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.statement.ErpSupplierStatementSummaryRespVO; |
| | | import cn.iocoder.yudao.module.erp.dal.dataobject.finance.ErpFinancePaymentDO; |
| | | import cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpPurchaseInvoiceDO; |
| | | import cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpPurchaseOrderDO; |
| | |
| | | return respVO; |
| | | } |
| | | |
| | | @Override |
| | | public List<ErpSupplierStatementSummaryRespVO> getSupplierSummaryList(ErpSupplierStatementSummaryReqVO reqVO) { |
| | | // 1. å£å¾ä¸å个ä¾åºå详æ
ä¿æä¸è´ï¼è®¢åæå®¡æ ¸ç¶æè¿æ»¤ãæ¥ç¥¨ä¸è¿æ»¤ç¶æã仿¬¾å«æªå®¡æ ¸/审æ¹ä¸/å·²å®¡æ ¸ |
| | | List<Integer> orderStatuses = Boolean.TRUE.equals(reqVO.getIncludeUnapprovedOrder()) |
| | | ? List.of(ErpAuditStatus.PROCESS.getStatus(), ErpAuditStatus.APPROVING.getStatus(), |
| | | ErpAuditStatus.APPROVE.getStatus()) |
| | | : List.of(ErpAuditStatus.APPROVE.getStatus()); |
| | | List<ErpPurchaseOrderDO> orders = purchaseOrderMapper.selectListByOrderTimeBetween( |
| | | reqVO.getBeginTime(), reqVO.getEndTime(), orderStatuses); |
| | | List<ErpPurchaseInvoiceDO> invoices = purchaseInvoiceMapper.selectListByInvoiceTimeBetween( |
| | | reqVO.getBeginTime(), reqVO.getEndTime()); |
| | | List<Integer> paymentStatuses = List.of(ErpAuditStatus.PROCESS.getStatus(), |
| | | ErpAuditStatus.APPROVING.getStatus(), ErpAuditStatus.APPROVE.getStatus()); |
| | | List<ErpFinancePaymentDO> payments = financePaymentMapper.selectListByPaymentTimeBetween( |
| | | reqVO.getBeginTime(), reqVO.getEndTime(), paymentStatuses); |
| | | |
| | | // 2. æä¾åºåæ±æ» |
| | | Map<Long, ErpSupplierStatementSummaryRespVO> summaryMap = new HashMap<>(); |
| | | for (ErpPurchaseOrderDO order : orders) { |
| | | if (order.getSupplierId() == null) { |
| | | continue; |
| | | } |
| | | ErpSupplierStatementSummaryRespVO summary = getOrCreateSummary(summaryMap, order.getSupplierId()); |
| | | summary.setOrderCount(summary.getOrderCount() + 1); |
| | | summary.setTotalPurchaseAmount(summary.getTotalPurchaseAmount().add(zero(order.getTotalPrice()))); |
| | | } |
| | | for (ErpPurchaseInvoiceDO invoice : invoices) { |
| | | if (invoice.getSupplierId() == null) { |
| | | continue; |
| | | } |
| | | ErpSupplierStatementSummaryRespVO summary = getOrCreateSummary(summaryMap, invoice.getSupplierId()); |
| | | summary.setInvoiceCount(summary.getInvoiceCount() + 1); |
| | | summary.setTotalInvoiceAmount(summary.getTotalInvoiceAmount().add(zero(invoice.getPrice()))); |
| | | } |
| | | for (ErpFinancePaymentDO payment : payments) { |
| | | if (payment.getSupplierId() == null) { |
| | | continue; |
| | | } |
| | | ErpSupplierStatementSummaryRespVO summary = getOrCreateSummary(summaryMap, payment.getSupplierId()); |
| | | summary.setPaymentCount(summary.getPaymentCount() + 1); |
| | | summary.setTotalPaymentAmount(summary.getTotalPaymentAmount().add(zero(payment.getPaymentPrice()))); |
| | | } |
| | | |
| | | // 3. å¡«å
ä¾åºåç¼ç / åç§°ï¼SRM ä¸å·²å é¤çä¾åºåç¨ ID å
åºå±ç¤ºï¼é¿å
åºç°ç©ºè¡ï¼ |
| | | Map<Long, SrmSupplierRespDTO> supplierMap = new HashMap<>(); |
| | | if (!summaryMap.isEmpty()) { |
| | | List<SrmSupplierRespDTO> suppliers = srmSupplierApi.getSupplierList(summaryMap.keySet()).getCheckedData(); |
| | | if (CollUtil.isNotEmpty(suppliers)) { |
| | | suppliers.forEach(item -> supplierMap.put(item.getId(), item)); |
| | | } |
| | | } |
| | | for (ErpSupplierStatementSummaryRespVO summary : summaryMap.values()) { |
| | | summary.setUnpaidAmount(summary.getTotalInvoiceAmount().subtract(summary.getTotalPaymentAmount())); |
| | | SrmSupplierRespDTO supplier = supplierMap.get(summary.getSupplierId()); |
| | | if (supplier == null) { |
| | | summary.setSupplierName("æªç¥ä¾åºå(ID=" + summary.getSupplierId() + ")"); |
| | | continue; |
| | | } |
| | | summary.setSupplierCode(supplier.getCode()); |
| | | summary.setSupplierName(StrUtil.blankToDefault(supplier.getName(), |
| | | "æªå½åä¾åºå(ID=" + summary.getSupplierId() + ")")); |
| | | } |
| | | |
| | | // 4. æªä»ä½é¢å¤çæåé¢ï¼å
¶æ¬¡æéè´é¢ãä¾åºååç§° |
| | | Comparator<ErpSupplierStatementSummaryRespVO> comparator = |
| | | Comparator.comparing(ErpSupplierStatementSummaryRespVO::getUnpaidAmount, |
| | | Comparator.nullsFirst(Comparator.<BigDecimal>naturalOrder())) |
| | | .thenComparing(ErpSupplierStatementSummaryRespVO::getTotalPurchaseAmount, |
| | | Comparator.nullsFirst(Comparator.<BigDecimal>naturalOrder())) |
| | | .reversed() |
| | | .thenComparing(ErpSupplierStatementSummaryRespVO::getSupplierName, |
| | | Comparator.nullsLast(Comparator.naturalOrder())); |
| | | return summaryMap.values().stream() |
| | | .sorted(comparator) |
| | | .collect(Collectors.toList()); |
| | | } |
| | | |
| | | private ErpSupplierStatementSummaryRespVO getOrCreateSummary( |
| | | Map<Long, ErpSupplierStatementSummaryRespVO> summaryMap, Long supplierId) { |
| | | return summaryMap.computeIfAbsent(supplierId, id -> { |
| | | ErpSupplierStatementSummaryRespVO summary = new ErpSupplierStatementSummaryRespVO(); |
| | | summary.setSupplierId(id); |
| | | summary.setOrderCount(0); |
| | | summary.setInvoiceCount(0); |
| | | summary.setPaymentCount(0); |
| | | summary.setTotalPurchaseAmount(BigDecimal.ZERO); |
| | | summary.setTotalInvoiceAmount(BigDecimal.ZERO); |
| | | summary.setTotalPaymentAmount(BigDecimal.ZERO); |
| | | summary.setUnpaidAmount(BigDecimal.ZERO); |
| | | return summary; |
| | | }); |
| | | } |
| | | |
| | | private BigDecimal zero(BigDecimal value) { |
| | | return value != null ? value : BigDecimal.ZERO; |
| | | } |
| | |
| | | @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY) |
| | | private LocalDate[] voucherDate; |
| | | |
| | | @Schema(description = "æ¥æºåæ®ç±»å", example = "CRM_INVOICE") |
| | | private String sourceType; |
| | | |
| | | @Schema(description = "æ¥æºåæ®ç¼å·", example = "1024") |
| | | private Long sourceId; |
| | | |
| | | @Schema(description = "æ¥æºåæ®å·", example = "KP20261029001") |
| | | private String sourceNo; |
| | | |
| | | } |
| | |
| | | @ExcelProperty("夿³¨") |
| | | private String remark; |
| | | |
| | | @Schema(description = "æ¥æºåæ®ç±»å", example = "CRM_INVOICE") |
| | | @ExcelProperty("æ¥æºåæ®ç±»å") |
| | | private String sourceType; |
| | | |
| | | @Schema(description = "æ¥æºåæ®ç¼å·", example = "1024") |
| | | private Long sourceId; |
| | | |
| | | @Schema(description = "æ¥æºåæ®å·", example = "KP20261029001") |
| | | @ExcelProperty("æ¥æºåæ®å·") |
| | | private String sourceNo; |
| | | |
| | | @Schema(description = "å建æ¶é´", requiredMode = Schema.RequiredMode.REQUIRED) |
| | | // ãyyyy-MM-dd HH:mm:ssãæ£å¥½ 19 个å符ï¼èªéåºå宽就åªç» 19ï¼è´´çè¾¹å¾é¾çï¼è¿éæ¾å®½å° 22 |
| | | @ColumnWidth(22) |
| | |
| | | @Schema(description = "éä»¶ç¼å·æ°ç»", example = "[]") |
| | | private List<Long> blobIds; |
| | | |
| | | @Schema(description = "æ¥æºåæ®ç±»åï¼CRM_INVOICEå¼ç¥¨ãCRM_RECEIVABLE忬¾ãERP_PURCHASE_INVOICEæ¥ç¥¨ãERP_PAYMENT仿¬¾", example = "CRM_INVOICE") |
| | | private String sourceType; |
| | | |
| | | @Schema(description = "æ¥æºåæ®ç¼å·", example = "1024") |
| | | private Long sourceId; |
| | | |
| | | @Schema(description = "æ¥æºåæ®å·", example = "KP20261029001") |
| | | private String sourceNo; |
| | | |
| | | } |
| | |
| | | */ |
| | | private String remark; |
| | | |
| | | /** |
| | | * æ¥æºåæ®ç±»å |
| | | * |
| | | * ä¾å¦ï¼CRM_INVOICEãCRM_RECEIVABLEãERP_PURCHASE_INVOICEãERP_PAYMENT |
| | | */ |
| | | private String sourceType; |
| | | |
| | | /** |
| | | * æ¥æºåæ®ç¼å· |
| | | */ |
| | | private Long sourceId; |
| | | |
| | | /** |
| | | * æ¥æºåæ®å·ï¼å¿«ç
§ï¼ |
| | | */ |
| | | private String sourceNo; |
| | | |
| | | } |
| | |
| | | // å¦åãèµµç£ãè¿ç§æµç§°æ°¸è¿å¹é
ä¸ä¸ï¼Service å·²ç»ææç´¢è¯è§£ææç¼å·éå |
| | | .inIfPresent(FinVoucherDO::getCreator, creatorIds) |
| | | .eqIfPresent(FinVoucherDO::getStatus, reqVO.getStatus()) |
| | | .eqIfPresent(FinVoucherDO::getSourceType, reqVO.getSourceType()) |
| | | .eqIfPresent(FinVoucherDO::getSourceId, reqVO.getSourceId()) |
| | | .likeIfPresent(FinVoucherDO::getSourceNo, reqVO.getSourceNo()) |
| | | .betweenIfPresent(FinVoucherDO::getVoucherDate, reqVO.getVoucherDate()) |
| | | .orderByDesc(FinVoucherDO::getVoucherDate) |
| | | .orderByDesc(FinVoucherDO::getId)); |
| | |
| | | ErrorCode RESIGNATION_APPLICATION_UPDATE_AUDIT_STATUS_FAIL_NOT_PROCESS = new ErrorCode(1_030_003_003, "æ´æ°ç¦»èç³è¯·å®¡æ¹ç¶æå¤±è´¥ï¼åå ï¼ä¸æ¯å®¡æ¹ä¸ç¶æ"); |
| | | ErrorCode RESIGNATION_APPLICATION_NO_EXISTS = new ErrorCode(1_030_003_004, "çæç¦»èç³è¯·åå·éå¤ï¼è¯·éè¯"); |
| | | ErrorCode RESIGNATION_APPLICATION_EXISTS = new ErrorCode(1_030_003_005, "该å工已åå¨ç¦»èç³è¯·ï¼è¯·å¿éå¤æäº¤"); |
| | | ErrorCode RESIGNATION_APPLICATION_BPM_PROCESS_DEFINITION_NOT_EXISTS = new ErrorCode(1_030_003_006, "离èå®¡æ¹æµç¨ä¸åå¨"); |
| | | ErrorCode RESIGNATION_APPLICATION_BPM_PROCESS_DEFINITION_NOT_EXISTS = new ErrorCode(1_030_003_006, "离èå®¡æ¹æµç¨ä¸åå¨ï¼è¯·å
å¨åååå
¬ä¸é
置并åå¸ç¦»èå®¡æ¹æµç¨"); |
| | | ErrorCode RESIGNATION_APPLICATION_CANCEL_FAIL_STATUS = new ErrorCode(1_030_003_007, "离èç³è¯·æ¤é失败ï¼åå ï¼ä»
è稿æå®¡æ¹ä¸ç¶æå¯ä»¥æ¤é"); |
| | | ErrorCode RESIGNATION_HANDOVER_EMPLOYEE_NOT_EXISTS = new ErrorCode(1_030_003_008, "交æ¥åå·¥ä¸åå¨ï¼è¯·éæ°éæ©äº¤æ¥åå·¥"); |
| | | ErrorCode RESIGNATION_HANDOVER_EMPLOYEE_NO_USER = new ErrorCode(1_030_003_009, "交æ¥åå·¥æªå
³èç³»ç»ç¨æ·ï¼æ æ³è½¬ç§»ç¨æ·æ°æ®"); |
| | | ErrorCode RESIGNATION_HANDOVER_SELF = new ErrorCode(1_030_003_010, "交æ¥äººä¸è½æ¯ç³è¯·äººæ¬äººï¼è¯·éæ©å
¶ä»åå·¥"); |
| | | ErrorCode RESIGNATION_HANDOVER_EMPLOYEE_RESIGNED = new ErrorCode(1_030_003_011, "交æ¥å工已离èï¼è¯·éæ°éæ©å¨èåå·¥"); |
| | | ErrorCode RESIGNATION_HANDOVER_TARGET_REQUIRED = new ErrorCode(1_030_003_012, "æªæå®äº¤æ¥åå·¥ï¼æ æ³å¼å§æå®æå·¥ä½äº¤æ¥"); |
| | | ErrorCode RESIGNATION_HANDOVER_COMPLETED_CANNOT_REVERT = new ErrorCode(1_030_003_013, "交æ¥å·²å®æï¼ä¸è½åé交æ¥ç¶æ"); |
| | | ErrorCode RESIGNATION_HANDOVER_NOT_APPROVED = new ErrorCode(1_030_003_014, "离èç³è¯·å®¡æ¹éè¿åæè½è¿è¡å·¥ä½äº¤æ¥"); |
| | | ErrorCode RESIGNATION_HANDOVER_NOT_STARTED = new ErrorCode(1_030_003_015, "å·¥ä½äº¤æ¥å°æªå¼å§ï¼ä¸è½ç´æ¥å®æ"); |
| | | ErrorCode RESIGNATION_HANDOVER_CHANGE_AFTER_START = new ErrorCode(1_030_003_016, "å·¥ä½äº¤æ¥å·²å¼å§ï¼ä¸è½æ´æ¢äº¤æ¥åå·¥"); |
| | | ErrorCode RESIGNATION_APPLICANT_NOT_EXISTS = new ErrorCode(1_030_003_017, "ç³è¯·äººä¸åå¨ï¼è¯·éæ°éæ©ç³è¯·äºº"); |
| | | ErrorCode RESIGNATION_HANDOVER_STATUS_INVALID = new ErrorCode(1_030_003_018, "交æ¥ç¶æå¼ä¸åæ³ï¼ä»
æ¯æ 0æªå¼å§ã10è¿è¡ä¸ã20已宿"); |
| | | |
| | | // ========== å çç³è¯· 1-030-008-000 ========== |
| | | ErrorCode OVERTIME_APPLICATION_NOT_EXISTS = new ErrorCode(1_030_008_000, "å çç³è¯·ä¸åå¨"); |
| | |
| | | return success(true); |
| | | } |
| | | |
| | | @PostMapping("/cancel") |
| | | @Operation(summary = "æ¤é离èç³è¯·") |
| | | @Parameter(name = "id", description = "ç³è¯·ID", required = true) |
| | | @PreAuthorize("@ss.hasPermission('hrm:resignation:cancel')") |
| | | public CommonResult<Boolean> cancelResignationApplication(@RequestParam("id") Long id) { |
| | | resignationApplicationService.cancelResignationApplication(id, |
| | | SecurityFrameworkUtils.getLoginUserId()); |
| | | return success(true); |
| | | } |
| | | |
| | | @GetMapping("/approve-process-definition-list") |
| | | @Operation(summary = "è·åå¯ç¨çå®¡æ¹æµç¨å®ä¹å表") |
| | | public CommonResult<List<Map<String, Object>>> getApproveProcessDefinitionList() { |
| | |
| | | @Schema(description = "ç³è¯·äººå§å", example = "å¼ ä¸") |
| | | private String userName; |
| | | |
| | | @Schema(description = "ç³è¯·äººåå·¥ID", example = "1") |
| | | private Long employeeId; |
| | | |
| | | @Schema(description = "ç³è¯·äººåå·¥å§å", example = "å¼ ä¸") |
| | | private String employeeName; |
| | | |
| | | @Schema(description = "ç³è¯·äººå²ä½åç§°", example = "éå®ç»ç") |
| | | private String postName; |
| | | |
| | | @Schema(description = "é¨é¨ID", example = "1") |
| | | private Long deptId; |
| | | |
| | |
| | | @Schema(description = "ç¨æ·æ°æ®äº¤æ¥ç¶æï¼0æªå¼å§ 10è¿è¡ä¸ 20已宿") |
| | | private Integer handoverDataStatus; |
| | | |
| | | @Schema(description = "ç¨æ·æ°æ®äº¤æ¥ç¶æåç§°", example = "æªå¼å§") |
| | | private String handoverDataStatusName; |
| | | |
| | | @Schema(description = "交æ¥ç¶æåç§°", example = "æªå¼å§") |
| | | private String handoverStatusName; |
| | | |
| | |
| | | import cn.iocoder.yudao.module.hrm.controller.admin.employee.vo.HrmEmployeeRespVO; |
| | | import cn.iocoder.yudao.module.hrm.controller.admin.employee.vo.HrmEmployeeSaveReqVO; |
| | | import cn.iocoder.yudao.module.hrm.controller.admin.employee.vo.HrmEmployeeSimpleRespVO; |
| | | import cn.iocoder.yudao.module.hrm.controller.admin.employee.vo.HrmEmployeeStatisticsRespVO; |
| | | import cn.iocoder.yudao.module.hrm.dal.dataobject.employee.HrmEmployeeDO; |
| | | import cn.iocoder.yudao.module.hrm.service.employee.HrmEmployeeService; |
| | | import cn.iocoder.yudao.module.system.api.dept.DeptApi; |
| | |
| | | } |
| | | } |
| | | |
| | | @GetMapping("/tenure-statistics") |
| | | @Operation(summary = "è·å¾å工人åç»è®¡", description = "å·¥é¾ãå¹´é¾ãå¦åãæ§å«ãé¨é¨å·¥é¾çç»è®¡ï¼ç¨äºäººåèµæºç»è®¡é¡µé¢") |
| | | public CommonResult<HrmEmployeeStatisticsRespVO> getTenureStatistics() { |
| | | return success(employeeService.getTenureStatistics()); |
| | | } |
| | | |
| | | @GetMapping("/simple-list") |
| | | @Operation(summary = "è·å¾å工精ç®å表", description = "ç¨äºä¸æéæ©") |
| | | public CommonResult<List<HrmEmployeeSimpleRespVO>> getEmployeeSimpleList( |
| | |
| | | @ExcelProperty("åå·¥ç¼å·") |
| | | private String employeeNo; |
| | | |
| | | @Schema(description = "å
³èçç³»ç»ç¨æ·ID") |
| | | private Long userId; |
| | | |
| | | @Schema(description = "é¨é¨ID") |
| | | private Long deptId; |
| | | |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.hrm.controller.admin.employee.vo; |
| | | |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | |
| | | import java.time.LocalDate; |
| | | import java.util.List; |
| | | |
| | | @Schema(description = "管çåå° - å工人åç»è®¡ Response VO") |
| | | @Data |
| | | public class HrmEmployeeStatisticsRespVO { |
| | | |
| | | @Schema(description = "å¨å²äººæ°ï¼å¨è + è¯ç¨ï¼", example = "128") |
| | | private Integer totalCount; |
| | | |
| | | @Schema(description = "å¨è人æ°", example = "120") |
| | | private Integer activeCount; |
| | | |
| | | @Schema(description = "è¯ç¨äººæ°", example = "8") |
| | | private Integer probationCount; |
| | | |
| | | @Schema(description = "离è人æ°", example = "15") |
| | | private Integer resignedCount; |
| | | |
| | | @Schema(description = "å¨å²å工平åå·¥é¾ï¼å¹´ï¼ä¿ç 1 ä½å°æ°ï¼", example = "3.5") |
| | | private Double averageTenureYears; |
| | | |
| | | @Schema(description = "å¨å²å工平åå¹´é¾ï¼å²ï¼ä¿ç 1 ä½å°æ°ï¼", example = "31.2") |
| | | private Double averageAge; |
| | | |
| | | @Schema(description = "æ¬å¹´å
¥è人æ°", example = "12") |
| | | private Integer thisYearHireCount; |
| | | |
| | | @Schema(description = "æ¬å¹´ç¦»è人æ°", example = "4") |
| | | private Integer thisYearResignCount; |
| | | |
| | | @Schema(description = "å·¥é¾åå¸ï¼åºå®åºé´ï¼å« 0 人çåºé´ï¼") |
| | | private List<ItemVO> tenureDistribution; |
| | | |
| | | @Schema(description = "å¹´é¾åå¸ï¼åºå®åºé´ï¼å« 0 人çåºé´ï¼") |
| | | private List<ItemVO> ageDistribution; |
| | | |
| | | @Schema(description = "å¦ååå¸") |
| | | private List<ItemVO> educationDistribution; |
| | | |
| | | @Schema(description = "æ§å«åå¸") |
| | | private List<ItemVO> genderDistribution; |
| | | |
| | | @Schema(description = "人åç¶æææï¼å¨è / è¯ç¨ / 离èï¼") |
| | | private List<ItemVO> statusDistribution; |
| | | |
| | | @Schema(description = "é¨é¨äººæ°åå¸ï¼æäººæ°ååº") |
| | | private List<ItemVO> deptDistribution; |
| | | |
| | | @Schema(description = "å²ä½åå¸ï¼æäººæ°ååº") |
| | | private List<ItemVO> postDistribution; |
| | | |
| | | @Schema(description = "å©å§»ç¶åµåå¸") |
| | | private List<ItemVO> marriageDistribution; |
| | | |
| | | @Schema(description = "æ¿æ²»é¢è²åå¸") |
| | | private List<ItemVO> politicalDistribution; |
| | | |
| | | @Schema(description = "è¿ 12 个æå
¥è / 离èè¶å¿ï¼ææä»½ååº") |
| | | private List<TrendVO> hireResignTrend; |
| | | |
| | | @Schema(description = "ååå°æé¢è¦ï¼å·²å°æ / 30天å
/ 31-90天 / 90å¤©ä»¥ä¸ / æ åºå®æéï¼") |
| | | private List<ItemVO> contractWarning; |
| | | |
| | | @Schema(description = "å¨å²æªç¾ææåå人æ°", example = "3") |
| | | private Integer noContractCount; |
| | | |
| | | @Schema(description = "åé¨é¨å·¥é¾ç»è®¡ï¼æå¹³åå·¥é¾ååº") |
| | | private List<DeptTenureVO> deptTenureList; |
| | | |
| | | @Schema(description = "å¨èå工工龿è¡ï¼å·¥é¾æé¿çå 10 åï¼") |
| | | private List<TenureEmployeeVO> topTenureEmployees; |
| | | |
| | | @Schema(description = "åå¸é¡¹") |
| | | @Data |
| | | public static class ItemVO { |
| | | |
| | | @Schema(description = "åç§°", example = "3-5å¹´") |
| | | private String name; |
| | | |
| | | @Schema(description = "人æ°", example = "30") |
| | | private Integer value; |
| | | |
| | | public ItemVO() { |
| | | } |
| | | |
| | | public ItemVO(String name, Integer value) { |
| | | this.name = name; |
| | | this.value = value; |
| | | } |
| | | |
| | | } |
| | | |
| | | @Schema(description = "é¨é¨å·¥é¾ç»è®¡") |
| | | @Data |
| | | public static class DeptTenureVO { |
| | | |
| | | @Schema(description = "é¨é¨ç¼å·") |
| | | private Long deptId; |
| | | |
| | | @Schema(description = "é¨é¨åç§°", example = "ç åé¨") |
| | | private String deptName; |
| | | |
| | | @Schema(description = "é¨é¨å¨å²äººæ°", example = "20") |
| | | private Integer count; |
| | | |
| | | @Schema(description = "é¨é¨å¹³åå·¥é¾ï¼å¹´ï¼ä¿ç 1 ä½å°æ°ï¼", example = "4.2") |
| | | private Double averageTenureYears; |
| | | |
| | | } |
| | | |
| | | @Schema(description = "å
¥è / 离èè¶å¿é¡¹") |
| | | @Data |
| | | public static class TrendVO { |
| | | |
| | | @Schema(description = "æä»½ï¼æ ¼å¼ yyyy-MM", example = "2026-11") |
| | | private String month; |
| | | |
| | | @Schema(description = "å
¥è人æ°", example = "3") |
| | | private Integer hireCount; |
| | | |
| | | @Schema(description = "离è人æ°", example = "1") |
| | | private Integer resignCount; |
| | | |
| | | } |
| | | |
| | | @Schema(description = "å工工龿ç»") |
| | | @Data |
| | | public static class TenureEmployeeVO { |
| | | @Schema(description = "åå·¥ç¼å·") |
| | | private Long id; |
| | | |
| | | @Schema(description = "åå·¥å§å", example = "å¼ æ") |
| | | private String name; |
| | | |
| | | @Schema(description = "é¨é¨åç§°", example = "ç åé¨") |
| | | private String deptName; |
| | | |
| | | @Schema(description = "å
¥èæ¥æ") |
| | | private LocalDate hireDate; |
| | | |
| | | @Schema(description = "å·¥é¾ï¼å¹´ï¼ä¿ç 1 ä½å°æ°ï¼", example = "6.5") |
| | | private Double tenureYears; |
| | | |
| | | } |
| | | |
| | | } |
| | |
| | | private Long id; |
| | | |
| | | /** |
| | | * 离èåå·¥ID |
| | | * |
| | | * å
³è HrmEmployeeDO#getId() |
| | | */ |
| | | private Long fromEmployeeId; |
| | | |
| | | /** |
| | | * 离èç¨æ·ID |
| | | * |
| | | * å
³è AdminUserDO#getId() |
| | |
| | | private Long fromUserId; |
| | | |
| | | /** |
| | | * 交æ¥ç®æ åå·¥ID |
| | | * |
| | | * å
³è HrmEmployeeDO#getId() |
| | | */ |
| | | private Long toEmployeeId; |
| | | |
| | | /** |
| | | * 交æ¥ç®æ ç¨æ·ID |
| | | * |
| | | * å
³è AdminUserDO#getId() |
| | |
| | | import cn.iocoder.yudao.module.hrm.dal.dataobject.approval.HrmResignationApplicationDO; |
| | | import org.apache.ibatis.annotations.Mapper; |
| | | |
| | | import java.time.LocalDate; |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * 离èç³è¯· Mapper |
| | | * |
| | |
| | | .ne(HrmResignationApplicationDO::getStatus, status)); |
| | | } |
| | | |
| | | /** |
| | | * æ¥è¯¢æå®å®¡æ¹ç¶æä¸ï¼é¢è®¡ç¦»èæ¥æå·²å°ä¸å°æªè®°å½å®é
ç¦»èæ¥æçç³è¯· |
| | | */ |
| | | default List<HrmResignationApplicationDO> selectListByStatusAndExpectedDateLe(Integer status, LocalDate date) { |
| | | return selectList(new LambdaQueryWrapperX<HrmResignationApplicationDO>() |
| | | .eq(HrmResignationApplicationDO::getStatus, status) |
| | | .le(HrmResignationApplicationDO::getExpectedDate, date) |
| | | .isNull(HrmResignationApplicationDO::getActualDate) |
| | | .orderByAsc(HrmResignationApplicationDO::getId)); |
| | | } |
| | | |
| | | } |
| | |
| | | import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; |
| | | import cn.iocoder.yudao.module.hrm.controller.admin.employee.vo.HrmEmployeePageReqVO; |
| | | import cn.iocoder.yudao.module.hrm.dal.dataobject.employee.HrmEmployeeDO; |
| | | import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; |
| | | import org.apache.ibatis.annotations.Mapper; |
| | | |
| | | import java.time.LocalDate; |
| | | import java.util.Collection; |
| | | import java.util.List; |
| | | |
| | |
| | | return selectCount(HrmEmployeeDO::getSalaryStructureId, salaryStructureId); |
| | | } |
| | | |
| | | /** |
| | | * æç³»ç»ç¨æ·ç¼å·æ´æ°å工离èç¶æä¸ç¦»èæ¥æ |
| | | */ |
| | | default int updateEmployeeStatusByUserId(Long userId, Integer employeeStatus, LocalDate leaveDate) { |
| | | return update(null, new LambdaUpdateWrapper<HrmEmployeeDO>() |
| | | .eq(HrmEmployeeDO::getUserId, userId) |
| | | .set(HrmEmployeeDO::getEmployeeStatus, employeeStatus) |
| | | .set(HrmEmployeeDO::getLeaveDate, leaveDate)); |
| | | } |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.hrm.job.approval; |
| | | |
| | | import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler; |
| | | import cn.iocoder.yudao.framework.tenant.core.job.TenantJob; |
| | | import cn.iocoder.yudao.module.hrm.service.approval.HrmResignationApplicationService; |
| | | import jakarta.annotation.Resource; |
| | | import org.springframework.stereotype.Component; |
| | | |
| | | /** |
| | | * 离èç³è¯·å°æèªå¨ç¦»è Job |
| | | * <p> |
| | | * æ«æå®¡æ¹éè¿ä¸é¢è®¡ç¦»èæ¥æå·²å°ç离èç³è¯·ï¼å°å¯¹åºåå·¥ç¶æç½®ä¸ºç¦»èå¹¶è®°å½å®é
ç¦»èæ¥æã |
| | | * |
| | | * @author è¶
级管çå |
| | | */ |
| | | @Component |
| | | public class HrmResignationAutoLeaveJob implements JobHandler { |
| | | |
| | | @Resource |
| | | private HrmResignationApplicationService resignationApplicationService; |
| | | |
| | | @Override |
| | | @TenantJob |
| | | public String execute(String param) { |
| | | int count = resignationApplicationService.autoLeaveResignationApplication(); |
| | | return String.format("å°æèªå¨ç¦»è %s 人", count); |
| | | } |
| | | |
| | | } |
| | |
| | | */ |
| | | void updateHandoverStatus(@Valid HrmResignationHandoverReqVO reqVO); |
| | | |
| | | /** |
| | | * æ¤é离èç³è¯· |
| | | * <p> |
| | | * èç¨¿ç´æ¥ç½®ä¸ºå·²æ¤éï¼å®¡æ¹ä¸åæ¤é BPM æµç¨å®ä¾å置为已æ¤é |
| | | * |
| | | * @param id ç³è¯·ID |
| | | * @param userId æä½äººID |
| | | */ |
| | | void cancelResignationApplication(Long id, Long userId); |
| | | |
| | | /** |
| | | * æ«æå°è¾¾é¢è®¡ç¦»èæ¥æçå·²éè¿ç¦»èç³è¯·ï¼å°åå·¥ç¶æèªå¨ç½®ä¸ºç¦»è |
| | | * |
| | | * @return æ¬æ¬¡å¤ççç³è¯·æ°é |
| | | */ |
| | | int autoLeaveResignationApplication(); |
| | | |
| | | } |
| | |
| | | |
| | | import cn.hutool.core.collection.CollUtil; |
| | | import cn.hutool.core.util.ObjUtil; |
| | | import cn.hutool.core.util.StrUtil; |
| | | import cn.hutool.json.JSONUtil; |
| | | import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; |
| | | import cn.iocoder.yudao.framework.common.exception.ServiceException; |
| | | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| | | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| | | import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; |
| | | import cn.iocoder.yudao.module.bpm.api.task.BpmProcessInstanceApi; |
| | | import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; |
| | | import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCancelReqVO; |
| | | import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionInfoDO; |
| | | import cn.iocoder.yudao.module.bpm.service.definition.BpmCategoryService; |
| | | import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService; |
| | | import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService; |
| | | import cn.iocoder.yudao.module.hrm.controller.admin.approval.vo.HrmResignationApplicationPageReqVO; |
| | | import cn.iocoder.yudao.module.hrm.controller.admin.approval.vo.HrmResignationApplicationRespVO; |
| | | import cn.iocoder.yudao.module.hrm.controller.admin.approval.vo.HrmResignationApplicationSaveReqVO; |
| | | import cn.iocoder.yudao.module.hrm.controller.admin.approval.vo.HrmResignationHandoverReqVO; |
| | | import cn.iocoder.yudao.module.hrm.dal.dataobject.approval.HrmResignationApplicationDO; |
| | | import cn.iocoder.yudao.module.hrm.dal.dataobject.employee.HrmEmployeeDO; |
| | | import cn.iocoder.yudao.module.hrm.dal.mysql.approval.HrmResignationApplicationMapper; |
| | | import cn.iocoder.yudao.module.hrm.dal.mysql.employee.HrmEmployeeMapper; |
| | | import cn.iocoder.yudao.module.hrm.dal.redis.HrmNoRedisDAO; |
| | | import cn.iocoder.yudao.module.hrm.enums.HrmAuditStatusEnum; |
| | | import cn.iocoder.yudao.module.hrm.enums.HrmResignationTypeEnum; |
| | | import cn.iocoder.yudao.module.hrm.service.employee.HrmEmployeeService; |
| | | import cn.iocoder.yudao.module.hrm.service.handover.HrmUserHandoverService; |
| | | import cn.iocoder.yudao.module.system.api.dept.DeptApi; |
| | | import cn.iocoder.yudao.module.system.api.dept.PostApi; |
| | | import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; |
| | | import cn.iocoder.yudao.module.system.api.dept.dto.PostRespDTO; |
| | | import cn.iocoder.yudao.module.system.api.storage.StorageAttachmentApi; |
| | | import cn.iocoder.yudao.module.system.api.user.AdminUserApi; |
| | | import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; |
| | |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | import org.springframework.validation.annotation.Validated; |
| | | |
| | | import java.time.LocalDate; |
| | | import java.time.LocalDateTime; |
| | | import java.util.ArrayList; |
| | | import java.util.Collections; |
| | | import java.util.HashMap; |
| | |
| | | private static final Integer HANDOVER_STATUS_IN_PROGRESS = 10; |
| | | private static final Integer HANDOVER_STATUS_COMPLETED = 20; |
| | | |
| | | /** åå·¥ç¶æï¼ç¦»è */ |
| | | private static final Integer EMPLOYEE_STATUS_RESIGNED = 3; |
| | | |
| | | @Resource |
| | | private HrmResignationApplicationMapper resignationApplicationMapper; |
| | | @Resource |
| | | private HrmNoRedisDAO noRedisDAO; |
| | | @Resource |
| | | private DeptApi deptApi; |
| | | @Resource |
| | | private PostApi postApi; |
| | | @Resource |
| | | private AdminUserApi adminUserApi; |
| | | @Resource |
| | |
| | | @Resource |
| | | private BpmProcessDefinitionService bpmProcessDefinitionService; |
| | | @Resource |
| | | private BpmProcessInstanceService bpmProcessInstanceService; |
| | | @Resource |
| | | private HrmUserHandoverService handoverService; |
| | | @Resource |
| | | private HrmEmployeeMapper employeeMapper; |
| | | @Resource |
| | | private HrmEmployeeService employeeService; |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public Long createResignationApplication(HrmResignationApplicationSaveReqVO createReqVO) { |
| | | Long userId = createReqVO.getUserId(); |
| | | if (userId == null) { |
| | | userId = getCurrentUserId(); |
| | | Long userId = createReqVO.getUserId() != null ? createReqVO.getUserId() : getCurrentUserId(); |
| | | AdminUserRespDTO user = adminUserApi.getUser(userId); |
| | | if (user == null) { |
| | | throw new ServiceException(RESIGNATION_APPLICANT_NOT_EXISTS.getCode(), |
| | | String.format("ç³è¯·äºº(ç¨æ·ID=%s)ä¸åå¨ï¼è¯·éæ°éæ©ç³è¯·äººåéè¯", userId)); |
| | | } |
| | | HrmResignationApplicationDO existing = resignationApplicationMapper.selectByUserIdAndStatusNot(userId, |
| | | HrmAuditStatusEnum.CANCEL.getStatus()); |
| | | if (existing != null) { |
| | | throw exception(RESIGNATION_APPLICATION_EXISTS); |
| | | } |
| | | String no = generateUniqueNo(); |
| | | AdminUserRespDTO user = adminUserApi.getUser(userId); |
| | | if (user == null) { |
| | | userId = getCurrentUserId(); |
| | | throw new ServiceException(RESIGNATION_APPLICATION_EXISTS.getCode(), |
| | | String.format("ç³è¯·äºº[%s]å·²å卿ªæ¤éç离èç³è¯·(åå·=%sï¼ç¶æ=%s)ï¼è¯·å
æ¤éæå é¤åç³è¯·ååæ°å»º", |
| | | user.getNickname(), existing.getNo(), |
| | | HrmAuditStatusEnum.getNameByStatus(existing.getStatus()))); |
| | | } |
| | | HrmResignationApplicationDO application = BeanUtils.toBean(createReqVO, HrmResignationApplicationDO.class); |
| | | application.setNo(no); |
| | | application.setNo(generateUniqueNo()); |
| | | application.setUserId(userId); |
| | | application.setDeptId(createReqVO.getDeptId() != null ? createReqVO.getDeptId() : user.getDeptId()); |
| | | application.setStatus(HrmAuditStatusEnum.DRAFT.getStatus()); |
| | | application.setHandoverStatus(HANDOVER_STATUS_NOT_STARTED); |
| | | application.setHandoverDataStatus(HANDOVER_STATUS_NOT_STARTED); |
| | | // ç»ä¸è§£æäº¤æ¥åå·¥ä¸ç³»ç»ç¨æ·ï¼ç¡®ä¿åå·¥IDãç¨æ·IDæå¯¹è½åº |
| | | resolveHandoverTarget(application, userId); |
| | | resignationApplicationMapper.insert(application); |
| | | storageAttachmentApi.bindAttachments("file", "hrm_resignation_application", |
| | | application.getId(), createReqVO.getBlobIds()); |
| | |
| | | } |
| | | |
| | | private Long getCurrentUserId() { |
| | | return 1L; |
| | | return SecurityFrameworkUtils.getLoginUserId(); |
| | | } |
| | | |
| | | private String generateUniqueNo() { |
| | |
| | | throw exception(RESIGNATION_APPLICATION_UPDATE_FAIL_NOT_DRAFT); |
| | | } |
| | | HrmResignationApplicationDO updateObj = BeanUtils.toBean(updateReqVO, HrmResignationApplicationDO.class); |
| | | // ä¸è¦çç³è¯·äººï¼äº¤æ¥äººç»ä¸è§£ææâåå·¥ID + ç¨æ·IDâ |
| | | updateObj.setUserId(null); |
| | | boolean handoverProvided = updateReqVO.getHandoverEmployeeId() != null |
| | | || updateReqVO.getHandoverUserId() != null; |
| | | if (handoverProvided) { |
| | | resolveHandoverTarget(updateObj, application.getUserId()); |
| | | Integer currentHandoverStatus = application.getHandoverStatus() != null |
| | | ? application.getHandoverStatus() : HANDOVER_STATUS_NOT_STARTED; |
| | | if (ObjUtil.notEqual(currentHandoverStatus, HANDOVER_STATUS_NOT_STARTED) |
| | | && !Objects.equals(updateObj.getHandoverEmployeeId(), application.getHandoverEmployeeId())) { |
| | | throw new ServiceException(RESIGNATION_HANDOVER_CHANGE_AFTER_START.getCode(), |
| | | String.format("å½å交æ¥ç¶æä¸º[%s]ï¼äº¤æ¥äºº[%s]ä¸è½åæ´æ¢ï¼è¯·å
å°äº¤æ¥ç¶æåé为[æªå¼å§]ï¼è¥å·²å®æäº¤æ¥ï¼è¯·éæ°æäº¤ç¦»èç³è¯·", |
| | | getHandoverStatusName(currentHandoverStatus), |
| | | getEmployeeDisplayName(application.getHandoverEmployeeId()))); |
| | | } |
| | | } |
| | | resignationApplicationMapper.updateById(updateObj); |
| | | storageAttachmentApi.updateAttachments("file", "hrm_resignation_application", updateReqVO.getId(), updateReqVO.getBlobIds()); |
| | | } |
| | |
| | | } |
| | | HrmResignationApplicationRespVO respVO = BeanUtils.toBean(application, HrmResignationApplicationRespVO.class); |
| | | fillUserNames(respVO, application); |
| | | fillApplicantEmployeeInfo(respVO, application); |
| | | if (application.getDeptId() != null) { |
| | | DeptRespDTO dept = deptApi.getDept(application.getDeptId()); |
| | | if (dept != null) { |
| | |
| | | } |
| | | respVO.setResignationTypeName(HrmResignationTypeEnum.getNameByStatus(application.getResignationType())); |
| | | respVO.setHandoverStatusName(getHandoverStatusName(application.getHandoverStatus())); |
| | | respVO.setHandoverDataStatusName(getHandoverStatusName(application.getHandoverDataStatus())); |
| | | respVO.setStatusName(HrmAuditStatusEnum.getNameByStatus(application.getStatus())); |
| | | respVO.setAttachmentList(storageAttachmentApi.listAttachments("hrm_resignation_application", id)); |
| | | return respVO; |
| | | } |
| | | |
| | | private void fillUserNames(HrmResignationApplicationRespVO respVO, HrmResignationApplicationDO application) { |
| | | Set<Long> userIds = Set.of(application.getUserId(), application.getHandoverUserId()) |
| | | .stream().filter(Objects::nonNull).collect(Collectors.toSet()); |
| | | Set<Long> userIds = Stream.of(application.getUserId(), application.getHandoverUserId()) |
| | | .filter(Objects::nonNull).collect(Collectors.toSet()); |
| | | Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(userIds); |
| | | if (application.getUserId() != null && userMap.containsKey(application.getUserId())) { |
| | | respVO.setUserName(userMap.get(application.getUserId()).getNickname()); |
| | |
| | | if (application.getHandoverUserId() != null && userMap.containsKey(application.getHandoverUserId())) { |
| | | respVO.setHandoverUserName(userMap.get(application.getHandoverUserId()).getNickname()); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * å¡«å
ç³è¯·äººå工信æ¯ï¼åå·¥ID ä¸å²ä½åç§°ï¼ä¾åç«¯åæ¾"ç³è¯·äºº + å²ä½" |
| | | */ |
| | | private void fillApplicantEmployeeInfo(HrmResignationApplicationRespVO respVO, |
| | | HrmResignationApplicationDO application) { |
| | | if (application.getUserId() == null) { |
| | | return; |
| | | } |
| | | HrmEmployeeDO employee = employeeService.getEmployeeByUserId(application.getUserId()); |
| | | if (employee == null) { |
| | | return; |
| | | } |
| | | respVO.setEmployeeId(employee.getId()); |
| | | respVO.setEmployeeName(employee.getName()); |
| | | if (StrUtil.isBlank(employee.getPostIds())) { |
| | | return; |
| | | } |
| | | List<Long> postIds = JSONUtil.toList(employee.getPostIds(), Long.class); |
| | | if (CollUtil.isEmpty(postIds)) { |
| | | return; |
| | | } |
| | | Map<Long, PostRespDTO> postMap = postApi.getPostMap(postIds); |
| | | respVO.setPostName(postIds.stream() |
| | | .filter(postMap::containsKey) |
| | | .map(id -> postMap.get(id).getName()) |
| | | .collect(Collectors.joining(","))); |
| | | } |
| | | |
| | | private String getHandoverStatusName(Integer handoverStatus) { |
| | |
| | | if (app.getUserId() != null && userMap.containsKey(app.getUserId())) { |
| | | vo.setUserName(userMap.get(app.getUserId()).getNickname()); |
| | | } |
| | | // ç³è¯·äººå工信æ¯ï¼åå·¥æªå»ºæ¡£æ¶ä¿æä¸ºç©º |
| | | HrmEmployeeDO applicantEmployee = app.getUserId() == null ? null |
| | | : employeeService.getEmployeeByUserId(app.getUserId()); |
| | | if (applicantEmployee != null) { |
| | | vo.setEmployeeId(applicantEmployee.getId()); |
| | | vo.setEmployeeName(applicantEmployee.getName()); |
| | | } |
| | | if (app.getHandoverUserId() != null && userMap.containsKey(app.getHandoverUserId())) { |
| | | vo.setHandoverUserName(userMap.get(app.getHandoverUserId()).getNickname()); |
| | | } |
| | |
| | | } |
| | | vo.setResignationTypeName(HrmResignationTypeEnum.getNameByStatus(app.getResignationType())); |
| | | vo.setHandoverStatusName(getHandoverStatusName(app.getHandoverStatus())); |
| | | vo.setHandoverDataStatusName(getHandoverStatusName(app.getHandoverDataStatus())); |
| | | vo.setStatusName(HrmAuditStatusEnum.getNameByStatus(app.getStatus())); |
| | | return vo; |
| | | }).collect(Collectors.toList()); |
| | |
| | | return; |
| | | } |
| | | |
| | | validateApproveCategoryAndProcessDefinition(); |
| | | ProcessDefinition processDefinition = bpmProcessDefinitionService.getActiveProcessDefinition(processDefinitionKey); |
| | | if (processDefinition == null) { |
| | | throw exception(RESIGNATION_APPLICATION_BPM_PROCESS_DEFINITION_NOT_EXISTS); |
| | | } |
| | | ProcessDefinition processDefinition = resolveActiveProcessDefinition(processDefinitionKey); |
| | | String processInstanceId = bpmProcessInstanceApi.createProcessInstance(userId, new BpmProcessInstanceCreateReqDTO() |
| | | .setProcessDefinitionKey(processDefinitionKey).setBusinessKey(String.valueOf(id))); |
| | | .setProcessDefinitionKey(processDefinition.getKey()).setBusinessKey(String.valueOf(id))); |
| | | resignationApplicationMapper.updateById(HrmResignationApplicationDO.builder() |
| | | .id(id) |
| | | .processInstanceId(processInstanceId) |
| | |
| | | if (!hasActiveDefinition) { |
| | | throw exception(RESIGNATION_APPLICATION_BPM_PROCESS_DEFINITION_NOT_EXISTS); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * è§£æç¦»è审æ¹å¯ç¨çæµç¨å®ä¹ |
| | | * <p> |
| | | * å端åå²çæ¬æåç±»ç¼ç (hrm_resignation_approve)å½ä½æµç¨ Key ä¼ å
¥ï¼ |
| | | * è¿éä¼å
使ç¨ä¼ å
¥ Keyï¼å¹é
ä¸å°æ¶åéå°æ å Keyï¼ååéå°è¯¥åç±»ä¸å¯ä¸çæ¿æ´»æµç¨ã |
| | | */ |
| | | private ProcessDefinition resolveActiveProcessDefinition(String processDefinitionKey) { |
| | | validateApproveCategoryAndProcessDefinition(); |
| | | List<BpmProcessDefinitionInfoDO> definitionInfoList = bpmProcessDefinitionService |
| | | .getProcessDefinitionInfoListByCategory(APPROVE_CATEGORY_CODE); |
| | | Set<String> processDefinitionIds = convertSet(definitionInfoList, BpmProcessDefinitionInfoDO::getProcessDefinitionId); |
| | | List<ProcessDefinition> processDefinitions = bpmProcessDefinitionService.getProcessDefinitionList(processDefinitionIds); |
| | | Map<String, ProcessDefinition> latestVersionMap = new HashMap<>(); |
| | | for (ProcessDefinition pd : processDefinitions) { |
| | | if (pd.isSuspended()) { |
| | | continue; |
| | | } |
| | | ProcessDefinition existing = latestVersionMap.get(pd.getKey()); |
| | | if (existing == null || pd.getVersion() > existing.getVersion()) { |
| | | latestVersionMap.put(pd.getKey(), pd); |
| | | } |
| | | } |
| | | if (latestVersionMap.isEmpty()) { |
| | | throw exception(RESIGNATION_APPLICATION_BPM_PROCESS_DEFINITION_NOT_EXISTS); |
| | | } |
| | | if (StrUtil.isNotBlank(processDefinitionKey) && latestVersionMap.containsKey(processDefinitionKey)) { |
| | | return latestVersionMap.get(processDefinitionKey); |
| | | } |
| | | if (latestVersionMap.containsKey(BPM_PROCESS_DEFINITION_KEY)) { |
| | | return latestVersionMap.get(BPM_PROCESS_DEFINITION_KEY); |
| | | } |
| | | if (latestVersionMap.size() == 1) { |
| | | return latestVersionMap.values().iterator().next(); |
| | | } |
| | | throw new ServiceException(RESIGNATION_APPLICATION_BPM_PROCESS_DEFINITION_NOT_EXISTS.getCode(), |
| | | String.format("离èå®¡æ¹æµç¨ä¸å¯ä¸(åç±»=%sï¼å¯ç¨Key=%s)ï¼è¯·ä¼ å
¥å
·ä½çæµç¨å®ä¹Keyåéè¯", |
| | | APPROVE_CATEGORY_CODE, String.join(",", latestVersionMap.keySet()))); |
| | | } |
| | | |
| | | @Override |
| | |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void updateHandoverStatus(HrmResignationHandoverReqVO reqVO) { |
| | | HrmResignationApplicationDO application = validateResignationApplicationExists(reqVO.getId()); |
| | | resignationApplicationMapper.updateById(HrmResignationApplicationDO.builder() |
| | | .id(reqVO.getId()) |
| | | .handoverStatus(reqVO.getHandoverStatus()) |
| | | .build()); |
| | | // 交æ¥å®ææ¶ï¼åå»ºç¨æ·æ°æ®äº¤æ¥æ å° |
| | | if (Objects.equals(reqVO.getHandoverStatus(), HANDOVER_STATUS_COMPLETED) |
| | | && application.getHandoverUserId() != null) { |
| | | handoverService.createHandover( |
| | | application.getUserId(), |
| | | application.getHandoverUserId(), |
| | | application.getId()); |
| | | Integer targetStatus = reqVO.getHandoverStatus(); |
| | | if (!Objects.equals(targetStatus, HANDOVER_STATUS_NOT_STARTED) |
| | | && !Objects.equals(targetStatus, HANDOVER_STATUS_IN_PROGRESS) |
| | | && !Objects.equals(targetStatus, HANDOVER_STATUS_COMPLETED)) { |
| | | throw new ServiceException(RESIGNATION_HANDOVER_STATUS_INVALID.getCode(), |
| | | String.format("交æ¥ç¶æå¼[%s]ä¸åæ³ï¼ä»
æ¯æ 0(æªå¼å§)ã10(è¿è¡ä¸)ã20(已宿)", targetStatus)); |
| | | } |
| | | if (!Objects.equals(application.getStatus(), HrmAuditStatusEnum.APPROVE.getStatus())) { |
| | | throw new ServiceException(RESIGNATION_HANDOVER_NOT_APPROVED.getCode(), |
| | | String.format("离èç³è¯·[%s]å½å审æ¹ç¶æä¸º[%s]ï¼å®¡æ¹éè¿åæè½äº¤æ¥ï¼è¯·å
宿审æ¹åæä½", |
| | | application.getNo(), HrmAuditStatusEnum.getNameByStatus(application.getStatus()))); |
| | | } |
| | | Integer currentStatus = application.getHandoverStatus() != null |
| | | ? application.getHandoverStatus() : HANDOVER_STATUS_NOT_STARTED; |
| | | if (Objects.equals(currentStatus, HANDOVER_STATUS_COMPLETED) |
| | | && !Objects.equals(targetStatus, HANDOVER_STATUS_COMPLETED)) { |
| | | throw new ServiceException(RESIGNATION_HANDOVER_COMPLETED_CANNOT_REVERT.getCode(), |
| | | String.format("å½å交æ¥ç¶æä¸º[已宿]ï¼ä¸è½ä¿®æ¹ä¸º[%s]ï¼å¦ééæ°äº¤æ¥ï¼è¯·å é¤è¯¥ç¦»èç³è¯·åéæ°æäº¤", |
| | | getHandoverStatusName(targetStatus))); |
| | | } |
| | | // 审æ¹éè¿åå
è®¸ä¸æ¥å®æäº¤æ¥ï¼æªå¼å§æè¿è¡ä¸åå¯ç´æ¥ç½®ä¸ºå·²å®æï¼é¿å
å¤ä¸æ¬¡æ æä¹çç¹å» |
| | | if (Objects.equals(targetStatus, HANDOVER_STATUS_COMPLETED)) { |
| | | completeHandover(application); |
| | | return; |
| | | } |
| | | if (Objects.equals(targetStatus, HANDOVER_STATUS_NOT_STARTED) |
| | | && !Objects.equals(currentStatus, HANDOVER_STATUS_NOT_STARTED) |
| | | && !Objects.equals(currentStatus, HANDOVER_STATUS_IN_PROGRESS)) { |
| | | throw new ServiceException(RESIGNATION_HANDOVER_COMPLETED_CANNOT_REVERT.getCode(), |
| | | String.format("å½å交æ¥ç¶æä¸º[%s]ï¼ä¸è½åé为[æªå¼å§]ï¼å¦ééæ°äº¤æ¥ï¼è¯·å é¤è¯¥ç¦»èç³è¯·åéæ°æäº¤", |
| | | getHandoverStatusName(currentStatus))); |
| | | } |
| | | // è¿è¡ä¸ï¼å¿
须已æå®äº¤æ¥åå·¥ï¼æªå¼å§ï¼å
è®¸å¨æªæå®äº¤æ¥äººæ¶åé |
| | | if (Objects.equals(targetStatus, HANDOVER_STATUS_IN_PROGRESS)) { |
| | | resolveStoredHandoverTarget(application); |
| | | } |
| | | resignationApplicationMapper.updateById(HrmResignationApplicationDO.builder() |
| | | .id(application.getId()) |
| | | .handoverStatus(targetStatus) |
| | | .handoverDataStatus(targetStatus) |
| | | .build()); |
| | | } |
| | | |
| | | /** |
| | | * 宿工ä½äº¤æ¥ï¼åå
¥ åå·¥ID + ç¨æ·ID äº¤æ¥æ å°ï¼äº¤æ¥äººéè¿ expandUserIds è·å¾ç¦»è人çä¸å¡æ°æ® |
| | | */ |
| | | private void completeHandover(HrmResignationApplicationDO application) { |
| | | resolveStoredHandoverTarget(application); |
| | | // ç³è¯·äººæªå»ºåå·¥æ¡£æ¡æ¶ï¼å¦ç®¡çåè´¦å·ï¼ï¼ä»å»ºç«ç¨æ·çº§äº¤æ¥æ å°ï¼ä¿è¯å
¶ä¸å¡æ°æ®è½è½¬äº¤ï¼å工侧 ID 为空 |
| | | HrmEmployeeDO fromEmployee = employeeService.getEmployeeByUserId(application.getUserId()); |
| | | if (fromEmployee == null) { |
| | | log.warn("[completeHandover][离èç³è¯·({}) ç³è¯·äºº(ç¨æ·ID={}) æªå
³èå工档æ¡ï¼ä»
建ç«ç¨æ·çº§äº¤æ¥æ å°]", |
| | | application.getNo(), application.getUserId()); |
| | | } |
| | | handoverService.createHandover(fromEmployee != null ? fromEmployee.getId() : null, |
| | | application.getUserId(), |
| | | application.getHandoverEmployeeId(), application.getHandoverUserId(), application.getId()); |
| | | resignationApplicationMapper.updateById(HrmResignationApplicationDO.builder() |
| | | .id(application.getId()) |
| | | .handoverStatus(HANDOVER_STATUS_COMPLETED) |
| | | .handoverDataStatus(HANDOVER_STATUS_COMPLETED) |
| | | .build()); |
| | | } |
| | | |
| | | /** |
| | | * æ ¡éªå¹¶åå¡«å·²ä¿åç交æ¥äººï¼å
¼å®¹å岿°æ®åªåäº handoverUserId çæ
åµï¼ |
| | | */ |
| | | private void resolveStoredHandoverTarget(HrmResignationApplicationDO application) { |
| | | if (application.getHandoverEmployeeId() == null && application.getHandoverUserId() == null) { |
| | | throw new ServiceException(RESIGNATION_HANDOVER_TARGET_REQUIRED.getCode(), |
| | | String.format("离èç³è¯·[%s]æªæå®äº¤æ¥åå·¥ï¼æ æ³å¼å§æå®æäº¤æ¥ï¼è¯·å
ç¼è¾ç³è¯·å¹¶éæ©äº¤æ¥äºº", |
| | | application.getNo())); |
| | | } |
| | | resolveHandoverTarget(application, application.getUserId()); |
| | | resignationApplicationMapper.updateById(HrmResignationApplicationDO.builder() |
| | | .id(application.getId()) |
| | | .handoverEmployeeId(application.getHandoverEmployeeId()) |
| | | .handoverUserId(application.getHandoverUserId()) |
| | | .build()); |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void cancelResignationApplication(Long id, Long userId) { |
| | | HrmResignationApplicationDO application = validateResignationApplicationExists(id); |
| | | Integer status = application.getStatus(); |
| | | if (Objects.equals(status, HrmAuditStatusEnum.DRAFT.getStatus())) { |
| | | resignationApplicationMapper.updateById(HrmResignationApplicationDO.builder() |
| | | .id(id) |
| | | .status(HrmAuditStatusEnum.CANCEL.getStatus()) |
| | | .build()); |
| | | return; |
| | | } |
| | | if (!Objects.equals(status, HrmAuditStatusEnum.PROCESS.getStatus())) { |
| | | throw new ServiceException(RESIGNATION_APPLICATION_CANCEL_FAIL_STATUS.getCode(), |
| | | String.format("离èç³è¯·[%s]å½å审æ¹ç¶æä¸º[%s]ï¼ä»
è稿æå®¡æ¹ä¸ç¶æå¯ä»¥æ¤é", |
| | | application.getNo(), HrmAuditStatusEnum.getNameByStatus(status))); |
| | | } |
| | | if (StrUtil.isNotBlank(application.getProcessInstanceId())) { |
| | | BpmProcessInstanceCancelReqVO cancelReqVO = new BpmProcessInstanceCancelReqVO(); |
| | | cancelReqVO.setId(application.getProcessInstanceId()); |
| | | cancelReqVO.setReason("ç³è¯·äººæ¤é离èç³è¯·ï¼" + application.getNo()); |
| | | Long startUserId = userId != null ? userId : application.getUserId(); |
| | | bpmProcessInstanceService.cancelProcessInstanceByStartUser(startUserId, cancelReqVO); |
| | | // æµç¨çå¬å¨ä¼åæ¥æ´æ°ç¶æï¼å
åºå¤çæªæ¶å°åè°çåºæ¯ |
| | | HrmResignationApplicationDO latest = resignationApplicationMapper.selectById(id); |
| | | if (latest != null && Objects.equals(latest.getStatus(), HrmAuditStatusEnum.PROCESS.getStatus())) { |
| | | resignationApplicationMapper.updateById(HrmResignationApplicationDO.builder() |
| | | .id(id) |
| | | .status(HrmAuditStatusEnum.CANCEL.getStatus()) |
| | | .build()); |
| | | } |
| | | return; |
| | | } |
| | | // æ æµç¨å®ä¾ï¼åå²å
å®¡æ¹æ°æ®ï¼ç´æ¥æ¤é |
| | | resignationApplicationMapper.updateById(HrmResignationApplicationDO.builder() |
| | | .id(id) |
| | | .status(HrmAuditStatusEnum.CANCEL.getStatus()) |
| | | .build()); |
| | | } |
| | | |
| | | @Override |
| | | public int autoLeaveResignationApplication() { |
| | | LocalDate today = LocalDate.now(); |
| | | List<HrmResignationApplicationDO> applications = resignationApplicationMapper |
| | | .selectListByStatusAndExpectedDateLe(HrmAuditStatusEnum.APPROVE.getStatus(), today); |
| | | int count = 0; |
| | | for (HrmResignationApplicationDO application : applications) { |
| | | if (application.getUserId() == null) { |
| | | log.warn("[autoLeaveResignationApplication][ç³è¯·({}) 缺å°ç³è¯·äººç¨æ·IDï¼è·³è¿]", application.getId()); |
| | | continue; |
| | | } |
| | | // 1. åç¨ç³»ç»ç»å½è´¦å· |
| | | AdminUserRespDTO user = adminUserApi.getUser(application.getUserId()); |
| | | if (user == null) { |
| | | log.warn("[autoLeaveResignationApplication][ç³è¯·({}) ç³è¯·äºº(ç¨æ·ID={}) ä¸åå¨ï¼è·³è¿è´¦å·åç¨]", |
| | | application.getId(), application.getUserId()); |
| | | } else if (!Objects.equals(user.getStatus(), CommonStatusEnum.DISABLE.getStatus())) { |
| | | adminUserApi.updateUserStatus(application.getUserId(), CommonStatusEnum.DISABLE.getStatus()); |
| | | log.info("[autoLeaveResignationApplication][ç¨æ·({}) å°è¾¾ç¦»èæ¥æ({})ï¼ç³»ç»è´¦å·å·²åç¨]", |
| | | application.getUserId(), application.getExpectedDate()); |
| | | } |
| | | // 2. å工档æ¡ç½®ä¸ºç¦»è |
| | | HrmEmployeeDO employee = employeeService.getEmployeeByUserId(application.getUserId()); |
| | | if (employee == null) { |
| | | log.warn("[autoLeaveResignationApplication][ç³è¯·({}) ç³è¯·äºº(ç¨æ·ID={}) æ å工档æ¡ï¼è·³è¿ï¼è¯·å
建ç«å工档æ¡]", |
| | | application.getId(), application.getUserId()); |
| | | continue; |
| | | } |
| | | if (!Objects.equals(employee.getEmployeeStatus(), EMPLOYEE_STATUS_RESIGNED)) { |
| | | employeeService.updateEmployeeStatusToResignedByUserId(application.getUserId(), |
| | | application.getExpectedDate()); |
| | | log.info("[autoLeaveResignationApplication][åå·¥({}) å°è¾¾ç¦»èæ¥æ({})ï¼ç¶æå·²æ´æ°ä¸ºç¦»è]", |
| | | employee.getId(), application.getExpectedDate()); |
| | | } |
| | | resignationApplicationMapper.updateById(HrmResignationApplicationDO.builder() |
| | | .id(application.getId()) |
| | | .actualDate(application.getExpectedDate()) |
| | | .build()); |
| | | count++; |
| | | } |
| | | return count; |
| | | } |
| | | |
| | | /** |
| | | * è§£æäº¤æ¥åå·¥ä¸ç³»ç»ç¨æ·ï¼ä¿è¯ handoverEmployeeId / handoverUserId æå¯¹ä¸ææ |
| | | * <p> |
| | | * å
¼å®¹å端æâ交æ¥äººâ䏿çåå·¥IDåå
¥ handoverUserId çåå²æäº¤æ¹å¼ï¼ |
| | | * å
æ handoverEmployeeId è§£æï¼æ²¡ææ¶æ handoverUserId å½åå·¥IDå°è¯ï¼åæç¨æ·IDè§£æã |
| | | */ |
| | | private void resolveHandoverTarget(HrmResignationApplicationDO application, Long applyUserId) { |
| | | Long employeeId = application.getHandoverEmployeeId(); |
| | | Long userId = application.getHandoverUserId(); |
| | | if (employeeId == null && userId == null) { |
| | | return; |
| | | } |
| | | HrmEmployeeDO employee; |
| | | if (employeeId != null) { |
| | | employee = employeeMapper.selectById(employeeId); |
| | | if (employee == null) { |
| | | throw new ServiceException(RESIGNATION_HANDOVER_EMPLOYEE_NOT_EXISTS.getCode(), |
| | | String.format("交æ¥åå·¥(ID=%s)ä¸åå¨ï¼è¯·éæ°éæ©äº¤æ¥åå·¥", employeeId)); |
| | | } |
| | | } else { |
| | | // åå²å端ï¼handoverUserId å®é
ä¼ çæ¯åå·¥ID |
| | | employee = employeeMapper.selectById(userId); |
| | | if (employee == null) { |
| | | AdminUserRespDTO user = adminUserApi.getUser(userId); |
| | | if (user == null) { |
| | | throw new ServiceException(RESIGNATION_HANDOVER_EMPLOYEE_NOT_EXISTS.getCode(), |
| | | String.format("交æ¥äºº(ID=%s)å¨å工档æ¡åç³»ç»ç¨æ·ä¸åä¸åå¨ï¼è¯·éæ°éæ©äº¤æ¥åå·¥", userId)); |
| | | } |
| | | employee = employeeMapper.selectByUserId(userId); |
| | | if (employee == null) { |
| | | throw new ServiceException(RESIGNATION_HANDOVER_EMPLOYEE_NO_USER.getCode(), |
| | | String.format("交æ¥äºº[%s](ç¨æ·ID=%s)æªå
³èå工档æ¡ï¼æ æ³ç¡®å®äº¤æ¥åå·¥ï¼è¯·å
å¨å工管çä¸ä¸ºè¯¥ç¨æ·å»ºç«å工档æ¡", |
| | | user.getNickname(), userId)); |
| | | } |
| | | } |
| | | employeeId = employee.getId(); |
| | | } |
| | | if (employee.getUserId() == null) { |
| | | throw new ServiceException(RESIGNATION_HANDOVER_EMPLOYEE_NO_USER.getCode(), |
| | | String.format("交æ¥åå·¥[%s](åå·¥ID=%s)æªå
³èç³»ç»ç¨æ·ï¼æ æ³è½¬ç§»å
¶ç¨æ·æ°æ®ï¼è¯·å
å¨å工管çä¸å
³èç³»ç»ç¨æ·", |
| | | employee.getName(), employee.getId())); |
| | | } |
| | | if (applyUserId != null && Objects.equals(employee.getUserId(), applyUserId)) { |
| | | throw new ServiceException(RESIGNATION_HANDOVER_SELF.getCode(), |
| | | String.format("交æ¥äºº[%s](åå·¥ID=%s)ä¸ç³è¯·äººæ¯åä¸äººï¼è¯·éæ©å
¶ä»åå·¥", |
| | | employee.getName(), employee.getId())); |
| | | } |
| | | if (Objects.equals(employee.getEmployeeStatus(), EMPLOYEE_STATUS_RESIGNED)) { |
| | | throw new ServiceException(RESIGNATION_HANDOVER_EMPLOYEE_RESIGNED.getCode(), |
| | | String.format("交æ¥åå·¥[%s](åå·¥ID=%s)å½åå·²æ¯ç¦»èç¶æï¼è¯·éæ°éæ©å¨èåå·¥", |
| | | employee.getName(), employee.getId())); |
| | | } |
| | | application.setHandoverEmployeeId(employeeId); |
| | | application.setHandoverUserId(employee.getUserId()); |
| | | } |
| | | |
| | | private String getEmployeeDisplayName(Long employeeId) { |
| | | if (employeeId == null) { |
| | | return "æªéæ©"; |
| | | } |
| | | HrmEmployeeDO employee = employeeMapper.selectById(employeeId); |
| | | return employee != null ? String.format("%s(ID=%s)", employee.getName(), employeeId) |
| | | : String.format("ID=%s", employeeId); |
| | | } |
| | | |
| | | } |
| | |
| | | import cn.iocoder.yudao.module.hrm.controller.admin.employee.vo.HrmEmployeeRespVO; |
| | | import cn.iocoder.yudao.module.hrm.controller.admin.employee.vo.HrmEmployeeSaveReqVO; |
| | | import cn.iocoder.yudao.module.hrm.controller.admin.employee.vo.HrmEmployeeSimpleRespVO; |
| | | import cn.iocoder.yudao.module.hrm.controller.admin.employee.vo.HrmEmployeeStatisticsRespVO; |
| | | import cn.iocoder.yudao.module.hrm.dal.dataobject.employee.HrmEmployeeDO; |
| | | import jakarta.validation.Valid; |
| | | |
| | |
| | | HrmEmployeeImportRespVO importEmployeeList(List<HrmEmployeeImportExcelVO> importEmployees, |
| | | HrmEmployeeImportReqVO importReqVO); |
| | | |
| | | /** |
| | | * å°æå®ç³»ç»ç¨æ·å¯¹åºçåå·¥ç¶ææ´æ°ä¸ºç¦»èï¼å¹¶è®°å½ç¦»èæ¥æ |
| | | * |
| | | * @param userId ç³»ç»ç¨æ·ç¼å· |
| | | * @param leaveDate ç¦»èæ¥æ |
| | | * @return æ¯å¦æ´æ°å°åå·¥æ¡£æ¡ |
| | | */ |
| | | boolean updateEmployeeStatusToResignedByUserId(Long userId, java.time.LocalDate leaveDate); |
| | | |
| | | /** |
| | | * è·å¾å工人åç»è®¡ï¼å·¥é¾ãå¹´é¾ãå¦åãæ§å«ãé¨é¨å·¥é¾çï¼ |
| | | * |
| | | * @return 人åç»è®¡æ°æ® |
| | | */ |
| | | HrmEmployeeStatisticsRespVO getTenureStatistics(); |
| | | |
| | | } |
| | |
| | | import cn.iocoder.yudao.module.hrm.controller.admin.employee.vo.HrmEmployeeRespVO; |
| | | import cn.iocoder.yudao.module.hrm.controller.admin.employee.vo.HrmEmployeeSaveReqVO; |
| | | import cn.iocoder.yudao.module.hrm.controller.admin.employee.vo.HrmEmployeeSimpleRespVO; |
| | | import cn.iocoder.yudao.module.hrm.controller.admin.employee.vo.HrmEmployeeStatisticsRespVO; |
| | | import cn.iocoder.yudao.module.hrm.controller.admin.employee.vo.HrmEmployeeWorkHistorySaveReqVO; |
| | | import cn.iocoder.yudao.module.hrm.dal.dataobject.employee.HrmEmployeeContractDO; |
| | | import cn.iocoder.yudao.module.hrm.dal.dataobject.employee.HrmEmployeeDO; |
| | | import cn.iocoder.yudao.module.hrm.dal.dataobject.employee.HrmEmployeeEducationDO; |
| | | import cn.iocoder.yudao.module.hrm.dal.dataobject.employee.HrmEmployeeEmergencyContactDO; |
| | | import cn.iocoder.yudao.module.hrm.dal.dataobject.employee.HrmEmployeeWorkHistoryDO; |
| | | import cn.iocoder.yudao.module.hrm.dal.mysql.employee.HrmEmployeeContractMapper; |
| | | import cn.iocoder.yudao.module.hrm.dal.mysql.employee.HrmEmployeeEducationMapper; |
| | | import cn.iocoder.yudao.module.hrm.dal.mysql.employee.HrmEmployeeEmergencyContactMapper; |
| | | import cn.iocoder.yudao.module.hrm.dal.mysql.employee.HrmEmployeeMapper; |
| | |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | import org.springframework.validation.annotation.Validated; |
| | | |
| | | import java.time.LocalDate; |
| | | import java.time.YearMonth; |
| | | import java.time.temporal.ChronoUnit; |
| | | import java.util.ArrayList; |
| | | import java.util.Collection; |
| | | import java.util.Collections; |
| | | import java.util.Comparator; |
| | | import java.util.HashSet; |
| | | import java.util.LinkedHashMap; |
| | | import java.util.LinkedHashSet; |
| | | import java.util.List; |
| | |
| | | @Validated |
| | | public class HrmEmployeeServiceImpl implements HrmEmployeeService { |
| | | |
| | | /** åå·¥ç¶æï¼ç¦»è */ |
| | | private static final Integer EMPLOYEE_STATUS_RESIGNED = 3; |
| | | |
| | | @Resource |
| | | private HrmEmployeeMapper employeeMapper; |
| | | @Resource |
| | | private HrmEmployeeEducationMapper educationMapper; |
| | | @Resource |
| | | private HrmEmployeeContractMapper contractMapper; |
| | | @Resource |
| | | private HrmEmployeeWorkHistoryMapper workHistoryMapper; |
| | | @Resource |
| | |
| | | } |
| | | |
| | | @Override |
| | | public boolean updateEmployeeStatusToResignedByUserId(Long userId, LocalDate leaveDate) { |
| | | if (userId == null) { |
| | | return false; |
| | | } |
| | | return employeeMapper.updateEmployeeStatusByUserId(userId, EMPLOYEE_STATUS_RESIGNED, leaveDate) > 0; |
| | | } |
| | | |
| | | @Override |
| | | public HrmEmployeeDO getEmployeeByName(String name) { |
| | | return employeeMapper.selectByName(name); |
| | | } |
| | |
| | | return roleIds; |
| | | } |
| | | |
| | | // ==================== 人åç»è®¡ ==================== |
| | | |
| | | /** åå·¥ç¶æï¼å¨è */ |
| | | private static final Integer EMPLOYEE_STATUS_ACTIVE = 1; |
| | | /** åå·¥ç¶æï¼è¯ç¨ */ |
| | | private static final Integer EMPLOYEE_STATUS_PROBATION = 2; |
| | | |
| | | /** å·¥é¾åºé´åç§°ï¼ä¸ä¸éï¼å«ï¼ä¸ä¸å¯¹åºï¼æå䏿¡£æ ä¸é */ |
| | | private static final String[] TENURE_BUCKET_NAMES = {"1年以å
", "1-3å¹´", "3-5å¹´", "5-10å¹´", "10年以ä¸"}; |
| | | private static final double[] TENURE_BUCKET_MIN = {0, 1, 3, 5, 10}; |
| | | |
| | | /** å¹´é¾åºé´åç§°ï¼ä¸ä¸éï¼å«ï¼ä¸ä¸å¯¹åºï¼æå䏿¡£æ ä¸é */ |
| | | private static final String[] AGE_BUCKET_NAMES = {"25å²ä»¥ä¸", "25-30å²", "30-35å²", "35-40å²", "40-50å²", "50å²ä»¥ä¸"}; |
| | | private static final int[] AGE_BUCKET_MIN = {0, 25, 30, 35, 40, 50}; |
| | | |
| | | @Override |
| | | public HrmEmployeeStatisticsRespVO getTenureStatistics() { |
| | | List<HrmEmployeeDO> allEmployees = employeeMapper.selectList(); |
| | | LocalDate today = LocalDate.now(); |
| | | int currentYear = today.getYear(); |
| | | |
| | | List<HrmEmployeeDO> activeEmployees = allEmployees.stream() |
| | | .filter(e -> Objects.equals(e.getEmployeeStatus(), EMPLOYEE_STATUS_ACTIVE) |
| | | || Objects.equals(e.getEmployeeStatus(), EMPLOYEE_STATUS_PROBATION)) |
| | | .collect(Collectors.toList()); |
| | | |
| | | HrmEmployeeStatisticsRespVO respVO = new HrmEmployeeStatisticsRespVO(); |
| | | respVO.setTotalCount(activeEmployees.size()); |
| | | respVO.setActiveCount((int) activeEmployees.stream() |
| | | .filter(e -> Objects.equals(e.getEmployeeStatus(), EMPLOYEE_STATUS_ACTIVE)).count()); |
| | | respVO.setProbationCount((int) activeEmployees.stream() |
| | | .filter(e -> Objects.equals(e.getEmployeeStatus(), EMPLOYEE_STATUS_PROBATION)).count()); |
| | | respVO.setResignedCount((int) allEmployees.stream() |
| | | .filter(e -> Objects.equals(e.getEmployeeStatus(), EMPLOYEE_STATUS_RESIGNED)).count()); |
| | | // æ¬å¹´å
¥èï¼å¨å²åå·¥ä¸å
¥èæ¥æè½å¨ä»å¹´ |
| | | respVO.setThisYearHireCount((int) activeEmployees.stream() |
| | | .filter(e -> e.getHireDate() != null && e.getHireDate().getYear() == currentYear).count()); |
| | | // æ¬å¹´ç¦»èï¼ç¦»èåå·¥ä¸ç¦»èæ¥æè½å¨ä»å¹´ |
| | | respVO.setThisYearResignCount((int) allEmployees.stream() |
| | | .filter(e -> Objects.equals(e.getEmployeeStatus(), EMPLOYEE_STATUS_RESIGNED)) |
| | | .filter(e -> e.getLeaveDate() != null && e.getLeaveDate().getYear() == currentYear).count()); |
| | | |
| | | // 1. å¹³åå·¥é¾ãå¹³åå¹´é¾ |
| | | List<Double> tenureList = activeEmployees.stream() |
| | | .map(e -> calculateTenureYears(e, today)) |
| | | .filter(Objects::nonNull) |
| | | .collect(Collectors.toList()); |
| | | respVO.setAverageTenureYears(averageOf(tenureList)); |
| | | List<Integer> ageList = activeEmployees.stream() |
| | | .map(e -> resolveAge(e, today)) |
| | | .filter(Objects::nonNull) |
| | | .collect(Collectors.toList()); |
| | | respVO.setAverageAge(averageOfInt(ageList)); |
| | | |
| | | // 2. å·¥é¾åå¸ |
| | | int[] tenureCounts = new int[TENURE_BUCKET_NAMES.length]; |
| | | for (Double tenure : tenureList) { |
| | | tenureCounts[resolveTenureBucket(tenure)]++; |
| | | } |
| | | List<HrmEmployeeStatisticsRespVO.ItemVO> tenureDistribution = new ArrayList<>(); |
| | | for (int i = 0; i < TENURE_BUCKET_NAMES.length; i++) { |
| | | tenureDistribution.add(new HrmEmployeeStatisticsRespVO.ItemVO(TENURE_BUCKET_NAMES[i], tenureCounts[i])); |
| | | } |
| | | respVO.setTenureDistribution(tenureDistribution); |
| | | |
| | | // 3. å¹´é¾åå¸ |
| | | int[] ageCounts = new int[AGE_BUCKET_NAMES.length]; |
| | | for (Integer age : ageList) { |
| | | ageCounts[resolveAgeBucket(age)]++; |
| | | } |
| | | List<HrmEmployeeStatisticsRespVO.ItemVO> ageDistribution = new ArrayList<>(); |
| | | for (int i = 0; i < AGE_BUCKET_NAMES.length; i++) { |
| | | ageDistribution.add(new HrmEmployeeStatisticsRespVO.ItemVO(AGE_BUCKET_NAMES[i], ageCounts[i])); |
| | | } |
| | | respVO.setAgeDistribution(ageDistribution); |
| | | |
| | | // 4. å¦ååå¸ï¼æªå¡«åçå½å
¥âæªå¡«åâï¼ |
| | | Map<String, Integer> educationMap = new LinkedHashMap<>(); |
| | | activeEmployees.stream() |
| | | .map(e -> StrUtil.blankToDefault(StrUtil.trim(e.getEducation()), "æªå¡«å")) |
| | | .forEach(name -> educationMap.merge(name, 1, Integer::sum)); |
| | | respVO.setEducationDistribution(toItemListSorted(educationMap)); |
| | | |
| | | // 5. æ§å«åå¸ï¼1 ç· / 2 女 / å
¶å® æªç¥ï¼ |
| | | Map<String, Integer> genderMap = new LinkedHashMap<>(); |
| | | activeEmployees.forEach(e -> { |
| | | String name = Objects.equals(e.getGender(), 1) ? "ç·" : Objects.equals(e.getGender(), 2) ? "女" : "æªç¥"; |
| | | genderMap.merge(name, 1, Integer::sum); |
| | | }); |
| | | respVO.setGenderDistribution(toItemListSorted(genderMap)); |
| | | |
| | | // 6. é¨é¨å·¥é¾ç»è®¡ |
| | | Set<Long> deptIds = activeEmployees.stream() |
| | | .map(HrmEmployeeDO::getDeptId) |
| | | .filter(Objects::nonNull) |
| | | .collect(Collectors.toSet()); |
| | | Map<Long, DeptRespDTO> deptMap = CollUtil.isEmpty(deptIds) ? Collections.emptyMap() : deptApi.getDeptMap(deptIds); |
| | | Map<Long, List<Double>> deptTenureMap = new LinkedHashMap<>(); |
| | | Map<Long, String> deptNameMap = new LinkedHashMap<>(); |
| | | for (HrmEmployeeDO employee : activeEmployees) { |
| | | Double tenure = calculateTenureYears(employee, today); |
| | | if (employee.getDeptId() == null) { |
| | | deptTenureMap.computeIfAbsent(0L, k -> new ArrayList<>()).add(tenure == null ? 0D : tenure); |
| | | deptNameMap.putIfAbsent(0L, "æªåé
é¨é¨"); |
| | | continue; |
| | | } |
| | | deptTenureMap.computeIfAbsent(employee.getDeptId(), k -> new ArrayList<>()) |
| | | .add(tenure == null ? 0D : tenure); |
| | | DeptRespDTO dept = deptMap.get(employee.getDeptId()); |
| | | deptNameMap.put(employee.getDeptId(), dept != null ? dept.getName() : "é¨é¨ID=" + employee.getDeptId()); |
| | | } |
| | | List<HrmEmployeeStatisticsRespVO.DeptTenureVO> deptTenureList = new ArrayList<>(); |
| | | deptTenureMap.forEach((deptId, tenures) -> { |
| | | HrmEmployeeStatisticsRespVO.DeptTenureVO deptVO = new HrmEmployeeStatisticsRespVO.DeptTenureVO(); |
| | | deptVO.setDeptId(deptId == 0L ? null : deptId); |
| | | deptVO.setDeptName(deptNameMap.get(deptId)); |
| | | deptVO.setCount(tenures.size()); |
| | | deptVO.setAverageTenureYears(averageOf(tenures)); |
| | | deptTenureList.add(deptVO); |
| | | }); |
| | | deptTenureList.sort(Comparator.comparing(HrmEmployeeStatisticsRespVO.DeptTenureVO::getAverageTenureYears, |
| | | Comparator.nullsLast(Comparator.reverseOrder()))); |
| | | respVO.setDeptTenureList(deptTenureList); |
| | | |
| | | // 6.1 é¨é¨äººæ°åå¸ï¼ä¸é¨é¨å·¥é¾åä¸ä»½åç»ï¼ç´æ¥å¤ç¨ï¼ |
| | | Map<String, Integer> deptCountMap = new LinkedHashMap<>(); |
| | | deptTenureMap.forEach((deptId, tenures) -> deptCountMap.put(deptNameMap.get(deptId), tenures.size())); |
| | | respVO.setDeptDistribution(toItemListSorted(deptCountMap)); |
| | | |
| | | // 7. 工龿è¡ï¼å 10 åï¼ |
| | | respVO.setTopTenureEmployees(activeEmployees.stream() |
| | | .filter(e -> e.getHireDate() != null) |
| | | .sorted(Comparator.comparing(HrmEmployeeDO::getHireDate)) |
| | | .limit(10) |
| | | .map(e -> { |
| | | HrmEmployeeStatisticsRespVO.TenureEmployeeVO employeeVO = new HrmEmployeeStatisticsRespVO.TenureEmployeeVO(); |
| | | employeeVO.setId(e.getId()); |
| | | employeeVO.setName(e.getName()); |
| | | DeptRespDTO dept = e.getDeptId() == null ? null : deptMap.get(e.getDeptId()); |
| | | employeeVO.setDeptName(dept != null ? dept.getName() : (e.getDeptId() == null ? "æªåé
é¨é¨" : "é¨é¨ID=" + e.getDeptId())); |
| | | employeeVO.setHireDate(e.getHireDate()); |
| | | employeeVO.setTenureYears(calculateTenureYears(e, today)); |
| | | return employeeVO; |
| | | }) |
| | | .collect(Collectors.toList())); |
| | | |
| | | // 8. 人åç¶æææï¼å¨è / è¯ç¨ / 离èï¼å
¶ä½ç¶æå½å
¥âå
¶å®âï¼ |
| | | int activeStatusCount = (int) activeEmployees.stream() |
| | | .filter(e -> Objects.equals(e.getEmployeeStatus(), EMPLOYEE_STATUS_ACTIVE)).count(); |
| | | int probationStatusCount = (int) activeEmployees.stream() |
| | | .filter(e -> Objects.equals(e.getEmployeeStatus(), EMPLOYEE_STATUS_PROBATION)).count(); |
| | | int resignedStatusCount = (int) allEmployees.stream() |
| | | .filter(e -> Objects.equals(e.getEmployeeStatus(), EMPLOYEE_STATUS_RESIGNED)).count(); |
| | | List<HrmEmployeeStatisticsRespVO.ItemVO> statusDistribution = new ArrayList<>(); |
| | | statusDistribution.add(new HrmEmployeeStatisticsRespVO.ItemVO("å¨è", activeStatusCount)); |
| | | statusDistribution.add(new HrmEmployeeStatisticsRespVO.ItemVO("è¯ç¨", probationStatusCount)); |
| | | statusDistribution.add(new HrmEmployeeStatisticsRespVO.ItemVO("离è", resignedStatusCount)); |
| | | int otherStatusCount = allEmployees.size() - activeStatusCount - probationStatusCount - resignedStatusCount; |
| | | if (otherStatusCount > 0) { |
| | | statusDistribution.add(new HrmEmployeeStatisticsRespVO.ItemVO("å
¶å®", otherStatusCount)); |
| | | } |
| | | respVO.setStatusDistribution(statusDistribution); |
| | | |
| | | // 9. å²ä½åå¸ï¼postIds 为 JSON æ°ç»ï¼å¯ä¸äººå¤å²ï¼æ å²ä½å½å
¥âæªåé
å²ä½âï¼ |
| | | Set<Long> postIds = new HashSet<>(); |
| | | for (HrmEmployeeDO employee : activeEmployees) { |
| | | if (StrUtil.isNotBlank(employee.getPostIds())) { |
| | | postIds.addAll(JSONUtil.toList(employee.getPostIds(), Long.class)); |
| | | } |
| | | } |
| | | Map<Long, PostRespDTO> postMap = CollUtil.isEmpty(postIds) ? Collections.emptyMap() : postApi.getPostMap(postIds); |
| | | Map<String, Integer> postCountMap = new LinkedHashMap<>(); |
| | | for (HrmEmployeeDO employee : activeEmployees) { |
| | | List<Long> employeePostIds = StrUtil.isNotBlank(employee.getPostIds()) |
| | | ? JSONUtil.toList(employee.getPostIds(), Long.class) : Collections.emptyList(); |
| | | if (CollUtil.isEmpty(employeePostIds)) { |
| | | postCountMap.merge("æªåé
å²ä½", 1, Integer::sum); |
| | | continue; |
| | | } |
| | | for (Long postId : employeePostIds) { |
| | | PostRespDTO post = postMap.get(postId); |
| | | postCountMap.merge(post != null ? post.getName() : "å²ä½ID=" + postId, 1, Integer::sum); |
| | | } |
| | | } |
| | | respVO.setPostDistribution(toItemListSorted(postCountMap)); |
| | | |
| | | // 10. å©å§»ç¶åµãæ¿æ²»é¢è²åå¸ï¼æ¡£æ¡èªç±ææ¬ï¼ç©ºå¼å½å
¥âæªå¡«åâï¼ |
| | | Map<String, Integer> marriageMap = new LinkedHashMap<>(); |
| | | Map<String, Integer> politicalMap = new LinkedHashMap<>(); |
| | | for (HrmEmployeeDO employee : activeEmployees) { |
| | | marriageMap.merge(StrUtil.blankToDefault(StrUtil.trim(employee.getMarriageStatus()), "æªå¡«å"), 1, Integer::sum); |
| | | politicalMap.merge(StrUtil.blankToDefault(StrUtil.trim(employee.getPoliticalStatus()), "æªå¡«å"), 1, Integer::sum); |
| | | } |
| | | respVO.setMarriageDistribution(toItemListSorted(marriageMap)); |
| | | respVO.setPoliticalDistribution(toItemListSorted(politicalMap)); |
| | | |
| | | // 11. è¿ 12 个æå
¥è / 离èè¶å¿ï¼å«æ¬æï¼ |
| | | Map<YearMonth, Integer> hireMonthMap = new LinkedHashMap<>(); |
| | | Map<YearMonth, Integer> resignMonthMap = new LinkedHashMap<>(); |
| | | allEmployees.forEach(e -> { |
| | | if (e.getHireDate() != null) { |
| | | hireMonthMap.merge(YearMonth.from(e.getHireDate()), 1, Integer::sum); |
| | | } |
| | | if (e.getLeaveDate() != null) { |
| | | resignMonthMap.merge(YearMonth.from(e.getLeaveDate()), 1, Integer::sum); |
| | | } |
| | | }); |
| | | List<HrmEmployeeStatisticsRespVO.TrendVO> trendList = new ArrayList<>(); |
| | | YearMonth startMonth = YearMonth.from(today).minusMonths(11); |
| | | for (int i = 0; i < 12; i++) { |
| | | YearMonth month = startMonth.plusMonths(i); |
| | | HrmEmployeeStatisticsRespVO.TrendVO trendVO = new HrmEmployeeStatisticsRespVO.TrendVO(); |
| | | trendVO.setMonth(month.toString()); |
| | | trendVO.setHireCount(hireMonthMap.getOrDefault(month, 0)); |
| | | trendVO.setResignCount(resignMonthMap.getOrDefault(month, 0)); |
| | | trendList.add(trendVO); |
| | | } |
| | | respVO.setHireResignTrend(trendList); |
| | | |
| | | // 12. ååå°æé¢è¦ï¼åªçå¨å²åå·¥çå½åçæååï¼ |
| | | Set<Long> activeEmployeeIds = activeEmployees.stream() |
| | | .map(HrmEmployeeDO::getId) |
| | | .collect(Collectors.toSet()); |
| | | Map<Long, HrmEmployeeContractDO> currentContractMap = contractMapper.selectList().stream() |
| | | .filter(c -> Boolean.TRUE.equals(c.getIsCurrent())) |
| | | .filter(c -> c.getTerminateStatus() == null || c.getTerminateStatus() == 0) |
| | | .filter(c -> activeEmployeeIds.contains(c.getEmployeeId())) |
| | | .collect(Collectors.toMap(HrmEmployeeContractDO::getEmployeeId, c -> c, (a, b) -> a)); |
| | | int expiredCount = 0; |
| | | int expireIn30Count = 0; |
| | | int expireIn90Count = 0; |
| | | int expireOver90Count = 0; |
| | | int unlimitedCount = 0; |
| | | for (HrmEmployeeContractDO contract : currentContractMap.values()) { |
| | | if (contract.getEndDate() == null) { |
| | | unlimitedCount++; |
| | | continue; |
| | | } |
| | | long days = ChronoUnit.DAYS.between(today, contract.getEndDate()); |
| | | if (days < 0) { |
| | | expiredCount++; |
| | | } else if (days <= 30) { |
| | | expireIn30Count++; |
| | | } else if (days <= 90) { |
| | | expireIn90Count++; |
| | | } else { |
| | | expireOver90Count++; |
| | | } |
| | | } |
| | | List<HrmEmployeeStatisticsRespVO.ItemVO> contractWarning = new ArrayList<>(); |
| | | contractWarning.add(new HrmEmployeeStatisticsRespVO.ItemVO("已尿", expiredCount)); |
| | | contractWarning.add(new HrmEmployeeStatisticsRespVO.ItemVO("30天å
å°æ", expireIn30Count)); |
| | | contractWarning.add(new HrmEmployeeStatisticsRespVO.ItemVO("31-90天尿", expireIn90Count)); |
| | | contractWarning.add(new HrmEmployeeStatisticsRespVO.ItemVO("90天以ä¸", expireOver90Count)); |
| | | contractWarning.add(new HrmEmployeeStatisticsRespVO.ItemVO("æ åºå®æé", unlimitedCount)); |
| | | respVO.setContractWarning(contractWarning); |
| | | respVO.setNoContractCount(Math.max(0, activeEmployeeIds.size() - currentContractMap.size())); |
| | | |
| | | return respVO; |
| | | } |
| | | |
| | | /** |
| | | * 计ç®å·¥é¾ï¼å¹´ï¼ä¿ç 1 ä½å°æ°ï¼ï¼ç¦»èåå·¥æç¦»èæ¥æè®¡ç®ï¼æ å
¥èæ¥æè¿å null |
| | | */ |
| | | private Double calculateTenureYears(HrmEmployeeDO employee, LocalDate today) { |
| | | if (employee.getHireDate() == null) { |
| | | return null; |
| | | } |
| | | LocalDate endDate = employee.getLeaveDate() != null ? employee.getLeaveDate() : today; |
| | | if (endDate.isBefore(employee.getHireDate())) { |
| | | return 0D; |
| | | } |
| | | double years = ChronoUnit.DAYS.between(employee.getHireDate(), endDate) / 365.25D; |
| | | return Math.round(years * 10D) / 10D; |
| | | } |
| | | |
| | | /** |
| | | * è§£æå¹´é¾ï¼ä¼å
åæ¡£æ¡å¹´é¾ï¼ç¼ºå¤±æ¶ç¨åºçæ¥ææ¨ç® |
| | | */ |
| | | private Integer resolveAge(HrmEmployeeDO employee, LocalDate today) { |
| | | if (employee.getAge() != null && employee.getAge() > 0) { |
| | | return employee.getAge(); |
| | | } |
| | | if (employee.getBirthday() == null) { |
| | | return null; |
| | | } |
| | | return (int) ChronoUnit.YEARS.between(employee.getBirthday(), today); |
| | | } |
| | | |
| | | private int resolveTenureBucket(double tenure) { |
| | | for (int i = TENURE_BUCKET_MIN.length - 1; i >= 0; i--) { |
| | | if (tenure >= TENURE_BUCKET_MIN[i]) { |
| | | return i; |
| | | } |
| | | } |
| | | return 0; |
| | | } |
| | | |
| | | private int resolveAgeBucket(int age) { |
| | | for (int i = AGE_BUCKET_MIN.length - 1; i >= 0; i--) { |
| | | if (age >= AGE_BUCKET_MIN[i]) { |
| | | return i; |
| | | } |
| | | } |
| | | return 0; |
| | | } |
| | | |
| | | private List<HrmEmployeeStatisticsRespVO.ItemVO> toItemListSorted(Map<String, Integer> countMap) { |
| | | return countMap.entrySet().stream() |
| | | .sorted(Map.Entry.<String, Integer>comparingByValue().reversed()) |
| | | .map(entry -> new HrmEmployeeStatisticsRespVO.ItemVO(entry.getKey(), entry.getValue())) |
| | | .collect(Collectors.toList()); |
| | | } |
| | | |
| | | private Double averageOf(List<Double> values) { |
| | | if (CollUtil.isEmpty(values)) { |
| | | return 0D; |
| | | } |
| | | double sum = values.stream().mapToDouble(Double::doubleValue).sum(); |
| | | return Math.round(sum / values.size() * 10D) / 10D; |
| | | } |
| | | |
| | | private Double averageOfInt(List<Integer> values) { |
| | | if (CollUtil.isEmpty(values)) { |
| | | return 0D; |
| | | } |
| | | double sum = values.stream().mapToInt(Integer::intValue).sum(); |
| | | return Math.round(sum / values.size() * 10D) / 10D; |
| | | } |
| | | |
| | | } |
| | |
| | | /** |
| | | * åå»ºäº¤æ¥æ å° |
| | | * |
| | | * @param fromUserId 离èç¨æ·ID |
| | | * @param toUserId 交æ¥ç®æ ç¨æ·ID |
| | | * @param resignationId 离èç³è¯·ID |
| | | * @param fromEmployeeId 离èåå·¥ID |
| | | * @param fromUserId 离èç¨æ·ID |
| | | * @param toEmployeeId 交æ¥ç®æ åå·¥ID |
| | | * @param toUserId 交æ¥ç®æ ç¨æ·ID |
| | | * @param resignationId 离èç³è¯·ID |
| | | */ |
| | | void createHandover(Long fromUserId, Long toUserId, Long resignationId); |
| | | void createHandover(Long fromEmployeeId, Long fromUserId, |
| | | Long toEmployeeId, Long toUserId, Long resignationId); |
| | | |
| | | /** |
| | | * æ©å±ç¨æ·IDéåï¼å°äº¤æ¥æºç¨æ·IDå å
¥ |
| | |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void createHandover(Long fromUserId, Long toUserId, Long resignationId) { |
| | | public void createHandover(Long fromEmployeeId, Long fromUserId, |
| | | Long toEmployeeId, Long toUserId, Long resignationId) { |
| | | // æ ¡éªæºç¨æ·åå¨ |
| | | AdminUserRespDTO fromUser = adminUserApi.getUser(fromUserId); |
| | | if (fromUser == null) { |
| | |
| | | throw exception(USER_HANDOVER_ALREADY_EXISTS); |
| | | } |
| | | HrmUserHandoverDO record = HrmUserHandoverDO.builder() |
| | | .fromEmployeeId(fromEmployeeId) |
| | | .fromUserId(fromUserId) |
| | | .toEmployeeId(toEmployeeId) |
| | | .toUserId(toUserId) |
| | | .resignationId(resignationId) |
| | | .handoverStatus(HrmHandoverStatusEnum.COMPLETED.getStatus()) |
| | | .handoverTime(LocalDateTime.now()) |
| | | .build(); |
| | | userHandoverMapper.insert(record); |
| | | log.info("[createHandover] åå»ºäº¤æ¥æ å°: fromUserId={}, toUserId={}, resignationId={}", fromUserId, toUserId, resignationId); |
| | | log.info("[createHandover] åå»ºäº¤æ¥æ å°: fromEmployeeId={}, fromUserId={}, toEmployeeId={}, toUserId={}, resignationId={}", |
| | | fromEmployeeId, fromUserId, toEmployeeId, toUserId, resignationId); |
| | | } |
| | | |
| | | @Override |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.mes.api.itemreceipt; |
| | | |
| | | import cn.iocoder.yudao.module.mes.api.itemreceipt.dto.MesWmItemReceiptRespDTO; |
| | | |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * MES éè´å
¥åºå API æ¥å£ |
| | | * |
| | | * ä¾ ERP æ¥ç¥¨ç»å®å
¥åºåä½¿ç¨ |
| | | */ |
| | | public interface MesWmItemReceiptApi { |
| | | |
| | | /** |
| | | * æ ¹æ®éè´è®¢åç¼å·æ¥è¯¢å·²å®æå
¥åºçå
¥åºåå表 |
| | | * |
| | | * @param purchaseOrderId éè´è®¢åç¼å· |
| | | * @return å
¥åºåå表ï¼å«æç»ï¼ |
| | | */ |
| | | List<MesWmItemReceiptRespDTO> getItemReceiptListByPurchaseOrderId(Long purchaseOrderId); |
| | | |
| | | /** |
| | | * è·å¾å
¥åºå |
| | | * |
| | | * @param id å
¥åºåç¼å· |
| | | * @return å
¥åºåï¼å«æç»ï¼ï¼ä¸å卿¶è¿å null |
| | | */ |
| | | MesWmItemReceiptRespDTO getItemReceipt(Long id); |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.mes.api.itemreceipt.dto; |
| | | |
| | | import lombok.Data; |
| | | |
| | | import java.math.BigDecimal; |
| | | |
| | | /** |
| | | * MES éè´å
¥åºåè¡ Response DTO |
| | | */ |
| | | @Data |
| | | public class MesWmItemReceiptLineRespDTO { |
| | | |
| | | /** |
| | | * å
¥åºåè¡ç¼å· |
| | | */ |
| | | private Long id; |
| | | |
| | | /** |
| | | * éè´è®¢åæç»ç¼å· |
| | | */ |
| | | private Long purchaseOrderItemId; |
| | | |
| | | /** |
| | | * ç©æç¼å· |
| | | */ |
| | | private Long itemId; |
| | | |
| | | /** |
| | | * å
¥åºæ°é |
| | | */ |
| | | private BigDecimal receivedQuantity; |
| | | |
| | | /** |
| | | * åä»·ï¼å
¥åºæ¶æéè´è®¢åè¡åä»·å¿«ç
§ï¼ |
| | | */ |
| | | private BigDecimal price; |
| | | |
| | | /** |
| | | * éé¢ |
| | | */ |
| | | private BigDecimal totalPrice; |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.mes.api.itemreceipt.dto; |
| | | |
| | | import lombok.Data; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.time.LocalDateTime; |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * MES éè´å
¥åºå Response DTO |
| | | */ |
| | | @Data |
| | | public class MesWmItemReceiptRespDTO { |
| | | |
| | | private Long id; |
| | | |
| | | /** |
| | | * å
¥åºåå· |
| | | */ |
| | | private String code; |
| | | |
| | | /** |
| | | * å
¥åºååç§° |
| | | */ |
| | | private String name; |
| | | |
| | | /** |
| | | * å°è´§éç¥åç¼å· |
| | | */ |
| | | private Long noticeId; |
| | | |
| | | /** |
| | | * éè´è®¢åç¼å· |
| | | */ |
| | | private Long purchaseOrderId; |
| | | |
| | | /** |
| | | * éè´è®¢åå· |
| | | */ |
| | | private String purchaseOrderCode; |
| | | |
| | | /** |
| | | * ä¾åºåç¼å· |
| | | */ |
| | | private Long vendorId; |
| | | |
| | | /** |
| | | * å
¥åºæ¥æ |
| | | */ |
| | | private LocalDateTime receiptDate; |
| | | |
| | | /** |
| | | * ç¶æ |
| | | */ |
| | | private Integer status; |
| | | |
| | | /** |
| | | * å
¥åºæ»éé¢ |
| | | */ |
| | | private BigDecimal totalPrice; |
| | | |
| | | /** |
| | | * å
¥åºæç» |
| | | */ |
| | | private List<MesWmItemReceiptLineRespDTO> lines; |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.mes.api.productsales; |
| | | |
| | | import cn.iocoder.yudao.module.mes.api.productsales.dto.MesWmProductSalesRespDTO; |
| | | |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * MES éå®åºåºå API æ¥å£ |
| | | * |
| | | * ä¾ CRM å¼ç¥¨ç»å®åºåºåãè´¢å¡å¯¹è´¦ä½¿ç¨ |
| | | */ |
| | | public interface MesWmProductSalesApi { |
| | | |
| | | /** |
| | | * æ ¹æ®éå®è®¢åç¼å·æ¥è¯¢åºåºåå表 |
| | | * |
| | | * @param saleOrderId éå®è®¢åç¼å· |
| | | * @return åºåºåå表ï¼å«æç»ï¼ |
| | | */ |
| | | List<MesWmProductSalesRespDTO> getProductSalesListBySaleOrderId(Long saleOrderId); |
| | | |
| | | /** |
| | | * æ ¹æ®å®¢æ·ç¼å·æ¥è¯¢åºåºåå表 |
| | | * |
| | | * @param clientId 客æ·ç¼å· |
| | | * @return åºåºåå表ï¼å«æç»ï¼ |
| | | */ |
| | | List<MesWmProductSalesRespDTO> getProductSalesListByClientId(Long clientId); |
| | | |
| | | /** |
| | | * è·å¾åºåºå |
| | | * |
| | | * @param id åºåºåç¼å· |
| | | * @return åºåºåï¼å«æç»ï¼ï¼ä¸å卿¶è¿å null |
| | | */ |
| | | MesWmProductSalesRespDTO getProductSales(Long id); |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.mes.api.productsales.dto; |
| | | |
| | | import lombok.Data; |
| | | |
| | | import java.math.BigDecimal; |
| | | |
| | | /** |
| | | * MES éå®åºåºåè¡ Response DTO |
| | | */ |
| | | @Data |
| | | public class MesWmProductSalesLineRespDTO { |
| | | |
| | | /** |
| | | * åºåºåè¡ç¼å· |
| | | */ |
| | | private Long id; |
| | | |
| | | /** |
| | | * éå®è®¢åæç»ç¼å·ï¼æå·¥åºåºæ¶å¯è½ä¸ºç©ºï¼ |
| | | */ |
| | | private Long saleOrderItemId; |
| | | |
| | | /** |
| | | * ç©æç¼å· |
| | | */ |
| | | private Long itemId; |
| | | |
| | | /** |
| | | * åºåºæ°é |
| | | */ |
| | | private BigDecimal quantity; |
| | | |
| | | /** |
| | | * åä»·ï¼åºåºæ¶æéå®è®¢åè¡åä»·å¿«ç
§ï¼ |
| | | */ |
| | | private BigDecimal price; |
| | | |
| | | /** |
| | | * éé¢ |
| | | */ |
| | | private BigDecimal totalPrice; |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.mes.api.productsales.dto; |
| | | |
| | | import lombok.Data; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.time.LocalDateTime; |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * MES éå®åºåºå Response DTO |
| | | */ |
| | | @Data |
| | | public class MesWmProductSalesRespDTO { |
| | | |
| | | private Long id; |
| | | |
| | | /** |
| | | * åºåºåå· |
| | | */ |
| | | private String code; |
| | | |
| | | /** |
| | | * 客æ·ç¼å· |
| | | */ |
| | | private Long clientId; |
| | | |
| | | /** |
| | | * éå®è®¢åç¼å· |
| | | */ |
| | | private Long saleOrderId; |
| | | |
| | | /** |
| | | * éå®è®¢åå· |
| | | */ |
| | | private String salesOrderCode; |
| | | |
| | | /** |
| | | * åè´§éç¥åç¼å· |
| | | */ |
| | | private Long noticeId; |
| | | |
| | | /** |
| | | * åºåºæ¥æ |
| | | */ |
| | | private LocalDateTime salesDate; |
| | | |
| | | /** |
| | | * ç¶æ |
| | | */ |
| | | private Integer status; |
| | | |
| | | /** |
| | | * åºåºæ»éé¢ |
| | | */ |
| | | private BigDecimal totalPrice; |
| | | |
| | | /** |
| | | * åºåºæç» |
| | | */ |
| | | private List<MesWmProductSalesLineRespDTO> lines; |
| | | |
| | | } |
| | |
| | | <version>${revision}</version> |
| | | </dependency> |
| | | |
| | | <!-- å®åå·¥å APIï¼ä»å¨éè´§å忥æµè½¬è®°å½ --> |
| | | <dependency> |
| | | <groupId>cn.iocoder.boot</groupId> |
| | | <artifactId>yudao-module-aftersales-api</artifactId> |
| | | <version>${revision}</version> |
| | | </dependency> |
| | | |
| | | <!-- ä¸å¡ç»ä»¶ --> |
| | | |
| | | <!-- Web ç¸å
³ --> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.mes.api.itemreceipt; |
| | | |
| | | import cn.hutool.core.collection.CollUtil; |
| | | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| | | import cn.iocoder.yudao.module.mes.api.itemreceipt.dto.MesWmItemReceiptLineRespDTO; |
| | | import cn.iocoder.yudao.module.mes.api.itemreceipt.dto.MesWmItemReceiptRespDTO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.itemreceipt.MesWmItemReceiptDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.itemreceipt.MesWmItemReceiptLineDO; |
| | | import cn.iocoder.yudao.module.mes.dal.mysql.wm.itemreceipt.MesWmItemReceiptLineMapper; |
| | | import cn.iocoder.yudao.module.mes.dal.mysql.wm.itemreceipt.MesWmItemReceiptMapper; |
| | | import jakarta.annotation.Resource; |
| | | import org.springframework.stereotype.Service; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.stream.Collectors; |
| | | |
| | | /** |
| | | * MES éè´å
¥åºå API å®ç°ç±» |
| | | */ |
| | | @Service |
| | | public class MesWmItemReceiptApiImpl implements MesWmItemReceiptApi { |
| | | |
| | | @Resource |
| | | private MesWmItemReceiptMapper itemReceiptMapper; |
| | | @Resource |
| | | private MesWmItemReceiptLineMapper itemReceiptLineMapper; |
| | | |
| | | @Override |
| | | public List<MesWmItemReceiptRespDTO> getItemReceiptListByPurchaseOrderId(Long purchaseOrderId) { |
| | | if (purchaseOrderId == null) { |
| | | return List.of(); |
| | | } |
| | | List<MesWmItemReceiptDO> receipts = itemReceiptMapper.selectListByPurchaseOrderId(purchaseOrderId); |
| | | if (CollUtil.isEmpty(receipts)) { |
| | | return List.of(); |
| | | } |
| | | Map<Long, List<MesWmItemReceiptLineDO>> lineMap = itemReceiptLineMapper |
| | | .selectListByReceiptIds(receipts.stream().map(MesWmItemReceiptDO::getId).toList()) |
| | | .stream().collect(Collectors.groupingBy(MesWmItemReceiptLineDO::getReceiptId)); |
| | | return receipts.stream() |
| | | .map(receipt -> convert(receipt, lineMap.getOrDefault(receipt.getId(), List.of()))) |
| | | .toList(); |
| | | } |
| | | |
| | | @Override |
| | | public MesWmItemReceiptRespDTO getItemReceipt(Long id) { |
| | | MesWmItemReceiptDO receipt = itemReceiptMapper.selectById(id); |
| | | if (receipt == null) { |
| | | return null; |
| | | } |
| | | return convert(receipt, itemReceiptLineMapper.selectListByReceiptId(id)); |
| | | } |
| | | |
| | | private MesWmItemReceiptRespDTO convert(MesWmItemReceiptDO receipt, List<MesWmItemReceiptLineDO> lines) { |
| | | MesWmItemReceiptRespDTO resp = BeanUtils.toBean(receipt, MesWmItemReceiptRespDTO.class); |
| | | List<MesWmItemReceiptLineRespDTO> lineResps = BeanUtils.toBean(lines, MesWmItemReceiptLineRespDTO.class); |
| | | resp.setLines(lineResps); |
| | | resp.setTotalPrice(lineResps.stream() |
| | | .map(line -> line.getTotalPrice() != null ? line.getTotalPrice() : calcLineAmount(line)) |
| | | .filter(amount -> amount != null) |
| | | .reduce(BigDecimal.ZERO, BigDecimal::add)); |
| | | return resp; |
| | | } |
| | | |
| | | private BigDecimal calcLineAmount(MesWmItemReceiptLineRespDTO line) { |
| | | if (line.getPrice() == null || line.getReceivedQuantity() == null) { |
| | | return null; |
| | | } |
| | | return line.getPrice().multiply(line.getReceivedQuantity()); |
| | | } |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.mes.api.productsales; |
| | | |
| | | import cn.hutool.core.collection.CollUtil; |
| | | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| | | import cn.iocoder.yudao.module.mes.api.productsales.dto.MesWmProductSalesLineRespDTO; |
| | | import cn.iocoder.yudao.module.mes.api.productsales.dto.MesWmProductSalesRespDTO; |
| | | 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.wm.productsales.MesWmProductSalesLineMapper; |
| | | import cn.iocoder.yudao.module.mes.dal.mysql.wm.productsales.MesWmProductSalesMapper; |
| | | import jakarta.annotation.Resource; |
| | | import org.springframework.stereotype.Service; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.stream.Collectors; |
| | | |
| | | /** |
| | | * MES éå®åºåºå API å®ç°ç±» |
| | | */ |
| | | @Service |
| | | public class MesWmProductSalesApiImpl implements MesWmProductSalesApi { |
| | | |
| | | @Resource |
| | | private MesWmProductSalesMapper productSalesMapper; |
| | | @Resource |
| | | private MesWmProductSalesLineMapper productSalesLineMapper; |
| | | |
| | | @Override |
| | | public List<MesWmProductSalesRespDTO> getProductSalesListBySaleOrderId(Long saleOrderId) { |
| | | if (saleOrderId == null) { |
| | | return List.of(); |
| | | } |
| | | List<MesWmProductSalesDO> salesList = productSalesMapper.selectListBySaleOrderId(saleOrderId); |
| | | return convertList(salesList); |
| | | } |
| | | |
| | | @Override |
| | | public List<MesWmProductSalesRespDTO> getProductSalesListByClientId(Long clientId) { |
| | | if (clientId == null) { |
| | | return List.of(); |
| | | } |
| | | return convertList(productSalesMapper.selectListByClientId(clientId)); |
| | | } |
| | | |
| | | @Override |
| | | public MesWmProductSalesRespDTO getProductSales(Long id) { |
| | | MesWmProductSalesDO sales = productSalesMapper.selectById(id); |
| | | if (sales == null) { |
| | | return null; |
| | | } |
| | | return convert(sales, productSalesLineMapper.selectListBySalesId(id)); |
| | | } |
| | | |
| | | private List<MesWmProductSalesRespDTO> convertList(List<MesWmProductSalesDO> salesList) { |
| | | if (CollUtil.isEmpty(salesList)) { |
| | | return List.of(); |
| | | } |
| | | Map<Long, List<MesWmProductSalesLineDO>> lineMap = productSalesLineMapper |
| | | .selectListBySalesIds(salesList.stream().map(MesWmProductSalesDO::getId).toList()) |
| | | .stream().collect(Collectors.groupingBy(MesWmProductSalesLineDO::getSalesId)); |
| | | return salesList.stream() |
| | | .map(sales -> convert(sales, lineMap.getOrDefault(sales.getId(), List.of()))) |
| | | .toList(); |
| | | } |
| | | |
| | | private MesWmProductSalesRespDTO convert(MesWmProductSalesDO sales, List<MesWmProductSalesLineDO> lines) { |
| | | MesWmProductSalesRespDTO resp = BeanUtils.toBean(sales, MesWmProductSalesRespDTO.class); |
| | | List<MesWmProductSalesLineRespDTO> lineResps = BeanUtils.toBean(lines, MesWmProductSalesLineRespDTO.class); |
| | | resp.setLines(lineResps); |
| | | resp.setTotalPrice(lineResps.stream() |
| | | .map(line -> line.getTotalPrice() != null ? line.getTotalPrice() : calcLineAmount(line)) |
| | | .filter(amount -> amount != null) |
| | | .reduce(BigDecimal.ZERO, BigDecimal::add)); |
| | | return resp; |
| | | } |
| | | |
| | | private BigDecimal calcLineAmount(MesWmProductSalesLineRespDTO line) { |
| | | if (line.getPrice() == null || line.getQuantity() == null) { |
| | | return null; |
| | | } |
| | | return line.getPrice().multiply(line.getQuantity()); |
| | | } |
| | | |
| | | } |
| | |
| | | @Schema(description = "设å¤ç¼å·", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") |
| | | private Long machineryId; |
| | | |
| | | @Schema(description = "设å¤ç¼ç ", example = "EQ001") |
| | | @Schema(description = "设å¤ç¼å·", example = "EQ001") |
| | | private String machineryCode; |
| | | |
| | | @Schema(description = "设å¤åç§°", example = "æ³¨å¡æºA") |
| | |
| | | @Schema(description = "设å¤ç¼å·", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") |
| | | private Long machineryId; |
| | | |
| | | @Schema(description = "设å¤ç¼ç ", example = "M001") |
| | | @ExcelProperty("设å¤ç¼ç ") |
| | | @Schema(description = "设å¤ç¼å·", example = "M001") |
| | | @ExcelProperty("设å¤ç¼å·") |
| | | private String machineryCode; |
| | | |
| | | @Schema(description = "设å¤åç§°", example = "æºåºA") |
| | |
| | | @NoArgsConstructor |
| | | public class MesDvMachineryImportExcelVO { |
| | | |
| | | @ExcelProperty("设å¤ç¼ç ") |
| | | @ExcelProperty("设å¤ç¼å·") |
| | | @cn.iocoder.yudao.framework.excel.core.handler.ExcelRequired |
| | | private String code; |
| | | |
| | |
| | | @Builder |
| | | public class MesDvMachineryImportRespVO { |
| | | |
| | | @Schema(description = "å建æåç设å¤ç¼ç æ°ç»", requiredMode = Schema.RequiredMode.REQUIRED) |
| | | @Schema(description = "å建æåç设å¤ç¼å·æ°ç»", requiredMode = Schema.RequiredMode.REQUIRED) |
| | | private List<String> createCodes; |
| | | |
| | | @Schema(description = "æ´æ°æåç设å¤ç¼ç æ°ç»", requiredMode = Schema.RequiredMode.REQUIRED) |
| | | @Schema(description = "æ´æ°æåç设å¤ç¼å·æ°ç»", requiredMode = Schema.RequiredMode.REQUIRED) |
| | | private List<String> updateCodes; |
| | | |
| | | @Schema(description = "导å
¥å¤±è´¥ç设å¤éåï¼key 为设å¤ç¼ç ï¼value 为失败åå ", requiredMode = Schema.RequiredMode.REQUIRED) |
| | | @Schema(description = "导å
¥å¤±è´¥ç设å¤éåï¼key 为设å¤ç¼å·ï¼value 为失败åå ", requiredMode = Schema.RequiredMode.REQUIRED) |
| | | private Map<String, String> failureCodes; |
| | | |
| | | } |
| | |
| | | @ToString(callSuper = true) |
| | | public class MesDvMachineryPageReqVO extends PageParam { |
| | | |
| | | @Schema(description = "设å¤ç¼ç ", example = "EQ-001") |
| | | @Schema(description = "设å¤ç¼å·", example = "EQ-001") |
| | | private String code; |
| | | |
| | | @Schema(description = "设å¤åç§°", example = "CNC å å·¥ä¸å¿") |
| | |
| | | @ExcelProperty("ç¼å·") |
| | | private Long id; |
| | | |
| | | @Schema(description = "设å¤ç¼ç ", requiredMode = Schema.RequiredMode.REQUIRED, example = "EQ-001") |
| | | @ExcelProperty("设å¤ç¼ç ") |
| | | @Schema(description = "设å¤ç¼å·", requiredMode = Schema.RequiredMode.REQUIRED, example = "EQ-001") |
| | | @ExcelProperty("设å¤ç¼å·") |
| | | private String code; |
| | | |
| | | @Schema(description = "设å¤åç§°", requiredMode = Schema.RequiredMode.REQUIRED, example = "CNC å å·¥ä¸å¿") |
| | |
| | | @Schema(description = "ç¼å·", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") |
| | | private Long id; |
| | | |
| | | @Schema(description = "设å¤ç¼ç ", requiredMode = Schema.RequiredMode.REQUIRED, example = "EQ-001") |
| | | @NotEmpty(message = "设å¤ç¼ç ä¸è½ä¸ºç©º") |
| | | @Schema(description = "设å¤ç¼å·", requiredMode = Schema.RequiredMode.REQUIRED, example = "EQ-001") |
| | | @NotEmpty(message = "设å¤ç¼å·ä¸è½ä¸ºç©º") |
| | | private String code; |
| | | |
| | | @Schema(description = "设å¤åç§°", requiredMode = Schema.RequiredMode.REQUIRED, example = "CNC å å·¥ä¸å¿") |
| | |
| | | @Schema(description = "设å¤ç¼å·", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") |
| | | private Long machineryId; |
| | | |
| | | @Schema(description = "设å¤ç¼ç ", example = "M001") |
| | | @ExcelProperty("设å¤ç¼ç ") |
| | | @Schema(description = "设å¤ç¼å·", example = "M001") |
| | | @ExcelProperty("设å¤ç¼å·") |
| | | private String machineryCode; |
| | | |
| | | @Schema(description = "设å¤åç§°", example = "æºåºA") |
| | |
| | | @Schema(description = "设å¤ç¼å·", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") |
| | | private Long machineryId; |
| | | |
| | | @Schema(description = "设å¤ç¼ç ", example = "M001") |
| | | @ExcelProperty("设å¤ç¼ç ") |
| | | @Schema(description = "设å¤ç¼å·", example = "M001") |
| | | @ExcelProperty("设å¤ç¼å·") |
| | | private String machineryCode; |
| | | |
| | | @Schema(description = "设å¤åç§°", example = "æ³¨å¡æº") |
| | |
| | | @Schema(description = "设å¤ç¼å·", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") |
| | | private Long machineryId; |
| | | |
| | | @Schema(description = "设å¤ç¼ç ", example = "M001") |
| | | @Schema(description = "设å¤ç¼å·", example = "M001") |
| | | private String machineryCode; |
| | | |
| | | @Schema(description = "设å¤åç§°", example = "CNCæ°æ§æºåº") |
| | |
| | | return BeanUtils.toBean(list, MesWmArrivalNoticeRespVO.class, vo -> { |
| | | MapUtils.findAndThen(supplierMap, vo.getVendorId(), supplier -> |
| | | vo.setVendorName(supplier.getName())); |
| | | MapUtils.findAndThen(purchaseOrderMap, vo.getPurchaseOrderId(), purchaseOrder -> |
| | | vo.setPurchaseOrderNo(purchaseOrder.getNo())); |
| | | MapUtils.findAndThen(purchaseOrderMap, vo.getPurchaseOrderId(), purchaseOrder -> { |
| | | vo.setPurchaseOrderNo(purchaseOrder.getNo()); |
| | | // åå²åæ®æªå¿«ç
§ååå·æ¶ï¼åå¡«éè´è®¢åä¸çååå· |
| | | if (cn.hutool.core.util.StrUtil.isBlank(vo.getContractNo())) { |
| | | vo.setContractNo(purchaseOrder.getContractNo()); |
| | | } |
| | | }); |
| | | }); |
| | | } |
| | | |
| | |
| | | @Schema(description = "éè´è®¢åç¼å·", example = "1") |
| | | private Long purchaseOrderId; |
| | | |
| | | @Schema(description = "éè´ååå·", example = "HT20260101") |
| | | private String contractNo; |
| | | |
| | | @Schema(description = "ä¾åºåç¼å·", example = "1") |
| | | private Long vendorId; |
| | | |
| | |
| | | @ExcelProperty("éè´è®¢åå·") |
| | | private String purchaseOrderNo; |
| | | |
| | | @Schema(description = "éè´ååå·", example = "HT20260101") |
| | | @ExcelProperty("éè´ååå·") |
| | | private String contractNo; |
| | | |
| | | @Schema(description = "ä¾åºåç¼å·", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") |
| | | private Long vendorId; |
| | | |
| | |
| | | @Schema(description = "éè´è®¢åç¼ç ", example = "PO20260101") |
| | | private String purchaseOrderCode; |
| | | |
| | | @Schema(description = "éè´ååå·", example = "HT20260101") |
| | | private String contractNo; |
| | | |
| | | @Schema(description = "ä¾åºåç¼å·", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") |
| | | @NotNull(message = "ä¾åºåç¼å·ä¸è½ä¸ºç©º") |
| | | private Long vendorId; |
| | |
| | | @TableId |
| | | private Long id; |
| | | /** |
| | | * 设å¤ç¼ç |
| | | * 设å¤ç¼å· |
| | | */ |
| | | private String code; |
| | | /** |
| | |
| | | */ |
| | | private String purchaseOrderCode; |
| | | /** |
| | | * éè´ååå·ï¼åä½å段ï¼å建æ¶ä»éè´è®¢åå¿«ç
§ï¼æ¢è´§å°è´§æ²¿ç¨åéè´§åååå·ï¼ |
| | | */ |
| | | private String contractNo; |
| | | /** |
| | | * ä¾åºåç¼å· |
| | | * |
| | | * å
³è ERP ä¾åºå {@link cn.iocoder.yudao.module.erp.api.purchase.dto.ErpSupplierRespDTO#getId()} |
| | |
| | | * å
¥åºæ°é |
| | | */ |
| | | private BigDecimal receivedQuantity; |
| | | |
| | | /** |
| | | * åä»·ï¼å
¥åºæ¶æéè´è®¢åè¡åä»·å¿«ç
§ï¼ |
| | | */ |
| | | private BigDecimal price; |
| | | |
| | | /** |
| | | * éé¢ |
| | | */ |
| | | private BigDecimal totalPrice; |
| | | /** |
| | | * æ¹æ¬¡ç¼å· |
| | | * |
| | |
| | | */ |
| | | private BigDecimal quantity; |
| | | /** |
| | | * åä»·ï¼åºåºæ¶æéå®è®¢åè¡åä»·å¿«ç
§ï¼ |
| | | */ |
| | | private BigDecimal price; |
| | | /** |
| | | * éé¢ |
| | | */ |
| | | private BigDecimal totalPrice; |
| | | /** |
| | | * æ¹æ¬¡ ID |
| | | * |
| | | * å
³è {@link MesWmBatchDO#getId()} |
| | |
| | | .likeIfPresent(MesWmArrivalNoticeDO::getCode, reqVO.getCode()) |
| | | .likeIfPresent(MesWmArrivalNoticeDO::getName, reqVO.getName()) |
| | | .eqIfPresent(MesWmArrivalNoticeDO::getPurchaseOrderId, reqVO.getPurchaseOrderId()) |
| | | .likeIfPresent(MesWmArrivalNoticeDO::getContractNo, reqVO.getContractNo()) |
| | | .eqIfPresent(MesWmArrivalNoticeDO::getVendorId, reqVO.getVendorId()) |
| | | .betweenIfPresent(MesWmArrivalNoticeDO::getArrivalDate, reqVO.getArrivalDate()) |
| | | .eqIfPresent(MesWmArrivalNoticeDO::getStatus, reqVO.getStatus()) |
| | |
| | | return selectOne(MesWmItemReceiptDO::getNoticeId, noticeId); |
| | | } |
| | | |
| | | default List<MesWmItemReceiptDO> selectListByPurchaseOrderId(Long purchaseOrderId) { |
| | | return selectList(new LambdaQueryWrapperX<MesWmItemReceiptDO>() |
| | | .eq(MesWmItemReceiptDO::getPurchaseOrderId, purchaseOrderId) |
| | | .orderByDesc(MesWmItemReceiptDO::getId)); |
| | | } |
| | | |
| | | } |
| | |
| | | return selectList(MesWmProductSalesLineDO::getSalesId, salesId); |
| | | } |
| | | |
| | | default List<MesWmProductSalesLineDO> selectListBySalesIds(java.util.Collection<Long> salesIds) { |
| | | return selectList(new LambdaQueryWrapperX<MesWmProductSalesLineDO>() |
| | | .in(MesWmProductSalesLineDO::getSalesId, salesIds)); |
| | | } |
| | | |
| | | default void deleteBySalesId(Long salesId) { |
| | | delete(MesWmProductSalesLineDO::getSalesId, salesId); |
| | | } |
| | |
| | | return selectList(MesWmProductSalesDO::getClientId, clientId); |
| | | } |
| | | |
| | | default List<MesWmProductSalesDO> selectListBySaleOrderId(Long saleOrderId) { |
| | | return selectList(new LambdaQueryWrapperX<MesWmProductSalesDO>() |
| | | .eq(MesWmProductSalesDO::getSaleOrderId, saleOrderId) |
| | | .orderByDesc(MesWmProductSalesDO::getId)); |
| | | } |
| | | |
| | | } |
| | |
| | | |
| | | // ========== MES 设å¤ç®¡ç-设å¤å°è´¦ï¼1-040-301-000ï¼ ========== |
| | | ErrorCode DV_MACHINERY_NOT_EXISTS = new ErrorCode(1_040_301_000, "设å¤ä¸åå¨"); |
| | | ErrorCode DV_MACHINERY_CODE_DUPLICATE = new ErrorCode(1_040_301_001, "设å¤ç¼ç å·²åå¨"); |
| | | ErrorCode DV_MACHINERY_CODE_DUPLICATE = new ErrorCode(1_040_301_001, "设å¤ç¼å·å·²åå¨"); |
| | | ErrorCode DV_MACHINERY_IS_DISABLE = new ErrorCode(1_040_301_007, "设å¤å·²ç¦ç¨"); |
| | | ErrorCode DV_MACHINERY_IMPORT_LIST_IS_EMPTY = new ErrorCode(1_040_301_002, "导å
¥è®¾å¤æ°æ®ä¸è½ä¸ºç©º"); |
| | | ErrorCode DV_MACHINERY_HAS_CHECK_PLAN = new ErrorCode(1_040_301_003, "设å¤å·²å
³èç¹æ£è®¡åï¼æ æ³å é¤"); |
| | |
| | | ErrorCode WM_RETURN_VENDOR_HANDLE_TYPE_INVALID = new ErrorCode(1_040_711_012, "ä¾åºåéè´§åå¤çæ¹å¼ä¸æ£ç¡®ï¼å½å为[{}]ï¼ä»
æ¯æ 1鿬¾ / 2æ¢è´§ï¼è¯·ä¿®æ¹å¤çæ¹å¼ååæä½"); |
| | | ErrorCode WM_RETURN_VENDOR_REFUND_AMOUNT_REQUIRED = new ErrorCode(1_040_711_013, "æ æ³èªå¨è®¡ç®é款éé¢ï¼éè´§å[{}]æªå
³èéè´è®¢åï¼æéè´§ç©æ[{}]æªå¹é
å°éè´è®¢åæç»ã请å¨éè´§åå¡«å鿬¾éé¢åå宿éè´§"); |
| | | ErrorCode WM_RETURN_VENDOR_FINISHED_REQUIRED = new ErrorCode(1_040_711_014, "ä¾åºåéè´§å[{}]å½åç¶æä¸º[{}]ï¼åªæå·²å®æçéè´§åæè½æ§è¡è¯¥æä½"); |
| | | ErrorCode WM_RETURN_VENDOR_ATTACHMENT_REQUIRED = new ErrorCode(1_040_711_015, "ä¾åºåéè´§å[{}]æªä¸ä¼ éè´§éä»¶ï¼è´¨éé¨åèµ·éè´§å¿
é¡»ä¸ä¼ è´¨æ£æ¥åãä¸åæ ¼ç
§ççéä»¶åæè½æäº¤å®¡æ¹ï¼è¯·å
ç¼è¾åæ®ä¸ä¼ éä»¶"); |
| | | |
| | | // ========== MES ä»åºç®¡ç-äº§åæ¶è´§åï¼1-040-712-000ï¼ ========== |
| | | ErrorCode WM_PRODUCT_RECPT_NOT_EXISTS = new ErrorCode(1_040_712_000, "äº§åæ¶è´§åä¸åå¨"); |
| | |
| | | WM_STOCK_TAKING_CODE("WM_STOCK_TAKING_CODE", "çç¹ä»»å¡ç¼ç "), |
| | | TRANSFER_CODE("TRANSFER_CODE", "è½¬ç§»è°æ¨åç¼ç "), |
| | | WM_OUTSOURCE_ISSUE_CODE("WM_OUTSOURCE_ISSUE_CODE", "å¤ååæåç¼ç "), |
| | | DV_MACHINERY_CODE("DV_MACHINERY_CODE", "设å¤ç¼ç "), |
| | | DV_MACHINERY_CODE("DV_MACHINERY_CODE", "设å¤ç¼å·"), |
| | | DV_MACHINERY_TYPE_CODE("DV_MACHINERY_TYPE_CODE", "设å¤ç±»åç¼ç "), |
| | | DV_SUBJECT_CODE("DV_SUBJECT_CODE", "ç¹æ£ä¿å
»é¡¹ç®ç¼ç "), |
| | | DV_REPAIR_CODE("DV_REPAIR_CODE", "ç»´ä¿®åç¼ç "), |
| | |
| | | import cn.hutool.core.util.ObjUtil; |
| | | import cn.hutool.core.util.StrUtil; |
| | | import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; |
| | | import cn.iocoder.yudao.framework.common.exception.ServiceException; |
| | | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| | | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| | | import cn.iocoder.yudao.framework.operatelog.core.util.OperateLogUtils; |
| | |
| | | return; |
| | | } |
| | | if (ObjUtil.notEqual(machinery.getId(), id)) { |
| | | throw exception(DV_MACHINERY_CODE_DUPLICATE); |
| | | throw new ServiceException(DV_MACHINERY_CODE_DUPLICATE.getCode(), |
| | | "设å¤ç¼å·[" + code + "]已被设å¤[" + machinery.getName() + "]使ç¨ï¼è¯·æ´æ¢ç¼å·ï¼æç¹å»âèªå¨çæâéæ°çæ"); |
| | | } |
| | | } |
| | | |
| | |
| | | // 3.1 æ ¡éªå¿
å¡«åæ®µ |
| | | String key = StrUtil.blankToDefault(importItem.getCode(), "第 " + currentIndex + " è¡"); |
| | | if (StrUtil.isBlank(importItem.getCode())) { |
| | | respVO.getFailureCodes().put(key, "设å¤ç¼ç ä¸è½ä¸ºç©º"); |
| | | respVO.getFailureCodes().put(key, "设å¤ç¼å·ä¸è½ä¸ºç©º"); |
| | | return; |
| | | } |
| | | if (StrUtil.isBlank(importItem.getName())) { |
| | |
| | | respVO.getUpdateCodes().add(importItem.getCode()); |
| | | } else { |
| | | // 䏿¯ææ´æ° |
| | | respVO.getFailureCodes().put(key, "设å¤ç¼ç å·²åå¨"); |
| | | respVO.getFailureCodes().put(key, "设å¤ç¼å·å·²åå¨ï¼å¦éè¦ç请å¾éâæ¯å¦è¦çâå鿰坼å
¥"); |
| | | } |
| | | }); |
| | | // è®°å½å¯¼å
¥ç»ææ±æ»ï¼ä¾ @LogRecord ç success ææ¡å¼ç¨ |
| | |
| | | |
| | | // æå
¥ |
| | | MesWmArrivalNoticeDO notice = BeanUtils.toBean(createReqVO, MesWmArrivalNoticeDO.class); |
| | | fillContractNoFromPurchaseOrder(notice); |
| | | notice.setStatus(MesWmArrivalNoticeStatusEnum.PREPARE.getStatus()); |
| | | arrivalNoticeMapper.insert(notice); |
| | | return notice.getId(); |
| | |
| | | |
| | | // æ´æ° |
| | | MesWmArrivalNoticeDO updateObj = BeanUtils.toBean(updateReqVO, MesWmArrivalNoticeDO.class); |
| | | fillContractNoFromPurchaseOrder(updateObj); |
| | | arrivalNoticeMapper.updateById(updateObj); |
| | | } |
| | | |
| | | /** |
| | | * éè´ååå·æªæ¾å¼ä¼ å
¥æ¶ï¼ä»å
³èçéè´è®¢å带å
¥ï¼æ¢è´§å°è´§å¿
é¡»è½è¿½æº¯å°åéè´ååï¼ |
| | | */ |
| | | private void fillContractNoFromPurchaseOrder(MesWmArrivalNoticeDO notice) { |
| | | if (notice.getPurchaseOrderId() == null || cn.hutool.core.util.StrUtil.isNotBlank(notice.getContractNo())) { |
| | | return; |
| | | } |
| | | ErpPurchaseOrderRespDTO purchaseOrder = purchaseOrderApi.getPurchaseOrder(notice.getPurchaseOrderId()).getCheckedData(); |
| | | if (purchaseOrder != null) { |
| | | notice.setContractNo(purchaseOrder.getContractNo()); |
| | | } |
| | | } |
| | | |
| | | private void validateArrivalNoticeSaveData(MesWmArrivalNoticeSaveReqVO reqVO) { |
| | |
| | | notice.setName(purchaseOrder.getNo() + "å°è´§éç¥"); |
| | | notice.setPurchaseOrderId(purchaseOrderId); |
| | | notice.setPurchaseOrderCode(purchaseOrder.getNo()); |
| | | notice.setContractNo(purchaseOrder.getContractNo()); |
| | | notice.setVendorId(purchaseOrder.getSupplierId()); |
| | | notice.setArrivalDate(java.time.LocalDateTime.now()); // å°è´§æ¶é´ä¸ºå½åæ¶é´ |
| | | notice.setStatus(MesWmArrivalNoticeStatusEnum.PENDING_RECEIPT.getStatus()); |
| | |
| | | notice.setName(returnVendor.getCode() + "æ¢è´§å°è´§"); |
| | | notice.setPurchaseOrderId(returnVendor.getPurchaseOrderId()); |
| | | notice.setPurchaseOrderCode(returnVendor.getPurchaseOrderCode()); |
| | | // æ¢è´§éæ°å
³èåéè´ååå·ï¼ä¼å
åéè´§åå¿«ç
§ï¼éè´§åæªå¿«ç
§æ¶åå¡«éè´è®¢åååå· |
| | | notice.setContractNo(returnVendor.getContractNo()); |
| | | fillContractNoFromPurchaseOrder(notice); |
| | | notice.setVendorId(returnVendor.getVendorId()); |
| | | notice.setArrivalDate(java.time.LocalDateTime.now()); |
| | | notice.setStatus(MesWmArrivalNoticeStatusEnum.PENDING_QC.getStatus()); |
| | |
| | | receiptLine.setItemId(noticeLine.getItemId()); |
| | | // 使ç¨åæ ¼æ°éï¼å¦ææ IQC åæ¯åæ ¼æ°éï¼å¦åæ¯å°è´§æ°éï¼ |
| | | receiptLine.setReceivedQuantity(noticeLine.getQualifiedQuantity() != null ? noticeLine.getQualifiedQuantity() : noticeLine.getArrivalQuantity()); |
| | | // æéè´è®¢åè¡åä»·å¿«ç
§éé¢ï¼ä¾æ¥ç¥¨/å¯¹è´¦ä½¿ç¨ |
| | | fillReceiptLinePrice(receiptLine); |
| | | itemReceiptLineService.createItemReceiptLineFromArrivalNoticeLine(receiptLine); |
| | | } |
| | | |
| | | return receipt.getId(); |
| | | } |
| | | |
| | | /** |
| | | * æéè´è®¢åè¡åä»·åå¡«å
¥åºè¡éé¢ï¼é¿å
对账æ¶åè表åä»· |
| | | */ |
| | | private void fillReceiptLinePrice(MesWmItemReceiptLineDO receiptLine) { |
| | | if (receiptLine.getPurchaseOrderItemId() == null) { |
| | | return; |
| | | } |
| | | try { |
| | | var item = purchaseOrderApi.getPurchaseOrderItem(receiptLine.getPurchaseOrderItemId()).getData(); |
| | | if (item == null || item.getProductPrice() == null) { |
| | | return; |
| | | } |
| | | receiptLine.setPrice(item.getProductPrice()); |
| | | if (receiptLine.getReceivedQuantity() != null) { |
| | | receiptLine.setTotalPrice(item.getProductPrice().multiply(receiptLine.getReceivedQuantity())); |
| | | } |
| | | } catch (Exception ex) { |
| | | // ä»·æ ¼åªæ¯å¿«ç
§ï¼éè´è®¢åè¡åä¸å°æ¶ä¸é»æå
¥åº |
| | | log.warn("[fillReceiptLinePrice][éè´è®¢åè¡({}) ä»·æ ¼å¿«ç
§å¤±è´¥]", receiptLine.getPurchaseOrderItemId(), ex); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void submitItemReceiptApproval(Long id, String processDefinitionKey) { |
| | |
| | | if (noticeLine != null) { |
| | | line.setSaleOrderItemId(noticeLine.getSaleOrderItemId()); |
| | | } |
| | | fillProductSalesLinePrice(line); |
| | | productSalesLineMapper.insert(line); |
| | | return line.getId(); |
| | | } |
| | | |
| | | /** |
| | | * æéå®è®¢åè¡åä»·åå¡«åºåºè¡éé¢ï¼ä¾å¼ç¥¨/å¯¹è´¦ä½¿ç¨ |
| | | */ |
| | | private void fillProductSalesLinePrice(MesWmProductSalesLineDO line) { |
| | | if (line.getSaleOrderItemId() == null) { |
| | | return; |
| | | } |
| | | try { |
| | | var item = saleOrderApi.getSaleOrderItem(line.getSaleOrderItemId()).getData(); |
| | | if (item == null || item.getProductPrice() == null) { |
| | | return; |
| | | } |
| | | line.setPrice(item.getProductPrice()); |
| | | if (line.getQuantity() != null) { |
| | | line.setTotalPrice(item.getProductPrice().multiply(line.getQuantity())); |
| | | } |
| | | } catch (Exception ex) { |
| | | // ä»·æ ¼åªæ¯å¿«ç
§ï¼è®¢åè¡åä¸å°æ¶ä¸é»æå¼å |
| | | log.warn("[fillProductSalesLinePrice][éå®è®¢åè¡({}) ä»·æ ¼å¿«ç
§å¤±è´¥]", line.getSaleOrderItemId(), ex); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | |
| | | if (noticeLine != null) { |
| | | updateObj.setSaleOrderItemId(noticeLine.getSaleOrderItemId()); |
| | | } |
| | | fillProductSalesLinePrice(updateObj); |
| | | productSalesLineMapper.updateById(updateObj); |
| | | |
| | | // æäº¤åºåºååç±è´¨æ£äººå鿩已宿çåºåæ£éªåã |
| | |
| | | |
| | | import cn.hutool.core.util.ObjUtil; |
| | | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| | | import cn.iocoder.yudao.module.aftersales.api.AfterSaleTicketApi; |
| | | import cn.iocoder.yudao.module.aftersales.api.dto.AfterSaleWarehouseReturnCreateReqDTO; |
| | | import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; |
| | | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| | | import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; |
| | |
| | | private MesMdmItemService mdmItemService; |
| | | @Resource |
| | | private MesWmTransactionService wmTransactionService; |
| | | @Resource |
| | | private AfterSaleTicketApi afterSaleTicketApi; |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | |
| | | MesWmReturnSalesDO returnSales = BeanUtils.toBean(createReqVO, MesWmReturnSalesDO.class); |
| | | returnSales.setStatus(MesWmReturnSalesStatusEnum.PREPARE.getStatus()); |
| | | returnSalesMapper.insert(returnSales); |
| | | |
| | | // 3. 忥å
³èå®åå·¥åï¼ä»å¨éè´§çç + å·¥åè¿å
¥å¾
éè´§ |
| | | AfterSaleWarehouseReturnCreateReqDTO returnReqDTO = new AfterSaleWarehouseReturnCreateReqDTO(); |
| | | returnReqDTO.setSaleOrderId(createReqVO.getSaleOrderId()); |
| | | returnReqDTO.setReturnSalesId(returnSales.getId()); |
| | | returnReqDTO.setReturnSalesCode(createReqVO.getCode()); |
| | | returnReqDTO.setReturnReason(createReqVO.getReturnReason()); |
| | | afterSaleTicketApi.onWarehouseReturnCreated(returnReqDTO); |
| | | |
| | | return returnSales.getId(); |
| | | } |
| | | |
| | |
| | | import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; |
| | | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| | | import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; |
| | | import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; |
| | | import cn.iocoder.yudao.module.bpm.api.task.BpmProcessInstanceApi; |
| | | import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.wm.returnvendor.vo.MesWmReturnVendorPageReqVO; |
| | |
| | | import cn.iocoder.yudao.module.mes.service.wm.transaction.dto.MesWmTransactionSaveReqDTO; |
| | | import cn.iocoder.yudao.module.system.api.storage.StorageAttachmentApi; |
| | | import jakarta.annotation.Resource; |
| | | import org.springframework.security.core.Authentication; |
| | | import org.springframework.security.core.context.SecurityContextHolder; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | import org.springframework.validation.annotation.Validated; |
| | |
| | | */ |
| | | @Service |
| | | @Validated |
| | | @Slf4j |
| | | public class MesWmReturnVendorServiceImpl implements MesWmReturnVendorService { |
| | | |
| | | /** |
| | |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void submitReturnVendorApproval(Long id, String processDefinitionKey) { |
| | | // 1. æ ¡éªåå¨ + èç¨¿ç¶æ + è³å°ä¸æ¡è¡ |
| | | validateReturnVendorExistsAndPrepare(id); |
| | | MesWmReturnVendorDO returnVendor = validateReturnVendorExistsAndPrepare(id); |
| | | if (CollUtil.isEmpty(returnVendorLineService.getReturnVendorLineListByReturnId(id))) { |
| | | throw exception(WM_RETURN_VENDOR_NO_LINE); |
| | | } |
| | | // 1.1. è´¨éé¨åèµ·éè´§å¿
é¡»ä¸ä¼ éä»¶ï¼è´¨æ£æ¥åãä¸åæ ¼ç
§ççï¼ï¼å¦å审æ¹äººæ æ³å¤æéè´§ä¾æ® |
| | | if (CollUtil.isEmpty(storageAttachmentApi.listAttachments(RETURN_VENDOR_RECORD_TYPE, id))) { |
| | | throw exception(WM_RETURN_VENDOR_ATTACHMENT_REQUIRED, returnVendor.getCode()); |
| | | } |
| | | |
| | | // 2. å
¨å±å
审æ¹ï¼ç´æ¥ç½®ä¸ºãå¾
æ£è´§ãï¼æ éæµç¨æ¨¡å |
| | |
| | | * è·åå½åç¨æ·ç¼å·ï¼BPM æµç¨å起人ãè´¢å¡äººåï¼ |
| | | */ |
| | | private Long getCurrentUserId() { |
| | | Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); |
| | | if (authentication != null && authentication.getPrincipal() instanceof Long) { |
| | | return (Long) authentication.getPrincipal(); |
| | | } |
| | | return null; |
| | | // ç»ä¸ä»å®å
¨æ¡æ¶åç»å½ç¨æ·ï¼Spring Security ç principal æ¯ LoginUser èé Longï¼ |
| | | // ç´æ¥å¼ºè½¬ä¼åå° nullï¼å¯¼è´ BPM æµç¨å®ä¾çå起人为å符串 "null" |
| | | return SecurityFrameworkUtils.getLoginUserId(); |
| | | } |
| | | |
| | | private void createTransactionList(MesWmReturnVendorDO returnVendor, List<MesWmReturnVendorDetailDO> details) { |
| | | wmTransactionService.createTransactionList(convertList(details, detail -> new MesWmTransactionSaveReqDTO() |
| | | .setType(MesWmTransactionTypeEnum.OUT.getType()).setItemId(detail.getItemId()) |
| | | // ææ£è´§æ¶éä¸çåºåè®°å½æ£åï¼çäº§æ¹æ¬¡å¯è½æ²¡æ vendor_idï¼ä»
é ç©æ+åºä½+æ¹æ¬¡+ä¾åºå ç»åé®ä¼æ¾ä¸å°åºå |
| | | .setMaterialStockId(detail.getMaterialStockId()) |
| | | .setQuantity(detail.getQuantity().negate()) // åºåºæ°éä¸ºè´æ° |
| | | .setBatchId(detail.getBatchId()).setBatchCode(detail.getBatchCode()) |
| | | .setWarehouseId(detail.getWarehouseId()).setLocationId(detail.getLocationId()).setAreaId(detail.getAreaId()) |
| | |
| | | } |
| | | try { |
| | | importPurchaseOrderItems(id); |
| | | } catch (ServiceException ignore) { |
| | | // éè´è®¢åæ æç» / æ å¯éç©æçä¸å¡å¼å¸¸ï¼åæ®ä¸»ä½ä»æ£å¸¸ä¿åï¼å¯å¨ç©æåºå¦è¡å¤ç |
| | | } catch (ServiceException ex) { |
| | | // éè´è®¢åæ æç» / æ å¯éç©æçä¸å¡å¼å¸¸ï¼åæ®ä¸»ä½ä»æ£å¸¸ä¿åï¼å¯å¨ç©æåºç¹ã鿰另å
¥è®¢åç©æã补带 |
| | | // ææ¥å¿ä¾¿äºææ¥ï¼ä¾å¦ï¼ä¿ååæå
¥åºï¼æ¤æ¶è®¢åè¿æ²¡æå¯éæ°éï¼ |
| | | log.warn("[autoImportLinesFromLinkedOrder][éè´§å({}) å
³èéè´è®¢å({}) èªå¨å¸¦å
¥ç©æå¤±è´¥ï¼{}]", |
| | | id, returnVendor.getPurchaseOrderId(), ex.getMessage()); |
| | | } |
| | | } |
| | | |
| | |
| | | orderItem.setCount(item.getQuantity()); |
| | | orderItem.setTaxPercent(quote.getTaxRate()); |
| | | orderItem.setRemark("SRM询价 " + inquiry.getNo()); |
| | | orderItem.setQcCheckFlag(false); |
| | | // ä¸éè´ç³è¯·/éè´å°è´¦ä¸è´ï¼æ°çæçéè´æç»é»è®¤è´¨æ£ |
| | | orderItem.setQcCheckFlag(true); |
| | | orderItems.add(orderItem); |
| | | } |
| | | ErpPurchaseOrderCreateReqDTO createReqDTO = new ErpPurchaseOrderCreateReqDTO(); |
| | |
| | | void updateUser(AdminUserUpdateReqDTO updateReqDTO); |
| | | |
| | | /** |
| | | * æ´æ°ç¨æ·ç¶æï¼å¼å¯ / åç¨ï¼ |
| | | * |
| | | * @param id ç¨æ·ç¼å· |
| | | * @param status ç¶æï¼è§ {@link cn.iocoder.yudao.framework.common.enums.CommonStatusEnum} |
| | | */ |
| | | void updateUserStatus(Long id, Integer status); |
| | | |
| | | /** |
| | | * éè¿ç¨æ· ID æ¥è¯¢ç¨æ· |
| | | * |
| | | * @param id ç¨æ·ID |
| | |
| | | } |
| | | |
| | | @Override |
| | | public void updateUserStatus(Long id, Integer status) { |
| | | userService.updateUserStatus(id, status); |
| | | } |
| | | |
| | | @Override |
| | | @DataPermission(enable = false) // å¿½ç¥æ°æ®æéï¼é¿å
å ä¸ºè¿æ»¤ï¼å¯¼è´æ æ³æ¥è¯¢ç¨æ·ã类似ï¼https://github.com/YunaiV/ruoyi-vue-pro/issues/1051 |
| | | public AdminUserRespDTO getUser(Long id) { |
| | | AdminUserDO user = userService.getUser(id); |
| | |
| | | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| | | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| | | import cn.iocoder.yudao.module.infra.api.websocket.WebSocketSenderApi; |
| | | import cn.iocoder.yudao.module.system.api.storage.StorageAttachmentApi; |
| | | import cn.iocoder.yudao.module.system.controller.admin.notice.vo.NoticePageReqVO; |
| | | import cn.iocoder.yudao.module.system.controller.admin.notice.vo.NoticeRespVO; |
| | | import cn.iocoder.yudao.module.system.controller.admin.notice.vo.NoticeSaveReqVO; |
| | |
| | | |
| | | @Resource |
| | | private WebSocketSenderApi webSocketSenderApi; |
| | | |
| | | @Resource |
| | | private StorageAttachmentApi storageAttachmentApi; |
| | | |
| | | @PostMapping("/create") |
| | | @Operation(summary = "å建éç¥å
Œ") |
| | |
| | | @Parameter(name = "id", description = "ç¼å·", required = true, example = "1024") |
| | | public CommonResult<NoticeRespVO> getNotice(@RequestParam("id") Long id) { |
| | | NoticeDO notice = noticeService.getNotice(id); |
| | | return success(BeanUtils.toBean(notice, NoticeRespVO.class)); |
| | | NoticeRespVO respVO = BeanUtils.toBean(notice, NoticeRespVO.class); |
| | | if (respVO != null) { |
| | | respVO.setAttachmentList(storageAttachmentApi.listAttachments("notice", id)); |
| | | } |
| | | return success(respVO); |
| | | } |
| | | |
| | | @PostMapping("/push") |
| | |
| | | package cn.iocoder.yudao.module.system.controller.admin.notice.vo; |
| | | |
| | | import cn.iocoder.yudao.module.system.api.storage.dto.StorageBlobRespDTO; |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | |
| | | import java.time.LocalDateTime; |
| | | import java.util.List; |
| | | |
| | | @Schema(description = "管çåå° - éç¥å
¬åä¿¡æ¯ Response VO") |
| | | @Data |
| | |
| | | @Schema(description = "å建æ¶é´", requiredMode = Schema.RequiredMode.REQUIRED, example = "æ¶é´æ³æ ¼å¼") |
| | | private LocalDateTime createTime; |
| | | |
| | | @Schema(description = "éä»¶å表") |
| | | private List<StorageBlobRespDTO> attachmentList; |
| | | |
| | | } |
| | |
| | | import jakarta.validation.constraints.NotNull; |
| | | import jakarta.validation.constraints.Size; |
| | | |
| | | import java.util.List; |
| | | |
| | | @Schema(description = "管çåå° - éç¥å
¬åå建/ä¿®æ¹ Request VO") |
| | | @Data |
| | | public class NoticeSaveReqVO { |
| | |
| | | @Schema(description = "ç¶æï¼åè§ CommonStatusEnum æä¸¾ç±»", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") |
| | | private Integer status; |
| | | |
| | | @Schema(description = "éä»¶ blobId å表", example = "[1, 2, 3]") |
| | | private List<Long> blobIds; |
| | | |
| | | } |
| | |
| | | |
| | | // ===== éç¥å
Œ ===== |
| | | NOTICE("notice", "éç¥å
Œ"), |
| | | OA_NOTICE("oa_notice", "åååå
¬-éç¥å
Œ"), |
| | | |
| | | // ===== 头å ===== |
| | | AVATAR("avatar", "头å"), |
| | |
| | | |
| | | // ===== å®å ===== |
| | | AFTER_SALE_TICKET("aftersales_after_sale_ticket", "å®åå·¥å"), |
| | | AFTER_SALE_TICKET_FEEDBACK("aftersales_after_sale_ticket_feedback", "å®åå·¥å-客æ·è¯æ±åé¦"), |
| | | AFTER_SALE_TICKET_RESULT("aftersales_after_sale_ticket_result", "å®åå·¥å-å¤çç»æ"), |
| | | AFTER_SALE_RETURN("aftersales_after_sale_return", "å®åéè´§ç³è¯·"), |
| | | AFTER_SALE_VISIT("aftersales_after_sale_visit", "å®åå访"), |
| | | AFTER_SALE_PROBLEM("aftersales_after_sale_problem", "å®åé®é¢åº"), |
| | | |
| | | // ===== MES ===== |
| | | MES_PD_DOCUMENT("mes_pd_document", "MES è®¾è®¡èµæ"), |
| | | MES_WM_RETURN_VENDOR("mes_wm_return_vendor", "MES ä¾åºåéè´§å"), |
| | | |
| | | MDM_ITEM_TECHNICAL_FILE("mdm_item_technical_file", "MDM ç©æææ¯æä»¶"), |
| | | MES_WORK_ORDER_TECHNICAL_FILE("mes_work_order_technical_file", "çäº§å·¥åææ¯æä»¶å¿«ç
§"), |
| | |
| | | |
| | | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| | | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| | | import cn.iocoder.yudao.module.system.api.storage.StorageAttachmentApi; |
| | | import cn.iocoder.yudao.module.system.controller.admin.notice.vo.NoticePageReqVO; |
| | | import cn.iocoder.yudao.module.system.controller.admin.notice.vo.NoticeSaveReqVO; |
| | | import cn.iocoder.yudao.module.system.dal.dataobject.notice.NoticeDO; |
| | |
| | | @Service |
| | | public class NoticeServiceImpl implements NoticeService { |
| | | |
| | | /** éä»¶å
³èçä¸å¡è®°å½ç±»å */ |
| | | private static final String RECORD_TYPE = "notice"; |
| | | /** éä»¶åºç¨ç¨é */ |
| | | private static final String APPLICATION = "file"; |
| | | |
| | | @Resource |
| | | private NoticeMapper noticeMapper; |
| | | |
| | | @Resource |
| | | private StorageAttachmentApi storageAttachmentApi; |
| | | |
| | | @Override |
| | | public Long createNotice(NoticeSaveReqVO createReqVO) { |
| | | NoticeDO notice = BeanUtils.toBean(createReqVO, NoticeDO.class); |
| | | noticeMapper.insert(notice); |
| | | storageAttachmentApi.bindAttachments(APPLICATION, RECORD_TYPE, notice.getId(), createReqVO.getBlobIds()); |
| | | return notice.getId(); |
| | | } |
| | | |
| | |
| | | // æ´æ°éç¥å
Œ |
| | | NoticeDO updateObj = BeanUtils.toBean(updateReqVO, NoticeDO.class); |
| | | noticeMapper.updateById(updateObj); |
| | | storageAttachmentApi.updateAttachments(APPLICATION, RECORD_TYPE, updateReqVO.getId(), updateReqVO.getBlobIds()); |
| | | } |
| | | |
| | | @Override |
| | | public void deleteNotice(Long id) { |
| | | // æ ¡éªæ¯å¦åå¨ |
| | | validateNoticeExists(id); |
| | | // å é¤éç¥å
Œ |
| | | // å é¤éç¥å
¬ååå
¶éä»¶å
³è |
| | | noticeMapper.deleteById(id); |
| | | storageAttachmentApi.deleteAttachmentsByRecord(RECORD_TYPE, id); |
| | | } |
| | | |
| | | @Override |
| | | public void deleteNoticeList(List<Long> ids) { |
| | | noticeMapper.deleteByIds(ids); |
| | | for (Long id : ids) { |
| | | storageAttachmentApi.deleteAttachmentsByRecord(RECORD_TYPE, id); |
| | | } |
| | | } |
| | | |
| | | @Override |