feat(basic): 添加产品条码功能并完善生产统计报表
- 在 ProductModel 中新增 barcode 字段及相应校验逻辑
- 实现根据条码查询产品规格的功能接口
- 添加生产报工记录中的设备信息字段
- 实现计件工资汇总统计及导出功能
- 实现产量统计报表(按设备/工序/产品维度)
- 完善 BOM 齐套分析功能
- 添加库存预警查询及导出功能
- 优化检验流程中的状态校验和幂等处理
- 修复产品删除时的关联检查逻辑
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | # å端èè°ææ¡£ â æ¨¡å10ï¼æææ¶èæ ¸ç®ï¼BOMæ å vs å®é
æå
¥ï¼ |
| | | |
| | | > 忝ï¼product-inventory-management-after-jdk25ï¼å®¢æ·åº product-inventory-management-qysjï¼ |
| | | > åç«¯å®ææ¥æï¼2026-09-10ãç¶æï¼å端已å®ç°å¹¶ç¼è¯éè¿ï¼å¾
å端èè° |
| | | |
| | | ## ä¸ãåè½è¯´æ |
| | | |
| | | 纯æ¥è¯¢æ¥è¡¨ï¼æ æ°è¡¨ãæ DDLï¼ï¼æ"ç产订å Ã ç©æ"è¾åºï¼ |
| | | |
| | | | å | å£å¾ | |
| | | |---|---| |
| | | | BOMåè | 订åBOMç»æ(`production_bom_structure`)éå±å±å¼åç**累计åè**ï¼ä¸çº§ç´¯è®¡Ãæ¬çº§ç¨éï¼ | |
| | | | å®å·¥æ°é | 订åå®å·¥æ°éï¼æªå®å·¥æ¶åéç¨è®¡åæ°éï¼è¯¥å£å¾ä¸å·®å¼ä»
ä¾åèï¼ | |
| | | | æ åæ¶è | BOM累计åè à å®å·¥æ°é | |
| | | | å®é
æ¶è | æ¥å·¥æå
¥å计ï¼`production_product_input.input_quantity`ï¼ç»å·¥åå½å°è®¢åï¼ | |
| | | | 差弿°é/å·®å¼ç | å®é
âæ åï¼å·®å¼ç=å·®å¼Ã·æ åÃ100ï¼æ å为0æ¶ä¸ºç©ºï¼ | |
| | | | BOM夿å
¥ | BOM没æä½æ¥å·¥æè¿çç©æä¹ä¼åºè¡ï¼åè/æ å为0ï¼ï¼ç¨äºåç°è¯¯é¢/è¶
æ ç©æ | |
| | | |
| | | ## äºãæ¥å£ï¼è¿å Rï¼{code:200,data:[...]}ï¼ |
| | | |
| | | ### 1. æ ¸ç®å表 |
| | | |
| | | `GET /materialConsumption/stat` |
| | | |
| | | | åæ° | 说æ | |
| | | |---|---| |
| | | | startDate / endDate | è®¢åæ¥æèå´ï¼`yyyy-MM-dd`ãå£å¾=`coalesce(create_time, start_time)`ï¼åå²è®¢å create_time 为空æ¶åéå¼å·¥æ¥æï¼é¿å
çä¸¢ï¼ | |
| | | | npsNo | ç产订åå·æ¨¡ç³ | |
| | | | productName | æååç§°/è§æ ¼æ¨¡ç³ | |
| | | | onlyDiff | true=åªä¿çå·®å¼â 0 è¡ | |
| | | |
| | | è¿åè¡å段ï¼`productionOrderId, npsNo, finishedProduct, materialModelId, materialName, materialModel, unit, unitQuantity, completeQty, standardQty, actualQty, diffQty, diffRate` |
| | | |
| | | ### 2. å¯¼åº |
| | | |
| | | `GET /materialConsumption/stat/export`ãåæ°åä¸ï¼Excel æµï¼æä»¶å"æææ¶èæ ¸ç®"ï¼ï¼å端 blob ä¸è½½ã |
| | | |
| | | ## ä¸ã页é¢å»ºè®® |
| | | |
| | | - **èåï¼å·²å ï¼**ï¼åç§°ãæææ¶èæ ¸ç®ãï¼menu_id=2350ï¼ç¶çº§ãç产管æ§ã(2058)ï¼è·¯ç± `materialConsumption`ï¼component `productionManagement/materialConsumption/index`ï¼å¯è§è§è² æ®é/å¶é ã |
| | | - 页é¢å½¢æï¼é¡¶é¨çéï¼æ¥æèå´/订åå·/æåï¼+ "åªçå·®å¼"å¼å
³ + å¯¼åºæé®ã |
| | | - å表æè®¢ååç»å±ç¤ºï¼npsNo/finishedProduct åå¯åå¹¶åå
æ ¼ï¼ï¼å·®å¼ç>10% æ 红ã |
| | | - 建议æä¾ä»æ ¸ç®é¡µç¹å»è®¢åå·è·³è½¬ç产订å详æ
çèå¨ã |
| | | |
| | | ## åãèè°èªæµæ¸
å |
| | | |
| | | - [ ] å·²å®å·¥è®¢åï¼æ å=åèÃå®å·¥ãå®é
=è¯¥è®¢åæ¥å·¥æå
¥å计ï¼ä¸æ°æ®åºæå·¥æ ¸å¯¹ä¸è´ |
| | | - [ ] å¤å±BOMï¼åæåå±ç©æåè为éå±ç´¯è®¡å¼ï¼ä¸çº§ç¨éÃæ¬çº§ç¨éï¼ |
| | | - [ ] BOM夿å
¥ç©æåºç°å¨åè¡¨ä¸ diffQty=actualQtyï¼æ å为0ãå·®å¼çä¸ºç©ºï¼ |
| | | - [ ] onlyDiff=true æ¶å·®å¼0è¡è¢«è¿æ»¤ |
| | | - [ ] æªå®å·¥è®¢ååé计åéå£å¾ |
| | | - [ ] 导åºå
容ä¸å表ä¸è´ |
| | | |
| | | ## äºãéç说æ |
| | | |
| | | - å®é
æ¶èå"æ¥å·¥æå
¥"å£å¾ï¼è¥å®¢æ·åç»è¦æ±æ"颿åºåº"å£å¾ï¼production_order_pickï¼ï¼äºæå `dataSource=pick` 忰忢ã |
| | | - å·®å¼éé¢ï¼Ãéè´åä»·ï¼å½å
¥æ¨¡å11ææ¬æ ¸ç®ã |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | # å端èè°ææ¡£ â æ¨¡å11ï¼ææ¬æ ¸ç®åæï¼ææ+人工+è½èï¼ |
| | | |
| | | > 忝ï¼product-inventory-management-after-jdk25ï¼å®¢æ·åº product-inventory-management-qysjï¼ |
| | | > åç«¯å®ææ¥æï¼2026-09-10ãç¶æï¼å端已å®ç°å¹¶ç¼è¯éè¿ï¼å¾
å端èè° |
| | | |
| | | ## ä¸ãåè½è¯´æ |
| | | |
| | | 纯æ¥è¯¢æ¥è¡¨ï¼æ æ°è¡¨ãæ DDLï¼ï¼ä»¥"ç产订å"ä¸ºæ ¸ç®ä¸»ä½ï¼è¾åºææ¬æ ¸ç®æç»ãææ¬æææ±æ»ãç¼ºä»·ç©ææ¸
åä¸ä¸ªè§å¾ï¼åå¯å¯¼åº Excelã |
| | | |
| | | ### ææ¬å£å¾ |
| | | |
| | | | ææ¬é¡¹ | å£å¾ | |
| | | |---|---| |
| | | | ææææ¬ | Σ(该订ååç©ææ¥å·¥æå
¥é à éè´åä»·)ãæå
¥éå `production_product_input.input_quantity`ï¼ç»å·¥åå½å°è®¢åï¼ï¼ä¸æ¨¡å10"å®é
æ¶è"åå£å¾ | |
| | | | éè´åä»· | æä¼å
级å第ä¸ä¸ªæä»·æ¥æºï¼**éè´ä»·ç®è¡¨ > éè´æç»(éå®å°è´¦ type=2) > éè´å
¥åºè®°å½ > éè´å票ç»è®°**ï¼å表å
åææ°ä¸æ¡ï¼max(id)ï¼ | |
| | | | äººå·¥ææ¬ | 䏿¨¡å5å·¥èµæ±æ»åå
¬å¼ï¼è®¡ä»¶åä»·(`piece_rate_config`) > 计æ¶(`poro.type=0`ï¼å·¥æ¶Ãæ¥å·¥ä¸»è¡¨å·¥æ¶åä»·) > å
¶ä»ï¼å·¥æ¶Ãå®å·¥æ°Ãè§æ ¼å
åµåä»·ï¼å³è§æ ¼æ«å°¾ `*æ°å` æ®µï¼ | |
| | | | è½èææ¬ | çéåºé´å
`Σ(设å¤ç¨çµéÃ彿¥çµä»·)`ï¼æè®¢å**产éå æ¯**åæå°å订å | |
| | | | 产é | å®å·¥æ°éä¼å
ï¼æªå®å·¥åéè®¡åæ°éï¼ä¸æ¨¡å10ä¸è´ï¼ | |
| | | | éå®åä»· | 订åå
³èç产计åâéå®åï¼åéå®å°è´¦ `type=1` å«ç¨åä»·ï¼å¤å¼ æ¶åææ° | |
| | | | æ¯å© / æ¯å©ç | (éå®åä»·âå使æ¬)Ã产éï¼æ¯å© ÷ (éå®åä»·Ã产é) Ã100 | |
| | | | åä½ææ¬ | æ»ææ¬ Ã· 产éï¼äº§é为0æ¶ä¸ºç©ºï¼ | |
| | | |
| | | ### æ°æ®è´¨éè¾
å©å |
| | | |
| | | - **ä»·æ ¼è¦çç%**ï¼æéè´ä»·çç©ææ¶èé ÷ å
¨é¨æ¶èé Ã100ãä½äº100è¯´æææææ¬è¢«ä½ä¼°ï¼éè¡¥å½åä»·ã |
| | | - **ç¼ºä»·ç©ææ°**ï¼è¯¥è®¢åæå
¥äºä½åä¸ªæ¥æºé½æ¥ä¸å°åä»·çç©æç§ç±»æ°ã |
| | | - **æ å·¥èµæ åè®°å½**ï¼æ¥å·¥æ ¸ç®è®°å½ä¸"å·¥æ¶ä¸º0䏿 计件åä»·"çè¡æ°ï¼>0 说æäººå·¥ææ¬ä¸å¯ä¿¡ï¼éè¡¥å½å·¥æ¶æç»´æ¤è®¡ä»¶åä»·ã |
| | | |
| | | ## äºãæ¥å£ï¼è¿å Rï¼{code:200,data:[...]}ï¼ |
| | | |
| | | å
Œ
±çéåæ°ï¼ä¸ä¸ªæ¥è¯¢æ¥å£ä¸è´ï¼ï¼ |
| | | |
| | | | åæ° | 说æ | |
| | | |---|---| |
| | | | startDate / endDate | è®¢åæ¥æèå´ï¼`yyyy-MM-dd`ã**æ¥æå£å¾= `coalesce(create_time, start_time)`**ï¼åå²è®¢å create_time 为空æ¶åéå¼å·¥æ¥æï¼é¿å
çä¸¢ï¼ | |
| | | | npsNo | ç产订åå·æ¨¡ç³ | |
| | | | productName | æååç§°/è§æ ¼æ¨¡ç³ | |
| | | |
| | | ### 1. ææ¬æ ¸ç®æç»ï¼æè®¢åï¼ |
| | | |
| | | `GET /costAccounting/stat` |
| | | |
| | | è¿åè¡åæ®µï¼ |
| | | `productionOrderId, npsNo, finishedProduct, unit, orderDate, outputQty, materialCost, laborCost, energyCost, totalCost, unitCost, salePrice, grossProfit, grossProfitRate, priceCoverageRate, missingPriceKinds, noRateRows` |
| | | |
| | | éé¢å为 BigDecimalï¼ä¿ç2ä½ï¼unitCost 4ä½ï¼ï¼salePrice/grossProfit/grossProfitRate å¯è½ä¸º nullï¼æ å
³èéå®åæäº§é为0ï¼ï¼å端éå空å¼å±ç¤ºï¼å¦"â"ï¼ã |
| | | |
| | | ### 2. ææ¬æææ±æ» |
| | | |
| | | `GET /costAccounting/summary?groupBy=month|product`ï¼é»è®¤ monthï¼ |
| | | |
| | | - `groupBy=month`ï¼æè®¢åæ¥ææä»½ï¼`yyyy-MM`ï¼æ æ¥æå½"æªå¡«æ¥æ"ï¼èå |
| | | - `groupBy=product`ï¼ææåï¼åç§°/è§æ ¼ï¼èå |
| | | |
| | | è¿åè¡åæ®µï¼ |
| | | `groupKey, orderCount, outputQty, materialCost, laborCost, energyCost, totalCost, unitCost, materialRate, laborRate, energyRate, grossProfit, grossProfitRate` |
| | | |
| | | å æ¯åï¼materialRate çï¼= å¯¹åºææ¬ Ã· æ»ææ¬ Ã100ï¼éåå端ç»å 积饼å¾/æ±å¾ã |
| | | |
| | | ### 3. ç¼ºä»·ç©ææ¸
å |
| | | |
| | | `GET /costAccounting/missingPrice` |
| | | |
| | | è¿åçéèå´å
**ææ¶è使 ä»»ä½éè´åä»·**çç©æï¼ |
| | | `productModelId, materialName, materialModel, unit, inputQty, orderCount, lastInputTime` |
| | | |
| | | ç¨éï¼ä½ä¸ºè¡¥å½éè´åä»·ç工使¸
åï¼ç¹å»å¯è·³è½¬ç©æç»´æ¤/ä»·ç®è¡¨é¡µé¢ï¼ã |
| | | |
| | | ### 4. 导åºï¼Excel æµï¼å端 blob ä¸è½½ï¼ |
| | | |
| | | | æ¥å£ | æä»¶å | åæ° | |
| | | |---|---|---| |
| | | | `GET /costAccounting/stat/export` | ææ¬æ ¸ç®æç» | å stat | |
| | | | `GET /costAccounting/summary/export` | ææ¬æææ±æ» | å summary | |
| | | | `GET /costAccounting/missingPrice/export` | ç¼ºä»·ç©ææ¸
å | å missingPrice | |
| | | |
| | | ## ä¸ã页é¢å»ºè®® |
| | | |
| | | - **èåï¼å·²å ï¼**ï¼åç§°ãææ¬æ ¸ç®åæãï¼menu_id=2351ï¼ç¶çº§ãç产管æ§ã(2058)ï¼è·¯ç± `costAccounting`ï¼component `productionManagement/costAccounting/index`ï¼å¯è§è§è² æ®é/HR/管ç/è´¢å¡/å¶é ãæ³¨ææçæ¯ãç产管æ§ãèéã管ç驾驶è±ãââåè
(2036)å½åæ¯åç¨ç¶æï¼æä¸å»ä¸ä¼æ¾ç¤ºã |
| | | - 页é¢å½¢æï¼ä¸ä¸ª Tabï¼ |
| | | 1. **æ ¸ç®æç»**ï¼é¡¶é¨çé + è¡¨æ ¼ï¼`priceCoverageRate<100` æ `missingPriceKinds>0` çè¡"ç¼ºä»·ç©ææ°"æ æ©ï¼`noRateRows>0` ç"äººå·¥ææ¬"æ æ©å¹¶ tooltip æç¤ºè¡¥å½ï¼æ¯å©çä¸ºè´æ 红ã |
| | | 2. **æææ±æ»**ï¼æä»½/æå忢 + ææ/人工/è½èå æ¯å ç§¯å¾ + è¡¨æ ¼ï¼ç¹å»æä»½å¯å¸¦æ¥æèå´è·³è½¬æç» Tabã |
| | | 3. **ç¼ºä»·ç©æ**ï¼è¡¨æ ¼ + "å»ç»´æ¤åä»·"æé®ï¼è·³éè´ä»·ç®è¡¨/产åç»´æ¤é¡µï¼ã |
| | | - æç»é¡µç¹å»è®¢åå·å¯è·³è½¬ç产订å详æ
ï¼ä¸æ¨¡å3/10 èå¨ä¸è´ï¼ã |
| | | |
| | | ## åãèè°èªæµæ¸
å |
| | | |
| | | - [ ] statï¼ä»»éå·²å®å·¥è®¢åï¼ææææ¬ = Σ(æå
¥éÃæä»·ç©æåä»·)ï¼ä¸æ°æ®åºæå·¥æ ¸å¯¹ä¸è´ï¼dev å·²éªè¯è®¢å1225ï¼äº§é1706ï¼ææææ¬46266.72ï¼å使æ¬â27.12ï¼ |
| | | - [ ] æ¥æçéå¨ create_time å
¨ç©ºçå岿°æ®ä¸ä»è½å½ä¸ï¼èµ° start_time åéï¼ |
| | | - [ ] summary(groupBy=month)ï¼åç»ææ¬å计 = æç»å¯¹åºåå计ï¼å æ¯ä¹åâ100ï¼æ»ææ¬>0 æ¶ï¼ |
| | | - [ ] summary(groupBy=product)ï¼åæåå¤è®¢ååå¹¶ãè®¢åæ°æ£ç¡® |
| | | - [ ] missingPrice è¿åçç©æå¨ stat è¡é missingPriceKinds å被计å
¥ |
| | | - [ ] æ å
³èéå®å订åï¼salePrice/grossProfit 为 nullï¼é¡µé¢ä¸æ¥é |
| | | - [ ] ä¸ä¸ªå¯¼åºå
容ä¸å表ä¸è´ï¼æ¥æåæ ¼å¼åæ£ç¡® |
| | | |
| | | ## äºãæ°æ®ç°ç¶ä¸éç说æï¼dev åºå®æµï¼ |
| | | |
| | | - **éè´åä»·æ¥æºç°ç¶**ï¼åä¸ªæ¥æºä¸ä»
"éè´æç»(éå®å°è´¦ type=2)"æç宿°æ®ï¼çº¦79ä¸ªè§æ ¼æä»·ï¼å
¶ä¸å½åæ¶èç©æå½ä¸4个ï¼ï¼éè´ä»·ç®è¡¨/éè´å
¥åºè®°å½/å票ç»è®°è¡¨æä¸ºç©ºè¡¨ï¼ä»£ç å·²æä¼å
级 UNIONï¼å®¢æ·å½å
¥åèªå¨çæï¼æ 鿹代ç ã |
| | | - **äººå·¥ææ¬å½å为0**ï¼dev æ°æ®æ¥å·¥å·¥æ¶(work_hours)å
¨ä¸º0ä¸è®¡ä»¶å价表为空ââ屿°æ®ç¼ºå¤±èé计ç®éè¯¯ï¼æ¥è¡¨ç¨"æ å·¥èµæ åè®°å½"åå¦å®æ´é²ï¼é车é´è¡¥å½å·¥æ¶æç»´æ¤ `piece_rate_config`ã |
| | | - **è½èææ¬å½å为0**ï¼`equipment_energy_consumption`ã`energy_period` å为空表ï¼ä¸"è®¾å¤æ°é"ï¼æ¨¡å1ï¼æç¼ï¼æ¥å
¥æ°é/æå·¥æè¡¨åèªå¨åºæ°ãåæé»è¾ä¸ºåºé´çµè´¹æ»é¢æäº§éå æ¯ï¼ä¸åºå订åå®é
弿ºæ¶é¿ï¼å®¢æ·å¦æå表计ééæ±äºæç»åã |
| | | - **éå®åä»·**ä¾èµè®¢åâç产计åâéå®åé¾è·¯ï¼`production_plan_ids` find_in_setï¼ï¼å岿ªå
³èéå®åçè®¢åæ¯å©ä¸ºç©ºã |
| | | - 模å10/模å3 çè®¢åæ¥æçé已忥æ¹ä¸º `coalesce(create_time, start_time)` å£å¾ï¼å端èè°æ¶æ³¨æè¯´æææ¡£ä¸è´ã |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | # å端èè°ææ¡£ â æ¨¡å3ï¼ç产质éè¿½æº¯ï¼æ¹æ¬¡é¾è·¯ï¼ |
| | | |
| | | > 忝ï¼product-inventory-management-after-jdk25ï¼å®¢æ·åº product-inventory-management-qysjï¼ |
| | | > åç«¯å®ææ¥æï¼2026-09-10ãç¶æï¼å端已å®ç°ãç¼è¯éè¿ï¼è¿½æº¯é¾è·¯å·²ç¨ç产åºç宿°æ®éªè¯ï¼å¾
å端èè° |
| | | > 说æï¼çº¯æ¥è¯¢æ¨¡åï¼æ æ°è¡¨ãæ DDLã䏿¹ä»»ä½åå
¥é»è¾ |
| | | |
| | | ## ä¸ãåè½è¯´æ |
| | | |
| | | æé"åææ¹å· â ç产订å â æ¥å·¥å·¥åº â æåæ¹å· â åºåºæµå"çååé¾è·¯ï¼ç¨äºè´¨é追责ä¸å¬ååå®èå´ã |
| | | |
| | | ### é¾è·¯å
³ç³»ï¼åç«¯åæ°å£å¾ï¼ |
| | | |
| | | ``` |
| | | éè´/èªå®ä¹å
¥åº(åææ¹å·) â çäº§é¢æ(production_order_pick.batch_no) |
| | | â ç产订å â å·¥èºè·¯çº¿å·¥åº/å·¥å â ç产æ¥å·¥(production_product_main) |
| | | ââ æ¥å·¥æå
¥(production_product_input) â åæå/ç©æ |
| | | ââ è¿ç¨æ£éª / åºåæ£éª(quality_inspect) â ä¸åæ ¼å¤ç(quality_unqualified) |
| | | ââ åæ ¼å
¥åº stock_in_record(æ¹å· = æåæ¹å·) |
| | | record_type=2 â record_id = æ¥å·¥åid |
| | | record_type=6 â record_id = æ£éªåid â æ£éªå.product_main_id = æ¥å·¥åid |
| | | â éå®åè´§åºåº(stock_out_recordï¼åæåæ¹å·) |
| | | ``` |
| | | |
| | | ## äºãæ¥å£ï¼è¿å Rï¼{code:200,data:...}ï¼æ¹å·ä¸ºç©ºè¿å codeâ 200ï¼msg="æ¹å·ä¸è½ä¸ºç©º"ï¼ |
| | | |
| | | ### 1. æ£åè¿½æº¯ï¼æåæ¹å· â å
¨é¾è·¯ |
| | | |
| | | `GET /quality/trace/forward?batchNo={æåæ¹å·}` |
| | | |
| | | ```jsonc |
| | | { |
| | | "batchNo": "20260826-6-001", |
| | | "chains": [ // ä¸ä¸ªæ¹å·å¯è½å½ä¸å¤ä¸ªè®¢åï¼æè®¢ååç» |
| | | { |
| | | "productionOrderId": 1198, |
| | | "npsNo": "SC202608231108", |
| | | "finishedProduct": "Q3åæ¶æå·¦æ¤æ¿/Q3åæ¶æå·¦æ¤æ¿", |
| | | "unit": "个", |
| | | "planQty": 62.00, "completeQty": 62.00, |
| | | "orderStatus": 3, // ç产订åç¶æï¼ä¸å表页åå
¸ä¿æä¸è´ |
| | | "orderCreateTime": "2026-08-23 11:08:00", |
| | | "batches": [ // å½ä¸å
¥åæ¹å·çå
¥åºè®°å½ |
| | | { "batchNo": "20260826-6-001", "productMainId": 1170, "productModelId": 503, |
| | | "qty": 62.0000, "inTime": "2026-08-26 00:00:00", "recordType": "6" } |
| | | ], |
| | | "reports": [ // 该订åçæ¥å·¥å·¥åºèç¹ï¼å«å
¨é¨å·¥åºï¼ä¸åªå½ä¸æ¹å·çé£éï¼ |
| | | { "productMainId": 1170, "workOrderNo": "GD20260823071", "operationName": "æç£¨", |
| | | "userName": "åç«æ¾", "deviceName": null, "productNo": "BG20260826019", |
| | | "outputQty": 62.0000, "scrapQty": 0.00, "reportTime": "2026-08-26 10:00:00", |
| | | "npsNo": "SC202608231108", "productionOrderId": 1198, "finishedProduct": "...", |
| | | "unit": "个", "planQty": 62.00, "completeQty": 62.00, "orderStatus": 3, "orderCreateTime": "..." } |
| | | ], |
| | | "inputs": [ // æ¥å·¥æå
¥ç©æï¼æ reports ç productMainId å½å±ï¼ |
| | | { "productMainId": 1170, "productModelId": 503, "materialName": "Q3åæ¶æå·¦æ¤æ¿", |
| | | "materialModel": "Q3åæ¶æå·¦æ¤æ¿", "unit": "个", "inputQty": 62.000000, |
| | | "workOrderNo": "GD20260823071", "operationName": "æç£¨" } |
| | | ], |
| | | "picks": [ // 该订åçé¢ææ¹æ¬¡ï¼åææ¹å·ï¼ï¼å·²å溯ä¾åºå/æ£éªç»è®º |
| | | { "productionOrderId": 1198, "productModelId": 704, "materialName": "HDPE HE120 ç½è²", |
| | | "materialModel": "HDPE HE120", "unit": "kg", "batchNo": "20260801-HDPE HE120-001", |
| | | "quantity": 5.96, "operationName": "䏿", "pickTime": "2026-08-23 14:00:00", |
| | | "supplierName": null, // 该æ¹å·ä¸ºèªå®ä¹å
¥åºæ¶æ ä¾åºåï¼éè´å
¥åºæ¹å·ä¼å¸¦åº |
| | | "contractNo": null, "checkResult": null } |
| | | ], |
| | | "inspects": [ // è¿ç¨/åºåæ£éªå |
| | | { "inspectId": 1825, "productMainId": 1170, "inspectType": 2, "inspectTypeName": "åºåæ£éª", |
| | | "process": null, "checkName": "å¼ å·¥", "productName": "Q3åæ¶æå·¦æ¤æ¿", "model": "Q3åæ¶æå·¦æ¤æ¿", |
| | | "unit": "个", "quantity": 62.00, "qualifiedQuantity": 62.00, "unqualifiedQuantity": 0.00, |
| | | "checkResult": "åæ ¼", "checkTime": "2026-08-25", "inspectState": 1, |
| | | "defectivePhenomena": null, "unqualifiedList": [] } |
| | | ], |
| | | "unqualifiedList": [ // ä¸åæ ¼å¤çï¼æå¹³åï¼ä¾¿äºæ¶é´çº¿å±ç¤ºï¼äº¦å¨ inspects[].unqualifiedList ä¸ï¼ |
| | | { "id": 12, "inspectId": 1825, "productName": "...", "model": "...", "unit": "个", |
| | | "quantity": 1.00, "defectivePhenomena": "å¤è§å伤", "dealResult": "æ¥åº", |
| | | "dealName": "ç强", "dealTime": "2026-08-26", "inspectState": 1, "checkTime": "2026-08-25" } |
| | | ] |
| | | } |
| | | ], |
| | | "outbounds": [ // åæ¹å·çåºåºæµåï¼éå®åè´§/éè´§çï¼ |
| | | { "id": 1349, "batchNo": "20260826-6-001", "productName": "Q3åæ¶æå·¦æ¤æ¿", |
| | | "productModel": "Q3åæ¶æå·¦æ¤æ¿", "unit": "个", "qty": 62.0000, |
| | | "recordType": "13", "outTime": "2026-08-26 10:00:00", "remark": null } |
| | | ] |
| | | } |
| | | ``` |
| | | |
| | | - `recordType` åå¼ï¼å
¥åº `2`=ç产æ¥å·¥å
¥åºã`6`=è´¨æ£åæ ¼å
¥åºï¼åºåº `13`=éå®åè´§åºåºã`8`=éå®åºåºã`3`=ç产æ¥å·¥åºåºã`1`=èªå®ä¹åºåºã |
| | | - æªå½ä¸ä»»ä½é¾è·¯æ¶ `chains`/`outbounds` å为空æ°ç»ï¼ä¸æ¯æ¥éï¼ï¼å端æç¤º"æªæ¥è¯¢å°è¯¥æ¹å·ç追溯记å½"ã |
| | | |
| | | ### 2. åå追溯ï¼åææ¹å· â åå½±åæå |
| | | |
| | | `GET /quality/trace/reverse?batchNo={åææ¹å·}` |
| | | |
| | | ```jsonc |
| | | { |
| | | "batchNo": "20260801-PA6 B100HS-UV 7CN MP25-001", |
| | | "material": { // 该æ¹å·çå
¥åº/æ£éª/éè´æ¥æºï¼æ å
¥åºè®°å½æ¶ä¸º null |
| | | "inRecordId": 300, "batchNo": "20260801-PA6 B100HS-UV 7CN MP25-001", |
| | | "productModelId": 705, "materialName": "PA6 B100HS-UV 7CN", "materialModel": "MP25", |
| | | "unit": "kg", "qty": 5000.0000, "inTime": "2026-08-01 09:00:00", "recordType": "10", |
| | | "inspectId": 664, "inspectQty": 5000.00, "qualifiedQty": 5000.00, "unqualifiedQty": 0.00, |
| | | "checkResult": "åæ ¼", "checkTime": "2026-08-01", |
| | | "supplierName": "æ²§å·æ
§å®äºéå¶åæéå
¬å¸", "contractNo": "CG20260730455", "entryDate": "2026-08-01" |
| | | }, |
| | | "orders": [ // é¢ç¨è¯¥æ¹å·çææç产订åï¼å¬åèå´ï¼ |
| | | { |
| | | "productionOrderId": 97, "npsNo": "SC202608010007", |
| | | "finishedProduct": "VW316-6åæ¶æå®è£
æ¯æ¶/K31 P58ç±³è²", "unit": "个", |
| | | "planQty": 5000.00, "completeQty": 5000.00, "orderStatus": 3, |
| | | "orderCreateTime": "2026-08-01 08:30:00", |
| | | "pickedQty": 575.00, // æ¬è®¢åé¢ç¨è¢«æ¥æ¹å·çå计 |
| | | "picks": [ { "batchNo": "20260801-PA6 B100HS-UV 7CN MP25-001", "quantity": 575.00, |
| | | "operationName": "䏿", "pickTime": "2026-08-01 10:00:00", "materialName": "...", |
| | | "materialModel": "...", "unit": "kg", "productModelId": 705, |
| | | "productionOrderId": 97, "supplierName": "...", "contractNo": "...", "checkResult": "åæ ¼" } ], |
| | | "reports": [ /* ç»æåæ£å reports */ ], |
| | | "finishedBatches": [ // 该订å产åºçå
¨é¨æåæ¹å· |
| | | { "productionOrderId": 97, "productMainId": 157, "batchNo": "20260801-6-011", |
| | | "productModelId": 505, "qty": 5000.0000, "inTime": "2026-08-02 00:00:00", "recordType": "6" } |
| | | ] |
| | | } |
| | | ] |
| | | } |
| | | ``` |
| | | |
| | | - ä¸ä¸ªåææ¹å·å¸¸è¢«å¤ä¸ªè®¢åé¢ç¨ï¼`orders` å¯è½æå¤æ¡ï¼æ¯æ¡è®¢åç `finishedBatches` å³å¯ç´æ¥ç¨äºè·³è½¬æ£å追溯ã |
| | | - è¥åææ¹å·åªæå
¥åº/éè´è®°å½ä½ä»æªé¢æï¼`material` æå¼ã`orders` 为空æ°ç»ã |
| | | |
| | | ### 3. æ¹å·åéï¼æç´¢ä¸æï¼ |
| | | |
| | | `GET /quality/trace/batchOptions?type=finished|material&keyword={模ç³}&limit={é»è®¤50ï¼æå¤§200}` |
| | | |
| | | è¿å `[{batchNo, productName, productModel, unit, qty, inTime, npsNo}]`ï¼ææ¶é´ååºã |
| | | - `type=finished`ï¼åèªç产å
¥åº/è´¨æ£åæ ¼å
¥åºçæåæ¹å·ï¼å«å¯å
³èç订åå·ï¼ä¾æ£å追溯ï¼ã |
| | | - `type=material`ï¼åèªçäº§é¢æçåææ¹å·ï¼ä¾åå追溯ï¼ã |
| | | |
| | | ### 4. 导åºï¼Excel æµï¼å端 blob ä¸è½½ï¼ |
| | | |
| | | | æ¥å£ | æä»¶å | è¡å«ä¹ | |
| | | |---|---|---| |
| | | | `GET /quality/trace/forward/export?batchNo=` | æåæ¹æ¬¡è¿½æº¯ | æ¯è¡ = 订å Ã é¢æåææ¹å·ï¼å«å·¥åºæ±æ»ãæ£éªç»è®ºæ±æ»ãä¸åæ ¼å¤çæ±æ»ãåæä¾åºå䏿£éªç»è®ºï¼è®¢åæ 颿æ¶è¾åºä¸è¡ç©ºç©æï¼ | |
| | | | `GET /quality/trace/reverse/export?batchNo=` | åææ¹æ¬¡æµå追溯 | æ¯è¡ = åå½±å订åï¼å«åææ¥æº(ä¾åºå/åå/éè´æ¥æ/æ£éªç»è®º)ãé¢ç¨æ°éã该订åäº§åºæåæ¹å·ï¼å¤ä¸ªä»¥ `/` åéï¼ | |
| | | |
| | | 导åºåï¼`æåæ¹å· ç产订åå· æå å®å·¥æ°é å·¥åº æ£éªç»è®º ä¸åæ ¼å¤ç åææ¹å· ç©æ ç©æè§æ ¼ 颿æ°é ä¾åºå åææ£éªç»è®º`ï¼ |
| | | ååï¼`åææ¹å· ç©æ ç©æè§æ ¼ åä½ ä¾åºå éè´ååå· éè´æ¥æ åææ£éªç»è®º ç产订åå· æå é¢ç¨æ°é äº§åºæåæ¹å·`ã |
| | | |
| | | ## ä¸ã页é¢å»ºè®® |
| | | |
| | | - **èåï¼æ²¿ç¨å·²æãç产追溯ãï¼menu_id=2294ï¼ç¶çº§ ç产管æ§ï¼component `productionManagement/productionTraceability/index`ï¼ï¼æ¬æ¬¡ä¸æ°å¢èåã** è¥å端è¦ç¬ç«å
¥å£ï¼éå¦å»ºç»ä»¶æä»¶ååå èåè¡ã |
| | | - 页é¢å½¢æï¼é¡¶é¨åæ¢ **æ£å / åå** ä¸¤ä¸ªé¡µç¾ + æ¹å·æç´¢ä¸æï¼batchOptionsï¼+ è¾å
¥æ¡ + æ¥è¯¢/å¯¼åºæé®ã |
| | | - æ£åç»æå»ºè®®ç¨"æ¶é´çº¿ + æå 颿¿"ï¼è®¢åå¡ â å·¥åºæ¥å·¥ï¼å¯å±å¼æå
¥ç©æï¼â é¢ææ¹æ¬¡ï¼ç¹åææ¹å·èªå¨åå°åå追溯ï¼â æ£éªåï¼å«ä¸åæ ¼å¤çï¼â åºåºæµåã |
| | | - ååç»æå»ºè®®è¡¨æ ¼ï¼ä¸è¡ä¸ä¸ªè®¢åï¼`finishedBatches` 渲æä¸ºå¯ç¹å»æ ç¾ï¼ç¹å»å³è·³è½¬æ£å追溯并åå¡«æ¹å·ã |
| | | - 建议æä¾ `npsNo` 跳转ç产订å详æ
ã`inspectId` 跳转æ£éªå详æ
çèå¨ã |
| | | |
| | | ## åãèè°èªæµæ¸
åï¼å·²ç¨ç宿°æ®æ ¸å¯¹çæ ·ä¾ï¼ |
| | | |
| | | - [x] æ£å `20260826-6-001` â 订å `SC202608231108`ãå·¥å `GD20260823071`(æç£¨)ã颿 `20260801-HDPE HE120-001`ãåºåæ£éª"åæ ¼"ãåºåºè®°å½ 1 æ¡(åè´§62) |
| | | - [x] æ£åå¤è®¢å/å¤å
¥åºç±»åï¼record_type 2 ä¸ 6 åå¯å½ä¸ï¼6 ç»æ£éªååè¿æ¥å·¥åï¼ |
| | | - [x] åå `20260801-PA6 B100HS-UV 7CN MP25-001` â å½ä¸ 5+ 个ç产订åï¼å¬åèå´ï¼ï¼å«å订åæåæ¹å·å¦ `20260801-6-011` |
| | | - [x] åååææ¥æºï¼`record_type=10/7` çæ¹å·å¯å¸¦åºä¾åºå/éè´ååå·/éè´æ¥æï¼`record_type=0`(èªå®ä¹å
¥åº) ä¾åºåä¸ºç©ºå±æ£å¸¸ |
| | | - [x] æ¹å·ä¸æï¼finished / material 两个æ¹åå坿¨¡ç³æç´¢ï¼ææ¹å·ã产ååç§°ãè§æ ¼ï¼ |
| | | - [x] ä¸åå¨çæ¹å·ï¼forward/reverse è¿å空æ°ç»è鿥é |
| | | - [ ] å端ï¼ä¸¤ä¸ªæ¹åç导åºå
容ä¸é¡µé¢å±ç¤ºä¸è´ |
| | | - [ ] åç«¯ï¼æ¹å·å¨åè§å¾é´è·³è½¬ï¼æ£åâååã订å详æ
ãæ£éªå详æ
ï¼ |
| | | |
| | | ## äºãéç说æ |
| | | |
| | | - `orderCreateTime` å£å¾ä¸º `coalesce(create_time, start_time)`ï¼åå²è®¢å create_time 为空æ¶åéå¼å·¥æ¥æï¼å端æ éç¹æ®å¤çã |
| | | - èªå®ä¹å
¥åº/åºåºçæ¹å·ï¼record_type 0/1ï¼æ²¡æåæ®æ¥æºï¼å
¶ä¾åºåã客æ·ä¿¡æ¯æ æ³èªå¨å¸¦åºï¼é¡µé¢æ¾ç¤ºä¸ºç©ºã |
| | | - éå®åºåºç客æ·åç§°éæ `stock_out_record.record_id` å
³èéå®åï¼å½åæªçº³å
¥é¾è·¯ï¼æ¶åé宿¨¡åæ¹é ï¼ï¼äºæå¯å `customer` åæ®µã |
| | | - åæåå¤å±æ¹å·ï¼ç®åæ"订åâæ¥å·¥âæå
¥"å¹³éºå±ç¤ºï¼æªå跨订åçç¶åæ¹å·éå½ï¼è¥å®¢æ·éè¦"æåæ¹å·âåæåæ¹å·âåææ¹å·"å¤çº§å±å¼ï¼äºæè¡¥ `depth` é彿¥å£ã |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | # å端èè°ææ¡£ â æ¨¡å4ï¼BOMç©ææ¸
åå®å |
| | | |
| | | > 忝ï¼product-inventory-management-after-jdk25ï¼å®¢æ·åº product-inventory-management-qysjï¼ |
| | | > åç«¯å®ææ¥æï¼2026-09-10ãç¶æï¼å端已å®ç°å¹¶ç¼è¯éè¿ï¼å¾
å端èè° |
| | | |
| | | ## ä¸ãæ¬æ¬¡æ¹å¨æ¦è§ |
| | | |
| | | åæ `/technologyBom` å·²æ¯æï¼æ°å¢/ä¿®æ¹/å é¤/å¤å¶/导å
¥å¯¼åº/æè§æ ¼æ¥è¯¢ãæ¬æ¬¡è¡¥å
ï¼ |
| | | |
| | | | è½å | 说æ | |
| | | |---|---| |
| | | | çæ¬å¯ç¨/åç¨ | `technology_bom.status`ï¼1å¯ç¨ 0åç¨ï¼ï¼åä¸äº§åè§æ ¼**ä»
ä¸ä¸ªå¯ç¨çæ¬** | |
| | | | BOMé½å¥åæ | æéæ±æ°ééå±å±å¼BOMï¼ä¸å¯ç¨åºåï¼æ°éâéå®éï¼æ¯å¯¹ï¼è¾åºç¼ºå£ | |
| | | | é½å¥åæå¯¼åº | Excel | |
| | | | 缺å£çæéè´éæ± | æ°è¡¨ `procurement_demand` + æ°èåãéè´éæ±ã(menu_id=2353ï¼è§ææ«èå说æ) | |
| | | |
| | | ### çæ¬è§åï¼éè¦ï¼ |
| | | |
| | | - æ°å¢BOMï¼`status` ä¸ä¼ é»è®¤ **1ï¼å¯ç¨ï¼**ï¼å¹¶èªå¨åç¨å产åè§æ ¼çå
¶å®å¯ç¨çæ¬ã |
| | | - å¤å¶BOMï¼æ°çæ¬å·åç¼ `FZ`ï¼ç¶æåºå® **0ï¼åç¨/è稿ï¼**ï¼æ¹å®ç»æååæå¨å¯ç¨ã |
| | | - å¯ç¨æçæ¬ï¼åè§æ ¼å
¶å®çæ¬èªå¨åç¨ã |
| | | - å表页建议å¢å "ç¶æ"åï¼el-tagï¼å¯ç¨=success / åç¨=infoï¼ã |
| | | |
| | | ### æ°æ®åºåçº§èæ¬ |
| | | |
| | | ```sql |
| | | ALTER TABLE technology_bom |
| | | ADD COLUMN status tinyint NOT NULL DEFAULT 1 COMMENT 'ç¶æ 1å¯ç¨ 0åç¨' AFTER version; |
| | | |
| | | CREATE TABLE procurement_demand ( |
| | | id bigint NOT NULL AUTO_INCREMENT COMMENT '主é®', |
| | | product_model_id bigint DEFAULT NULL COMMENT '产åè§æ ¼id', |
| | | product_name varchar(255) DEFAULT NULL COMMENT '产ååç§°(åä½)', |
| | | product_model varchar(255) DEFAULT NULL COMMENT 'è§æ ¼åå·(åä½)', |
| | | unit varchar(32) DEFAULT NULL COMMENT 'åä½(åä½)', |
| | | demand_quantity decimal(18,4) DEFAULT NULL COMMENT '缺å£éæ±é', |
| | | stock_quantity decimal(18,4) DEFAULT NULL COMMENT 'çææ¶å¯ç¨åºåå¿«ç
§', |
| | | source_bom_id bigint DEFAULT NULL COMMENT 'æ¥æºBOM id', |
| | | source_bom_no varchar(64) DEFAULT NULL COMMENT 'æ¥æºBOMç¼å·', |
| | | status tinyint NOT NULL DEFAULT 0 COMMENT '0å¾
å¤ç 1已转éè´ 2已忶', |
| | | remark varchar(500) DEFAULT NULL COMMENT '夿³¨', |
| | | create_time datetime DEFAULT CURRENT_TIMESTAMP, |
| | | create_user bigint DEFAULT NULL, |
| | | update_time datetime DEFAULT NULL, |
| | | update_user bigint DEFAULT NULL, |
| | | tenant_id bigint DEFAULT NULL, |
| | | dept_id bigint DEFAULT NULL, |
| | | PRIMARY KEY (id), |
| | | KEY idx_procurement_demand_model (product_model_id, status) |
| | | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='éè´éæ±-BOMé½å¥ç¼ºå£'; |
| | | ``` |
| | | |
| | | ## äºã/technologyBom æ¥å£æç»ï¼åç¼åç°æï¼ |
| | | |
| | | è¿å使²¿ç¨ `R` ç»æï¼`{code:200, msg, data}`ï¼æå code=200ï¼ã |
| | | |
| | | ### 1. BOMå¯ç¨/åç¨ï¼æ°å¢ï¼ |
| | | |
| | | `PUT /technologyBom/changeStatus`ãbody: `{"id": 56, "status": 1}` |
| | | |
| | | - æåï¼`{code:200}`ï¼å¤±è´¥ï¼`code:500`ï¼"åæ°é误â¦"/"BOMä¸åå¨"ï¼ |
| | | - status=1 æ¶å端èªå¨åç¨åè§æ ¼å
¶å®å¯ç¨çæ¬ï¼å端åªéå·æ°å表 |
| | | |
| | | ### 2. BOMé½å¥åæï¼æ°å¢ï¼ |
| | | |
| | | `POST /technologyBom/kitCheck`ãbody: `{"bomId": 56, "demandQty": 100}` |
| | | |
| | | ```json |
| | | { |
| | | "code": 200, |
| | | "data": [ |
| | | { |
| | | "productModelId": 470, "productName": "å±±æ ¸æ¡", "model": "æ£è£
", "unit": "kg", |
| | | "requiredQty": 105.00, "availableQty": 300.00, "shortageQty": 0 |
| | | }, |
| | | { |
| | | "productModelId": 471, "productName": "é£ç¨ç", "model": "500g", "unit": "è¢", |
| | | "requiredQty": 500.00, "availableQty": 20.00, "shortageQty": 480.00 |
| | | } |
| | | ] |
| | | } |
| | | ``` |
| | | |
| | | - æåºï¼æç¼ºå£æ°ééåºï¼ç¼ºçæåé¢ï¼ |
| | | - å£å¾ï¼å¯ç¨åºå = Σ(åºå表æ°é â 订åéå®é)ï¼å¤å±çº§ç©æéæ±é = ä¸çº§éæ± Ã åä½ç¨éï¼æ ¹èç¹ä¸è®¡å
¥ï¼ |
| | | - æ ¡éªå¤±è´¥ï¼code=500ï¼ï¼"è¯·ä¼ å
¥bomIdåéæ±æ°é(须大äº0)"ã"BOMä¸åå¨"ã"BOMç»æä¸ºç©ºï¼è¯·å
ç»´æ¤ç©ææ¸
å"ã"BOM䏿 ç©æèç¹" |
| | | |
| | | ### 3. é½å¥åæå¯¼åºï¼æ°å¢ï¼ |
| | | |
| | | `POST /technologyBom/kitCheck/export`ãbody å kitCheckï¼ååºä¸º Excel æµï¼æä»¶å"BOMé½å¥åæ"ï¼ï¼å端 blob ä¸è½½ã |
| | | |
| | | ### 4. 缺å£çæéè´éæ±ï¼æ°å¢ï¼ |
| | | |
| | | `POST /technologyBom/kitCheck/generateDemand`ãbody å kitCheck |
| | | |
| | | - æç¼ºå£ï¼`{code:200, data:"éè´éæ±çæå®æï¼æ°å¢ 2 æ¡ï¼ç´¯å åå¹¶ 1 æ¡"}` |
| | | - æ 缺å£ï¼`{code:200, data:"åºåé½å¥ï¼æ éçæéè´éæ±"}` |
| | | - è§åï¼ä»
`shortageQty>0` çç©æå
¥åºï¼åè§æ ¼å·²åå¨**å¾
å¤ç**è®°å½åæ°éç´¯å å¹¶å·æ°å¿«ç
§ï¼å·²è½¬éè´/已忶çè®°å½ä¸åä¸åå¹¶ï¼å次ç¹å»ä¼æ°å»ºï¼ |
| | | |
| | | ### 5. èæ¥å£ååºåå |
| | | |
| | | - `GET /technologyBom/listPage`ã`GET /technologyBom/getByModel`ï¼è¡æ°æ®æ°å¢ `status` åæ®µ |
| | | - `POST /technologyBom/add`ï¼body å¯éä¼ `status`ï¼ä¸ä¼ é»è®¤å¯ç¨ |
| | | - `PUT /technologyBom/update`ï¼body è¥å¸¦ `status:1` åæ ·è§¦å"åè§æ ¼äºæ¥åç¨" |
| | | |
| | | ## ä¸ã/procurementDemand éè´éæ±ç®¡çï¼æ°å¢é¡µé¢ï¼ |
| | | |
| | | | æ¥å£ | 说æ | |
| | | |---|---| |
| | | | `GET /procurementDemand/listPage` | å页ï¼åæ° `pageNum`/`pageSize`ã`productName`(模ç³)ã`productModel`(模ç³)ã`status`ï¼è¿å `data.records/total`ï¼æ id ååº | |
| | | | `PUT /procurementDemand/changeStatus?ids=1,2&status=1` | æ¹éç¶æåæ´ï¼status: 0å¾
å¤ç/1已转éè´/2已忶 | |
| | | | `DELETE /procurementDemand/del` | body `[id...]`ï¼ä»
å¾
å¤çå¯å ï¼å¦å `code:500 "åå¨éå¾
å¤çç¶æçéæ±ï¼åªè½å é¤å¾
å¤çæ°æ®"` | |
| | | | `POST /procurementDemand/export` | query åæ°å listPageï¼Excel æµï¼æä»¶å"éè´éæ±"ï¼ | |
| | | |
| | | è¡å段ï¼`id, productModelId, productName, productModel, unit, demandQuantity, stockQuantity, sourceBomId, sourceBomNo, status, remark, createTime, updateTime` |
| | | |
| | | 页é¢å»ºè®®ï¼å表 + ç¶æçéï¼æä½å"æ 记已转éè´/åæ¶/å é¤"ï¼é¡¶é¨"导åº"ã"转éè´"æ¬æåªæ¹ç¶ææ è®°ï¼ä¸èªå¨å»ºéè´åï¼å¾
ä¸éè´æ¨¡åæµç¨ç¡®è®¤åäºææ¥ï¼ã |
| | | |
| | | **èåï¼å·²å ï¼**ï¼åç§°ãéè´éæ±ãï¼menu_id=2353ï¼ç¶çº§ãéè´ç®¡çã(2015)ï¼è·¯ç± `procurementDemand`ï¼component `procurementManagement/procurementDemand/index`ï¼å¯è§è§è² æ®é/HR/éè´/管ç/è´¢å¡ã |
| | | |
| | | BOM æ¬ä½æ²¿ç¨å·²æèåãBOMãï¼menu_id=2240ï¼ç¶çº§ å·¥èºè®¾è®¡ 2291ï¼component `productionManagement/productStructure/index`ï¼ï¼æ¬æ¬¡ä¸æ°å¢ã |
| | | |
| | | ## åãèè°èªæµæ¸
å |
| | | |
| | | - [ ] 对åä¸è§æ ¼æ°å¢ç¬¬äºä¸ªBOMï¼ç¬¬ä¸ä¸ªèªå¨ååç¨ï¼åè¡¨ç¶æåæ£ç¡® |
| | | - [ ] å¤å¶åºçBOM为åç¨æï¼å¯ç¨ååå¯ç¨çæ¬èªå¨åç¨ |
| | | - [ ] kitCheckï¼demandQty=0 / bomId ä¸åå¨çæ¥éæç¤ºæ£å¸¸å±ç¤º |
| | | - [ ] é½å¥ç»æå¯ç¨åºåæ°å¼ = åºå页(æ°éâéå®)æ ¸å¯¹ä¸è´ |
| | | - [ ] generateDemand 两次ç¹å»ï¼ç¬¬ä¸æ¬¡æ°å¢ãç¬¬äºæ¬¡åè§æ ¼æ°éç´¯å ï¼ä¸éå¤å»ºè¡ï¼ |
| | | - [ ] éè´éæ±é¡µçé/å页/å 餿¦æª/ç¶ææ¹éåæ´/å¯¼åº |
| | | - [ ] åå½ï¼BOMåæ å¢å æ¹æ¥/导å
¥å¯¼åº/å¤å¶ ä¸åå½±å |
| | | |
| | | ## äºãéç说æ |
| | | |
| | | - é½å¥åæå«åæåä¸é´å±ï¼ææå±çº§ç©æé½æ¯å¯¹åºåï¼ï¼è¥å®¢æ·åªè¦å¶ååæï¼äºæå `onlyLeaf` åæ°ã |
| | | - "转éè´"ä¸èå¨çæéè´å°è´¦åæ®ï¼ä»
ç¶ææµè½¬ï¼å¾
确认éè´ä¾§æµç¨ã |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | # å端èè°ææ¡£ â æ¨¡å5+2ï¼ç产æ¥å·¥ï¼è®¾å¤/计件åä»·/å·¥èµæ±æ»ï¼ä¸è®¾å¤äº§éç»è®¡ |
| | | |
| | | > 忝ï¼product-inventory-management-after-jdk25ï¼å®¢æ·åº product-inventory-management-qysjï¼ |
| | | > åç«¯å®ææ¥æï¼2026-09-10ãç¶æï¼å端已å®ç°å¹¶ç¼è¯éè¿ï¼å¾
å端èè° |
| | | |
| | | ## ä¸ãæ¬æ¬¡æ¹å¨æ¦è§ |
| | | |
| | | | è½å | 说æ | |
| | | |---|---| |
| | | | æ¥å·¥å
³èè®¾å¤ | `production_product_main` æ°å¢ `device_id/device_name`ï¼æ¥å·¥åå¯é填使ç¨è®¾å¤ | |
| | | | 计件åä»·é
ç½® | æ°è¡¨ `piece_rate_config`ï¼äº§åè§æ ¼+å·¥åº å¯ä¸ï¼+ æ°èåã计件åä»·é
ç½®ã(menu_id=2352) | |
| | | | å·¥èµå£å¾å级 | çäº§æ ¸ç®æç»(wages)ï¼**å½ä¸è®¡ä»¶åä»·âæ°éÃåä»·ï¼è®¡ä»¶ï¼**ï¼å¦ååéå"å·¥æ¶å®é¢Ãå·¥æ¶"å£å¾ï¼è®¡æ¶ï¼ï¼è¿å `wageMode` æ è¯ | |
| | | | è®¡ä»¶å·¥èµæ±æ» | æäººåæ±æ»ï¼æ¥å·¥åæ°/ç产æ°é/æ»å·¥æ¶/计件工èµ/åºåå计ï¼å¯å¯¼åº | |
| | | | 产éç»è®¡ | æ 设å¤/å·¥åº/产å ä¸ç»´åº¦æ±æ»äº§éãæ¥åºãå·¥æ¶ï¼å¯å¯¼åº | |
| | | |
| | | ### æ°æ®åºåçº§èæ¬ |
| | | |
| | | ```sql |
| | | ALTER TABLE production_product_main |
| | | ADD COLUMN device_id bigint NULL COMMENT '使ç¨è®¾å¤id(device_ledger.id)' AFTER user_name, |
| | | ADD COLUMN device_name varchar(100) NULL COMMENT '设å¤åç§°(åä½)' AFTER device_id, |
| | | ADD INDEX idx_ppm_device_id (device_id); |
| | | |
| | | CREATE TABLE piece_rate_config ( |
| | | id bigint NOT NULL AUTO_INCREMENT COMMENT '主é®', |
| | | product_model_id bigint NOT NULL COMMENT '产åè§æ ¼id', |
| | | product_model varchar(255) DEFAULT NULL COMMENT 'è§æ ¼åå·(åä½)', |
| | | operation_name varchar(100) NOT NULL COMMENT 'å·¥åºåç§°', |
| | | unit_price decimal(10,4) NOT NULL COMMENT '计件åä»·(å
/ä»¶)', |
| | | status tinyint NOT NULL DEFAULT 1 COMMENT '1å¯ç¨ 0åç¨', |
| | | remark varchar(500) DEFAULT NULL, |
| | | create_time datetime DEFAULT CURRENT_TIMESTAMP, |
| | | create_user bigint DEFAULT NULL, |
| | | update_time datetime DEFAULT NULL, |
| | | update_user bigint DEFAULT NULL, |
| | | dept_id bigint DEFAULT NULL, |
| | | PRIMARY KEY (id), |
| | | UNIQUE KEY uk_piece_rate_model_op (product_model_id, operation_name), |
| | | KEY idx_piece_rate_op (operation_name) |
| | | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='计件åä»·é
ç½®(æäº§åè§æ ¼+å·¥åº)'; |
| | | ``` |
| | | > 注ï¼product_model åä½åå·²éè¿ä»£ç åå
¥ï¼è¥å»ºè¡¨æ¶æªå«è¯¥å请补 `ALTER TABLE piece_rate_config ADD COLUMN product_model varchar(255) NULL AFTER product_model_id;` |
| | | |
| | | ### 计件å¹é
è§å |
| | | |
| | | æ¥å·¥æ ¸ç®è¡(production_account) ç `产åè§æ ¼ + å·¥åºåç§°(technology_operation_name)` 精确å¹é
**å¯ç¨ä¸** ç计件åä»·ï¼å¹é
ä¸å°ååéå计æ¶å
¬å¼ãå æ¤å·¥åºåç§°å¿
须䏿£éª/å·¥èºéçå·¥åºåä¸è´ï¼å»ºè®®é
置页工åºç¨ä¸æåèªå·²ææ ¸ç®å·¥åºåï¼ã |
| | | |
| | | ## äºã/pieceRateConfig 计件åä»·é
ç½®ï¼æ°å¢é¡µé¢ï¼ |
| | | |
| | | | æ¥å£ | 说æ | |
| | | |---|---| |
| | | | `GET /pieceRateConfig/listPage` | åæ° `pageNum/pageSize`ã`operationName`(模ç³)ã`productModel`(模ç³)ã`productModelId`ã`status` | |
| | | | `POST /pieceRateConfig/add` | body: `{productModelId, operationName, unitPrice, remark}`ï¼æ ¡éªï¼è§æ ¼å¿
å¡«ãå·¥åºå¿
å¡«ãåä»·>0ãåè§æ ¼åå·¥åºå¯ä¸ | |
| | | | `PUT /pieceRateConfig/update` | body å« idï¼æ ¡éªå add | |
| | | | `PUT /pieceRateConfig/changeStatus` | body: `{"id":1,"status":0}` | |
| | | | `DELETE /pieceRateConfig/batchDelete` | body `[id...]` | |
| | | | `GET /pieceRateConfig/export` | query å listPageï¼Excel æµ"计件åä»·é
ç½®" | |
| | | |
| | | è¡å段ï¼`id, productModelId, productModel, operationName, unitPrice, status, remark, createTime, updateTime` |
| | | |
| | | **èåï¼å·²å ï¼**ï¼åç§°ã计件åä»·é
ç½®ãï¼menu_id=2352ï¼ç¶çº§ãç产管æ§ã(2058)ï¼è·¯ç± `pieceRateConfig`ï¼component `productionManagement/pieceRateConfig/index`ï¼å¯è§è§è² æ®é/å¶é ã |
| | | |
| | | ## ä¸ãæ¥å·¥æ¥å£ååï¼/productionProductMainï¼ |
| | | |
| | | - `POST /productionProductMain/addProductMain`ã`POST`ã`PUT`ï¼body å¯éä¼ `deviceId`ï¼è®¾å¤å°è´¦idï¼ï¼è®¾å¤ä¸å卿¥ `设å¤ä¸åå¨ï¼ID=x`ï¼device_name å端èªå¨åä½ã |
| | | - `GET /listPage`ï¼è¡æ°æ®æ°å¢ `deviceId/deviceName`ï¼çéåæ°æ°å¢ `deviceId`(精确)ã`deviceName`(模ç³)ã |
| | | - æ¥å·¥å表页建议å¢å "使ç¨è®¾å¤"åä¸è®¾å¤ä¸æçéï¼ä¸ææ°æ®æºï¼`GET /device/ledger/listPage` ç°æè®¾å¤å°è´¦æ¥å£ï¼ã |
| | | |
| | | ## åãæ°å¢ç»è®¡æ¥å£ |
| | | |
| | | ### 1. è®¡ä»¶å·¥èµæ±æ» |
| | | |
| | | `GET /productionProductMain/wageSummary?startDate=2026-09-01&endDate=2026-09-30&userName=å¼ ` |
| | | |
| | | ```json |
| | | { "code": 200, "data": [ |
| | | { "userId": 18, "userName": "å¼ ä¸", "workCount": 12, "quantity": 3600, "workHour": 96, "pieceWage": 1800.00, "wages": 2450.00 } |
| | | ]} |
| | | ``` |
| | | - æ `production_account.scheduling_user` åç»ï¼`pieceWage` ä»
计件é¨åï¼`wages`=计件ä¼å
+æªå½ä¸åé计æ¶çå计ã |
| | | - 导åºï¼`GET /productionProductMain/wageSummary/export`ï¼ååæ°ï¼blob ä¸è½½"è®¡ä»¶å·¥èµæ±æ»"ï¼ã |
| | | |
| | | ### 2. 产éç»è®¡ |
| | | |
| | | `GET /productionProductMain/outputStat?dimension=device&startDate=&endDate=&deviceId=` |
| | | |
| | | - `dimension`ï¼`device`设å¤(é»è®¤)/`operation`å·¥åº/`product`产å-è§æ ¼ï¼éæ³å¼æ¥ `ç»è®¡ç»´åº¦ä¸åæ³â¦` |
| | | - è¿åï¼`[{groupId, groupName, workCount, quantity, scrapQty, workHour}]`ï¼ææ°ééåºï¼è®¾å¤æªå¡«æ¥å·¥å½å
¥"æªæå®è®¾å¤"ã |
| | | - å£å¾ï¼`quantity`=åå·¥åºå®å·¥æ°(`production_account.finished_num`)åè®¡ï¼æå·¥åºå±å¼ç´¯å ï¼`workCount`=å»éæ¥å·¥åæ°ï¼`workHour`/`scrapQty` æ¯**æ¥å·¥å级æ é**ï¼ææ¥å·¥åå»éå计å
¥ââä¸å¼ æ¥å·¥åå½å¤éå·¥åºæ¶ä¸ä¼éå¤ç´¯å ï¼å·¥æ¶å½å
¥è¯¥åé¦éå·¥åºè¡ï¼ã |
| | | - 导åºï¼`GET /productionProductMain/outputStat/export`ï¼ååæ°ï¼"产éç»è®¡"ï¼ã |
| | | |
| | | **èåï¼å·²å ï¼**ï¼åç§°ã产éç»è®¡ãï¼menu_id=2349ï¼ç¶çº§ãç产管æ§ã(2058)ï¼è·¯ç± `outputStatistics`ï¼component `productionManagement/outputStatistics/index`ï¼å¯è§è§è² æ®é/å¶é ãä¸å·²æãå·¥åºç产å®åµã(2296) å
容æéå ââè¥å端å³å®æäº§éç»è®¡åæè¯¥é¡µçä¸ä¸ª Tabï¼è¯·å é¤ 2349 è¿æ¡èåè¡ï¼`DELETE FROM sys_menu WHERE menu_id=2349` åå
¶ sys_role_menu å
³èï¼ã |
| | | |
| | | ### 3. æ ¸ç®æç»ï¼èæ¥å£ååºååï¼ |
| | | |
| | | `listProductionDetails`ï¼çäº§æ ¸ç®é¡µï¼æ¯è¡æ°å¢ï¼`wageMode`(计件/计æ¶)ã`deviceId`ã`deviceName`ï¼`wages` 计件ä¼å
ã |
| | | |
| | | ## äºãèè°èªæµæ¸
å |
| | | |
| | | - [ ] 计件åä»·é¡µï¼æ°å¢/é夿°å¢æ¦æª/åç¨åä¸åçæ/å¯¼åº |
| | | - [ ] æ¥å·¥æ¶éè®¾å¤ â å表/详æ
/å¯¼åºæ¾ç¤ºè®¾å¤ï¼deviceId çéæ£ç¡® |
| | | - [ ] é
ç½®"è§æ ¼A+çå¶=0.5å
/ä»¶"åæ¥æ ¸ç®æç»ï¼è¯¥å·¥åºè¡ wageMode=计件ãwages=æ°éÃ0.5 |
| | | - [ ] æªé
ç½®åä»·çå·¥åºè¡ï¼wageMode=计æ¶ãwages 䏿¹é åä¸è´ï¼åå½ï¼ |
| | | - [ ] wageSummary æ°å¼ = æ ¸ç®æç»æäººå计 |
| | | - [ ] outputStat ä¸ç»´åº¦åæ¢ãæ¶é´çéã设å¤çéãå¯¼åº |
| | | - [ ] æ¥å·¥åæ æ°å¢/ä¿®æ¹/å é¤/å表/åæ°å¿«ç
§ ä¸åå½±å |
| | | |
| | | ## å
ãéç说æ |
| | | |
| | | - 计件工èµä¸èªå¨åå
¥ `staff_salary_detail.piece_salary`ï¼è¯¥è¡¨ä¸ºæå·¥å·¥èµæ¨¡åï¼è卿¹æ¡éä¸äººäºæµç¨ç¡®è®¤ï¼äºææ¥å
¥ï¼ã |
| | | - 计件åä»·æå·¥åºåç§°ææ¬å¹é
ï¼æ ¸ç®è¡¨åçæ¯åç§°å¿«ç
§ï¼ï¼æ¹åå·¥åºä¼å¤±é
ââæ¹ååéåæ¥ç»´æ¤è®¡ä»¶é
ç½®ã |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | # å端èè°ææ¡£ â æ¨¡å6ï¼åææ£éªå
¥åºï¼åæ ¼èªå¨å
¥åº + ä¸åæ ¼æ è¯éç¦»ï¼ |
| | | |
| | | > 忝ï¼product-inventory-management-after-jdk25ï¼å®¢æ·åº product-inventory-management-qysjï¼ |
| | | > åç«¯å®ææ¥æï¼2026-09-10ãç¶æï¼å端已å®ç°å¹¶ç¼è¯éè¿ï¼å¾
å端èè° |
| | | |
| | | ## ä¸ãæ¬æ¬¡æ¹å¨æ¦è§ |
| | | |
| | | åææ£éªï¼`quality_inspect.inspect_type = 0`ï¼ä¸»æµç¨å·²åå¨ï¼æ¬æ¬¡è¡¥é½**å¹ç䏿°æ®ä¸è´æ§**å
³é®ç¼ºå£ï¼ |
| | | |
| | | | è½å | 说æ | |
| | | |---|---| |
| | | | åæ ¼èªå¨å
¥åº | æäº¤æ¶å¯¹"åæ ¼æ°é>0"èªå¨çæå
¥åºè®°å½ï¼åæï¼ä¿çï¼ | |
| | | | éå¤æäº¤æ¦æª | å·²æäº¤ï¼inspect_state=1ï¼çæ£éªå忬¡ submit æ¥ `æ£éªåå·²æäº¤ï¼è¯·å¿éå¤æäº¤`ï¼æ°å¢ï¼ | |
| | | | å·²æäº¤ç¦æ¹ | å·²æäº¤çæ£éªåè°ç¨ `/quality/inspect/update` æ¥ `æ£éªåå·²æäº¤ï¼ä¸å
许修æ¹`ï¼æ°å¢ï¼ | |
| | | | æ°éæ ¡éª | åæ ¼æ°é+ä¸åæ ¼æ°é > æ£éªæ°éæ¶æ¥éï¼æ°å¢ï¼ | |
| | | | ä¸åæ ¼æ è¯é离 | ä¸åæ ¼æ°é>0 èªå¨çæä¸åæ ¼å¤çåï¼åæï¼ï¼å¤çå**éå¤å¤çæ¦æª + å¤çç»æå¿
ä¼ + äºå¡å**ï¼æ°å¢ï¼ | |
| | | |
| | | ## äºãå
¥åº/é离é¾è·¯ï¼å端éçè§£çå£å¾ï¼ |
| | | |
| | | 1. **æäº¤æ£éª** `POST /quality/inspect/submit`ï¼body: `{"id": æ£éªåid}`ï¼ |
| | | - æ ¡éªï¼æ£éªååå¨ãæªéå¤æäº¤ãcheckResult 已填ãåæ ¼/ä¸åæ ¼æ°éå·²å¡«ãæ°éä¹å ⤠æ£éªæ°éã |
| | | - åæ ¼æ°é > 0 ä¸éè¿ç¨æ£ï¼çæ**å¾
å®¡æ ¸å
¥åºè®°å½**ï¼`stock_in_record`ï¼ |
| | | - æ `purchaseLedgerId`ï¼éè´å°è´§è´¨æ£ï¼â record_type = **10**ï¼éè´-è´¨æ£-åæ ¼å
¥åºï¼ |
| | | - å
¶ä½ â record_type = **6**ï¼è´¨æ£-åæ ¼å
¥åºï¼ |
| | | - æ¹å·ï¼ä¼å
沿ç¨ä¸çº§ç产/è´¨æ£æ¹æ¬¡ï¼å¦åæ `æ¥æ-产åç¼ç -åºå·` èªå¨çæ |
| | | - **注æï¼æäº¤ååºåä¸ä¼ç«å³å¢å **ï¼éå¨"å
¥åºè®°å½"é¡µå®¡æ ¸éè¿åæç´¯å `stock_inventory`ï¼æ²¿ç¨ç°æå®¡æ ¸æµï¼å端æ éæ¹å¨ï¼ã |
| | | - ä¸åæ ¼æ°é > 0 â èªå¨çæä¸åæ ¼å¤çåï¼`quality_unqualified`ï¼inspect_state=0 å¾
å¤çï¼ï¼ä¸åæ ¼ç°è±¡ååæ°é¡¹æ¼æ¥ã |
| | | |
| | | 2. **ä¸åæ ¼å¤ç** `POST /quality/qualityUnqualified/deal`ï¼body å« `id`ã`dealResult`ï¼ |
| | | - åæç±»ï¼inspect_type=0ï¼æ¯æå¤çç»æï¼`æ¥åº`ï¼å
¥ä¸åæ ¼é离åºå stock_uninventoryï¼record_type=4ï¼ã`è®©æ¥æ¾è¡`ï¼å
¥æ£å¼åºåï¼record_type=11ï¼ã |
| | | - æ°å¢æ¦æªï¼ |
| | | - è®°å½ä¸åå¨ â `ä¸åæ ¼è®°å½ä¸åå¨` |
| | | - å·²å¤ç忬¡æäº¤ â `该ä¸åæ ¼è®°å½å·²å¤çï¼è¯·å¿é夿ä½` |
| | | - dealResult æªä¼ â `è¯·éæ©å¤çç»æ` |
| | | - "éä¾åºå"ä¸å¨æ¬æèå¨èå´ï¼èµ°ç°æéè´é货模åï¼è§éç说æï¼ã |
| | | |
| | | ## ä¸ãæ¥å£æç»ï¼åç¼åç°æï¼è¿å Rï¼{code:200,msg,data}ï¼ |
| | | |
| | | | æ¥å£ | åå | |
| | | |---|---| |
| | | | `POST /quality/inspect/add` | æ ååï¼ä¿åè稿ï¼inspect_state=0ï¼ | |
| | | | `POST /quality/inspect/update` | **æ°å¢æ¦æª**ï¼å·²æäº¤åæ®è¿å code=500 `æ£éªåå·²æäº¤ï¼ä¸å
许修æ¹` | |
| | | | `POST /quality/inspect/submit` | **æ°å¢æ¦æª**ï¼éå¤æäº¤ code=500 `æ£éªåå·²æäº¤ï¼è¯·å¿éå¤æäº¤`ï¼**æ°å¢æ ¡éª** `åæ ¼æ°éä¸ä¸åæ ¼æ°éä¹åä¸è½å¤§äºæ£éªæ°é` | |
| | | | `POST /quality/inspect/autoSubmit?id=` | æ ååï¼å·²æäº¤æ¶è¿å `æ£éªåå·²æäº¤` | |
| | | | `GET /quality/inspect/listPage` | æ ååï¼è¡æ°æ®å« `inspectState/checkResult/qualifiedQuantity/unqualifiedQuantity` | |
| | | | `POST /quality/qualityUnqualified/deal` | **æ°å¢æ¦æª**ï¼éå¤å¤ç/æªä¼ å¤çç»æï¼äºå¡åæ» | |
| | | | `GET /quality/qualityUnqualified/listPage` | æ ååï¼inspect_state 0å¾
å¤ç/1å·²å¤çï¼ | |
| | | |
| | | ## åãå端建议 |
| | | |
| | | - **èåï¼æ²¿ç¨å·²æãåæææ£éªãï¼menu_id=2046ï¼ç¶çº§ è´¨é管ç 2040ï¼component `qualityManagement/rawMaterialInspection/index`ï¼ï¼æ¬æ¬¡ä¸æ°å¢èåã** |
| | | - æäº¤æé®ç¹å»åç½®ç°/å 确认弹çªï¼"æäº¤åå°çæå
¥åºè®°å½ä¸ä¸å¯ä¿®æ¹"ï¼ï¼æ¶å° 500 æ¥éç´æ¥ `message.error(msg)`ã |
| | | - ç¼è¾é¡µè¿å
¥æ¶è¥ `inspectState===1`ï¼è¡¨åæ´ä½åªè¯»ãéèä¿åæé®ã |
| | | - ä¸åæ ¼å¤çå¼¹çªï¼dealResult 䏿å¿
éï¼åæï¼æ¥åº/è®©æ¥æ¾è¡ï¼ï¼æäº¤æååå·æ°å表ã |
| | | - æäº¤æåæç¤ºè¯å»ºè®®ï¼"æäº¤æåï¼åæ ¼é¨åå·²çæå
¥åºè®°å½ï¼å¾
å®¡æ ¸ï¼ï¼ä¸åæ ¼é¨åå·²çæå¤çå"ã |
| | | |
| | | ## äºãèè°èªæµæ¸
å |
| | | |
| | | - [ ] æ°å¢åææ£éªå â æäº¤ â å
¥åºè®°å½é¡µåºç° record_type=10/6 çå¾
å®¡æ ¸è®°å½ |
| | | - [ ] å
¥åºè®°å½å®¡æ ¸éè¿ â 宿¶åºåæ°éå¢å ï¼æ°éä¸åæ ¼æ°éä¸è´ï¼æ¹å·æ£ç¡®ï¼ |
| | | - [ ] å䏿£éªåéå¤ submit â æ¥é"请å¿éå¤æäº¤"ï¼åºåä¸éå¤å¢å |
| | | - [ ] å·²æäº¤åæ®è° update â æ¥é"ä¸å
许修æ¹" |
| | | - [ ] åæ ¼+ä¸åæ ¼ > æ£éªæ°é â submit æ¥é |
| | | - [ ] ä¸åæ ¼æ°é>0 â ä¸åæ ¼å表åºç°å¾
å¤çè®°å½ï¼å¤çååºå/é离åºååæ£ç¡® |
| | | - [ ] åä¸ä¸åæ ¼è®°å½éå¤ deal â æ¥é"请å¿é夿ä½" |
| | | - [ ] è¿ç¨æ£ï¼inspect_type=1ï¼æäº¤ â ä¸äº§çå
¥åºè®°å½ï¼åå½ï¼ |
| | | |
| | | ## å
ãéç说æ |
| | | |
| | | - åæä¸åæ ¼"éä¾åºå"ä¸èªå¨èå¨éè´éè´§åï¼ä»èµ°éè´é货页é¢äººå·¥å»ºåï¼æ¶åå°è´¦/é颿 ¸éï¼äºæä¸éè´ä¾§ç¡®è®¤æµç¨å忥ï¼ã |
| | | - åæ ¼å
¥åºæ²¿ç¨"å
¥åºè®°å½å®¡æ ¸"ç¯èï¼å¦å®¢æ·è¦æ±æäº¤å³å
¥è´¦ï¼å
å®¡æ ¸ï¼ï¼éåç¬ç¡®è®¤åæ¾å¼ã |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | # å端èè°ææ¡£ â æ¨¡å7ï¼æåæ£éªç®¡çï¼åæ ¼å
¥åº/è¿ä¿®è¿å·¥/æ¥åºï¼ |
| | | |
| | | > 忝ï¼product-inventory-management-after-jdk25ï¼å®¢æ·åº product-inventory-management-qysjï¼ |
| | | > åç«¯å®ææ¥æï¼2026-09-10ãç¶æï¼å端已å®ç°å¹¶ç¼è¯éè¿ï¼å¾
å端èè° |
| | | |
| | | ## ä¸ãä¸å¡é¾è·¯æ»è§ï¼æåä¾§ï¼ |
| | | |
| | | ``` |
| | | ç产æ¥å·¥ï¼æåä¸éå·¥åºä¸è¯¥å·¥åº isQuality=1ï¼ |
| | | ââ èªå¨çæ"åºåæ£éªå"ï¼quality_inspect.inspect_type=2ï¼èªå¨å¸¦åºæ£éªæ ååæ°ï¼å
³èæ¥å·¥å productMainIdï¼ |
| | | æäº¤æ£éªåï¼/quality/inspect/submitï¼ |
| | | ââ åæ ¼æ°é>0 â çæå¾
å®¡æ ¸å
¥åºè®°å½ï¼record_type=6 è´¨æ£-åæ ¼å
¥åºï¼æ¹å·æ²¿ç¨æ¥å·¥å
¥åºæ¹æ¬¡ï¼ |
| | | â â å
¥åºè®°å½é¡µå®¡æ ¸éè¿åç´¯å æååºå stock_inventory |
| | | ââ ä¸åæ ¼æ°é>0 â çæä¸åæ ¼å¤çåï¼quality_unqualifiedï¼å¾
å¤çï¼ |
| | | ä¸åæ ¼å¤çï¼/quality/qualityUnqualified/dealï¼ |
| | | ââ è¿ä¿®/è¿å·¥ â èªå¨å建 FG åç¼è¿å·¥ç产订åï¼å¤å¶å订åå·¥èºè·¯çº¿å¹¶éå·¥åºçæå·¥åä»»å¡ï¼ |
| | | ââ æ¥åº â æ°éå
¥ä¸åæ ¼é离åºåï¼stock_uninventoryï¼record_type=4ï¼ |
| | | ââ è®©æ¥æ¾è¡ â æ°éå
¥æ£å¼åæ ¼åºåï¼record_type=11ï¼ |
| | | ``` |
| | | |
| | | è¿ç¨æ£éªï¼inspect_type=1ï¼éæåå·¥åºçè´¨æ£å·¥åºï¼åæ ·èªå¨çææ£éªåï¼æäº¤æ¶**ä¸äº§çå
¥åº**ï¼ä»
ä¸åæ ¼èµ°å¤çåã |
| | | |
| | | ## äºãæ¬æ¬¡å端æ¹å¨ |
| | | |
| | | 1. **å¤çç»ææä¸¾æ ¡éªï¼æ°å¢ï¼**ï¼æå/è¿ç¨ç±»ä¸åæ ¼åä»
æ¥å `è¿ä¿®/è¿å·¥/æ¥åº/è®©æ¥æ¾è¡`ï¼åæç±»ä»
`æ¥åº/è®©æ¥æ¾è¡`ãä¸åæ³è¿å code=500 `å¤çç»æä¸åæ³ï¼ä»
æ¯æï¼â¦`ã |
| | | 2. **éå¤å¤çæ¦æª**ï¼ä¸æ¨¡å6å
±ç¨ï¼ï¼å·²å¤çè®°å½å次 deal â `该ä¸åæ ¼è®°å½å·²å¤çï¼è¯·å¿é夿ä½`ã |
| | | 3. **é²ç¯¡æ¹ååï¼æ°å¢ï¼**ï¼å¤çæ´æ°ä»¥åºä¸è®°å½ä¸ºåï¼ä»
ååå¤çç»æ/å¤ç人/å¤çæ¥æï¼è¯·æ±ä½æ æ³åè¦çæ°éãç¶æçåæ®µã |
| | | 4. **å¤ç人/æ¥æèªå¨å¡«å
ï¼æ°å¢ï¼**ï¼å端ä¸ä¼ `dealName` æ¶å端åå½åç»å½ç¨æ·åï¼ä¸ä¼ `dealTime` æ¶åå½åæ¶é´ã |
| | | 5. **æ£éªåå¹çï¼ä¸æ¨¡å6å
±ç¨ï¼**ï¼æäº¤/ç¼è¾æ¦æªåæ ·ä½ç¨äºåºå/è¿ç¨æ£éªåã |
| | | |
| | | ## ä¸ãæ¥å£æç»ï¼è¿å Rï¼{code:200,msg,data}ï¼ |
| | | |
| | | | æ¥å£ | 说æ | |
| | | |---|---| |
| | | | `GET /quality/inspect/listPage` | æ£éªåå页ï¼åæ°å« `inspectType`ï¼æå页åºå®ä¼ 2ï¼ | |
| | | | `POST /quality/inspect/submit` | æäº¤ï¼æ¥éè§æ¨¡å6ææ¡£ | |
| | | | `POST /quality/inspect/update` | å·²æäº¤åæ®ç¦æ¹ | |
| | | | `POST /quality/inspect/export` | æ inspectType 导åºï¼2=åºåæ£éªå¯¼åºï¼ | |
| | | | `POST /quality/inspect/down` | çææ£éªæ¥å docxï¼æ¨¡æ¿æ¸²æï¼ | |
| | | | `GET /quality/qualityUnqualified/listPage` | ä¸åæ ¼åå页ï¼å« inspectType/inspectState çéï¼ | |
| | | | `POST /quality/qualityUnqualified/deal` | å¤çï¼body: `{"id": xx, "dealResult": "è¿å·¥"}`ï¼å¯é dealName/dealTime | |
| | | |
| | | ## åãå端页é¢å»ºè®® |
| | | |
| | | - **èåï¼æ²¿ç¨å·²æãè¿ç¨æ£éªã(menu_id=2047) /ãåºåæ£éªã(menu_id=2048)ï¼ç¶çº§ è´¨é管ç 2040ï¼æ¬æ¬¡ä¸æ°å¢èåã** æåæ£éªï¼inspectType=2ï¼å¤ç¨è¿ä¸¤ä¸ªå·²æé¡µé¢ï¼ç¨ `inspectType` åºåã |
| | | - æåæ£éªé¡µï¼å表çéåºå® `inspectType=2`ï¼æä½å æäº¤/æ¥çæ¥åï¼`inspectState=1` æ¶è¡¨ååªè¯»ã |
| | | - ä¸åæ ¼å¤çå¼¹çªï¼æååºæ¯"å¤çç»æ"䏿å项ï¼è¿ä¿®/è¿å·¥/æ¥åº/è®©æ¥æ¾è¡ï¼ï¼éè¿ä¿®/è¿å·¥æ¶æç¤º"å°èªå¨å建è¿å·¥ç产订åï¼FGåå·ï¼"ã |
| | | - å¤çæåå建议跳转å°ç产订ååè¡¨ï¼æ°åå·ä¸º FG+æ¥æ+åºå·ï¼ï¼ä¾¿äºç»§ç»è·è¸ªè¿å·¥è¿åº¦ã |
| | | - æäº¤/å¤çè¿å code=500 æ¶ç´æ¥å±ç¤º msgã |
| | | |
| | | ## äºãèè°èªæµæ¸
å |
| | | |
| | | - [ ] æåä¸éè´¨æ£å·¥åºæ¥å·¥ â åºåæ£éªå表åºç°å¾
æäº¤æ£éªåï¼åæ°å·²ææ£éªæ åå¸¦åº |
| | | - [ ] æäº¤åæ ¼æ°é â å
¥åºè®°å½é¡µåºç°å¾
å®¡æ ¸è®°å½ï¼æ¹å·=æ¥å·¥æ¹æ¬¡ï¼â å®¡æ ¸åæååºåå¢å |
| | | - [ ] ä¸åæ ¼æäº¤ â å¤çåçæï¼åå«èµ° è¿ä¿®/è¿å·¥ â çæ FG ç产订å+å·¥åºå·¥åï¼æ¥åº â é离åºåå¢å ï¼è®©æ¥æ¾è¡ â åæ ¼åºåå¢å |
| | | - [ ] åæä¸åæ ¼åä¼ `è¿å·¥` â æ¥é"å¤çç»æä¸åæ³" |
| | | - [ ] åä¸ä¸åæ ¼åéå¤å¤ç â æ¥é"请å¿é夿ä½" |
| | | - [ ] å·²å¤çååæ¥è¯¦æ
â dealResult/dealName/dealTime æ£ç¡®è½åº |
| | | - [ ] è¿ç¨æ£ï¼type=1ï¼æäº¤ â ä¸äº§çå
¥åºè®°å½ï¼ä¸åæ ¼å¤çæ£å¸¸ |
| | | |
| | | ## å
ãéç说æ |
| | | |
| | | - è¿å·¥è®¢åä¸åæ£éªåçå
³èä»
è½éè¿å·¥åº/产åé´æ¥è¿½è¸ªï¼ä¸åæ ¼åæªåè¿å·¥è®¢åå·ï¼ï¼äºæå¯å¨ quality_unqualified å `rework_order_id` åæ®µååã |
| | | - è®©æ¥æ¾è¡ä¸åºåæ¯å¦æ¶è´¹/æ£ä¾åºå款ï¼ä¸éè´å°è´¦æ ¸éå¾
éè´ä¾§ç¡®è®¤ã |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | # å端èè°ææ¡£ â æ¨¡å8ï¼å®æ¶åºå管çï¼çç¹ + å·®å¼åæ + é¢è¦ï¼ |
| | | |
| | | > 忝ï¼product-inventory-management-after-jdk25ï¼å®¢æ·åº product-inventory-management-qysjï¼ |
| | | > åç«¯å®ææ¥æï¼2026-09-10ãç¶æï¼å端已å®ç°å¹¶ç¼è¯éè¿ï¼å¾
å端èè° |
| | | |
| | | ## ä¸ãæ¬æ¬¡æ¹å¨æ¦è§ |
| | | |
| | | | è½å | 说æ | |
| | | |---|---| |
| | | | åºåçç¹ | æ°è¡¨ `stock_check_main`/`stock_check_detail` + æ°èåãåºåçç¹ã(menu_id=2354) | |
| | | | çç¹æµç¨ | åèµ·(å¿«ç
§è´¦é¢) â å½å
¥å®ç â 宿(å·®å¼èªå¨çæå¾
å®¡æ ¸è°è´¦åæ®)/åæ¶ | |
| | | | å·®å¼åæ | çç¹åå·®å¼å表 + å¯¼åº | |
| | | | åºåé¢è¦ | å¤ç¨åºåå页æ°å¢ `warnPage`/`warnExport`ï¼å¯ç¨æ°é=æ°éâéå® â¤ é¢è¦å¼ ä¸ é¢è¦å¼>0ï¼ | |
| | | |
| | | ### æ°æ®åºåçº§èæ¬ |
| | | |
| | | ```sql |
| | | CREATE TABLE stock_check_main ( |
| | | id bigint NOT NULL AUTO_INCREMENT, |
| | | check_no varchar(64) NOT NULL COMMENT 'çç¹åå·', |
| | | check_name varchar(255) DEFAULT NULL COMMENT 'çç¹åç§°', |
| | | check_date date DEFAULT NULL COMMENT 'çç¹æ¥æ', |
| | | checker varchar(64) DEFAULT NULL COMMENT 'çç¹äºº', |
| | | status tinyint NOT NULL DEFAULT 0 COMMENT '0çç¹ä¸ 1已宿 2已忶', |
| | | total_kinds int DEFAULT 0 COMMENT 'çç¹ç§ç±»æ°', |
| | | diff_kinds int DEFAULT 0 COMMENT 'å·®å¼ç§ç±»æ°', |
| | | remark varchar(500) DEFAULT NULL, |
| | | create_time datetime DEFAULT CURRENT_TIMESTAMP, |
| | | create_user bigint DEFAULT NULL, update_time datetime DEFAULT NULL, |
| | | update_user bigint DEFAULT NULL, dept_id bigint DEFAULT NULL, |
| | | PRIMARY KEY (id), UNIQUE KEY uk_stock_check_no (check_no), KEY idx_stock_check_status (status) |
| | | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='åºåçç¹ä¸»è¡¨'; |
| | | |
| | | CREATE TABLE stock_check_detail ( |
| | | id bigint NOT NULL AUTO_INCREMENT, |
| | | main_id bigint NOT NULL COMMENT 'çç¹ä¸»è¡¨id', |
| | | inventory_id bigint DEFAULT NULL COMMENT 'åºåè¡id', |
| | | product_model_id bigint NOT NULL, |
| | | product_name varchar(255), product_model varchar(255), unit varchar(32), |
| | | batch_no varchar(64) DEFAULT NULL COMMENT 'æ¹å·', |
| | | book_qty decimal(18,4) COMMENT 'è´¦é¢æ°éå¿«ç
§', |
| | | actual_qty decimal(18,4) COMMENT 'å®çæ°é', |
| | | diff_qty decimal(18,4) COMMENT 'å·®å¼=å®ç-è´¦é¢', |
| | | adjusted tinyint NOT NULL DEFAULT 0 COMMENT '0æªè°è´¦ 1å·²çæè°è´¦åæ®', |
| | | remark varchar(500), |
| | | create_time datetime DEFAULT CURRENT_TIMESTAMP, |
| | | create_user bigint DEFAULT NULL, update_time datetime DEFAULT NULL, |
| | | update_user bigint DEFAULT NULL, dept_id bigint DEFAULT NULL, |
| | | PRIMARY KEY (id), KEY idx_check_detail_main (main_id), KEY idx_check_detail_model (product_model_id) |
| | | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='åºåçç¹æç»è¡¨'; |
| | | ``` |
| | | |
| | | ## äºã/stockCheck çç¹æ¥å£ï¼è¿å Rï¼{code,msg,data}ï¼ |
| | | |
| | | | æ¥å£ | 说æ | |
| | | |---|---| |
| | | | `POST /stockCheck/start` | body `{checkName, checkDate?, checker?, remark?, productModelIds?}`ï¼ä¸ä¼ è§æ ¼=å
¨é¨åºåè¡å¿«ç
§ï¼æåè¿åæ°çç¹å idï¼åè§æ ¼åå¨çç¹ä¸åæ®æ¶æ¥éå¹¶ååºå²çªè§æ ¼ | |
| | | | `GET /stockCheck/listPage` | åæ° `checkNo`/`checkName`(模ç³)ã`status`ã`beginTime`/`endTime`(yyyy-MM-dd HH:mm:ss) | |
| | | | `GET /stockCheck/{id}` | 主表详æ
| |
| | | | `GET /stockCheck/detailPage?mainId=&onlyDiff=` | æç»å页ï¼onlyDiff=true åªçå·²å½å
¥ä¸æå·®å¼çè¡ | |
| | | | `PUT /stockCheck/entry` | body æ°ç» `[{id, actualQty, remark?}]`ï¼actualQty>=0ï¼çç¹ç»æåå½å
¥æ¥é | |
| | | | `POST /stockCheck/finish` | body `{id}`ï¼æªå½æ»¡æ¥éï¼å·®å¼è¡çæå¾
å®¡æ ¸åºå
¥åºè®°å½ï¼ççâå
¥åºèªå®ä¹ãçäºâåºåºèªå®ä¹ï¼å¤æ³¨"çç¹è°è´¦ PDåå·"ï¼ï¼è¿åæç¤ºè¯å«å·®å¼æ¡æ° | |
| | | | `POST /stockCheck/cancel` | body `{id}`ï¼ä»
çç¹ä¸å¯åæ¶ | |
| | | | `GET /stockCheck/diffList?mainId=` | å·®å¼åæå表 | |
| | | | `GET /stockCheck/diffList/export?mainId=` / `GET /stockCheck/detailExport?mainId=` / `GET /stockCheck/export` | ä¸ä¸ª Excel æµ | |
| | | |
| | | æç»è¡å段ï¼`id, mainId, productModelId, productName, productModel, unit, batchNo, bookQty, actualQty, diffQty, adjusted, remark` |
| | | |
| | | **è°è´¦çæå£å¾**ï¼finish åå·®å¼ä»¥"å¾
å®¡æ ¸åºå
¥åºè®°å½"å½¢å¼åå¨ï¼éå¨å
¥åºè®°å½/åºåºè®°å½é¡µå®¡æ ¸éè¿å `stock_inventory` æåå¨ï¼ä¸å
¨ç³»ç»åºåå®¡æ ¸æµä¸è´ï¼ã |
| | | |
| | | ## ä¸ãåºåé¢è¦ï¼/stockInventoryï¼ |
| | | |
| | | - `GET /stockInventory/warnPage`ï¼åæ°åç°æåºåå页ï¼`productName` æ¨¡ç³ + å页ï¼ï¼ä»
è¿åé¢è¦è¡ï¼è¡åæ®µå« `qualitity/lockedQuantity/warnNum`ï¼`un_locked_quantity` 为å¯ç¨æ°éã |
| | | - `GET /stockInventory/warnExport`ï¼ååæ°ï¼Excel"åºåé¢è¦"ã |
| | | - ç°æ `pagestockInventory` 乿¯æä¼ `warnOnly=true`ï¼ä¸ warnPage çæï¼ä¸è¬ç¨æ°æ¥å£ï¼ã |
| | | |
| | | ## åã页é¢å»ºè®® |
| | | |
| | | - **èåï¼å·²å ï¼**ï¼åç§°ãåºåçç¹ãï¼menu_id=2354ï¼ç¶çº§ãä»å¨ç©æµã(2029)ï¼è·¯ç± `stockCheck`ï¼component `inventoryManagement/stockCheck/index`ï¼å¯è§è§è² æ®é/HR/å¶é /åºç®¡ãçç¹è¯¦æ
页å¯ç´æ¥å¤ç¨ãåºå管çã(2032) çæ¢æé¡µé¢è·¯ç±ï¼`inventoryManagement/stockManagement/index`ï¼ï¼å»ºè®®åæè¯¥é¡µçä¸ä¸ªåè·¯ç±æå¼¹çªãé¢è¦é¡µæ ç¬ç«èåï¼æå¨ãåºå管çã页å
ã |
| | | - çç¹å表页ï¼ç¶æåï¼el-tagï¼çç¹ä¸=warning/已宿=success/已忶=infoï¼ï¼æä½å 详æ
/宿/åæ¶ã |
| | | - çç¹è¯¦æ
é¡µï¼æç»è¡¨æ ¼"è´¦é¢æ°(åªè¯»)ãå®çæ°(è¾å
¥æ¡)ãå·®å¼(å端å¯å³æ¶è®¡ç®=å®çâè´¦é¢)"ï¼æ¯æè¡¨æ ¼éè¡ä¿åæåºé¨"æ¹éå½å
¥"è° entryï¼onlyDiff å¼å
³ï¼å®ææé®å äºæ¬¡ç¡®è®¤ï¼"å·®å¼å°çæè°è´¦åæ®ï¼å®¡æ ¸éè¿åè´¦é¢çæ"ï¼ã |
| | | - é¢è¦é¡µï¼å¯ç¨æ°é ⤠é¢è¦å¼ 红è²é«äº®ï¼é¢è¦å¼ç»´æ¤å
¥å£æ²¿ç¨åºåç¼è¾ï¼warnNum åæ®µï¼ã |
| | | |
| | | ## äºãèè°èªæµæ¸
å |
| | | |
| | | - [ ] åèµ·çç¹ï¼å
¨é¨/æå®è§æ ¼ï¼â æç»ä¸åºåè¡ä¸è´ï¼è´¦é¢å¿«ç
§ï¼ |
| | | - [ ] åè§æ ¼éå¤åèµ· â æ¥éååºå²çªè§æ ¼ |
| | | - [ ] å½å
¥å®çï¼å¤è¡ä¸æ¬¡æäº¤ï¼â diffQty è½åºæ£ç¡®ï¼ç»æååå½å
¥è¢«æ¦æª |
| | | - [ ] finishï¼æªå½æ»¡æ¦æªï¼çç/çäºåå«åºç°å¨å
¥åº/åºåºè®°å½é¡µï¼å¾
å®¡æ ¸ï¼å¤æ³¨å«çç¹åå·ï¼â å®¡æ ¸ååºåå¢åæ£ç¡® |
| | | - [ ] å·®å¼åæå表/ä¸ä¸ªå¯¼åº |
| | | - [ ] warnPageï¼è°æ´æè¡ warnNum åé¢è¦ç»ææ£ç¡®ï¼å¯ç¨æ°é=æ°éâéå®å£å¾ä¸å表ä¸è´ |
| | | - [ ] åå½ï¼åºååå页/èååºå/å»ç»è§£å»ä¸åå½±å |
| | | |
| | | ## å
ãéç说æ |
| | | |
| | | - çäºè°è´¦èµ°åºåº"å¯ç¨åºå"æ ¡éªï¼éå®+å¾
å®¡æ ¸å ç¨ï¼ï¼è¥çç¹æé´åºåºè¶
å伿¦æªï¼éå
å¤çåºåºåæ®å宿çç¹ã |
| | | - æªå"çç¹æé´éå®åºååºå
¥åº"强管æ§ï¼äºæå¯å çç¹éï¼ã |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | # å端èè°ææ¡£ â æ¨¡å9ï¼äº§åç»´æ¤ |
| | | |
| | | > 忝ï¼product-inventory-management-after-jdk25ï¼å®¢æ·åº product-inventory-management-qysjï¼ |
| | | > åç«¯å®ææ¥æï¼2026-09-10ãç¶æï¼å端已å®ç°å¹¶ç¼è¯éè¿ï¼å¾
å端èè° |
| | | |
| | | ## ä¸ãæ¬æ¬¡æ¹å¨æ¦è§ |
| | | |
| | | | åæ´ç¹ | 说æ | |
| | | |---|---| |
| | | | 产åè§æ ¼æ°å¢"æ¡å½¢ç "åæ®µ | `product_model.barcode`ï¼varchar 64ï¼å¯ç©ºï¼å
¨å±å¯ä¸ï¼ | |
| | | | æ°å¢æ¡ç 精确æ¥è¯¢æ¥å£ | ä¾éè´/éå®/åºå页æ«ç å¿«ééåå | |
| | | | æ¹é导å
¥æ¯ææ¡ç å | æ¨¡æ¿æ°å¢"æ¡å½¢ç "åï¼å«æä»¶å
/åºå
æ¥é | |
| | | | è§æ ¼å页æ¥è¯¢æ¯ææ¡ç çé | `pageModel` æ°å¢ `barcode` æ¨¡ç³æ¥è¯¢åæ° | |
| | | | 产åå 餿 ¡éªå 强 | æ°å¢"åå¨ååç±»/åå¨åºåè®°å½"ä¸¤ç±»æ¦æª | |
| | | |
| | | ### æ°æ®åºåçº§èæ¬ï¼å
¶ä»ç¯å¢é¨ç½²éæ§è¡ï¼ |
| | | |
| | | ```sql |
| | | ALTER TABLE product_model |
| | | ADD COLUMN barcode varchar(64) NULL DEFAULT NULL COMMENT 'æ¡å½¢ç ' AFTER product_code, |
| | | ADD INDEX idx_product_model_barcode (barcode); |
| | | ``` |
| | | |
| | | ## äºãæ¥å£æç»ï¼**èåï¼æ²¿ç¨å·²æã产åç»´æ¤ãï¼menu_id=2023ï¼ç¶çº§ åºç¡æ°æ® 2000ï¼component `basicData/product/index`ï¼æ¬æ¬¡ä¸æ°å¢èå**ï¼ |
| | | |
| | | åºç¡è·¯å¾åç¼ä¸ç°æä¸è´ï¼æ¬å° `http://127.0.0.1:7005`ï¼ï¼é´ææ²¿ç¨ Authorization tokenï¼æ æ°å¢æéæ è¯ï¼è¯¥ Controller åæ¬æªæ @PreAuthorizeï¼ã |
| | | |
| | | ### 1. æ°å¢/ç¼è¾äº§åè§æ ¼ï¼æ©å±ï¼ |
| | | |
| | | `POST /basic/product/addOrEditProductModel` |
| | | |
| | | 请æ±ä½å¨ååæ®µåºç¡ä¸**æ°å¢ `barcode`ï¼éå¡«ï¼**ï¼ |
| | | |
| | | ```json |
| | | { |
| | | "id": null, |
| | | "productId": 12, |
| | | "model": "500g/è¢", |
| | | "productCode": "CP0001", |
| | | "unit": "è¢", |
| | | "barcode": "6901234567890" |
| | | } |
| | | ``` |
| | | |
| | | æ ¡éªè§åï¼å端è¿å error msgï¼ï¼ |
| | | - `æ¡å½¢ç 6901234567890å·²ç»åå¨`ï¼barcode å
¨å±æ¥éï¼ç¼è¾æ¶æé¤èªèº«ï¼ä¸ä¼ /ç©ºä¸²ä¸æ ¡éªï¼ |
| | | - åæè§åä¸åï¼åå·+产åç¼ç ç»åå¯ä¸ |
| | | |
| | | ### 2. æ¡ç 精确æ¥è¯¢ï¼æ°å¢ï¼ |
| | | |
| | | `GET /basic/product/model/byBarcode?barcode=6901234567890` |
| | | |
| | | æåï¼ |
| | | ```json |
| | | { |
| | | "code": 200, |
| | | "msg": "æä½æå", |
| | | "data": { |
| | | "id": 88, "productId": 12, "productName": "å±±æ ¸æ¡ä»", |
| | | "model": "500g/è¢", "productCode": "CP0001", "unit": "è¢", |
| | | "barcode": "6901234567890" |
| | | } |
| | | } |
| | | ``` |
| | | æªå¹é
ï¼`code=500`ï¼`msg="æ¡ç xxx æªå¹é
å°äº§åè§æ ¼"`ã |
| | | éç¨åºæ¯ï¼æ«ç æªå车åç´æ¥åå¡«ååï¼ç²¾ç¡®å¹é
ï¼é模ç³ï¼ã |
| | | |
| | | ### 3. è§æ ¼å页æ¥è¯¢ï¼æ©å±ï¼ |
| | | |
| | | `GET /basic/product/pageModel` |
| | | |
| | | - æ°å¢æ¥è¯¢åæ°ï¼`barcode`ï¼æ¨¡ç³å¹é
ï¼ |
| | | - ååºè¡å¯¹è±¡æ°å¢å段ï¼`barcode`ï¼åæ¶ä¿®å¤äº resultMapï¼`productCode` ç°å¨ç¨³å®è¿å |
| | | - å
¶ä½åæ°ä¸åï¼`model`ã`productName`ã`topProductParentId` |
| | | |
| | | ### 4. 导å
¥æ¨¡æ¿ä¸è½½ï¼æ©å±ï¼ |
| | | |
| | | `GET /basic/product/export` |
| | | |
| | | 模æ¿ååæ´ä¸ºï¼`产åç¼ç | è§æ ¼åå· | åä½ | æ¡å½¢ç `ãæ¡å½¢ç å**éå¡«**ã |
| | | |
| | | ### 5. æ¹é导å
¥ï¼æ©å±ï¼ |
| | | |
| | | `POST /basic/product/import`ï¼multipart `file` + query `productId`ï¼ç¨æ³ä¸åï¼ |
| | | |
| | | æ°å¢æ ¡éªï¼æ´ä½å¤±è´¥å¹¶æç¤ºè¡å·ï¼è¡å·=Excel å®é
è¡ï¼ï¼ |
| | | - `第 N è¡å¯¼å
¥å¤±è´¥: æ¡å½¢ç xxx 卿件ä¸éå¤` |
| | | - `第 N è¡å¯¼å
¥å¤±è´¥: æ¡å½¢ç xxx å·²åå¨` |
| | | |
| | | åæè¡ä¸ºä¿çï¼ç¼ç /åå·/åä½ä¸ºç©ºæ¥éï¼`è§æ ¼åå·` å·²åå¨äºè¯¥äº§åä¸åè·³è¿å¹¶è®¡å
¥"è·³è¿å·²å卿°æ® N æ¡"ã |
| | | |
| | | ### 6. å é¤äº§åï¼æ ¡éªå å¼ºï¼ |
| | | |
| | | `DELETE /basic/product/delProduct`ï¼body: `[id1,id2]`ï¼ç¨æ³ä¸åï¼ |
| | | |
| | | æ°å¢ä¸¤ç±»æ¦æªï¼åæ¥åªæ ¡éªéå®/éè´è®°å½ï¼ï¼ |
| | | - `该产åä¸åå¨ååç±»ï¼è¯·å
å é¤ååç±»` |
| | | - `该产åè§æ ¼å·²åå¨åºåè®°å½ï¼ä¸è½å é¤` |
| | | |
| | | 建议å端æ error msg ç´æ¥ toast ç»ç¨æ·ï¼æ é颿£ã |
| | | |
| | | ### 7. åå½±åçèæ¥å£ï¼ä»
ååºä½å åæ®µï¼ |
| | | |
| | | `GET /basic/product/modelList`ã`GET /basic/product/modelListPage`ï¼ProductModel åºåååå¤åº `barcode` åæ®µï¼æªå¡«æ¶ä¸º nullï¼ï¼å端å表/表åéè¡¥ä¸åå±ç¤ºã |
| | | |
| | | ## ä¸ãèè°èªæµæ¸
åï¼åç«¯ææ¤èµ°æ¥ï¼ |
| | | |
| | | - [ ] è§æ ¼æ°å¢ä¸å¡«æ¡ç å¯ä¿åï¼å¡«é夿¡ç æç¤º"å·²ç»åå¨" |
| | | - [ ] ç¼è¾å·²æè§æ ¼ï¼æ¡ç çç©ºâæ¹å¡«â忏
空ï¼ä¸ç§æ
åµåæ£å¸¸ |
| | | - [ ] pageModel ææ¡ç æ¨¡ç³æç´¢çæ |
| | | - [ ] byBarcode æ«ç 精确å½ä¸ï¼è¿åå« productName |
| | | - [ ] ä¸è½½æ°æ¨¡æ¿å«"æ¡å½¢ç "åï¼å¯¼å
¥ï¼æä»¶å
é夿¡ç / ä¸åºå
éå¤ / æ£å¸¸æ¡ç ä¸ç§ç¨ä¾ |
| | | - [ ] å é¤å«ååç±»ç产åãå é¤è§æ ¼å·²æåºåç产åï¼åè¢«æ¦æªå¹¶æç¤º |
| | | - [ ] å 餿 å¼ç¨äº§å仿£å¸¸ï¼åå½ï¼ |
| | | |
| | | ## åãéç说æ |
| | | |
| | | - æ¡ç å¯ä¸æ§ä¸ºå
¨å±ï¼ä¸éç§æ·ï¼ï¼ä¸ç°æ"åå·+ç¼ç "æ¥éå£å¾ä¸è´ï¼`product_model` å¨ç§æ·æ¦æªå¿½ç¥è¡¨ä¸ï¼ã |
| | | - æªå å¯ç¨/åç¨ç¶æå段ï¼éæ±è¡¨æªè¦æ±ï¼ï¼å¦åç»è¦"䏿¶åå"å说ã |
| | |
| | | } |
| | | |
| | | /** |
| | | * æ ¹æ®æ¡ç 精确æ¥è¯¢äº§åè§æ ¼ï¼éè´/éå®/åºåæ«ç éååï¼ |
| | | */ |
| | | @Operation(summary = "æ ¹æ®æ¡ç æ¥è¯¢äº§åè§æ ¼") |
| | | @GetMapping("/model/byBarcode") |
| | | public AjaxResult selectByBarcode(@RequestParam String barcode) { |
| | | if (barcode == null || barcode.trim().isEmpty()) { |
| | | return AjaxResult.error("è¯·ä¼ å
¥æ¡ç "); |
| | | } |
| | | ProductModel productModel = productModelService.selectByBarcode(barcode); |
| | | if (productModel == null) { |
| | | return AjaxResult.error("æ¡ç " + barcode + " æªå¹é
å°äº§åè§æ ¼"); |
| | | } |
| | | return AjaxResult.success(productModel); |
| | | } |
| | | |
| | | /** |
| | | * 导å
¥äº§å |
| | | */ |
| | | @PostMapping("/import") |
| | |
| | | @Excel(name = "åä½") |
| | | private String unit; |
| | | |
| | | @Excel(name = "æ¡å½¢ç ") |
| | | private String barcode; |
| | | |
| | | } |
| | |
| | | @Excel(name = "产åç¼ç ") |
| | | private String productCode; |
| | | |
| | | @Schema(description = "æ¡å½¢ç ") |
| | | @Excel(name = "æ¡å½¢ç ") |
| | | private String barcode; |
| | | |
| | | /** |
| | | * åä½ |
| | | */ |
| | |
| | | IPage<ProductModel> modelListPage(Page page , ProductDto productDto); |
| | | |
| | | AjaxResult importProductModel(MultipartFile file, Integer productId); |
| | | |
| | | /** |
| | | * æ ¹æ®æ¡ç æ¥è¯¢äº§åè§æ ¼ï¼å«äº§ååç§°ï¼ |
| | | */ |
| | | ProductModel selectByBarcode(String barcode); |
| | | } |
| | |
| | | |
| | | import java.util.ArrayList; |
| | | import java.util.Arrays; |
| | | import java.util.HashSet; |
| | | import java.util.List; |
| | | import java.util.Set; |
| | | import java.util.stream.Collectors; |
| | |
| | | public int addOrEditProductModel(ProductModelDto productModelDto) { |
| | | String model = StringUtils.trim(productModelDto.getModel()); |
| | | String productCode = StringUtils.trim(productModelDto.getProductCode()); |
| | | String barcode = StringUtils.trim(productModelDto.getBarcode()); |
| | | productModelDto.setModel(model); |
| | | productModelDto.setProductCode(productCode); |
| | | productModelDto.setBarcode(barcode); |
| | | checkModelAndProductCodeUnique(model, productCode, productModelDto.getId()); |
| | | checkBarcodeUnique(barcode, productModelDto.getId()); |
| | | |
| | | if (productModelDto.getId() == null) { |
| | | ProductModel productModel = new ProductModel(); |
| | |
| | | ProductModel duplicateProductModel = productModelMapper.selectOne(queryWrapper); |
| | | if (duplicateProductModel != null) { |
| | | throw new ServiceException("对åºçåå·" + model + "ç产åç¼ç " + productCode + "å·²ç»åå¨"); |
| | | } |
| | | } |
| | | |
| | | private void checkBarcodeUnique(String barcode, Long currentId) { |
| | | if (StringUtils.isEmpty(barcode)) { |
| | | return; |
| | | } |
| | | LambdaQueryWrapper<ProductModel> queryWrapper = new LambdaQueryWrapper<>(); |
| | | queryWrapper.eq(ProductModel::getBarcode, barcode) |
| | | .ne(currentId != null, ProductModel::getId, currentId) |
| | | .last("limit 1"); |
| | | if (productModelMapper.selectOne(queryWrapper) != null) { |
| | | throw new ServiceException("æ¡å½¢ç " + barcode + "å·²ç»åå¨"); |
| | | } |
| | | } |
| | | |
| | |
| | | List<ProductModel> existingModels = list(new LambdaQueryWrapper<ProductModel>().eq(ProductModel::getProductId, productId)); |
| | | Set<String> existingModelNames = existingModels.stream().map(ProductModel::getModel).collect(Collectors.toSet()); |
| | | |
| | | // å·²åå¨äºæ°æ®åºä¸çæ¡ç ï¼å
¨å±æ¥éï¼ |
| | | List<String> importBarcodes = productModelList.stream() |
| | | .map(item -> StringUtils.trim(item.getBarcode())) |
| | | .filter(StringUtils::isNotEmpty) |
| | | .distinct() |
| | | .collect(Collectors.toList()); |
| | | Set<String> dbBarcodeSet = importBarcodes.isEmpty() ? new HashSet<>() |
| | | : list(new LambdaQueryWrapper<ProductModel>().in(ProductModel::getBarcode, importBarcodes)) |
| | | .stream().map(ProductModel::getBarcode).collect(Collectors.toSet()); |
| | | Set<String> fileBarcodes = new HashSet<>(); |
| | | |
| | | List<ProductModel> waitToSaveList = new ArrayList<>(); |
| | | int skipCount = 0; |
| | | |
| | |
| | | } |
| | | if (StringUtils.isEmpty(item.getUnit())) { |
| | | return AjaxResult.error("第 " + rowNum + " è¡å¯¼å
¥å¤±è´¥: [åä½] ä¸è½ä¸ºç©º"); |
| | | } |
| | | |
| | | item.setBarcode(StringUtils.trim(item.getBarcode())); |
| | | if (StringUtils.isNotEmpty(item.getBarcode())) { |
| | | if (!fileBarcodes.add(item.getBarcode())) { |
| | | return AjaxResult.error("第 " + rowNum + " è¡å¯¼å
¥å¤±è´¥: æ¡å½¢ç " + item.getBarcode() + " 卿件ä¸éå¤"); |
| | | } |
| | | if (dbBarcodeSet.contains(item.getBarcode())) { |
| | | return AjaxResult.error("第 " + rowNum + " è¡å¯¼å
¥å¤±è´¥: æ¡å½¢ç " + item.getBarcode() + " å·²åå¨"); |
| | | } |
| | | } |
| | | |
| | | // å»é,妿已å
å«è¯¥åå·,åè·³è¿ |
| | |
| | | throw new ServiceException("导å
¥å¤±è´¥"); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public ProductModel selectByBarcode(String barcode) { |
| | | if (StringUtils.isEmpty(barcode)) { |
| | | return null; |
| | | } |
| | | LambdaQueryWrapper<ProductModel> queryWrapper = new LambdaQueryWrapper<>(); |
| | | queryWrapper.eq(ProductModel::getBarcode, StringUtils.trim(barcode)) |
| | | .last("limit 1"); |
| | | ProductModel productModel = productModelMapper.selectOne(queryWrapper); |
| | | if (productModel != null && productModel.getProductId() != null) { |
| | | Product product = productMapper.selectById(productModel.getProductId()); |
| | | if (product != null) { |
| | | productModel.setProductName(product.getProductName()); |
| | | } |
| | | } |
| | | return productModel; |
| | | } |
| | | } |
| | |
| | | import com.ruoyi.basic.pojo.ProductModel; |
| | | import com.ruoyi.basic.service.IProductService; |
| | | import com.ruoyi.basic.vo.ProductModelVo; |
| | | import com.ruoyi.common.exception.ServiceException; |
| | | import com.ruoyi.common.utils.StringUtils; |
| | | import com.ruoyi.common.utils.bean.BeanUtils; |
| | | import com.ruoyi.stock.mapper.StockInventoryMapper; |
| | | import com.ruoyi.stock.pojo.StockInventory; |
| | | import lombok.AllArgsConstructor; |
| | | import org.springframework.stereotype.Service; |
| | | |
| | | import java.util.ArrayList; |
| | | import java.util.Arrays; |
| | | import java.util.List; |
| | | import java.util.stream.Collectors; |
| | | |
| | | @Service |
| | | @AllArgsConstructor |
| | |
| | | private ProductMapper productMapper; |
| | | |
| | | private ProductModelMapper productModelMapper; |
| | | |
| | | private StockInventoryMapper stockInventoryMapper; |
| | | |
| | | @Override |
| | | public List<ProductTreeDto> selectProductList(ProductDto productDto) { |
| | |
| | | |
| | | @Override |
| | | public int delProductByIds(Long[] ids) { |
| | | // 1. å é¤å表 product_model ä¸å
³èçæ°æ® |
| | | List<Long> idList = Arrays.asList(ids); |
| | | |
| | | // 1. åå¨ååç±»æ¶ä¸å
许å é¤ï¼é¿å
æ ç»æåºç°å¤å¿èç¹ |
| | | LambdaQueryWrapper<Product> childWrapper = new LambdaQueryWrapper<>(); |
| | | childWrapper.in(Product::getParentId, idList); |
| | | if (productMapper.selectCount(childWrapper) > 0) { |
| | | throw new ServiceException("该产åä¸åå¨ååç±»ï¼è¯·å
å é¤ååç±»"); |
| | | } |
| | | |
| | | // 2. è§æ ¼å·²è¢«åºåè®°å½å¼ç¨æ¶ä¸å
许å é¤ï¼é¿å
å岿°æ®æé¾ |
| | | LambdaQueryWrapper<ProductModel> queryWrapper = new LambdaQueryWrapper<>(); |
| | | queryWrapper.in(ProductModel::getProductId, ids); |
| | | productModelMapper.delete(queryWrapper); |
| | | queryWrapper.in(ProductModel::getProductId, idList); |
| | | List<ProductModel> models = productModelMapper.selectList(queryWrapper); |
| | | if (!models.isEmpty()) { |
| | | List<Long> modelIds = models.stream().map(ProductModel::getId).collect(Collectors.toList()); |
| | | LambdaQueryWrapper<StockInventory> stockWrapper = new LambdaQueryWrapper<>(); |
| | | stockWrapper.in(StockInventory::getProductModelId, modelIds); |
| | | if (stockInventoryMapper.selectCount(stockWrapper) > 0) { |
| | | throw new ServiceException("该产åè§æ ¼å·²åå¨åºåè®°å½ï¼ä¸è½å é¤"); |
| | | } |
| | | productModelMapper.delete(queryWrapper); |
| | | } |
| | | |
| | | // 2. å é¤ä¸»è¡¨ product æ°æ® |
| | | int deleteCount = productMapper.deleteBatchIds(Arrays.asList(ids)); |
| | | |
| | | return deleteCount; |
| | | // 3. å é¤ä¸»è¡¨ product æ°æ® |
| | | return productMapper.deleteBatchIds(idList); |
| | | } |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.cost.bean.vo; |
| | | |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | |
| | | import java.math.BigDecimal; |
| | | |
| | | @Data |
| | | @Schema(name = "CostEnergyVo", description = "ææ¬æ ¸ç®-åºé´è½èæ±æ»") |
| | | public class CostEnergyVo { |
| | | |
| | | @Schema(description = "ç¨çµé(kWh)") |
| | | private BigDecimal kwh; |
| | | |
| | | @Schema(description = "çµè´¹éé¢(设å¤ç¨çµéÃå¯¹åºæ¥æçµä»·)") |
| | | private BigDecimal energyCost; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.cost.bean.vo; |
| | | |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | |
| | | import java.math.BigDecimal; |
| | | |
| | | @Data |
| | | @Schema(name = "CostLaborVo", description = "ææ¬æ ¸ç®-订åäººå·¥ææ¬") |
| | | public class CostLaborVo { |
| | | |
| | | @Schema(description = "ç产订åid") |
| | | private Long productionOrderId; |
| | | |
| | | @Schema(description = "äººå·¥ææ¬") |
| | | private BigDecimal laborCost; |
| | | |
| | | @Schema(description = "æ ¸ç®è®°å½æ°") |
| | | private Integer accountRows; |
| | | |
| | | @Schema(description = "å·¥æ¶ä¸º0䏿 计件åä»·çæ ¸ç®è®°å½æ°ï¼æ å·¥èµæ åï¼") |
| | | private Integer noRateRows; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.cost.bean.vo; |
| | | |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | |
| | | import java.math.BigDecimal; |
| | | |
| | | @Data |
| | | @Schema(name = "CostMaterialInputVo", description = "ææ¬æ ¸ç®-订åç©æå®é
æå
¥") |
| | | public class CostMaterialInputVo { |
| | | |
| | | @Schema(description = "ç产订åid") |
| | | private Long productionOrderId; |
| | | |
| | | @Schema(description = "ç©æè§æ ¼id") |
| | | private Long productModelId; |
| | | |
| | | @Schema(description = "æå
¥æ°é") |
| | | private BigDecimal inputQty; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.cost.bean.vo; |
| | | |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | |
| | | import java.math.BigDecimal; |
| | | |
| | | @Data |
| | | @Schema(name = "CostMaterialPriceVo", description = "ææ¬æ ¸ç®-ç©æåä»·ï¼å¤æ¥æºï¼æä¼å
级å馿¡ï¼") |
| | | public class CostMaterialPriceVo { |
| | | |
| | | @Schema(description = "ç©æè§æ ¼id") |
| | | private Long productModelId; |
| | | |
| | | @Schema(description = "åä»·") |
| | | private BigDecimal price; |
| | | |
| | | @Schema(description = "ä»·æ ¼æ¥æº") |
| | | private String priceSource; |
| | | |
| | | @Schema(description = "ä¼å
çº§ï¼æ°å¼è¶å°è¶ä¼å
") |
| | | private Integer priority; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.cost.bean.vo; |
| | | |
| | | import com.ruoyi.framework.aspectj.lang.annotation.Excel; |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.time.LocalDateTime; |
| | | |
| | | @Data |
| | | @Schema(name = "CostMissingPriceVo", description = "缺éè´åä»·çæ¶èç©ææ¸
å") |
| | | public class CostMissingPriceVo { |
| | | |
| | | @Schema(description = "ç©æè§æ ¼id") |
| | | private Long productModelId; |
| | | |
| | | @Excel(name = "ç©æåç§°") |
| | | @Schema(description = "ç©æåç§°") |
| | | private String materialName; |
| | | |
| | | @Excel(name = "ç©æè§æ ¼") |
| | | @Schema(description = "ç©æè§æ ¼") |
| | | private String materialModel; |
| | | |
| | | @Excel(name = "åä½") |
| | | @Schema(description = "åä½") |
| | | private String unit; |
| | | |
| | | @Excel(name = "æ¶èæ°é") |
| | | @Schema(description = "çéèå´å
æå
¥å计") |
| | | private BigDecimal inputQty; |
| | | |
| | | @Excel(name = "æ¶åè®¢åæ°") |
| | | @Schema(description = "使ç¨è¯¥ç©æççäº§è®¢åæ°") |
| | | private Integer orderCount; |
| | | |
| | | @Excel(name = "æè¿æå
¥æ¶é´", width = 22, dateFormat = "yyyy-MM-dd HH:mm:ss") |
| | | @Schema(description = "æè¿ä¸æ¬¡æå
¥æ¶é´") |
| | | private LocalDateTime lastInputTime; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.cost.bean.vo; |
| | | |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.time.LocalDateTime; |
| | | |
| | | @Data |
| | | @Schema(name = "CostOrderVo", description = "ææ¬æ ¸ç®-ç产订ååºç¡è¡") |
| | | public class CostOrderVo { |
| | | |
| | | @Schema(description = "ç产订åid") |
| | | private Long productionOrderId; |
| | | |
| | | @Schema(description = "ç产订åå·") |
| | | private String npsNo; |
| | | |
| | | @Schema(description = "æåè§æ ¼id") |
| | | private Long productModelId; |
| | | |
| | | @Schema(description = "æå åç§°/è§æ ¼") |
| | | private String finishedProduct; |
| | | |
| | | @Schema(description = "æååç§°") |
| | | private String productName; |
| | | |
| | | @Schema(description = "æåè§æ ¼") |
| | | private String productModel; |
| | | |
| | | @Schema(description = "åä½") |
| | | private String unit; |
| | | |
| | | @Schema(description = "å®å·¥æ°é") |
| | | private BigDecimal completeQty; |
| | | |
| | | @Schema(description = "è®¡åæ°é") |
| | | private BigDecimal planQty; |
| | | |
| | | @Schema(description = "订åå建æ¶é´") |
| | | private LocalDateTime createTime; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.cost.bean.vo; |
| | | |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | |
| | | import java.math.BigDecimal; |
| | | |
| | | @Data |
| | | @Schema(name = "CostSalePriceVo", description = "ææ¬æ ¸ç®-订åå
³èéå®åä»·") |
| | | public class CostSalePriceVo { |
| | | |
| | | @Schema(description = "ç产订åid") |
| | | private Long productionOrderId; |
| | | |
| | | @Schema(description = "å«ç¨éå®åä»·") |
| | | private BigDecimal salePrice; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.cost.bean.vo; |
| | | |
| | | import com.ruoyi.framework.aspectj.lang.annotation.Excel; |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.time.LocalDate; |
| | | |
| | | @Data |
| | | @Schema(name = "CostStatVo", description = "ææ¬æ ¸ç®ï¼ææ+人工+è½èï¼") |
| | | public class CostStatVo { |
| | | |
| | | @Schema(description = "ç产订åid") |
| | | private Long productionOrderId; |
| | | |
| | | @Excel(name = "ç产订åå·") |
| | | @Schema(description = "ç产订åå·") |
| | | private String npsNo; |
| | | |
| | | @Excel(name = "æå") |
| | | @Schema(description = "æå åç§°/è§æ ¼") |
| | | private String finishedProduct; |
| | | |
| | | @Excel(name = "åä½") |
| | | @Schema(description = "åä½") |
| | | private String unit; |
| | | |
| | | @Excel(name = "è®¢åæ¥æ", width = 20, dateFormat = "yyyy-MM-dd") |
| | | @Schema(description = "订ååå»ºæ¥æ") |
| | | private LocalDate orderDate; |
| | | |
| | | @Excel(name = "产é") |
| | | @Schema(description = "产éï¼å®å·¥æ°éï¼æªå®å·¥åéè®¡åæ°é") |
| | | private BigDecimal outputQty; |
| | | |
| | | @Excel(name = "ææææ¬") |
| | | @Schema(description = "ææææ¬=Σ(ç©ææå
¥éÃéè´åä»·)") |
| | | private BigDecimal materialCost; |
| | | |
| | | @Excel(name = "äººå·¥ææ¬") |
| | | @Schema(description = "äººå·¥ææ¬=计件/计æ¶å·¥èµå计") |
| | | private BigDecimal laborCost; |
| | | |
| | | @Excel(name = "è½èææ¬") |
| | | @Schema(description = "è½èææ¬=åºé´çµè´¹æäº§éå æ¯åæ") |
| | | private BigDecimal energyCost; |
| | | |
| | | @Excel(name = "æ»ææ¬") |
| | | @Schema(description = "æ»ææ¬=ææ+人工+è½è") |
| | | private BigDecimal totalCost; |
| | | |
| | | @Excel(name = "å使æ¬") |
| | | @Schema(description = "å使æ¬=æ»ææ¬/产é") |
| | | private BigDecimal unitCost; |
| | | |
| | | @Excel(name = "éå®åä»·") |
| | | @Schema(description = "å
³èéå®åå«ç¨åä»·") |
| | | private BigDecimal salePrice; |
| | | |
| | | @Excel(name = "æ¯å©") |
| | | @Schema(description = "æ¯å©=(éå®åä»·-å使æ¬)Ã产é") |
| | | private BigDecimal grossProfit; |
| | | |
| | | @Excel(name = "æ¯å©ç%") |
| | | @Schema(description = "æ¯å©ç=æ¯å©/(éå®åä»·Ã产é)Ã100") |
| | | private BigDecimal grossProfitRate; |
| | | |
| | | @Excel(name = "ä»·æ ¼è¦çç%") |
| | | @Schema(description = "æéè´ä»·çç©ææ¶èéå æ¯ï¼ä½äº100说ææç¼ºä»·ç©æ") |
| | | private BigDecimal priceCoverageRate; |
| | | |
| | | @Excel(name = "ç¼ºä»·ç©ææ°") |
| | | @Schema(description = "æå
¥ä½æ éè´åä»·çç©æç§ç±»æ°") |
| | | private Integer missingPriceKinds; |
| | | |
| | | @Excel(name = "æ å·¥èµæ åè®°å½") |
| | | @Schema(description = "å·¥æ¶ä¸º0䏿 计件åä»·çæ¥å·¥æ ¸ç®è®°å½æ°") |
| | | private Integer noRateRows; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.cost.bean.vo; |
| | | |
| | | import com.ruoyi.framework.aspectj.lang.annotation.Excel; |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | |
| | | import java.math.BigDecimal; |
| | | |
| | | @Data |
| | | @Schema(name = "CostSummaryVo", description = "ææ¬æææ±æ»ï¼ææ/ææåï¼") |
| | | public class CostSummaryVo { |
| | | |
| | | @Excel(name = "åç»") |
| | | @Schema(description = "åç»é®ï¼æä»½ yyyy-MM ææååç§°/è§æ ¼") |
| | | private String groupKey; |
| | | |
| | | @Excel(name = "è®¢åæ°") |
| | | @Schema(description = "è®¢åæ°") |
| | | private Integer orderCount; |
| | | |
| | | @Excel(name = "产é") |
| | | @Schema(description = "产éå计") |
| | | private BigDecimal outputQty; |
| | | |
| | | @Excel(name = "ææææ¬") |
| | | @Schema(description = "ææææ¬å计") |
| | | private BigDecimal materialCost; |
| | | |
| | | @Excel(name = "äººå·¥ææ¬") |
| | | @Schema(description = "äººå·¥ææ¬å计") |
| | | private BigDecimal laborCost; |
| | | |
| | | @Excel(name = "è½èææ¬") |
| | | @Schema(description = "è½èææ¬å计") |
| | | private BigDecimal energyCost; |
| | | |
| | | @Excel(name = "æ»ææ¬") |
| | | @Schema(description = "æ»ææ¬å计") |
| | | private BigDecimal totalCost; |
| | | |
| | | @Excel(name = "å¹³åå使æ¬") |
| | | @Schema(description = "æ»ææ¬/产é") |
| | | private BigDecimal unitCost; |
| | | |
| | | @Excel(name = "ææå æ¯%") |
| | | @Schema(description = "ææææ¬/æ»ææ¬Ã100") |
| | | private BigDecimal materialRate; |
| | | |
| | | @Excel(name = "äººå·¥å æ¯%") |
| | | @Schema(description = "äººå·¥ææ¬/æ»ææ¬Ã100") |
| | | private BigDecimal laborRate; |
| | | |
| | | @Excel(name = "è½èå æ¯%") |
| | | @Schema(description = "è½èææ¬/æ»ææ¬Ã100") |
| | | private BigDecimal energyRate; |
| | | |
| | | @Excel(name = "æ¯å©") |
| | | @Schema(description = "æ¯å©å计") |
| | | private BigDecimal grossProfit; |
| | | |
| | | @Excel(name = "æ¯å©ç%") |
| | | @Schema(description = "æ¯å©/éå®é¢Ã100") |
| | | private BigDecimal grossProfitRate; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.cost.controller; |
| | | |
| | | import com.ruoyi.common.utils.poi.ExcelUtil; |
| | | import com.ruoyi.cost.bean.vo.CostMissingPriceVo; |
| | | import com.ruoyi.cost.bean.vo.CostStatVo; |
| | | import com.ruoyi.cost.bean.vo.CostSummaryVo; |
| | | import com.ruoyi.cost.service.CostAccountingService; |
| | | import com.ruoyi.framework.aspectj.lang.annotation.Log; |
| | | import com.ruoyi.framework.aspectj.lang.enums.BusinessType; |
| | | import com.ruoyi.framework.web.domain.R; |
| | | import io.swagger.v3.oas.annotations.Operation; |
| | | import io.swagger.v3.oas.annotations.tags.Tag; |
| | | import jakarta.servlet.http.HttpServletResponse; |
| | | import lombok.RequiredArgsConstructor; |
| | | import org.springframework.format.annotation.DateTimeFormat; |
| | | 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.time.LocalDate; |
| | | import java.util.List; |
| | | |
| | | @RestController |
| | | @RequestMapping("/costAccounting") |
| | | @RequiredArgsConstructor |
| | | @Tag(name = "ææ¬æ ¸ç®åæ") |
| | | public class CostAccountingController { |
| | | |
| | | private final CostAccountingService costAccountingService; |
| | | |
| | | @GetMapping("/stat") |
| | | @Operation(summary = "ææ¬æ ¸ç®æç»ï¼ææ+人工+è½èï¼æç产订åï¼") |
| | | public R<List<CostStatVo>> stat( |
| | | @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate startDate, |
| | | @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate endDate, |
| | | @RequestParam(required = false) String npsNo, |
| | | @RequestParam(required = false) String productName) { |
| | | return R.ok(costAccountingService.stat(startDate, endDate, npsNo, productName)); |
| | | } |
| | | |
| | | @GetMapping("/summary") |
| | | @Operation(summary = "ææ¬æææ±æ»ï¼groupBy=month/product") |
| | | public R<List<CostSummaryVo>> summary( |
| | | @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate startDate, |
| | | @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate endDate, |
| | | @RequestParam(required = false) String npsNo, |
| | | @RequestParam(required = false) String productName, |
| | | @RequestParam(required = false, defaultValue = "month") String groupBy) { |
| | | return R.ok(costAccountingService.summary(startDate, endDate, npsNo, productName, groupBy)); |
| | | } |
| | | |
| | | @GetMapping("/missingPrice") |
| | | @Operation(summary = "缺éè´åä»·çæ¶èç©ææ¸
å") |
| | | public R<List<CostMissingPriceVo>> missingPrice( |
| | | @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate startDate, |
| | | @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate endDate, |
| | | @RequestParam(required = false) String npsNo, |
| | | @RequestParam(required = false) String productName) { |
| | | return R.ok(costAccountingService.missingPrice(startDate, endDate, npsNo, productName)); |
| | | } |
| | | |
| | | @GetMapping("/stat/export") |
| | | @Log(title = "Export cost stat", businessType = BusinessType.EXPORT) |
| | | @Operation(summary = "ææ¬æ ¸ç®æç»å¯¼åº") |
| | | public void exportStat(HttpServletResponse response, |
| | | @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate startDate, |
| | | @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate endDate, |
| | | @RequestParam(required = false) String npsNo, |
| | | @RequestParam(required = false) String productName) { |
| | | List<CostStatVo> list = costAccountingService.stat(startDate, endDate, npsNo, productName); |
| | | ExcelUtil<CostStatVo> util = new ExcelUtil<>(CostStatVo.class); |
| | | util.exportExcel(response, list, "ææ¬æ ¸ç®æç»"); |
| | | } |
| | | |
| | | @GetMapping("/summary/export") |
| | | @Log(title = "Export cost summary", businessType = BusinessType.EXPORT) |
| | | @Operation(summary = "ææ¬æææ±æ»å¯¼åº") |
| | | public void exportSummary(HttpServletResponse response, |
| | | @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate startDate, |
| | | @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate endDate, |
| | | @RequestParam(required = false) String npsNo, |
| | | @RequestParam(required = false) String productName, |
| | | @RequestParam(required = false, defaultValue = "month") String groupBy) { |
| | | List<CostSummaryVo> list = costAccountingService.summary(startDate, endDate, npsNo, productName, groupBy); |
| | | ExcelUtil<CostSummaryVo> util = new ExcelUtil<>(CostSummaryVo.class); |
| | | util.exportExcel(response, list, "ææ¬æææ±æ»"); |
| | | } |
| | | |
| | | @GetMapping("/missingPrice/export") |
| | | @Log(title = "Export missing price materials", businessType = BusinessType.EXPORT) |
| | | @Operation(summary = "ç¼ºä»·ç©ææ¸
å导åº") |
| | | public void exportMissingPrice(HttpServletResponse response, |
| | | @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate startDate, |
| | | @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate endDate, |
| | | @RequestParam(required = false) String npsNo, |
| | | @RequestParam(required = false) String productName) { |
| | | List<CostMissingPriceVo> list = costAccountingService.missingPrice(startDate, endDate, npsNo, productName); |
| | | ExcelUtil<CostMissingPriceVo> util = new ExcelUtil<>(CostMissingPriceVo.class); |
| | | util.exportExcel(response, list, "ç¼ºä»·ç©ææ¸
å"); |
| | | } |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.cost.mapper; |
| | | |
| | | import com.ruoyi.cost.bean.vo.CostEnergyVo; |
| | | import com.ruoyi.cost.bean.vo.CostLaborVo; |
| | | import com.ruoyi.cost.bean.vo.CostMaterialInputVo; |
| | | import com.ruoyi.cost.bean.vo.CostMaterialPriceVo; |
| | | import com.ruoyi.cost.bean.vo.CostMissingPriceVo; |
| | | import com.ruoyi.cost.bean.vo.CostOrderVo; |
| | | import com.ruoyi.cost.bean.vo.CostSalePriceVo; |
| | | import org.apache.ibatis.annotations.Mapper; |
| | | import org.apache.ibatis.annotations.Param; |
| | | |
| | | import java.time.LocalDate; |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * ææ¬æ ¸ç®åæï¼åªè¯»ï¼æç产订åå½éææ/人工/è½èï¼ |
| | | */ |
| | | @Mapper |
| | | public interface CostAccountingMapper { |
| | | |
| | | /** 订ååºç¡ä¿¡æ¯ */ |
| | | List<CostOrderVo> listOrders(@Param("startDate") LocalDate startDate, |
| | | @Param("endDate") LocalDate endDate, |
| | | @Param("npsNo") String npsNo, |
| | | @Param("productName") String productName); |
| | | |
| | | /** 订åç©æå®é
æå
¥ï¼æ¥å·¥æå
¥å£å¾ï¼ */ |
| | | List<CostMaterialInputVo> listMaterialInputs(@Param("startDate") LocalDate startDate, |
| | | @Param("endDate") LocalDate endDate, |
| | | @Param("npsNo") String npsNo, |
| | | @Param("productName") String productName); |
| | | |
| | | /** æ¶èç©ææ±æ»ï¼ç¨äºç¼ºä»·æ¸
åï¼ */ |
| | | List<CostMissingPriceVo> listConsumedMaterials(@Param("startDate") LocalDate startDate, |
| | | @Param("endDate") LocalDate endDate, |
| | | @Param("npsNo") String npsNo, |
| | | @Param("productName") String productName); |
| | | |
| | | /** ç©æåä»·ï¼å¤æ¥æºï¼priority è¶å°è¶ä¼å
ï¼ */ |
| | | List<CostMaterialPriceVo> listMaterialPrices(); |
| | | |
| | | /** 订åäººå·¥ææ¬ï¼ä¸æ¥å·¥å·¥èµå£å¾ä¸è´ï¼è®¡ä»¶ä¼å
ï¼å
¶æ¬¡è®¡æ¶ï¼åæ¬¡è§æ ¼å
åµåä»·ï¼ */ |
| | | List<CostLaborVo> listLaborCosts(@Param("startDate") LocalDate startDate, |
| | | @Param("endDate") LocalDate endDate, |
| | | @Param("npsNo") String npsNo, |
| | | @Param("productName") String productName); |
| | | |
| | | /** 订åå
³èçéå®å«ç¨åä»· */ |
| | | List<CostSalePriceVo> listSalePrices(@Param("startDate") LocalDate startDate, |
| | | @Param("endDate") LocalDate endDate, |
| | | @Param("npsNo") String npsNo, |
| | | @Param("productName") String productName); |
| | | |
| | | /** åºé´çµè´¹æ»é¢ï¼è®¾å¤è½èÃ彿¥çµä»·ï¼ */ |
| | | CostEnergyVo sumEnergyCost(@Param("startDate") LocalDate startDate, |
| | | @Param("endDate") LocalDate endDate); |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.cost.service; |
| | | |
| | | import com.ruoyi.cost.bean.vo.CostMissingPriceVo; |
| | | import com.ruoyi.cost.bean.vo.CostStatVo; |
| | | import com.ruoyi.cost.bean.vo.CostSummaryVo; |
| | | |
| | | import java.time.LocalDate; |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * ææ¬æ ¸ç®åæï¼æç产订åå½éææ/人工/è½èææ¬ï¼è¾åºå使æ¬ä¸æ¯å© |
| | | */ |
| | | public interface CostAccountingService { |
| | | |
| | | /** |
| | | * ææ¬æ ¸ç®æç»ï¼ä¸è¡ä¸ä¸ªç产订åï¼ |
| | | */ |
| | | List<CostStatVo> stat(LocalDate startDate, LocalDate endDate, String npsNo, String productName); |
| | | |
| | | /** |
| | | * ææ¬æææ±æ» |
| | | * |
| | | * @param groupBy month=æè®¢åæä»½ï¼product=ææå |
| | | */ |
| | | List<CostSummaryVo> summary(LocalDate startDate, LocalDate endDate, |
| | | String npsNo, String productName, String groupBy); |
| | | |
| | | /** |
| | | * 缺éè´åä»·çæ¶èç©ææ¸
åï¼ä¾è¡¥å½ä»·æ ¼ï¼ |
| | | */ |
| | | List<CostMissingPriceVo> missingPrice(LocalDate startDate, LocalDate endDate, |
| | | String npsNo, String productName); |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.cost.service.impl; |
| | | |
| | | import com.ruoyi.cost.bean.vo.CostEnergyVo; |
| | | import com.ruoyi.cost.bean.vo.CostLaborVo; |
| | | import com.ruoyi.cost.bean.vo.CostMaterialInputVo; |
| | | import com.ruoyi.cost.bean.vo.CostMaterialPriceVo; |
| | | import com.ruoyi.cost.bean.vo.CostMissingPriceVo; |
| | | import com.ruoyi.cost.bean.vo.CostOrderVo; |
| | | import com.ruoyi.cost.bean.vo.CostSalePriceVo; |
| | | import com.ruoyi.cost.bean.vo.CostStatVo; |
| | | import com.ruoyi.cost.bean.vo.CostSummaryVo; |
| | | import com.ruoyi.cost.mapper.CostAccountingMapper; |
| | | import com.ruoyi.cost.service.CostAccountingService; |
| | | import lombok.RequiredArgsConstructor; |
| | | import org.springframework.stereotype.Service; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.math.RoundingMode; |
| | | import java.time.LocalDate; |
| | | import java.time.format.DateTimeFormatter; |
| | | import java.util.ArrayList; |
| | | import java.util.HashMap; |
| | | import java.util.LinkedHashMap; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.stream.Collectors; |
| | | |
| | | @Service |
| | | @RequiredArgsConstructor |
| | | public class CostAccountingServiceImpl implements CostAccountingService { |
| | | |
| | | private static final BigDecimal HUNDRED = BigDecimal.valueOf(100); |
| | | private static final DateTimeFormatter MONTH_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM"); |
| | | |
| | | private final CostAccountingMapper costAccountingMapper; |
| | | |
| | | @Override |
| | | public List<CostStatVo> stat(LocalDate startDate, LocalDate endDate, String npsNo, String productName) { |
| | | List<CostOrderVo> orders = costAccountingMapper.listOrders(startDate, endDate, npsNo, productName); |
| | | if (orders.isEmpty()) { |
| | | return new ArrayList<>(); |
| | | } |
| | | Map<Long, List<CostMaterialInputVo>> inputsByOrder = costAccountingMapper |
| | | .listMaterialInputs(startDate, endDate, npsNo, productName).stream() |
| | | .filter(i -> i.getProductionOrderId() != null) |
| | | .collect(Collectors.groupingBy(CostMaterialInputVo::getProductionOrderId)); |
| | | Map<Long, CostMaterialPriceVo> priceByModel = priceByModel(); |
| | | Map<Long, CostLaborVo> laborByOrder = costAccountingMapper |
| | | .listLaborCosts(startDate, endDate, npsNo, productName).stream() |
| | | .filter(l -> l.getProductionOrderId() != null) |
| | | .collect(Collectors.toMap(CostLaborVo::getProductionOrderId, l -> l, (a, b) -> a)); |
| | | Map<Long, BigDecimal> salePriceByOrder = new LinkedHashMap<>(); |
| | | for (CostSalePriceVo sale : costAccountingMapper.listSalePrices(startDate, endDate, npsNo, productName)) { |
| | | if (sale.getProductionOrderId() != null) { |
| | | //SQL å·²æ slp.id ååºï¼ä¿çææ°ä¸å¼ éå®åçåä»· |
| | | salePriceByOrder.putIfAbsent(sale.getProductionOrderId(), sale.getSalePrice()); |
| | | } |
| | | } |
| | | |
| | | CostEnergyVo energy = nvlEnergy(costAccountingMapper.sumEnergyCost(startDate, endDate)); |
| | | BigDecimal energyTotal = nvl(energy.getEnergyCost()); |
| | | BigDecimal totalOutput = orders.stream().map(this::outputQty).reduce(BigDecimal.ZERO, BigDecimal::add); |
| | | |
| | | List<CostStatVo> result = new ArrayList<>(); |
| | | for (CostOrderVo order : orders) { |
| | | BigDecimal output = outputQty(order); |
| | | |
| | | //ææææ¬ï¼Î£(æå
¥éÃåä»·)ï¼åæ¶ç»è®¡å·²è®¡ä»·æ¶èéä¸ç¼ºä»·ç©ææ° |
| | | BigDecimal materialCost = BigDecimal.ZERO; |
| | | BigDecimal pricedQty = BigDecimal.ZERO; |
| | | BigDecimal inputQty = BigDecimal.ZERO; |
| | | int missingKinds = 0; |
| | | for (CostMaterialInputVo input : inputsByOrder.getOrDefault(order.getProductionOrderId(), new ArrayList<>())) { |
| | | BigDecimal qty = nvl(input.getInputQty()); |
| | | inputQty = inputQty.add(qty); |
| | | CostMaterialPriceVo price = input.getProductModelId() == null |
| | | ? null : priceByModel.get(input.getProductModelId()); |
| | | if (price == null || nvl(price.getPrice()).compareTo(BigDecimal.ZERO) <= 0) { |
| | | if (qty.compareTo(BigDecimal.ZERO) != 0) { |
| | | missingKinds++; |
| | | } |
| | | continue; |
| | | } |
| | | pricedQty = pricedQty.add(qty); |
| | | materialCost = materialCost.add(qty.multiply(nvl(price.getPrice()))); |
| | | } |
| | | materialCost = scale(materialCost, 2); |
| | | |
| | | //äººå·¥ææ¬ |
| | | CostLaborVo labor = laborByOrder.get(order.getProductionOrderId()); |
| | | BigDecimal laborCost = labor == null ? BigDecimal.ZERO : scale(nvl(labor.getLaborCost()), 2); |
| | | |
| | | //è½èææ¬ï¼åºé´çµè´¹æäº§éå æ¯åæ |
| | | BigDecimal energyCost = energyTotal.compareTo(BigDecimal.ZERO) > 0 && totalOutput.compareTo(BigDecimal.ZERO) > 0 |
| | | ? scale(energyTotal.multiply(output).divide(totalOutput, 6, RoundingMode.HALF_UP), 2) |
| | | : BigDecimal.ZERO; |
| | | |
| | | BigDecimal totalCost = materialCost.add(laborCost).add(energyCost); |
| | | BigDecimal unitCost = output.compareTo(BigDecimal.ZERO) > 0 |
| | | ? totalCost.divide(output, 4, RoundingMode.HALF_UP) : null; |
| | | BigDecimal salePrice = salePriceByOrder.get(order.getProductionOrderId()); |
| | | |
| | | CostStatVo vo = new CostStatVo(); |
| | | vo.setProductionOrderId(order.getProductionOrderId()); |
| | | vo.setNpsNo(order.getNpsNo()); |
| | | vo.setFinishedProduct(order.getFinishedProduct()); |
| | | vo.setUnit(order.getUnit()); |
| | | vo.setOrderDate(order.getCreateTime() == null ? null : order.getCreateTime().toLocalDate()); |
| | | vo.setOutputQty(output); |
| | | vo.setMaterialCost(materialCost); |
| | | vo.setLaborCost(laborCost); |
| | | vo.setEnergyCost(energyCost); |
| | | vo.setTotalCost(scale(totalCost, 2)); |
| | | vo.setUnitCost(unitCost); |
| | | vo.setSalePrice(salePrice); |
| | | if (salePrice != null && unitCost != null) { |
| | | BigDecimal profit = salePrice.subtract(unitCost).multiply(output); |
| | | vo.setGrossProfit(scale(profit, 2)); |
| | | BigDecimal revenue = salePrice.multiply(output); |
| | | if (revenue.compareTo(BigDecimal.ZERO) != 0) { |
| | | vo.setGrossProfitRate(profit.multiply(HUNDRED).divide(revenue, 2, RoundingMode.HALF_UP)); |
| | | } |
| | | } |
| | | if (inputQty.compareTo(BigDecimal.ZERO) > 0) { |
| | | vo.setPriceCoverageRate(pricedQty.multiply(HUNDRED).divide(inputQty, 2, RoundingMode.HALF_UP)); |
| | | } |
| | | vo.setMissingPriceKinds(missingKinds); |
| | | vo.setNoRateRows(labor == null ? 0 : labor.getNoRateRows()); |
| | | result.add(vo); |
| | | } |
| | | return result; |
| | | } |
| | | |
| | | @Override |
| | | public List<CostSummaryVo> summary(LocalDate startDate, LocalDate endDate, |
| | | String npsNo, String productName, String groupBy) { |
| | | List<CostStatVo> stats = stat(startDate, endDate, npsNo, productName); |
| | | boolean byProduct = "product".equals(groupBy); |
| | | Map<String, CostSummaryVo> grouped = new LinkedHashMap<>(); |
| | | for (CostStatVo stat : stats) { |
| | | String key = byProduct ? nvlText(stat.getFinishedProduct()) |
| | | : (stat.getOrderDate() == null ? "æªå¡«æ¥æ" : stat.getOrderDate().format(MONTH_FORMAT)); |
| | | CostSummaryVo vo = grouped.computeIfAbsent(key, k -> { |
| | | CostSummaryVo created = new CostSummaryVo(); |
| | | created.setGroupKey(k); |
| | | created.setOrderCount(0); |
| | | created.setOutputQty(BigDecimal.ZERO); |
| | | created.setMaterialCost(BigDecimal.ZERO); |
| | | created.setLaborCost(BigDecimal.ZERO); |
| | | created.setEnergyCost(BigDecimal.ZERO); |
| | | created.setTotalCost(BigDecimal.ZERO); |
| | | created.setGrossProfit(BigDecimal.ZERO); |
| | | return created; |
| | | }); |
| | | vo.setOrderCount(vo.getOrderCount() + 1); |
| | | vo.setOutputQty(vo.getOutputQty().add(nvl(stat.getOutputQty()))); |
| | | vo.setMaterialCost(vo.getMaterialCost().add(nvl(stat.getMaterialCost()))); |
| | | vo.setLaborCost(vo.getLaborCost().add(nvl(stat.getLaborCost()))); |
| | | vo.setEnergyCost(vo.getEnergyCost().add(nvl(stat.getEnergyCost()))); |
| | | vo.setTotalCost(vo.getTotalCost().add(nvl(stat.getTotalCost()))); |
| | | vo.setGrossProfit(vo.getGrossProfit().add(nvl(stat.getGrossProfit()))); |
| | | } |
| | | List<CostSummaryVo> result = new ArrayList<>(grouped.values()); |
| | | for (CostSummaryVo vo : result) { |
| | | BigDecimal total = vo.getTotalCost(); |
| | | vo.setMaterialCost(scale(vo.getMaterialCost(), 2)); |
| | | vo.setLaborCost(scale(vo.getLaborCost(), 2)); |
| | | vo.setEnergyCost(scale(vo.getEnergyCost(), 2)); |
| | | vo.setTotalCost(scale(total, 2)); |
| | | vo.setGrossProfit(scale(vo.getGrossProfit(), 2)); |
| | | if (vo.getOutputQty().compareTo(BigDecimal.ZERO) > 0) { |
| | | vo.setUnitCost(total.divide(vo.getOutputQty(), 4, RoundingMode.HALF_UP)); |
| | | } |
| | | if (total.compareTo(BigDecimal.ZERO) > 0) { |
| | | vo.setMaterialRate(rate(vo.getMaterialCost(), total)); |
| | | vo.setLaborRate(rate(vo.getLaborCost(), total)); |
| | | vo.setEnergyRate(rate(vo.getEnergyCost(), total)); |
| | | } |
| | | } |
| | | return result; |
| | | } |
| | | |
| | | @Override |
| | | public List<CostMissingPriceVo> missingPrice(LocalDate startDate, LocalDate endDate, |
| | | String npsNo, String productName) { |
| | | Map<Long, CostMaterialPriceVo> priceByModel = priceByModel(); |
| | | return costAccountingMapper.listConsumedMaterials(startDate, endDate, npsNo, productName).stream() |
| | | .filter(m -> m.getProductModelId() != null && !priceByModel.containsKey(m.getProductModelId())) |
| | | .collect(Collectors.toList()); |
| | | } |
| | | |
| | | /** åä»·æ¥æºæä¼å
级åç¬¬ä¸æ¡ï¼SQL å·²æ productModelIdãpriority æåºï¼ */ |
| | | private Map<Long, CostMaterialPriceVo> priceByModel() { |
| | | Map<Long, CostMaterialPriceVo> map = new HashMap<>(); |
| | | for (CostMaterialPriceVo price : costAccountingMapper.listMaterialPrices()) { |
| | | if (price.getProductModelId() != null) { |
| | | map.putIfAbsent(price.getProductModelId(), price); |
| | | } |
| | | } |
| | | return map; |
| | | } |
| | | |
| | | /** 产éå£å¾ï¼å®å·¥æ°éä¼å
ï¼æªå®å·¥åéè®¡åæ°é */ |
| | | private BigDecimal outputQty(CostOrderVo order) { |
| | | return nvl(order.getCompleteQty()).compareTo(BigDecimal.ZERO) > 0 |
| | | ? order.getCompleteQty() : nvl(order.getPlanQty()); |
| | | } |
| | | |
| | | private BigDecimal rate(BigDecimal part, BigDecimal total) { |
| | | return part.multiply(HUNDRED).divide(total, 2, RoundingMode.HALF_UP); |
| | | } |
| | | |
| | | private CostEnergyVo nvlEnergy(CostEnergyVo energy) { |
| | | if (energy == null) { |
| | | energy = new CostEnergyVo(); |
| | | } |
| | | if (energy.getKwh() == null) { |
| | | energy.setKwh(BigDecimal.ZERO); |
| | | } |
| | | if (energy.getEnergyCost() == null) { |
| | | energy.setEnergyCost(BigDecimal.ZERO); |
| | | } |
| | | return energy; |
| | | } |
| | | |
| | | private BigDecimal nvl(BigDecimal value) { |
| | | return value == null ? BigDecimal.ZERO : value; |
| | | } |
| | | |
| | | private String nvlText(String value) { |
| | | return value == null ? "" : value; |
| | | } |
| | | |
| | | private BigDecimal scale(BigDecimal value, int scale) { |
| | | return nvl(value).setScale(scale, RoundingMode.HALF_UP); |
| | | } |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.procurementrecord.controller; |
| | | |
| | | import com.baomidou.mybatisplus.core.metadata.IPage; |
| | | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
| | | import com.ruoyi.common.utils.poi.ExcelUtil; |
| | | import com.ruoyi.framework.aspectj.lang.annotation.Log; |
| | | import com.ruoyi.framework.aspectj.lang.enums.BusinessType; |
| | | import com.ruoyi.framework.web.controller.BaseController; |
| | | import com.ruoyi.framework.web.domain.AjaxResult; |
| | | import com.ruoyi.procurementrecord.pojo.ProcurementDemand; |
| | | import com.ruoyi.procurementrecord.service.ProcurementDemandService; |
| | | import io.swagger.v3.oas.annotations.Operation; |
| | | import io.swagger.v3.oas.annotations.tags.Tag; |
| | | import jakarta.servlet.http.HttpServletResponse; |
| | | import lombok.AllArgsConstructor; |
| | | import org.springframework.web.bind.annotation.*; |
| | | |
| | | import java.util.List; |
| | | |
| | | @RestController |
| | | @Tag(name = "éè´éæ±") |
| | | @RequestMapping("/procurementDemand") |
| | | @AllArgsConstructor |
| | | public class ProcurementDemandController extends BaseController { |
| | | |
| | | private final ProcurementDemandService procurementDemandService; |
| | | |
| | | @GetMapping("/listPage") |
| | | @Operation(summary = "éè´éæ±-å页æ¥è¯¢") |
| | | public AjaxResult listPage(Page<ProcurementDemand> page, ProcurementDemand req) { |
| | | return AjaxResult.success(procurementDemandService.pageList(page, req)); |
| | | } |
| | | |
| | | @PutMapping("/changeStatus") |
| | | @Log(title = "éè´éæ±ç¶æåæ´", businessType = BusinessType.UPDATE) |
| | | @Operation(summary = "éè´éæ±-ç¶æåæ´(0å¾
å¤ç/1已转éè´/2已忶)") |
| | | public AjaxResult changeStatus(@RequestParam List<Long> ids, @RequestParam Integer status) { |
| | | return toAjax(procurementDemandService.changeStatus(ids, status)); |
| | | } |
| | | |
| | | @DeleteMapping("/del") |
| | | @Log(title = "å é¤éè´éæ±", businessType = BusinessType.DELETE) |
| | | @Operation(summary = "éè´éæ±-å é¤(ä»
å¾
å¤ç)") |
| | | public AjaxResult del(@RequestBody List<Long> ids) { |
| | | return toAjax(procurementDemandService.removePending(ids)); |
| | | } |
| | | |
| | | @PostMapping("/export") |
| | | @Log(title = "导åºéè´éæ±", businessType = BusinessType.EXPORT) |
| | | @Operation(summary = "éè´éæ±-导åº") |
| | | public void export(HttpServletResponse response, ProcurementDemand req) { |
| | | List<ProcurementDemand> list = procurementDemandService.listByCondition(req); |
| | | ExcelUtil<ProcurementDemand> util = new ExcelUtil<>(ProcurementDemand.class); |
| | | util.exportExcel(response, list, "éè´éæ±"); |
| | | } |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.procurementrecord.mapper; |
| | | |
| | | import com.baomidou.mybatisplus.core.mapper.BaseMapper; |
| | | import com.ruoyi.procurementrecord.pojo.ProcurementDemand; |
| | | |
| | | public interface ProcurementDemandMapper extends BaseMapper<ProcurementDemand> { |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.procurementrecord.pojo; |
| | | |
| | | import com.baomidou.mybatisplus.annotation.FieldFill; |
| | | import com.baomidou.mybatisplus.annotation.IdType; |
| | | import com.baomidou.mybatisplus.annotation.TableField; |
| | | import com.baomidou.mybatisplus.annotation.TableId; |
| | | import com.baomidou.mybatisplus.annotation.TableName; |
| | | import com.fasterxml.jackson.annotation.JsonFormat; |
| | | import com.ruoyi.framework.aspectj.lang.annotation.Excel; |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | |
| | | import java.io.Serializable; |
| | | import java.math.BigDecimal; |
| | | import java.time.LocalDateTime; |
| | | |
| | | @Data |
| | | @TableName("procurement_demand") |
| | | @Schema(name = "ProcurementDemand对象", description = "éè´éæ±-BOMé½å¥ç¼ºå£") |
| | | public class ProcurementDemand implements Serializable { |
| | | |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | @Schema(description = "主é®") |
| | | @TableId(type = IdType.AUTO) |
| | | private Long id; |
| | | |
| | | @Schema(description = "产åè§æ ¼id") |
| | | private Long productModelId; |
| | | |
| | | @Excel(name = "产ååç§°") |
| | | @Schema(description = "产ååç§°") |
| | | private String productName; |
| | | |
| | | @Excel(name = "è§æ ¼åå·") |
| | | @Schema(description = "è§æ ¼åå·") |
| | | private String productModel; |
| | | |
| | | @Excel(name = "åä½") |
| | | @Schema(description = "åä½") |
| | | private String unit; |
| | | |
| | | @Excel(name = "缺å£éæ±é") |
| | | @Schema(description = "缺å£éæ±é") |
| | | private BigDecimal demandQuantity; |
| | | |
| | | @Excel(name = "å¯ç¨åºåå¿«ç
§") |
| | | @Schema(description = "çææ¶å¯ç¨åºåå¿«ç
§") |
| | | private BigDecimal stockQuantity; |
| | | |
| | | @Schema(description = "æ¥æºBOM id") |
| | | private Long sourceBomId; |
| | | |
| | | @Excel(name = "æ¥æºBOMç¼å·") |
| | | @Schema(description = "æ¥æºBOMç¼å·") |
| | | private String sourceBomNo; |
| | | |
| | | @Excel(name = "ç¶æ", readConverterExp = "0=å¾
å¤ç,1=已转éè´,2=已忶") |
| | | @Schema(description = "0å¾
å¤ç 1已转éè´ 2已忶") |
| | | private Integer status; |
| | | |
| | | @Excel(name = "夿³¨") |
| | | @Schema(description = "夿³¨") |
| | | private String remark; |
| | | |
| | | @Schema(description = "å建æ¶é´") |
| | | @TableField(fill = FieldFill.INSERT) |
| | | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") |
| | | private LocalDateTime createTime; |
| | | |
| | | @Schema(description = "æ´æ°æ¶é´") |
| | | @TableField(fill = FieldFill.INSERT_UPDATE) |
| | | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") |
| | | @Excel(name = "æ´æ°æ¶é´", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss") |
| | | private LocalDateTime updateTime; |
| | | |
| | | @Schema(description = "å建人") |
| | | @TableField(fill = FieldFill.INSERT) |
| | | private Long createUser; |
| | | |
| | | @Schema(description = "æ´æ°äºº") |
| | | @TableField(fill = FieldFill.INSERT_UPDATE) |
| | | private Long updateUser; |
| | | |
| | | @Schema(description = "é¨é¨ID") |
| | | @TableField(fill = FieldFill.INSERT) |
| | | private Long deptId; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.procurementrecord.service; |
| | | |
| | | import com.baomidou.mybatisplus.core.metadata.IPage; |
| | | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
| | | import com.baomidou.mybatisplus.extension.service.IService; |
| | | import com.ruoyi.procurementrecord.pojo.ProcurementDemand; |
| | | |
| | | import java.util.List; |
| | | |
| | | public interface ProcurementDemandService extends IService<ProcurementDemand> { |
| | | |
| | | IPage<ProcurementDemand> pageList(Page<ProcurementDemand> page, ProcurementDemand req); |
| | | |
| | | List<ProcurementDemand> listByCondition(ProcurementDemand req); |
| | | |
| | | boolean changeStatus(List<Long> ids, Integer status); |
| | | |
| | | boolean removePending(List<Long> ids); |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.procurementrecord.service.impl; |
| | | |
| | | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
| | | import com.baomidou.mybatisplus.core.metadata.IPage; |
| | | import com.baomidou.mybatisplus.core.toolkit.Wrappers; |
| | | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
| | | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; |
| | | import com.ruoyi.common.exception.ServiceException; |
| | | import com.ruoyi.common.utils.StringUtils; |
| | | import com.ruoyi.procurementrecord.mapper.ProcurementDemandMapper; |
| | | import com.ruoyi.procurementrecord.pojo.ProcurementDemand; |
| | | import com.ruoyi.procurementrecord.service.ProcurementDemandService; |
| | | import org.springframework.stereotype.Service; |
| | | |
| | | import java.util.List; |
| | | |
| | | @Service |
| | | public class ProcurementDemandServiceImpl extends ServiceImpl<ProcurementDemandMapper, ProcurementDemand> implements ProcurementDemandService { |
| | | |
| | | @Override |
| | | public IPage<ProcurementDemand> pageList(Page<ProcurementDemand> page, ProcurementDemand req) { |
| | | return this.page(page, buildWrapper(req)); |
| | | } |
| | | |
| | | @Override |
| | | public List<ProcurementDemand> listByCondition(ProcurementDemand req) { |
| | | return this.list(buildWrapper(req)); |
| | | } |
| | | |
| | | private LambdaQueryWrapper<ProcurementDemand> buildWrapper(ProcurementDemand req) { |
| | | ProcurementDemand condition = req == null ? new ProcurementDemand() : req; |
| | | return Wrappers.<ProcurementDemand>lambdaQuery() |
| | | .like(StringUtils.isNotEmpty(condition.getProductName()), ProcurementDemand::getProductName, condition.getProductName()) |
| | | .like(StringUtils.isNotEmpty(condition.getProductModel()), ProcurementDemand::getProductModel, condition.getProductModel()) |
| | | .eq(condition.getStatus() != null, ProcurementDemand::getStatus, condition.getStatus()) |
| | | .orderByDesc(ProcurementDemand::getId); |
| | | } |
| | | |
| | | @Override |
| | | public boolean changeStatus(List<Long> ids, Integer status) { |
| | | if (ids == null || ids.isEmpty() || status == null || status < 0 || status > 2) { |
| | | throw new ServiceException("è¯·éæ©è¦æä½çéæ±å¹¶ä¼ å
¥åæ³ç¶æ(0å¾
å¤ç/1已转éè´/2已忶)"); |
| | | } |
| | | return this.update(Wrappers.<ProcurementDemand>lambdaUpdate() |
| | | .set(ProcurementDemand::getStatus, status) |
| | | .in(ProcurementDemand::getId, ids)); |
| | | } |
| | | |
| | | @Override |
| | | public boolean removePending(List<Long> ids) { |
| | | if (ids == null || ids.isEmpty()) { |
| | | throw new ServiceException("请è³å°éæ©ä¸æ¡éè´éæ±"); |
| | | } |
| | | long handledCount = this.count(Wrappers.<ProcurementDemand>lambdaQuery() |
| | | .in(ProcurementDemand::getId, ids) |
| | | .ne(ProcurementDemand::getStatus, 0)); |
| | | if (handledCount > 0) { |
| | | throw new ServiceException("åå¨éå¾
å¤çç¶æçéæ±ï¼åªè½å é¤å¾
å¤çæ°æ®"); |
| | | } |
| | | return this.removeByIds(ids); |
| | | } |
| | | } |
| | |
| | | @Schema(description = "å·¥èµ") |
| | | private BigDecimal wages; |
| | | |
| | | @Schema(description = "å·¥èµè®¡ç®æ¹å¼ 计件/计æ¶") |
| | | private String wageMode; |
| | | |
| | | @Schema(description = "å·¥åºåæ°å表") |
| | | private List<ProductionOrderRoutingOperationParam> productionOperationParamList; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.production.bean.vo; |
| | | |
| | | import com.ruoyi.framework.aspectj.lang.annotation.Excel; |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | |
| | | import java.math.BigDecimal; |
| | | |
| | | @Data |
| | | @Schema(name = "DeviceOutputStatVo", description = "产éç»è®¡(设å¤/å·¥åº/产å维度)") |
| | | public class DeviceOutputStatVo { |
| | | |
| | | @Schema(description = "åç»id(设å¤ç»´åº¦ä¸ºdevice_id)") |
| | | private Long groupId; |
| | | |
| | | @Excel(name = "ç»è®¡å¯¹è±¡") |
| | | @Schema(description = "åç»åç§°ï¼è®¾å¤å/å·¥åºå/产å-è§æ ¼") |
| | | private String groupName; |
| | | |
| | | @Excel(name = "æ¥å·¥åæ°") |
| | | @Schema(description = "æ¥å·¥åæ°") |
| | | private Long workCount; |
| | | |
| | | @Excel(name = "ç产æ°é") |
| | | @Schema(description = "ç产æ°é") |
| | | private BigDecimal quantity; |
| | | |
| | | @Excel(name = "æ¥åºæ°é") |
| | | @Schema(description = "æ¥åºæ°é") |
| | | private BigDecimal scrapQty; |
| | | |
| | | @Excel(name = "æ»å·¥æ¶") |
| | | @Schema(description = "æ»å·¥æ¶") |
| | | private BigDecimal workHour; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.production.bean.vo; |
| | | |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | |
| | | import java.math.BigDecimal; |
| | | |
| | | @Data |
| | | @Schema(name = "MaterialConsumptionActualVo", description = "订åç©æå®é
æå
¥è¡") |
| | | public class MaterialConsumptionActualVo { |
| | | |
| | | @Schema(description = "ç产订åid") |
| | | private Long productionOrderId; |
| | | |
| | | @Schema(description = "ç©æè§æ ¼id") |
| | | private Long productModelId; |
| | | |
| | | @Schema(description = "å®é
æå
¥å计") |
| | | private BigDecimal actualQty; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.production.bean.vo; |
| | | |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | |
| | | import java.math.BigDecimal; |
| | | |
| | | @Data |
| | | @Schema(name = "MaterialConsumptionOrderVo", description = "æææ¶èæ ¸ç®-订ååºç¡è¡") |
| | | public class MaterialConsumptionOrderVo { |
| | | |
| | | @Schema(description = "ç产订åid") |
| | | private Long productionOrderId; |
| | | |
| | | @Schema(description = "ç产订åå·") |
| | | private String npsNo; |
| | | |
| | | @Schema(description = "æåè§æ ¼id") |
| | | private Long productModelId; |
| | | |
| | | @Schema(description = "æå åç§°/è§æ ¼") |
| | | private String finishedProduct; |
| | | |
| | | @Schema(description = "å®å·¥æ°é") |
| | | private BigDecimal completeQty; |
| | | |
| | | @Schema(description = "è®¡åæ°é") |
| | | private BigDecimal planQty; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.production.bean.vo; |
| | | |
| | | import com.ruoyi.framework.aspectj.lang.annotation.Excel; |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | |
| | | import java.math.BigDecimal; |
| | | |
| | | @Data |
| | | @Schema(name = "MaterialConsumptionStatVo", description = "æææ¶èæ ¸ç®(æ åvså®é
)") |
| | | public class MaterialConsumptionStatVo { |
| | | |
| | | @Schema(description = "ç产订åid") |
| | | private Long productionOrderId; |
| | | |
| | | @Excel(name = "ç产订åå·") |
| | | @Schema(description = "ç产订åå·") |
| | | private String npsNo; |
| | | |
| | | @Excel(name = "æå") |
| | | @Schema(description = "æå åç§°/è§æ ¼") |
| | | private String finishedProduct; |
| | | |
| | | @Schema(description = "ç©æè§æ ¼id") |
| | | private Long materialModelId; |
| | | |
| | | @Excel(name = "ç©æåç§°") |
| | | @Schema(description = "ç©æåç§°") |
| | | private String materialName; |
| | | |
| | | @Excel(name = "ç©æè§æ ¼") |
| | | @Schema(description = "ç©æè§æ ¼") |
| | | private String materialModel; |
| | | |
| | | @Excel(name = "åä½") |
| | | @Schema(description = "åä½") |
| | | private String unit; |
| | | |
| | | @Excel(name = "BOMåè") |
| | | @Schema(description = "BOMåä½ç¨é") |
| | | private BigDecimal unitQuantity; |
| | | |
| | | @Excel(name = "å®å·¥æ°é") |
| | | @Schema(description = "订åå®å·¥æ°é") |
| | | private BigDecimal completeQty; |
| | | |
| | | @Excel(name = "æ åæ¶è") |
| | | @Schema(description = "æ åæ¶è=BOMåèÃå®å·¥æ°é") |
| | | private BigDecimal standardQty; |
| | | |
| | | @Excel(name = "å®é
æ¶è") |
| | | @Schema(description = "å®é
æ¶è=æ¥å·¥æå
¥å计") |
| | | private BigDecimal actualQty; |
| | | |
| | | @Excel(name = "差弿°é") |
| | | @Schema(description = "å·®å¼=å®é
-æ å") |
| | | private BigDecimal diffQty; |
| | | |
| | | @Excel(name = "å·®å¼ç%") |
| | | @Schema(description = "å·®å¼ç=å·®å¼/æ åÃ100") |
| | | private BigDecimal diffRate; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.production.bean.vo; |
| | | |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | |
| | | import java.math.BigDecimal; |
| | | |
| | | @Data |
| | | @Schema(name = "MaterialConsumptionStructureVo", description = "订åBOMç»æè¡") |
| | | public class MaterialConsumptionStructureVo { |
| | | |
| | | @Schema(description = "ç产订åid") |
| | | private Long productionOrderId; |
| | | |
| | | @Schema(description = "ç»æè¡id") |
| | | private Long id; |
| | | |
| | | @Schema(description = "ç¶ç»æè¡id(æ ¹ä¸ºç©º/0)") |
| | | private Long parentId; |
| | | |
| | | @Schema(description = "ç©æè§æ ¼id") |
| | | private Long productModelId; |
| | | |
| | | @Schema(description = "åä½ç¨é") |
| | | private BigDecimal unitQuantity; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.production.bean.vo; |
| | | |
| | | import com.ruoyi.framework.aspectj.lang.annotation.Excel; |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | |
| | | import java.math.BigDecimal; |
| | | |
| | | @Data |
| | | @Schema(name = "PieceWageSummaryVo", description = "è®¡ä»¶å·¥èµæ±æ»(æäººå)") |
| | | public class PieceWageSummaryVo { |
| | | |
| | | @Schema(description = "人åid") |
| | | private Long userId; |
| | | |
| | | @Excel(name = "å§å") |
| | | @Schema(description = "å§å") |
| | | private String userName; |
| | | |
| | | @Excel(name = "æ¥å·¥åæ°") |
| | | @Schema(description = "æ¥å·¥åæ°") |
| | | private Long workCount; |
| | | |
| | | @Excel(name = "ç产æ°é") |
| | | @Schema(description = "ç产æ°é") |
| | | private BigDecimal quantity; |
| | | |
| | | @Excel(name = "æ»å·¥æ¶") |
| | | @Schema(description = "æ»å·¥æ¶") |
| | | private BigDecimal workHour; |
| | | |
| | | @Excel(name = "计件工èµ") |
| | | @Schema(description = "计件工èµ(å½ä¸è®¡ä»¶åä»·çé¨å)") |
| | | private BigDecimal pieceWage; |
| | | |
| | | @Excel(name = "åºåå·¥èµå计") |
| | | @Schema(description = "åºåå·¥èµå计(计件ä¼å
ï¼æ åä»·åéåå·¥æ¶å®é¢å£å¾)") |
| | | private BigDecimal wages; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.production.controller; |
| | | |
| | | import com.ruoyi.common.utils.poi.ExcelUtil; |
| | | import com.ruoyi.framework.aspectj.lang.annotation.Log; |
| | | import com.ruoyi.framework.aspectj.lang.enums.BusinessType; |
| | | import com.ruoyi.framework.web.domain.R; |
| | | import com.ruoyi.production.bean.vo.MaterialConsumptionStatVo; |
| | | import com.ruoyi.production.service.MaterialConsumptionService; |
| | | import io.swagger.v3.oas.annotations.Operation; |
| | | import io.swagger.v3.oas.annotations.tags.Tag; |
| | | import jakarta.servlet.http.HttpServletResponse; |
| | | import lombok.RequiredArgsConstructor; |
| | | import org.springframework.format.annotation.DateTimeFormat; |
| | | 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.time.LocalDate; |
| | | import java.util.List; |
| | | |
| | | @RestController |
| | | @RequestMapping("/materialConsumption") |
| | | @RequiredArgsConstructor |
| | | @Tag(name = "æææ¶èæ ¸ç®") |
| | | public class MaterialConsumptionController { |
| | | |
| | | private final MaterialConsumptionService materialConsumptionService; |
| | | |
| | | @GetMapping("/stat") |
| | | @Operation(summary = "æææ¶èæ ¸ç®ï¼BOMæ åvså®é
æå
¥ï¼") |
| | | public R<List<MaterialConsumptionStatVo>> stat( |
| | | @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate startDate, |
| | | @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate endDate, |
| | | @RequestParam(required = false) String npsNo, |
| | | @RequestParam(required = false) String productName, |
| | | @RequestParam(required = false) Boolean onlyDiff) { |
| | | return R.ok(materialConsumptionService.stat(startDate, endDate, npsNo, productName, onlyDiff)); |
| | | } |
| | | |
| | | @GetMapping("/stat/export") |
| | | @Log(title = "Export material consumption", businessType = BusinessType.EXPORT) |
| | | @Operation(summary = "æææ¶èæ ¸ç®å¯¼åº") |
| | | public void export(HttpServletResponse response, |
| | | @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate startDate, |
| | | @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate endDate, |
| | | @RequestParam(required = false) String npsNo, |
| | | @RequestParam(required = false) String productName, |
| | | @RequestParam(required = false) Boolean onlyDiff) { |
| | | List<MaterialConsumptionStatVo> list = |
| | | materialConsumptionService.stat(startDate, endDate, npsNo, productName, onlyDiff); |
| | | ExcelUtil<MaterialConsumptionStatVo> util = new ExcelUtil<>(MaterialConsumptionStatVo.class); |
| | | util.exportExcel(response, list, "æææ¶èæ ¸ç®"); |
| | | } |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.production.controller; |
| | | |
| | | import com.baomidou.mybatisplus.core.metadata.IPage; |
| | | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
| | | import com.ruoyi.common.utils.poi.ExcelUtil; |
| | | import com.ruoyi.framework.aspectj.lang.annotation.Log; |
| | | import com.ruoyi.framework.aspectj.lang.enums.BusinessType; |
| | | import com.ruoyi.framework.web.domain.R; |
| | | import com.ruoyi.production.pojo.PieceRateConfig; |
| | | import com.ruoyi.production.service.PieceRateConfigService; |
| | | import io.swagger.v3.oas.annotations.Operation; |
| | | import io.swagger.v3.oas.annotations.tags.Tag; |
| | | import jakarta.servlet.http.HttpServletResponse; |
| | | import lombok.RequiredArgsConstructor; |
| | | import org.springframework.web.bind.annotation.*; |
| | | |
| | | import java.util.List; |
| | | |
| | | @RestController |
| | | @RequestMapping("/pieceRateConfig") |
| | | @RequiredArgsConstructor |
| | | @Tag(name = "计件åä»·é
ç½®") |
| | | public class PieceRateConfigController { |
| | | |
| | | private final PieceRateConfigService pieceRateConfigService; |
| | | |
| | | @GetMapping("/listPage") |
| | | @Operation(summary = "计件åä»·å页æ¥è¯¢") |
| | | public R<IPage<PieceRateConfig>> listPage(Page<PieceRateConfig> page, PieceRateConfig query) { |
| | | return R.ok(pieceRateConfigService.listPage(page, query)); |
| | | } |
| | | |
| | | @PostMapping("/add") |
| | | @Log(title = "Add piece rate config", businessType = BusinessType.INSERT) |
| | | @Operation(summary = "æ°å¢è®¡ä»¶åä»·") |
| | | public R add(@RequestBody PieceRateConfig config) { |
| | | return pieceRateConfigService.add(config); |
| | | } |
| | | |
| | | @PutMapping("/update") |
| | | @Log(title = "Update piece rate config", businessType = BusinessType.UPDATE) |
| | | @Operation(summary = "ä¿®æ¹è®¡ä»¶åä»·") |
| | | public R update(@RequestBody PieceRateConfig config) { |
| | | return pieceRateConfigService.update(config); |
| | | } |
| | | |
| | | @PutMapping("/changeStatus") |
| | | @Log(title = "Change piece rate status", businessType = BusinessType.UPDATE) |
| | | @Operation(summary = "å¯ç¨/åç¨è®¡ä»¶åä»·") |
| | | public R changeStatus(@RequestBody PieceRateConfig config) { |
| | | return pieceRateConfigService.changeStatus(config.getId(), config.getStatus()); |
| | | } |
| | | |
| | | @DeleteMapping("/batchDelete") |
| | | @Log(title = "Delete piece rate config", businessType = BusinessType.DELETE) |
| | | @Operation(summary = "æ¹éå é¤è®¡ä»¶åä»·") |
| | | public R batchDelete(@RequestBody List<Long> ids) { |
| | | return R.ok(pieceRateConfigService.removeByIds(ids)); |
| | | } |
| | | |
| | | @GetMapping("/export") |
| | | @Log(title = "Export piece rate config", businessType = BusinessType.EXPORT) |
| | | @Operation(summary = "导åºè®¡ä»¶åä»·é
ç½®") |
| | | public void export(HttpServletResponse response, PieceRateConfig query) { |
| | | List<PieceRateConfig> list = pieceRateConfigService.listPage(new Page<>(1, -1), query).getRecords(); |
| | | ExcelUtil<PieceRateConfig> util = new ExcelUtil<>(PieceRateConfig.class); |
| | | util.exportExcel(response, list, "计件åä»·é
ç½®"); |
| | | } |
| | | } |
| | |
| | | import com.ruoyi.common.utils.poi.ExcelUtil; |
| | | import com.ruoyi.framework.web.domain.R; |
| | | import com.ruoyi.production.bean.dto.ProductionProductMainDto; |
| | | import com.ruoyi.production.bean.vo.DeviceOutputStatVo; |
| | | import com.ruoyi.production.bean.vo.PieceWageSummaryVo; |
| | | import com.ruoyi.production.service.ProductionProductMainService; |
| | | import io.swagger.v3.oas.annotations.Operation; |
| | | import io.swagger.v3.oas.annotations.tags.Tag; |
| | | import jakarta.servlet.http.HttpServletResponse; |
| | | import lombok.AllArgsConstructor; |
| | | import org.springframework.format.annotation.DateTimeFormat; |
| | | import org.springframework.security.access.prepost.PreAuthorize; |
| | | import org.springframework.web.bind.annotation.*; |
| | | |
| | | import java.time.LocalDate; |
| | | import java.util.List; |
| | | |
| | | @RequestMapping("/productionProductMain") |
| | |
| | | ExcelUtil<ProductionProductMainDto> util = new ExcelUtil<ProductionProductMainDto>(ProductionProductMainDto.class); |
| | | util.exportExcel(response, list, "ç产æ¥å·¥æ°æ®"); |
| | | } |
| | | |
| | | @GetMapping("/wageSummary") |
| | | @Operation(summary = "è®¡ä»¶å·¥èµæ±æ»ï¼æäººåï¼è®¡ä»¶åä»·ä¼å
ï¼") |
| | | public R<List<PieceWageSummaryVo>> wageSummary( |
| | | @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate startDate, |
| | | @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate endDate, |
| | | @RequestParam(required = false) String userName) { |
| | | return R.ok(productionProductMainService.wageSummary(startDate, endDate, userName)); |
| | | } |
| | | |
| | | @GetMapping("/wageSummary/export") |
| | | @Operation(summary = "è®¡ä»¶å·¥èµæ±æ»å¯¼åº") |
| | | public void wageSummaryExport(HttpServletResponse response, |
| | | @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate startDate, |
| | | @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate endDate, |
| | | @RequestParam(required = false) String userName) { |
| | | List<PieceWageSummaryVo> list = productionProductMainService.wageSummary(startDate, endDate, userName); |
| | | ExcelUtil<PieceWageSummaryVo> util = new ExcelUtil<>(PieceWageSummaryVo.class); |
| | | util.exportExcel(response, list, "è®¡ä»¶å·¥èµæ±æ»"); |
| | | } |
| | | |
| | | @GetMapping("/outputStat") |
| | | @Operation(summary = "产éç»è®¡ï¼dimension: device设å¤/operationå·¥åº/product产åï¼") |
| | | public R<List<DeviceOutputStatVo>> outputStat( |
| | | @RequestParam(required = false, defaultValue = "device") String dimension, |
| | | @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate startDate, |
| | | @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate endDate, |
| | | @RequestParam(required = false) Long deviceId) { |
| | | return R.ok(productionProductMainService.outputStat(dimension, startDate, endDate, deviceId)); |
| | | } |
| | | |
| | | @GetMapping("/outputStat/export") |
| | | @Operation(summary = "产éç»è®¡å¯¼åº") |
| | | public void outputStatExport(HttpServletResponse response, |
| | | @RequestParam(required = false, defaultValue = "device") String dimension, |
| | | @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate startDate, |
| | | @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate endDate, |
| | | @RequestParam(required = false) Long deviceId) { |
| | | List<DeviceOutputStatVo> list = productionProductMainService.outputStat(dimension, startDate, endDate, deviceId); |
| | | ExcelUtil<DeviceOutputStatVo> util = new ExcelUtil<>(DeviceOutputStatVo.class); |
| | | util.exportExcel(response, list, "产éç»è®¡"); |
| | | } |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.production.mapper; |
| | | |
| | | import com.ruoyi.production.bean.vo.MaterialConsumptionOrderVo; |
| | | import com.ruoyi.production.bean.vo.MaterialConsumptionActualVo; |
| | | import com.ruoyi.production.bean.vo.MaterialConsumptionStructureVo; |
| | | import org.apache.ibatis.annotations.Mapper; |
| | | import org.apache.ibatis.annotations.Param; |
| | | |
| | | import java.time.LocalDate; |
| | | import java.util.List; |
| | | |
| | | @Mapper |
| | | public interface MaterialConsumptionMapper { |
| | | |
| | | List<MaterialConsumptionOrderVo> listOrders(@Param("startDate") LocalDate startDate, |
| | | @Param("endDate") LocalDate endDate, |
| | | @Param("npsNo") String npsNo, |
| | | @Param("productName") String productName); |
| | | |
| | | List<MaterialConsumptionStructureVo> listStructures(@Param("orderIds") List<Long> orderIds); |
| | | |
| | | List<MaterialConsumptionActualVo> listActualInputs(@Param("orderIds") List<Long> orderIds); |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.production.mapper; |
| | | |
| | | import com.baomidou.mybatisplus.core.mapper.BaseMapper; |
| | | import com.ruoyi.production.pojo.PieceRateConfig; |
| | | import org.apache.ibatis.annotations.Mapper; |
| | | |
| | | @Mapper |
| | | public interface PieceRateConfigMapper extends BaseMapper<PieceRateConfig> { |
| | | } |
| | |
| | | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
| | | import com.ruoyi.production.bean.dto.ProductionAccountDto; |
| | | import com.ruoyi.production.bean.dto.ProductionProductMainDto; |
| | | import com.ruoyi.production.bean.vo.DeviceOutputStatVo; |
| | | import com.ruoyi.production.bean.vo.PieceWageSummaryVo; |
| | | import com.ruoyi.production.pojo.ProductionOrder; |
| | | import com.ruoyi.production.pojo.ProductionProductMain; |
| | | import org.apache.ibatis.annotations.Mapper; |
| | | import org.apache.ibatis.annotations.Param; |
| | | |
| | | import java.time.LocalDate; |
| | | import java.util.ArrayList; |
| | | import java.util.List; |
| | | |
| | |
| | | IPage<ProductionProductMainDto> listProductionDetails(@Param("c") ProductionAccountDto productionAccountDto, Page page); |
| | | |
| | | ArrayList<Long> listMain(List<Long> idList); |
| | | |
| | | List<PieceWageSummaryVo> wageSummary(@Param("startDate") LocalDate startDate, |
| | | @Param("endDate") LocalDate endDate, |
| | | @Param("userName") String userName); |
| | | |
| | | List<DeviceOutputStatVo> outputStat(@Param("dimension") String dimension, |
| | | @Param("startDate") LocalDate startDate, |
| | | @Param("endDate") LocalDate endDate, |
| | | @Param("deviceId") Long deviceId); |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.production.pojo; |
| | | |
| | | import com.baomidou.mybatisplus.annotation.FieldFill; |
| | | import com.baomidou.mybatisplus.annotation.IdType; |
| | | import com.baomidou.mybatisplus.annotation.TableField; |
| | | import com.baomidou.mybatisplus.annotation.TableId; |
| | | import com.baomidou.mybatisplus.annotation.TableName; |
| | | import com.fasterxml.jackson.annotation.JsonFormat; |
| | | import com.ruoyi.framework.aspectj.lang.annotation.Excel; |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | import org.springframework.format.annotation.DateTimeFormat; |
| | | |
| | | import java.io.Serializable; |
| | | import java.math.BigDecimal; |
| | | import java.time.LocalDateTime; |
| | | |
| | | /** |
| | | * 计件åä»·é
ç½®ï¼æäº§åè§æ ¼+å·¥åºï¼ |
| | | */ |
| | | @Data |
| | | @TableName("piece_rate_config") |
| | | @Schema(name = "PieceRateConfig", description = "计件åä»·é
ç½®") |
| | | public class PieceRateConfig implements Serializable { |
| | | |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | @TableId(type = IdType.AUTO) |
| | | private Long id; |
| | | |
| | | @Schema(description = "产åè§æ ¼id") |
| | | private Long productModelId; |
| | | |
| | | @Schema(description = "产åè§æ ¼åå·(åä½)") |
| | | @Excel(name = "è§æ ¼åå·") |
| | | private String productModel; |
| | | |
| | | @Schema(description = "å·¥åºåç§°") |
| | | @Excel(name = "å·¥åº") |
| | | private String operationName; |
| | | |
| | | @Schema(description = "计件åä»·(å
/ä»¶)") |
| | | @Excel(name = "计件åä»·(å
/ä»¶)") |
| | | private BigDecimal unitPrice; |
| | | |
| | | @Schema(description = "ç¶æ 1å¯ç¨ 0åç¨") |
| | | @Excel(name = "ç¶æ", readConverterExp = "1=å¯ç¨,0=åç¨") |
| | | private Integer status; |
| | | |
| | | @Schema(description = "夿³¨") |
| | | @Excel(name = "夿³¨") |
| | | private String remark; |
| | | |
| | | @Schema(description = "å建æ¶é´") |
| | | @TableField(fill = FieldFill.INSERT) |
| | | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") |
| | | @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") |
| | | private LocalDateTime createTime; |
| | | |
| | | @Schema(description = "æ´æ°æ¶é´") |
| | | @TableField(fill = FieldFill.INSERT_UPDATE) |
| | | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") |
| | | @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") |
| | | private LocalDateTime updateTime; |
| | | |
| | | @Schema(description = "å建人") |
| | | @TableField(fill = FieldFill.INSERT) |
| | | private Long createUser; |
| | | |
| | | @Schema(description = "æ´æ°äºº") |
| | | @TableField(fill = FieldFill.INSERT_UPDATE) |
| | | private Long updateUser; |
| | | |
| | | @Schema(description = "é¨é¨ID") |
| | | @TableField(fill = FieldFill.INSERT) |
| | | private Long deptId; |
| | | } |
| | |
| | | @Schema(description = "æ¥å·¥äººå") |
| | | private String userName; |
| | | |
| | | @Schema(description = "使ç¨è®¾å¤id(device_ledger.id)") |
| | | private Long deviceId; |
| | | |
| | | @Schema(description = "设å¤åç§°(åä½)") |
| | | @Excel(name = "使ç¨è®¾å¤") |
| | | private String deviceName; |
| | | |
| | | @Schema(description = "ç产工åºå·¥åid") |
| | | private Long productionOperationTaskId; |
| | | |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.production.service; |
| | | |
| | | import com.ruoyi.production.bean.vo.MaterialConsumptionStatVo; |
| | | |
| | | import java.time.LocalDate; |
| | | import java.util.List; |
| | | |
| | | public interface MaterialConsumptionService { |
| | | |
| | | /** |
| | | * æææ¶èæ ¸ç®ï¼BOMæ åæ¶è(åèÃå®å·¥éï¼æªå®å·¥æè®¡åé) vs æ¥å·¥å®é
æå
¥ |
| | | */ |
| | | List<MaterialConsumptionStatVo> stat(LocalDate startDate, LocalDate endDate, |
| | | String npsNo, String productName, Boolean onlyDiff); |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.production.service; |
| | | |
| | | import com.baomidou.mybatisplus.core.metadata.IPage; |
| | | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
| | | import com.baomidou.mybatisplus.extension.service.IService; |
| | | import com.ruoyi.framework.web.domain.R; |
| | | import com.ruoyi.production.pojo.PieceRateConfig; |
| | | |
| | | import java.math.BigDecimal; |
| | | |
| | | public interface PieceRateConfigService extends IService<PieceRateConfig> { |
| | | |
| | | IPage<PieceRateConfig> listPage(Page<PieceRateConfig> page, PieceRateConfig query); |
| | | |
| | | R add(PieceRateConfig config); |
| | | |
| | | R update(PieceRateConfig config); |
| | | |
| | | R changeStatus(Long id, Integer status); |
| | | |
| | | /** |
| | | * å¹é
å¯ç¨ä¸ç计件åä»·ï¼è§æ ¼+å·¥åºï¼æ é
ç½®è¿å null |
| | | */ |
| | | BigDecimal matchPrice(Long productModelId, String operationName); |
| | | } |
| | |
| | | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
| | | import com.baomidou.mybatisplus.extension.service.IService; |
| | | import com.ruoyi.production.bean.dto.ProductionProductMainDto; |
| | | import com.ruoyi.production.bean.vo.DeviceOutputStatVo; |
| | | import com.ruoyi.production.bean.vo.PieceWageSummaryVo; |
| | | import com.ruoyi.production.pojo.ProductionProductMain; |
| | | |
| | | import java.time.LocalDate; |
| | | import java.util.ArrayList; |
| | | import java.util.List; |
| | | |
| | |
| | | Boolean removeProductMain(Long id); |
| | | |
| | | ArrayList<Long> listMain(List<Long> idList); |
| | | |
| | | List<PieceWageSummaryVo> wageSummary(LocalDate startDate, LocalDate endDate, String userName); |
| | | |
| | | List<DeviceOutputStatVo> outputStat(String dimension, LocalDate startDate, LocalDate endDate, Long deviceId); |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.production.service.impl; |
| | | |
| | | import com.ruoyi.basic.mapper.ProductMapper; |
| | | import com.ruoyi.basic.mapper.ProductModelMapper; |
| | | import com.ruoyi.basic.pojo.Product; |
| | | import com.ruoyi.basic.pojo.ProductModel; |
| | | import com.ruoyi.production.bean.vo.MaterialConsumptionActualVo; |
| | | import com.ruoyi.production.bean.vo.MaterialConsumptionOrderVo; |
| | | import com.ruoyi.production.bean.vo.MaterialConsumptionStatVo; |
| | | import com.ruoyi.production.bean.vo.MaterialConsumptionStructureVo; |
| | | import com.ruoyi.production.mapper.MaterialConsumptionMapper; |
| | | import com.ruoyi.production.service.MaterialConsumptionService; |
| | | import lombok.RequiredArgsConstructor; |
| | | import org.springframework.stereotype.Service; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.math.RoundingMode; |
| | | import java.time.LocalDate; |
| | | import java.util.ArrayList; |
| | | 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 java.util.stream.Collectors; |
| | | |
| | | @Service |
| | | @RequiredArgsConstructor |
| | | public class MaterialConsumptionServiceImpl implements MaterialConsumptionService { |
| | | |
| | | private final MaterialConsumptionMapper materialConsumptionMapper; |
| | | private final ProductModelMapper productModelMapper; |
| | | private final ProductMapper productMapper; |
| | | |
| | | @Override |
| | | public List<MaterialConsumptionStatVo> stat(LocalDate startDate, LocalDate endDate, |
| | | String npsNo, String productName, Boolean onlyDiff) { |
| | | List<MaterialConsumptionOrderVo> orders = |
| | | materialConsumptionMapper.listOrders(startDate, endDate, npsNo, productName); |
| | | if (orders.isEmpty()) { |
| | | return new ArrayList<>(); |
| | | } |
| | | List<Long> orderIds = orders.stream().map(MaterialConsumptionOrderVo::getProductionOrderId) |
| | | .filter(Objects::nonNull).distinct().collect(Collectors.toList()); |
| | | List<MaterialConsumptionStructureVo> structures = materialConsumptionMapper.listStructures(orderIds); |
| | | List<MaterialConsumptionActualVo> actuals = materialConsumptionMapper.listActualInputs(orderIds); |
| | | |
| | | Map<Long, MaterialConsumptionStructureVo> structureById = structures.stream() |
| | | .collect(Collectors.toMap(MaterialConsumptionStructureVo::getId, s -> s, (a, b) -> a)); |
| | | Map<String, BigDecimal> actualMap = new HashMap<>(); |
| | | for (MaterialConsumptionActualVo actual : actuals) { |
| | | actualMap.merge(actual.getProductionOrderId() + "_" + actual.getProductModelId(), |
| | | nvl(actual.getActualQty()), BigDecimal::add); |
| | | } |
| | | |
| | | //BOMéå±å±å¼ï¼ç´¯è®¡åè=ä¸çº§ç´¯è®¡Ãæ¬çº§åèï¼æç©æåå¹¶ |
| | | Map<Long, Map<Long, BigDecimal>> orderStandard = new HashMap<>(); |
| | | for (MaterialConsumptionStructureVo row : structures) { |
| | | if (isRoot(row)) { |
| | | continue; |
| | | } |
| | | BigDecimal cumulative = cumulativeUnitQuantity(row, structureById); |
| | | orderStandard.computeIfAbsent(row.getProductionOrderId(), k -> new LinkedHashMap<>()) |
| | | .merge(row.getProductModelId(), cumulative, BigDecimal::add); |
| | | } |
| | | |
| | | Set<Long> materialModelIds = new HashSet<>(); |
| | | orderStandard.values().forEach(m -> materialModelIds.addAll(m.keySet())); |
| | | materialModelIds.addAll(actualMap.keySet().stream() |
| | | .map(k -> Long.valueOf(k.substring(k.indexOf('_') + 1))).collect(Collectors.toSet())); |
| | | Map<Long, ProductModel> modelMap = modelIds(materialModelIds); |
| | | Map<Long, Product> productMap = products(modelMap.values()); |
| | | |
| | | List<MaterialConsumptionStatVo> result = new ArrayList<>(); |
| | | for (MaterialConsumptionOrderVo order : orders) { |
| | | Map<Long, BigDecimal> standardMap = orderStandard.getOrDefault(order.getProductionOrderId(), new LinkedHashMap<>()); |
| | | //æ¥å·¥æå
¥äºä½BOM没æçç©æä¹è¦å±ç¤ºï¼è¶
æ /误é¢ï¼ |
| | | Set<Long> materialIds = new java.util.LinkedHashSet<>(standardMap.keySet()); |
| | | actualMap.keySet().stream() |
| | | .filter(k -> k.startsWith(order.getProductionOrderId() + "_")) |
| | | .forEach(k -> materialIds.add(Long.valueOf(k.substring(k.indexOf('_') + 1)))); |
| | | if (materialIds.isEmpty()) { |
| | | continue; |
| | | } |
| | | BigDecimal outputQty = nvl(order.getCompleteQty()).compareTo(BigDecimal.ZERO) > 0 |
| | | ? order.getCompleteQty() : nvl(order.getPlanQty()); |
| | | for (Long materialId : materialIds) { |
| | | BigDecimal unitQty = standardMap.getOrDefault(materialId, BigDecimal.ZERO); |
| | | BigDecimal standard = unitQty.multiply(outputQty).setScale(4, RoundingMode.HALF_UP); |
| | | BigDecimal actual = actualMap.getOrDefault( |
| | | order.getProductionOrderId() + "_" + materialId, BigDecimal.ZERO); |
| | | BigDecimal diff = actual.subtract(standard); |
| | | if (Boolean.TRUE.equals(onlyDiff) && diff.compareTo(BigDecimal.ZERO) == 0) { |
| | | continue; |
| | | } |
| | | MaterialConsumptionStatVo vo = new MaterialConsumptionStatVo(); |
| | | vo.setProductionOrderId(order.getProductionOrderId()); |
| | | vo.setNpsNo(order.getNpsNo()); |
| | | vo.setFinishedProduct(order.getFinishedProduct()); |
| | | vo.setMaterialModelId(materialId); |
| | | ProductModel pm = modelMap.get(materialId); |
| | | if (pm != null) { |
| | | vo.setMaterialModel(pm.getModel()); |
| | | vo.setUnit(pm.getUnit()); |
| | | Product p = productMap.get(pm.getProductId()); |
| | | if (p != null) { |
| | | vo.setMaterialName(p.getProductName()); |
| | | } |
| | | } |
| | | vo.setUnitQuantity(unitQty); |
| | | vo.setCompleteQty(outputQty); |
| | | vo.setStandardQty(standard); |
| | | vo.setActualQty(actual); |
| | | vo.setDiffQty(diff); |
| | | if (standard.compareTo(BigDecimal.ZERO) > 0) { |
| | | vo.setDiffRate(diff.multiply(BigDecimal.valueOf(100)) |
| | | .divide(standard, 2, RoundingMode.HALF_UP)); |
| | | } |
| | | result.add(vo); |
| | | } |
| | | } |
| | | return result; |
| | | } |
| | | |
| | | private boolean isRoot(MaterialConsumptionStructureVo row) { |
| | | return row.getParentId() == null || row.getParentId() == 0L; |
| | | } |
| | | |
| | | private BigDecimal cumulativeUnitQuantity(MaterialConsumptionStructureVo row, |
| | | Map<Long, MaterialConsumptionStructureVo> structureById) { |
| | | BigDecimal cumulative = nvl(row.getUnitQuantity()); |
| | | Long parentId = row.getParentId(); |
| | | int guard = 0; |
| | | while (parentId != null && parentId != 0L && guard++ < 20) { |
| | | MaterialConsumptionStructureVo parent = structureById.get(parentId); |
| | | if (parent == null) { |
| | | break; |
| | | } |
| | | cumulative = cumulative.multiply(nvl(parent.getUnitQuantity())); |
| | | parentId = parent.getParentId(); |
| | | } |
| | | return cumulative.setScale(6, RoundingMode.HALF_UP); |
| | | } |
| | | |
| | | private Map<Long, ProductModel> modelIds(Set<Long> ids) { |
| | | if (ids.isEmpty()) { |
| | | return new HashMap<>(); |
| | | } |
| | | return productModelMapper.selectBatchIds(ids).stream() |
| | | .collect(Collectors.toMap(ProductModel::getId, m -> m, (a, b) -> a)); |
| | | } |
| | | |
| | | private Map<Long, Product> products(java.util.Collection<ProductModel> models) { |
| | | List<Long> ids = models.stream().map(ProductModel::getProductId) |
| | | .filter(Objects::nonNull).distinct().collect(Collectors.toList()); |
| | | if (ids.isEmpty()) { |
| | | return new HashMap<>(); |
| | | } |
| | | return productMapper.selectBatchIds(ids).stream() |
| | | .collect(Collectors.toMap(Product::getId, p -> p, (a, b) -> a)); |
| | | } |
| | | |
| | | private BigDecimal nvl(BigDecimal value) { |
| | | return value == null ? BigDecimal.ZERO : value; |
| | | } |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.production.service.impl; |
| | | |
| | | import com.baomidou.mybatisplus.core.metadata.IPage; |
| | | import com.baomidou.mybatisplus.core.toolkit.Wrappers; |
| | | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
| | | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; |
| | | import com.ruoyi.basic.mapper.ProductModelMapper; |
| | | import com.ruoyi.basic.pojo.ProductModel; |
| | | import com.ruoyi.common.exception.ServiceException; |
| | | import com.ruoyi.framework.web.domain.R; |
| | | import com.ruoyi.production.mapper.PieceRateConfigMapper; |
| | | import com.ruoyi.production.pojo.PieceRateConfig; |
| | | import com.ruoyi.production.service.PieceRateConfigService; |
| | | import lombok.AllArgsConstructor; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | |
| | | import java.math.BigDecimal; |
| | | |
| | | @AllArgsConstructor |
| | | @Service |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public class PieceRateConfigServiceImpl extends ServiceImpl<PieceRateConfigMapper, PieceRateConfig> implements PieceRateConfigService { |
| | | |
| | | private final ProductModelMapper productModelMapper; |
| | | |
| | | @Override |
| | | public IPage<PieceRateConfig> listPage(Page<PieceRateConfig> page, PieceRateConfig query) { |
| | | return this.page(page, Wrappers.<PieceRateConfig>lambdaQuery() |
| | | .like(query.getOperationName() != null && !query.getOperationName().isEmpty(), |
| | | PieceRateConfig::getOperationName, query.getOperationName()) |
| | | .like(query.getProductModel() != null && !query.getProductModel().isEmpty(), |
| | | PieceRateConfig::getProductModel, query.getProductModel()) |
| | | .eq(query.getProductModelId() != null, PieceRateConfig::getProductModelId, query.getProductModelId()) |
| | | .eq(query.getStatus() != null, PieceRateConfig::getStatus, query.getStatus()) |
| | | .orderByDesc(PieceRateConfig::getId)); |
| | | } |
| | | |
| | | @Override |
| | | public R add(PieceRateConfig config) { |
| | | validate(config); |
| | | checkDuplicate(config.getProductModelId(), config.getOperationName(), null); |
| | | fillProductModel(config); |
| | | if (config.getStatus() == null) { |
| | | config.setStatus(1); |
| | | } |
| | | this.save(config); |
| | | return R.ok(); |
| | | } |
| | | |
| | | @Override |
| | | public R update(PieceRateConfig config) { |
| | | if (config.getId() == null) { |
| | | throw new ServiceException("åæ°é误ï¼idä¸è½ä¸ºç©º"); |
| | | } |
| | | PieceRateConfig exist = this.getById(config.getId()); |
| | | if (exist == null) { |
| | | throw new ServiceException("计件åä»·é
ç½®ä¸åå¨"); |
| | | } |
| | | validate(config); |
| | | checkDuplicate(config.getProductModelId(), config.getOperationName(), config.getId()); |
| | | fillProductModel(config); |
| | | this.updateById(config); |
| | | return R.ok(); |
| | | } |
| | | |
| | | @Override |
| | | public R changeStatus(Long id, Integer status) { |
| | | if (id == null || status == null || (status != 0 && status != 1)) { |
| | | throw new ServiceException("åæ°é误ï¼idä¸ç¶æ(0/1)å¿
ä¼ "); |
| | | } |
| | | PieceRateConfig exist = this.getById(id); |
| | | if (exist == null) { |
| | | throw new ServiceException("计件åä»·é
ç½®ä¸åå¨"); |
| | | } |
| | | PieceRateConfig update = new PieceRateConfig(); |
| | | update.setId(id); |
| | | update.setStatus(status); |
| | | this.updateById(update); |
| | | return R.ok(); |
| | | } |
| | | |
| | | @Override |
| | | public BigDecimal matchPrice(Long productModelId, String operationName) { |
| | | if (productModelId == null || operationName == null || operationName.isEmpty()) { |
| | | return null; |
| | | } |
| | | PieceRateConfig config = this.getOne(Wrappers.<PieceRateConfig>lambdaQuery() |
| | | .eq(PieceRateConfig::getProductModelId, productModelId) |
| | | .eq(PieceRateConfig::getOperationName, operationName) |
| | | .eq(PieceRateConfig::getStatus, 1) |
| | | .orderByDesc(PieceRateConfig::getId) |
| | | .last("limit 1"), false); |
| | | return config == null ? null : config.getUnitPrice(); |
| | | } |
| | | |
| | | private void validate(PieceRateConfig config) { |
| | | if (config.getProductModelId() == null) { |
| | | throw new ServiceException("è¯·éæ©äº§åè§æ ¼"); |
| | | } |
| | | if (config.getOperationName() == null || config.getOperationName().trim().isEmpty()) { |
| | | throw new ServiceException("å·¥åºåç§°ä¸è½ä¸ºç©º"); |
| | | } |
| | | config.setOperationName(config.getOperationName().trim()); |
| | | if (config.getUnitPrice() == null || config.getUnitPrice().compareTo(BigDecimal.ZERO) <= 0) { |
| | | throw new ServiceException("计件åä»·å¿
须大äº0"); |
| | | } |
| | | } |
| | | |
| | | private void checkDuplicate(Long productModelId, String operationName, Long excludeId) { |
| | | long count = this.count(Wrappers.<PieceRateConfig>lambdaQuery() |
| | | .eq(PieceRateConfig::getProductModelId, productModelId) |
| | | .eq(PieceRateConfig::getOperationName, operationName) |
| | | .ne(excludeId != null, PieceRateConfig::getId, excludeId)); |
| | | if (count > 0) { |
| | | throw new ServiceException("该产åè§æ ¼ä¸å·¥åº[" + operationName + "]å·²åå¨è®¡ä»¶åä»·é
ç½®"); |
| | | } |
| | | } |
| | | |
| | | private void fillProductModel(PieceRateConfig config) { |
| | | ProductModel model = productModelMapper.selectById(config.getProductModelId()); |
| | | if (model == null) { |
| | | throw new ServiceException("产åè§æ ¼ä¸åå¨"); |
| | | } |
| | | config.setProductModel(model.getModel()); |
| | | } |
| | | } |
| | |
| | | import com.ruoyi.common.enums.StockOutQualifiedRecordTypeEnum; |
| | | import com.ruoyi.common.exception.ServiceException; |
| | | import com.ruoyi.common.utils.bean.BeanUtils; |
| | | import com.ruoyi.device.mapper.DeviceLedgerMapper; |
| | | import com.ruoyi.device.pojo.DeviceLedger; |
| | | import com.ruoyi.procurementrecord.utils.StockUtils; |
| | | import com.ruoyi.production.bean.dto.ProductStructureDto; |
| | | import com.ruoyi.production.bean.dto.ProductionProductMainDto; |
| | | import com.ruoyi.production.bean.vo.DeviceOutputStatVo; |
| | | import com.ruoyi.production.bean.vo.PieceWageSummaryVo; |
| | | import com.ruoyi.production.enums.ProductOrderStatusEnum; |
| | | import com.ruoyi.production.mapper.*; |
| | | import com.ruoyi.production.pojo.*; |
| | | import com.ruoyi.production.service.PieceRateConfigService; |
| | | import com.ruoyi.production.service.ProductionProductMainService; |
| | | import com.ruoyi.project.system.domain.SysUser; |
| | | import com.ruoyi.project.system.mapper.SysUserMapper; |
| | |
| | | import java.time.LocalDateTime; |
| | | import java.time.format.DateTimeFormatter; |
| | | import java.util.ArrayList; |
| | | import java.util.Arrays; |
| | | import java.util.Collections; |
| | | import java.util.HashMap; |
| | | import java.util.LinkedHashMap; |
| | |
| | | private final StockUtils stockUtils; |
| | | private final StockInRecordService stockInRecordService; |
| | | private final StockInventoryService stockInventoryService; |
| | | private final DeviceLedgerMapper deviceLedgerMapper; |
| | | private final PieceRateConfigService pieceRateConfigService; |
| | | |
| | | @Override |
| | | public IPage<ProductionProductMainDto> listPageProductionProductMainDto(Page page, ProductionProductMainDto productionProductMainDto) { |
| | |
| | | productionProductMain.setProductNo(generateProductNo()); |
| | | productionProductMain.setUserId(user == null ? dto.getUserId() : user.getUserId()); |
| | | productionProductMain.setUserName(user == null ? dto.getUserName() : user.getNickName()); |
| | | if (dto.getDeviceId() != null) { |
| | | DeviceLedger device = deviceLedgerMapper.selectById(dto.getDeviceId()); |
| | | if (device == null) { |
| | | throw new ServiceException("设å¤ä¸åå¨ï¼ID=" + dto.getDeviceId()); |
| | | } |
| | | productionProductMain.setDeviceId(device.getId()); |
| | | productionProductMain.setDeviceName(device.getDeviceName()); |
| | | } |
| | | productionProductMain.setProductionOperationTaskId(taskId); |
| | | productionProductMain.setStatus(0); |
| | | productionProductMain.setWorkHour(dto.getWorkHour()); |
| | |
| | | // æ¥è¯¢ä¸»è¡¨IDéå |
| | | return productionProductMainMapper.listMain(idList); |
| | | } |
| | | |
| | | @Override |
| | | public List<PieceWageSummaryVo> wageSummary(LocalDate startDate, LocalDate endDate, String userName) { |
| | | return productionProductMainMapper.wageSummary(startDate, endDate, userName); |
| | | } |
| | | |
| | | @Override |
| | | public List<DeviceOutputStatVo> outputStat(String dimension, LocalDate startDate, LocalDate endDate, Long deviceId) { |
| | | String dim = dimension == null || dimension.isEmpty() ? "device" : dimension; |
| | | if (!Arrays.asList("device", "operation", "product").contains(dim)) { |
| | | throw new ServiceException("ç»è®¡ç»´åº¦ä¸åæ³ï¼ä»
æ¯æ device/operation/product"); |
| | | } |
| | | return productionProductMainMapper.outputStat(dim, startDate, endDate, deviceId); |
| | | } |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.quality.controller; |
| | | |
| | | import com.ruoyi.common.utils.poi.ExcelUtil; |
| | | import com.ruoyi.framework.aspectj.lang.annotation.Log; |
| | | import com.ruoyi.framework.aspectj.lang.enums.BusinessType; |
| | | import com.ruoyi.framework.web.domain.R; |
| | | import com.ruoyi.quality.dto.QualityTraceBatchOptionVo; |
| | | import com.ruoyi.quality.dto.QualityTraceForwardExportVo; |
| | | import com.ruoyi.quality.dto.QualityTraceForwardVo; |
| | | import com.ruoyi.quality.dto.QualityTraceReverseExportVo; |
| | | import com.ruoyi.quality.dto.QualityTraceReverseVo; |
| | | import com.ruoyi.quality.service.QualityTraceService; |
| | | import io.swagger.v3.oas.annotations.Operation; |
| | | import io.swagger.v3.oas.annotations.tags.Tag; |
| | | import jakarta.servlet.http.HttpServletResponse; |
| | | import lombok.RequiredArgsConstructor; |
| | | 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; |
| | | |
| | | /** |
| | | * ç产质éè¿½æº¯ï¼æ¹æ¬¡é¾è·¯ï¼ |
| | | */ |
| | | @RestController |
| | | @RequestMapping("/quality/trace") |
| | | @RequiredArgsConstructor |
| | | @Tag(name = "ç产质é追溯") |
| | | public class QualityTraceController { |
| | | |
| | | private final QualityTraceService qualityTraceService; |
| | | |
| | | @GetMapping("/forward") |
| | | @Operation(summary = "æ£åè¿½æº¯ï¼æåæ¹å·â订å/å·¥åº/æå
¥/é¢ææ¹æ¬¡/æ£éª/åºåºæµå") |
| | | @Log(title = "è´¨é追溯æ£åæ¥è¯¢", businessType = BusinessType.OTHER) |
| | | public R<QualityTraceForwardVo> forward(@RequestParam String batchNo) { |
| | | return R.ok(qualityTraceService.forward(batchNo)); |
| | | } |
| | | |
| | | @GetMapping("/batchOptions") |
| | | @Operation(summary = "æ¹å·åéï¼type=finishedæåæ¹å·/materialåææ¹å·") |
| | | public R<List<QualityTraceBatchOptionVo>> batchOptions(@RequestParam(required = false, defaultValue = "finished") String type, |
| | | @RequestParam(required = false) String keyword, |
| | | @RequestParam(required = false, defaultValue = "50") Integer limit) { |
| | | return R.ok(qualityTraceService.batchOptions(type, keyword, limit)); |
| | | } |
| | | |
| | | @GetMapping("/reverse") |
| | | @Operation(summary = "åå追溯ï¼åææ¹å·âéè´æ¥æº/使ç¨è®¢å/äº§åºæåæ¹å·") |
| | | @Log(title = "è´¨é追溯ååæ¥è¯¢", businessType = BusinessType.OTHER) |
| | | public R<QualityTraceReverseVo> reverse(@RequestParam String batchNo) { |
| | | return R.ok(qualityTraceService.reverse(batchNo)); |
| | | } |
| | | |
| | | @GetMapping("/forward/export") |
| | | @Operation(summary = "æ£å追溯导åº") |
| | | @Log(title = "è´¨é追溯æ£å导åº", businessType = BusinessType.EXPORT) |
| | | public void forwardExport(HttpServletResponse response, @RequestParam String batchNo) { |
| | | List<QualityTraceForwardExportVo> list = qualityTraceService.forwardExportRows(batchNo); |
| | | ExcelUtil<QualityTraceForwardExportVo> util = new ExcelUtil<>(QualityTraceForwardExportVo.class); |
| | | util.exportExcel(response, list, "æåæ¹æ¬¡è¿½æº¯"); |
| | | } |
| | | |
| | | @GetMapping("/reverse/export") |
| | | @Operation(summary = "åå追溯导åº") |
| | | @Log(title = "è´¨é追溯åå导åº", businessType = BusinessType.EXPORT) |
| | | public void reverseExport(HttpServletResponse response, @RequestParam String batchNo) { |
| | | List<QualityTraceReverseExportVo> list = qualityTraceService.reverseExportRows(batchNo); |
| | | ExcelUtil<QualityTraceReverseExportVo> util = new ExcelUtil<>(QualityTraceReverseExportVo.class); |
| | | util.exportExcel(response, list, "åææ¹æ¬¡æµå追溯"); |
| | | } |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.quality.dto; |
| | | |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.time.LocalDateTime; |
| | | |
| | | @Data |
| | | @Schema(name = "QualityTraceBatchOptionVo", description = "追溯æ¹å·åé项") |
| | | public class QualityTraceBatchOptionVo { |
| | | |
| | | @Schema(description = "æ¹å·") |
| | | private String batchNo; |
| | | |
| | | @Schema(description = "产ååç§°") |
| | | private String productName; |
| | | |
| | | @Schema(description = "产åè§æ ¼") |
| | | private String productModel; |
| | | |
| | | @Schema(description = "åä½") |
| | | private String unit; |
| | | |
| | | @Schema(description = "æ°é") |
| | | private BigDecimal qty; |
| | | |
| | | @Schema(description = "å
¥åºæ¶é´") |
| | | private LocalDateTime inTime; |
| | | |
| | | @Schema(description = "å
³èç产订åå·(å¯è¿½æº¯æ¶)") |
| | | private String npsNo; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.quality.dto; |
| | | |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.time.LocalDateTime; |
| | | import java.util.ArrayList; |
| | | import java.util.List; |
| | | |
| | | @Data |
| | | @Schema(name = "QualityTraceChainVo", description = "追溯é¾è·¯(æç产订ååç»)") |
| | | public class QualityTraceChainVo { |
| | | |
| | | @Schema(description = "ç产订åid") |
| | | private Long productionOrderId; |
| | | |
| | | @Schema(description = "ç产订åå·") |
| | | private String npsNo; |
| | | |
| | | @Schema(description = "æå åç§°/è§æ ¼") |
| | | private String finishedProduct; |
| | | |
| | | @Schema(description = "æååä½") |
| | | private String unit; |
| | | |
| | | @Schema(description = "订åè®¡åæ°é") |
| | | private BigDecimal planQty; |
| | | |
| | | @Schema(description = "订åå®å·¥æ°é") |
| | | private BigDecimal completeQty; |
| | | |
| | | @Schema(description = "订åç¶æ") |
| | | private Integer orderStatus; |
| | | |
| | | @Schema(description = "订åå建æ¶é´") |
| | | private LocalDateTime orderCreateTime; |
| | | |
| | | @Schema(description = "该订åä¸å½ä¸æ¥è¯¢æ¹å·çæåå
¥åºè®°å½") |
| | | private List<QualityTraceFinishedBatchVo> batches = new ArrayList<>(); |
| | | |
| | | @Schema(description = "æ¥å·¥(å·¥åº)èç¹") |
| | | private List<QualityTraceReportVo> reports = new ArrayList<>(); |
| | | |
| | | @Schema(description = "æ¥å·¥æå
¥ç©æ") |
| | | private List<QualityTraceInputVo> inputs = new ArrayList<>(); |
| | | |
| | | @Schema(description = "çäº§é¢ææ¹æ¬¡(åææ¹å·)") |
| | | private List<QualityTracePickVo> picks = new ArrayList<>(); |
| | | |
| | | @Schema(description = "è¿ç¨/åºåæ£éªå") |
| | | private List<QualityTraceInspectVo> inspects = new ArrayList<>(); |
| | | |
| | | @Schema(description = "ä¸åæ ¼å¤çè®°å½") |
| | | private List<QualityTraceUnqualifiedVo> unqualifiedList = new ArrayList<>(); |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.quality.dto; |
| | | |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.time.LocalDateTime; |
| | | |
| | | @Data |
| | | @Schema(name = "QualityTraceFinishedBatchVo", description = "追溯-订å产åºçæåæ¹å·") |
| | | public class QualityTraceFinishedBatchVo { |
| | | |
| | | @Schema(description = "ç产订åid") |
| | | private Long productionOrderId; |
| | | |
| | | @Schema(description = "å
³èæ¥å·¥åid") |
| | | private Long productMainId; |
| | | |
| | | @Schema(description = "æåæ¹å·") |
| | | private String batchNo; |
| | | |
| | | @Schema(description = "æåè§æ ¼id") |
| | | private Long productModelId; |
| | | |
| | | @Schema(description = "å
¥åºæ°é") |
| | | private BigDecimal qty; |
| | | |
| | | @Schema(description = "å
¥åºæ¶é´") |
| | | private LocalDateTime inTime; |
| | | |
| | | @Schema(description = "å
¥åºç±»å(2ç产æ¥å·¥å
¥åº/6è´¨æ£åæ ¼å
¥åº)") |
| | | private String recordType; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.quality.dto; |
| | | |
| | | import com.ruoyi.framework.aspectj.lang.annotation.Excel; |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | |
| | | import java.math.BigDecimal; |
| | | |
| | | @Data |
| | | @Schema(name = "QualityTraceForwardExportVo", description = "æ£å追溯导åºè¡(æåæ¹å·âåææ¹å·)") |
| | | public class QualityTraceForwardExportVo { |
| | | |
| | | @Excel(name = "æåæ¹å·") |
| | | @Schema(description = "æåæ¹å·") |
| | | private String batchNo; |
| | | |
| | | @Excel(name = "ç产订åå·") |
| | | @Schema(description = "ç产订åå·") |
| | | private String npsNo; |
| | | |
| | | @Excel(name = "æå") |
| | | @Schema(description = "æå åç§°/è§æ ¼") |
| | | private String finishedProduct; |
| | | |
| | | @Excel(name = "å®å·¥æ°é") |
| | | @Schema(description = "订åå®å·¥æ°é") |
| | | private BigDecimal completeQty; |
| | | |
| | | @Excel(name = "å·¥åº") |
| | | @Schema(description = "æ¥å·¥å·¥åºæ±æ»") |
| | | private String operations; |
| | | |
| | | @Excel(name = "æ£éªç»è®º") |
| | | @Schema(description = "æ£éªç»è®ºæ±æ»") |
| | | private String inspectResults; |
| | | |
| | | @Excel(name = "ä¸åæ ¼å¤ç") |
| | | @Schema(description = "ä¸åæ ¼å¤çæ±æ»") |
| | | private String unqualifiedResults; |
| | | |
| | | @Excel(name = "åææ¹å·") |
| | | @Schema(description = "颿忿¹å·") |
| | | private String materialBatchNo; |
| | | |
| | | @Excel(name = "ç©æ") |
| | | @Schema(description = "ç©æåç§°") |
| | | private String materialName; |
| | | |
| | | @Excel(name = "ç©æè§æ ¼") |
| | | @Schema(description = "ç©æè§æ ¼") |
| | | private String materialModel; |
| | | |
| | | @Excel(name = "颿æ°é") |
| | | @Schema(description = "颿æ°é") |
| | | private BigDecimal pickQty; |
| | | |
| | | @Excel(name = "ä¾åºå") |
| | | @Schema(description = "ä¾åºå") |
| | | private String supplierName; |
| | | |
| | | @Excel(name = "åææ£éªç»è®º") |
| | | @Schema(description = "åææ£éªç»è®º") |
| | | private String materialCheckResult; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.quality.dto; |
| | | |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | |
| | | import java.util.ArrayList; |
| | | import java.util.List; |
| | | |
| | | @Data |
| | | @Schema(name = "QualityTraceForwardVo", description = "æ£åè¿½æº¯ï¼æåæ¹å·â订å/å·¥åº/æå
¥/æ£éª/æµåº") |
| | | public class QualityTraceForwardVo { |
| | | |
| | | @Schema(description = "æ¥è¯¢çæåæ¹å·") |
| | | private String batchNo; |
| | | |
| | | @Schema(description = "æ¹å·å¯¹åºçç产å
¥åºè®°å½(å¯è½å¤æ¡/å¤ä¸ªè®¢å)") |
| | | private List<QualityTraceChainVo> chains = new ArrayList<>(); |
| | | |
| | | @Schema(description = "åæ¹å·åºåºæµå") |
| | | private List<QualityTraceOutboundVo> outbounds = new ArrayList<>(); |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.quality.dto; |
| | | |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | |
| | | import java.math.BigDecimal; |
| | | |
| | | @Data |
| | | @Schema(name = "QualityTraceInputVo", description = "追溯-æ¥å·¥æå
¥ç©æ") |
| | | public class QualityTraceInputVo { |
| | | |
| | | @Schema(description = "æå±æ¥å·¥åid") |
| | | private Long productMainId; |
| | | |
| | | @Schema(description = "ç©æè§æ ¼id") |
| | | private Long productModelId; |
| | | |
| | | @Schema(description = "ç©æåç§°") |
| | | private String materialName; |
| | | |
| | | @Schema(description = "ç©æè§æ ¼") |
| | | private String materialModel; |
| | | |
| | | @Schema(description = "åä½") |
| | | private String unit; |
| | | |
| | | @Schema(description = "æå
¥æ°é") |
| | | private BigDecimal inputQty; |
| | | |
| | | @Schema(description = "å·¥åå·") |
| | | private String workOrderNo; |
| | | |
| | | @Schema(description = "å·¥åºåç§°") |
| | | private String operationName; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.quality.dto; |
| | | |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.time.LocalDate; |
| | | import java.util.ArrayList; |
| | | import java.util.List; |
| | | |
| | | @Data |
| | | @Schema(name = "QualityTraceInspectVo", description = "追溯-æ£éªå") |
| | | public class QualityTraceInspectVo { |
| | | |
| | | @Schema(description = "æ£éªåid") |
| | | private Long inspectId; |
| | | |
| | | @Schema(description = "å
³èæ¥å·¥åid(æ¥å·¥æ£éªæ¶æå¼)") |
| | | private Long productMainId; |
| | | |
| | | @Schema(description = "æ£éªç±»å 0åæ/1è¿ç¨/2åºå") |
| | | private Integer inspectType; |
| | | |
| | | @Schema(description = "æ£éªç±»ååç§°") |
| | | private String inspectTypeName; |
| | | |
| | | @Schema(description = "æ£éªå·¥åº") |
| | | private String process; |
| | | |
| | | @Schema(description = "æ£éªå") |
| | | private String checkName; |
| | | |
| | | @Schema(description = "产ååç§°") |
| | | private String productName; |
| | | |
| | | @Schema(description = "è§æ ¼åå·") |
| | | private String model; |
| | | |
| | | @Schema(description = "åä½") |
| | | private String unit; |
| | | |
| | | @Schema(description = "æ£éªæ°é") |
| | | private BigDecimal quantity; |
| | | |
| | | @Schema(description = "åæ ¼æ°é") |
| | | private BigDecimal qualifiedQuantity; |
| | | |
| | | @Schema(description = "ä¸åæ ¼æ°é") |
| | | private BigDecimal unqualifiedQuantity; |
| | | |
| | | @Schema(description = "æ£éªç»è®º") |
| | | private String checkResult; |
| | | |
| | | @Schema(description = "æ£éªæ¥æ") |
| | | private LocalDate checkTime; |
| | | |
| | | @Schema(description = "æäº¤ç¶æ 0æªæäº¤/1å·²æäº¤") |
| | | private Integer inspectState; |
| | | |
| | | @Schema(description = "ä¸åæ ¼ç°è±¡") |
| | | private String defectivePhenomena; |
| | | |
| | | @Schema(description = "该æ£éªå产ççä¸åæ ¼å¤çè®°å½") |
| | | private List<QualityTraceUnqualifiedVo> unqualifiedList = new ArrayList<>(); |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.quality.dto; |
| | | |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.time.LocalDate; |
| | | import java.time.LocalDateTime; |
| | | |
| | | @Data |
| | | @Schema(name = "QualityTraceMaterialBatchVo", description = "追溯-åææ¹å·æ¥æº(å
¥åº/æ£éª/éè´)") |
| | | public class QualityTraceMaterialBatchVo { |
| | | |
| | | @Schema(description = "å
¥åºè®°å½id") |
| | | private Long inRecordId; |
| | | |
| | | @Schema(description = "æ¹å·") |
| | | private String batchNo; |
| | | |
| | | @Schema(description = "ç©æè§æ ¼id") |
| | | private Long productModelId; |
| | | |
| | | @Schema(description = "ç©æåç§°") |
| | | private String materialName; |
| | | |
| | | @Schema(description = "ç©æè§æ ¼") |
| | | private String materialModel; |
| | | |
| | | @Schema(description = "åä½") |
| | | private String unit; |
| | | |
| | | @Schema(description = "å
¥åºæ°é") |
| | | private BigDecimal qty; |
| | | |
| | | @Schema(description = "å
¥åºæ¶é´") |
| | | private LocalDateTime inTime; |
| | | |
| | | @Schema(description = "å
¥åºç±»å(7éè´å
¥åº/10éè´è´¨æ£åæ ¼å
¥åº/6è´¨æ£åæ ¼å
¥åº/0èªå®ä¹å
¥åº)") |
| | | private String recordType; |
| | | |
| | | @Schema(description = "å
³èæ£éªåid") |
| | | private Long inspectId; |
| | | |
| | | @Schema(description = "æ£éªæ°é") |
| | | private BigDecimal inspectQty; |
| | | |
| | | @Schema(description = "åæ ¼æ°é") |
| | | private BigDecimal qualifiedQty; |
| | | |
| | | @Schema(description = "ä¸åæ ¼æ°é") |
| | | private BigDecimal unqualifiedQty; |
| | | |
| | | @Schema(description = "æ£éªç»è®º") |
| | | private String checkResult; |
| | | |
| | | @Schema(description = "æ£éªæ¥æ") |
| | | private LocalDate checkTime; |
| | | |
| | | @Schema(description = "ä¾åºå") |
| | | private String supplierName; |
| | | |
| | | @Schema(description = "éè´ååå·") |
| | | private String contractNo; |
| | | |
| | | @Schema(description = "éè´æ¥æ") |
| | | private LocalDate entryDate; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.quality.dto; |
| | | |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.time.LocalDateTime; |
| | | |
| | | @Data |
| | | @Schema(name = "QualityTraceOutboundVo", description = "追溯-æåæ¹å·æµåº(åºåºè®°å½)") |
| | | public class QualityTraceOutboundVo { |
| | | |
| | | @Schema(description = "åºåºè®°å½id") |
| | | private Long id; |
| | | |
| | | @Schema(description = "æ¹å·") |
| | | private String batchNo; |
| | | |
| | | @Schema(description = "产ååç§°") |
| | | private String productName; |
| | | |
| | | @Schema(description = "产åè§æ ¼") |
| | | private String productModel; |
| | | |
| | | @Schema(description = "åä½") |
| | | private String unit; |
| | | |
| | | @Schema(description = "åºåºæ°é") |
| | | private BigDecimal qty; |
| | | |
| | | @Schema(description = "åºåºç±»å(8éå®åºåº/13éå®åè´§åºåº/3ç产æ¥å·¥åºåº/1èªå®ä¹åºåº)") |
| | | private String recordType; |
| | | |
| | | @Schema(description = "åºåºæ¶é´") |
| | | private LocalDateTime outTime; |
| | | |
| | | @Schema(description = "夿³¨") |
| | | private String remark; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.quality.dto; |
| | | |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.time.LocalDateTime; |
| | | |
| | | @Data |
| | | @Schema(name = "QualityTracePickVo", description = "追溯-çäº§é¢ææ¹æ¬¡") |
| | | public class QualityTracePickVo { |
| | | |
| | | @Schema(description = "ç产订åid") |
| | | private Long productionOrderId; |
| | | |
| | | @Schema(description = "ç©æè§æ ¼id") |
| | | private Long productModelId; |
| | | |
| | | @Schema(description = "ç©æåç§°") |
| | | private String materialName; |
| | | |
| | | @Schema(description = "ç©æè§æ ¼") |
| | | private String materialModel; |
| | | |
| | | @Schema(description = "åä½") |
| | | private String unit; |
| | | |
| | | @Schema(description = "åææ¹å·") |
| | | private String batchNo; |
| | | |
| | | @Schema(description = "颿æ°é") |
| | | private BigDecimal quantity; |
| | | |
| | | @Schema(description = "颿工åº") |
| | | private String operationName; |
| | | |
| | | @Schema(description = "颿æ¶é´") |
| | | private LocalDateTime pickTime; |
| | | |
| | | @Schema(description = "ä¾åºå(ç±åææ¹å·å溯éè´/æ£éªè®°å½å¸¦åº)") |
| | | private String supplierName; |
| | | |
| | | @Schema(description = "éè´ååå·") |
| | | private String contractNo; |
| | | |
| | | @Schema(description = "åææ£éªç»è®º") |
| | | private String checkResult; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.quality.dto; |
| | | |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.time.LocalDateTime; |
| | | |
| | | @Data |
| | | @Schema(name = "QualityTraceReportVo", description = "追溯-ç产æ¥å·¥èç¹") |
| | | public class QualityTraceReportVo { |
| | | |
| | | @Schema(description = "æ¥å·¥åid(production_product_main.id)") |
| | | private Long productMainId; |
| | | |
| | | @Schema(description = "ç产订åid") |
| | | private Long productionOrderId; |
| | | |
| | | @Schema(description = "ç产订åå·") |
| | | private String npsNo; |
| | | |
| | | @Schema(description = "æå åç§°/è§æ ¼") |
| | | private String finishedProduct; |
| | | |
| | | @Schema(description = "æååä½") |
| | | private String unit; |
| | | |
| | | @Schema(description = "订åè®¡åæ°é") |
| | | private BigDecimal planQty; |
| | | |
| | | @Schema(description = "订åå®å·¥æ°é") |
| | | private BigDecimal completeQty; |
| | | |
| | | @Schema(description = "订åç¶æ") |
| | | private Integer orderStatus; |
| | | |
| | | @Schema(description = "订åå建æ¶é´") |
| | | private LocalDateTime orderCreateTime; |
| | | |
| | | @Schema(description = "å·¥åå·") |
| | | private String workOrderNo; |
| | | |
| | | @Schema(description = "å·¥åºåç§°") |
| | | private String operationName; |
| | | |
| | | @Schema(description = "æ¥å·¥äºº") |
| | | private String userName; |
| | | |
| | | @Schema(description = "使ç¨è®¾å¤") |
| | | private String deviceName; |
| | | |
| | | @Schema(description = "æ¥å·¥äº§åºæ°é") |
| | | private BigDecimal outputQty; |
| | | |
| | | @Schema(description = "æ¥å·¥æ¥åºæ°é") |
| | | private BigDecimal scrapQty; |
| | | |
| | | @Schema(description = "æ¥å·¥åå·") |
| | | private String productNo; |
| | | |
| | | @Schema(description = "æ¥å·¥æ¶é´") |
| | | private LocalDateTime reportTime; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.quality.dto; |
| | | |
| | | import com.ruoyi.framework.aspectj.lang.annotation.Excel; |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.time.LocalDate; |
| | | |
| | | @Data |
| | | @Schema(name = "QualityTraceReverseExportVo", description = "åå追溯导åºè¡(åææ¹å·âåå½±åæåæ¹å·)") |
| | | public class QualityTraceReverseExportVo { |
| | | |
| | | @Excel(name = "åææ¹å·") |
| | | @Schema(description = "åææ¹å·") |
| | | private String batchNo; |
| | | |
| | | @Excel(name = "ç©æ") |
| | | @Schema(description = "ç©æåç§°") |
| | | private String materialName; |
| | | |
| | | @Excel(name = "ç©æè§æ ¼") |
| | | @Schema(description = "ç©æè§æ ¼") |
| | | private String materialModel; |
| | | |
| | | @Excel(name = "åä½") |
| | | @Schema(description = "åä½") |
| | | private String unit; |
| | | |
| | | @Excel(name = "ä¾åºå") |
| | | @Schema(description = "ä¾åºå") |
| | | private String supplierName; |
| | | |
| | | @Excel(name = "éè´ååå·") |
| | | @Schema(description = "éè´ååå·") |
| | | private String contractNo; |
| | | |
| | | @Excel(name = "éè´æ¥æ", width = 20, dateFormat = "yyyy-MM-dd") |
| | | @Schema(description = "éè´æ¥æ") |
| | | private LocalDate entryDate; |
| | | |
| | | @Excel(name = "åææ£éªç»è®º") |
| | | @Schema(description = "åææ£éªç»è®º") |
| | | private String materialCheckResult; |
| | | |
| | | @Excel(name = "ç产订åå·") |
| | | @Schema(description = "ç产订åå·") |
| | | private String npsNo; |
| | | |
| | | @Excel(name = "æå") |
| | | @Schema(description = "æå åç§°/è§æ ¼") |
| | | private String finishedProduct; |
| | | |
| | | @Excel(name = "é¢ç¨æ°é") |
| | | @Schema(description = "该订åé¢ç¨è¢«æ¥æ¹å·çæ°é") |
| | | private BigDecimal pickedQty; |
| | | |
| | | @Excel(name = "äº§åºæåæ¹å·") |
| | | @Schema(description = "该订å产åºçæåæ¹å·ï¼å¤ä¸ªä»¥/åé") |
| | | private String finishedBatchNos; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.quality.dto; |
| | | |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.time.LocalDateTime; |
| | | import java.util.ArrayList; |
| | | import java.util.List; |
| | | |
| | | @Data |
| | | @Schema(name = "QualityTraceReverseOrderVo", description = "åå追溯ï¼åææ¹å·â使ç¨è¯¥æ¹å·çç产订å") |
| | | public class QualityTraceReverseOrderVo { |
| | | |
| | | @Schema(description = "ç产订åid") |
| | | private Long productionOrderId; |
| | | |
| | | @Schema(description = "ç产订åå·") |
| | | private String npsNo; |
| | | |
| | | @Schema(description = "æå åç§°/è§æ ¼") |
| | | private String finishedProduct; |
| | | |
| | | @Schema(description = "æååä½") |
| | | private String unit; |
| | | |
| | | @Schema(description = "订åè®¡åæ°é") |
| | | private BigDecimal planQty; |
| | | |
| | | @Schema(description = "订åå®å·¥æ°é") |
| | | private BigDecimal completeQty; |
| | | |
| | | @Schema(description = "订åç¶æ") |
| | | private Integer orderStatus; |
| | | |
| | | @Schema(description = "订åå建æ¶é´") |
| | | private LocalDateTime orderCreateTime; |
| | | |
| | | @Schema(description = "该订å使ç¨è¢«æ¥æ¹å·çé¢ç¨å计") |
| | | private BigDecimal pickedQty; |
| | | |
| | | @Schema(description = "该æ¹å·å¨æ¬è®¢åç颿æç»") |
| | | private List<QualityTracePickVo> picks = new ArrayList<>(); |
| | | |
| | | @Schema(description = "æ¬è®¢åæ¥å·¥(å·¥åº)èç¹") |
| | | private List<QualityTraceReportVo> reports = new ArrayList<>(); |
| | | |
| | | @Schema(description = "æ¬è®¢å产åºçæåæ¹å·") |
| | | private List<QualityTraceFinishedBatchVo> finishedBatches = new ArrayList<>(); |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.quality.dto; |
| | | |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | |
| | | import java.util.ArrayList; |
| | | import java.util.List; |
| | | |
| | | @Data |
| | | @Schema(name = "QualityTraceReverseVo", description = "åå追溯ï¼åææ¹å·âéè´æ¥æº+åå½±å订å+æåæ¹å·") |
| | | public class QualityTraceReverseVo { |
| | | |
| | | @Schema(description = "æ¥è¯¢çåææ¹å·") |
| | | private String batchNo; |
| | | |
| | | @Schema(description = "æ¹å·å
¥åº/æ£éª/éè´æ¥æº(å馿¡å
¥åºè®°å½)") |
| | | private QualityTraceMaterialBatchVo material; |
| | | |
| | | @Schema(description = "使ç¨è¯¥æ¹å·çç产订å") |
| | | private List<QualityTraceReverseOrderVo> orders = new ArrayList<>(); |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.quality.dto; |
| | | |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.time.LocalDate; |
| | | |
| | | @Data |
| | | @Schema(name = "QualityTraceUnqualifiedVo", description = "追溯-ä¸åæ ¼å¤çè®°å½") |
| | | public class QualityTraceUnqualifiedVo { |
| | | |
| | | @Schema(description = "ä¸åæ ¼è®°å½id") |
| | | private Long id; |
| | | |
| | | @Schema(description = "å
³èæ£éªåid") |
| | | private Long inspectId; |
| | | |
| | | @Schema(description = "产ååç§°") |
| | | private String productName; |
| | | |
| | | @Schema(description = "è§æ ¼åå·") |
| | | private String model; |
| | | |
| | | @Schema(description = "åä½") |
| | | private String unit; |
| | | |
| | | @Schema(description = "ä¸åæ ¼æ°é") |
| | | private BigDecimal quantity; |
| | | |
| | | @Schema(description = "ä¸åæ ¼ç°è±¡") |
| | | private String defectivePhenomena; |
| | | |
| | | @Schema(description = "å¤çç»æ æ¥åº/è®©æ¥æ¾è¡/è¿ä¿®/è¿å·¥") |
| | | private String dealResult; |
| | | |
| | | @Schema(description = "å¤ç人") |
| | | private String dealName; |
| | | |
| | | @Schema(description = "å¤çæ¶é´") |
| | | private LocalDate dealTime; |
| | | |
| | | @Schema(description = "å¤çç¶æ 0å¾
å¤ç/1å·²å¤ç") |
| | | private Integer inspectState; |
| | | |
| | | @Schema(description = "æ£éªæ¥æ") |
| | | private LocalDate checkTime; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.quality.mapper; |
| | | |
| | | import com.ruoyi.quality.dto.QualityTraceBatchOptionVo; |
| | | import com.ruoyi.quality.dto.QualityTraceFinishedBatchVo; |
| | | import com.ruoyi.quality.dto.QualityTraceInputVo; |
| | | import com.ruoyi.quality.dto.QualityTraceInspectVo; |
| | | import com.ruoyi.quality.dto.QualityTraceMaterialBatchVo; |
| | | import com.ruoyi.quality.dto.QualityTraceOutboundVo; |
| | | import com.ruoyi.quality.dto.QualityTracePickVo; |
| | | import com.ruoyi.quality.dto.QualityTraceReportVo; |
| | | import com.ruoyi.quality.dto.QualityTraceUnqualifiedVo; |
| | | import org.apache.ibatis.annotations.Mapper; |
| | | import org.apache.ibatis.annotations.Param; |
| | | |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * ç产质é追溯ï¼åªè¯»é¾è·¯æ¥è¯¢ï¼ |
| | | */ |
| | | @Mapper |
| | | public interface QualityTraceMapper { |
| | | |
| | | /** æåæ¹å·âå½ä¸çç产å
¥åºè®°å½(æ¥å·¥å
¥åº/è´¨æ£åæ ¼å
¥åº) */ |
| | | List<QualityTraceFinishedBatchVo> listInboundByFinishedBatch(@Param("batchNo") String batchNo); |
| | | |
| | | /** æ¥å·¥åâæ¥å·¥èç¹(å«è®¢åä¿¡æ¯) */ |
| | | List<QualityTraceReportVo> listReportsByMainIds(@Param("ids") List<Long> ids); |
| | | |
| | | /** ç产订åâæ¥å·¥èç¹(å«è®¢åä¿¡æ¯) */ |
| | | List<QualityTraceReportVo> listReportsByOrderIds(@Param("ids") List<Long> ids); |
| | | |
| | | /** æ¥å·¥åâæå
¥ç©æ */ |
| | | List<QualityTraceInputVo> listInputsByMainIds(@Param("ids") List<Long> ids); |
| | | |
| | | /** ç产订åâé¢ææ¹æ¬¡ */ |
| | | List<QualityTracePickVo> listPicksByOrderIds(@Param("ids") List<Long> ids); |
| | | |
| | | /** åææ¹å·â颿æç» */ |
| | | List<QualityTracePickVo> listPicksByBatchNo(@Param("batchNo") String batchNo); |
| | | |
| | | /** æ¥å·¥åâæ£éªå */ |
| | | List<QualityTraceInspectVo> listInspectsByMainIds(@Param("ids") List<Long> ids); |
| | | |
| | | /** æ£éªåâä¸åæ ¼å¤çè®°å½ */ |
| | | List<QualityTraceUnqualifiedVo> listUnqualifiedByInspectIds(@Param("ids") List<Long> ids); |
| | | |
| | | /** æ¹å·âåºåºæµå */ |
| | | List<QualityTraceOutboundVo> listOutboundByBatch(@Param("batchNo") String batchNo); |
| | | |
| | | /** ç产订åâäº§åºæåæ¹å· */ |
| | | List<QualityTraceFinishedBatchVo> listFinishedBatchesByOrderIds(@Param("ids") List<Long> ids); |
| | | |
| | | /** æ¹å·éåâå
¥åº/æ£éª/éè´æ¥æºä¿¡æ¯ */ |
| | | List<QualityTraceMaterialBatchVo> listMaterialBatchInfoByBatches(@Param("batchNos") List<String> batchNos); |
| | | |
| | | /** |
| | | * æ¹å·åéï¼åç«¯ä¸æ/æç´¢ï¼ |
| | | * |
| | | * @param type finished=æåæ¹å·(ç产å
¥åº/è´¨æ£åæ ¼å
¥åº)ï¼material=åææ¹å·(çäº§é¢æ) |
| | | */ |
| | | List<QualityTraceBatchOptionVo> listBatchOptions(@Param("type") String type, |
| | | @Param("keyword") String keyword, |
| | | @Param("limit") Integer limit); |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.quality.service; |
| | | |
| | | import com.ruoyi.quality.dto.QualityTraceBatchOptionVo; |
| | | import com.ruoyi.quality.dto.QualityTraceForwardExportVo; |
| | | import com.ruoyi.quality.dto.QualityTraceForwardVo; |
| | | import com.ruoyi.quality.dto.QualityTraceReverseExportVo; |
| | | import com.ruoyi.quality.dto.QualityTraceReverseVo; |
| | | |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * ç产质éè¿½æº¯ï¼æåæ¹å·æ£å追溯ãåææ¹å·åå追溯 |
| | | */ |
| | | public interface QualityTraceService { |
| | | |
| | | /** |
| | | * æ£åè¿½æº¯ï¼æåæ¹å· â ç产订å/æ¥å·¥å·¥åº/æå
¥ç©æ/é¢ææ¹æ¬¡/æ£éªä¸ä¸åæ ¼å¤ç/åºåºæµå |
| | | */ |
| | | QualityTraceForwardVo forward(String batchNo); |
| | | |
| | | /** |
| | | * åå追溯ï¼åææ¹å· â éè´æ¥æº + 使ç¨è¯¥æ¹å·ç订å + 订å产åºçæåæ¹å· |
| | | */ |
| | | QualityTraceReverseVo reverse(String batchNo); |
| | | |
| | | /** |
| | | * æ£å追溯导åºï¼æåæ¹å·âåææ¹å·é¾è·¯è¡ï¼ |
| | | */ |
| | | List<QualityTraceForwardExportVo> forwardExportRows(String batchNo); |
| | | |
| | | /** |
| | | * åå追溯导åºï¼åææ¹å·âåå½±åæåæ¹å·è¡ï¼ |
| | | */ |
| | | List<QualityTraceReverseExportVo> reverseExportRows(String batchNo); |
| | | |
| | | /** |
| | | * æ¹å·åéï¼å端æç´¢ä¸æï¼ |
| | | * |
| | | * @param type finished=æåæ¹å·ï¼material=åææ¹å· |
| | | */ |
| | | List<QualityTraceBatchOptionVo> batchOptions(String type, String keyword, Integer limit); |
| | | } |
| | |
| | | @Override |
| | | public int submit(QualityInspect inspect) { |
| | | QualityInspect qualityInspect = qualityInspectMapper.selectById(inspect.getId()); |
| | | if (qualityInspect == null) { |
| | | throw new ServiceException("æ£éªåä¸åå¨"); |
| | | } |
| | | //å¹çï¼å·²æäº¤çæ£éªåä¸å
许éå¤æäº¤ï¼é²æ¢éå¤çæå
¥åº/ä¸åæ ¼è®°å½ |
| | | if (Integer.valueOf(1).equals(qualityInspect.getInspectState())) { |
| | | throw new ServiceException("æ£éªåå·²æäº¤ï¼è¯·å¿éå¤æäº¤"); |
| | | } |
| | | |
| | | //æäº¤åå¿
须夿æ¯å¦åæ ¼ |
| | | if (ObjectUtils.isNull(qualityInspect.getCheckResult())) { |
| | |
| | | // 妿ä¸åæ ¼æ°é为空ï¼è®¾ä¸º0 |
| | | if (qualityInspect.getUnqualifiedQuantity() == null) { |
| | | qualityInspect.setUnqualifiedQuantity(BigDecimal.ZERO); |
| | | } |
| | | |
| | | //æ°éä¸è´æ§ï¼åæ ¼+ä¸åæ ¼ ä¸å¾è¶
è¿æ£éªæ°é |
| | | if (qualityInspect.getQuantity() != null |
| | | && qualityInspect.getQualifiedQuantity().add(qualityInspect.getUnqualifiedQuantity()) |
| | | .compareTo(qualityInspect.getQuantity()) > 0) { |
| | | throw new ServiceException("åæ ¼æ°éä¸ä¸åæ ¼æ°éä¹åä¸è½å¤§äºæ£éªæ°é"); |
| | | } |
| | | |
| | | // åæ ¼ç´æ¥å
¥åº |
| | |
| | | |
| | | @Override |
| | | public int updateQualityInspect(QualityInspectDto qualityInspectDto) { |
| | | QualityInspect exist = qualityInspectMapper.selectById(qualityInspectDto.getId()); |
| | | if (exist == null) { |
| | | throw new ServiceException("æ£éªåä¸åå¨"); |
| | | } |
| | | //å·²æäº¤çæ£éªåå·²èå¨å
¥åº/ä¸åæ ¼è®°å½ï¼ç¦æ¢åä¿®æ¹ |
| | | if (Integer.valueOf(1).equals(exist.getInspectState())) { |
| | | throw new ServiceException("æ£éªåå·²æäº¤ï¼ä¸å
许修æ¹"); |
| | | } |
| | | if (ObjectUtils.isNotNull(qualityInspectDto.getQualityInspectParams())) { |
| | | qualityInspectParamService.remove(Wrappers.<QualityInspectParam>lambdaQuery().eq(QualityInspectParam::getInspectId, qualityInspectDto.getId())); |
| | | for (QualityInspectParam qualityInspectParam : qualityInspectDto.getQualityInspectParams()) { |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.quality.service.impl; |
| | | |
| | | import com.ruoyi.common.exception.ServiceException; |
| | | import com.ruoyi.common.utils.StringUtils; |
| | | import com.ruoyi.quality.dto.QualityTraceBatchOptionVo; |
| | | import com.ruoyi.quality.dto.QualityTraceChainVo; |
| | | import com.ruoyi.quality.dto.QualityTraceFinishedBatchVo; |
| | | import com.ruoyi.quality.dto.QualityTraceForwardExportVo; |
| | | import com.ruoyi.quality.dto.QualityTraceForwardVo; |
| | | import com.ruoyi.quality.dto.QualityTraceInputVo; |
| | | import com.ruoyi.quality.dto.QualityTraceInspectVo; |
| | | import com.ruoyi.quality.dto.QualityTraceMaterialBatchVo; |
| | | import com.ruoyi.quality.dto.QualityTraceOutboundVo; |
| | | import com.ruoyi.quality.dto.QualityTracePickVo; |
| | | import com.ruoyi.quality.dto.QualityTraceReportVo; |
| | | import com.ruoyi.quality.dto.QualityTraceReverseExportVo; |
| | | import com.ruoyi.quality.dto.QualityTraceReverseOrderVo; |
| | | import com.ruoyi.quality.dto.QualityTraceReverseVo; |
| | | import com.ruoyi.quality.dto.QualityTraceUnqualifiedVo; |
| | | import com.ruoyi.quality.mapper.QualityTraceMapper; |
| | | import com.ruoyi.quality.service.QualityTraceService; |
| | | import lombok.RequiredArgsConstructor; |
| | | import org.springframework.stereotype.Service; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.util.ArrayList; |
| | | import java.util.Collections; |
| | | import java.util.LinkedHashMap; |
| | | import java.util.LinkedHashSet; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.Objects; |
| | | import java.util.Set; |
| | | import java.util.stream.Collectors; |
| | | |
| | | @Service |
| | | @RequiredArgsConstructor |
| | | public class QualityTraceServiceImpl implements QualityTraceService { |
| | | |
| | | private final QualityTraceMapper qualityTraceMapper; |
| | | |
| | | @Override |
| | | public QualityTraceForwardVo forward(String batchNo) { |
| | | String no = requireBatchNo(batchNo); |
| | | QualityTraceForwardVo result = new QualityTraceForwardVo(); |
| | | result.setBatchNo(no); |
| | | |
| | | //1.æ¹å·å½ä¸çç产å
¥åºè®°å½ï¼æ¥å·¥å
¥åº2 / è´¨æ£åæ ¼å
¥åº6ï¼ |
| | | List<QualityTraceFinishedBatchVo> inbound = qualityTraceMapper.listInboundByFinishedBatch(no); |
| | | if (inbound.isEmpty()) { |
| | | result.setOutbounds(qualityTraceMapper.listOutboundByBatch(no)); |
| | | return result; |
| | | } |
| | | Map<Long, List<QualityTraceFinishedBatchVo>> inboundByOrder = inbound.stream() |
| | | .filter(b -> b.getProductionOrderId() != null) |
| | | .collect(Collectors.groupingBy(QualityTraceFinishedBatchVo::getProductionOrderId, |
| | | LinkedHashMap::new, Collectors.toList())); |
| | | List<Long> mainIds = distinct(inbound.stream().map(QualityTraceFinishedBatchVo::getProductMainId) |
| | | .filter(Objects::nonNull).collect(Collectors.toList())); |
| | | |
| | | //2.æ¥å·¥èç¹ï¼å«è®¢åä¿¡æ¯ï¼ |
| | | List<QualityTraceReportVo> reports = mainIds.isEmpty() |
| | | ? new ArrayList<>() : qualityTraceMapper.listReportsByMainIds(mainIds); |
| | | Map<Long, List<QualityTraceReportVo>> reportsByOrder = reports.stream() |
| | | .filter(r -> r.getProductionOrderId() != null) |
| | | .collect(Collectors.groupingBy(QualityTraceReportVo::getProductionOrderId, |
| | | LinkedHashMap::new, Collectors.toList())); |
| | | Map<Long, Long> orderOfMain = new LinkedHashMap<>(); |
| | | reports.forEach(r -> orderOfMain.putIfAbsent(r.getProductMainId(), r.getProductionOrderId())); |
| | | |
| | | //3.æå
¥ç©æï¼ææ¥å·¥åï¼ |
| | | List<QualityTraceInputVo> inputs = mainIds.isEmpty() |
| | | ? new ArrayList<>() : qualityTraceMapper.listInputsByMainIds(mainIds); |
| | | |
| | | //4.é¢ææ¹æ¬¡ï¼æè®¢åï¼ï¼å¹¶ç¨åææ¹å·å溯ä¾åºå/éè´/æ£éª |
| | | List<Long> orderIds = new ArrayList<>(inboundByOrder.keySet()); |
| | | List<QualityTracePickVo> picks = orderIds.isEmpty() |
| | | ? new ArrayList<>() : qualityTraceMapper.listPicksByOrderIds(orderIds); |
| | | fillPickSource(picks); |
| | | Map<Long, List<QualityTracePickVo>> picksByOrder = picks.stream() |
| | | .filter(p -> p.getProductionOrderId() != null) |
| | | .collect(Collectors.groupingBy(QualityTracePickVo::getProductionOrderId, |
| | | LinkedHashMap::new, Collectors.toList())); |
| | | |
| | | //5.æ£éªåä¸ä¸åæ ¼å¤ç |
| | | List<QualityTraceInspectVo> inspects = mainIds.isEmpty() |
| | | ? new ArrayList<>() : qualityTraceMapper.listInspectsByMainIds(mainIds); |
| | | List<Long> inspectIds = distinct(inspects.stream().map(QualityTraceInspectVo::getInspectId) |
| | | .filter(Objects::nonNull).collect(Collectors.toList())); |
| | | List<QualityTraceUnqualifiedVo> unqualified = inspectIds.isEmpty() |
| | | ? new ArrayList<>() : qualityTraceMapper.listUnqualifiedByInspectIds(inspectIds); |
| | | Map<Long, List<QualityTraceUnqualifiedVo>> unqualifiedByInspect = unqualified.stream() |
| | | .filter(u -> u.getInspectId() != null) |
| | | .collect(Collectors.groupingBy(QualityTraceUnqualifiedVo::getInspectId)); |
| | | inspects.forEach(ins -> ins.setUnqualifiedList( |
| | | unqualifiedByInspect.getOrDefault(ins.getInspectId(), new ArrayList<>()))); |
| | | Map<Long, List<QualityTraceInspectVo>> inspectsByOrder = inspects.stream() |
| | | .filter(i -> i.getProductMainId() != null && orderOfMain.get(i.getProductMainId()) != null) |
| | | .collect(Collectors.groupingBy(i -> orderOfMain.get(i.getProductMainId()), |
| | | LinkedHashMap::new, Collectors.toList())); |
| | | |
| | | Set<Long> chainOrderIds = new LinkedHashSet<>(inboundByOrder.keySet()); |
| | | chainOrderIds.addAll(reportsByOrder.keySet()); |
| | | for (Long orderId : chainOrderIds) { |
| | | QualityTraceChainVo chain = new QualityTraceChainVo(); |
| | | chain.setProductionOrderId(orderId); |
| | | List<QualityTraceReportVo> orderReports = |
| | | reportsByOrder.getOrDefault(orderId, new ArrayList<>()); |
| | | if (!orderReports.isEmpty()) { |
| | | QualityTraceReportVo first = orderReports.get(0); |
| | | chain.setNpsNo(first.getNpsNo()); |
| | | chain.setFinishedProduct(first.getFinishedProduct()); |
| | | chain.setUnit(first.getUnit()); |
| | | chain.setPlanQty(first.getPlanQty()); |
| | | chain.setCompleteQty(first.getCompleteQty()); |
| | | chain.setOrderStatus(first.getOrderStatus()); |
| | | chain.setOrderCreateTime(first.getOrderCreateTime()); |
| | | } |
| | | chain.setBatches(inboundByOrder.getOrDefault(orderId, new ArrayList<>())); |
| | | chain.setReports(orderReports); |
| | | Set<Long> orderMainIds = orderReports.stream() |
| | | .map(QualityTraceReportVo::getProductMainId).filter(Objects::nonNull) |
| | | .collect(Collectors.toCollection(LinkedHashSet::new)); |
| | | chain.setInputs(inputs.stream() |
| | | .filter(i -> i.getProductMainId() != null && orderMainIds.contains(i.getProductMainId())) |
| | | .collect(Collectors.toList())); |
| | | chain.setPicks(picksByOrder.getOrDefault(orderId, new ArrayList<>())); |
| | | chain.setInspects(inspectsByOrder.getOrDefault(orderId, new ArrayList<>())); |
| | | chain.setUnqualifiedList(chain.getInspects().stream() |
| | | .flatMap(i -> i.getUnqualifiedList().stream()).collect(Collectors.toList())); |
| | | result.getChains().add(chain); |
| | | } |
| | | result.setOutbounds(qualityTraceMapper.listOutboundByBatch(no)); |
| | | return result; |
| | | } |
| | | |
| | | @Override |
| | | public QualityTraceReverseVo reverse(String batchNo) { |
| | | String no = requireBatchNo(batchNo); |
| | | QualityTraceReverseVo result = new QualityTraceReverseVo(); |
| | | result.setBatchNo(no); |
| | | |
| | | //1.æ¹å·å
¥åº/éè´/æ£éªæ¥æº |
| | | List<QualityTraceMaterialBatchVo> materialInfo = |
| | | qualityTraceMapper.listMaterialBatchInfoByBatches(Collections.singletonList(no)); |
| | | if (!materialInfo.isEmpty()) { |
| | | result.setMaterial(materialInfo.get(0)); |
| | | } |
| | | |
| | | //2.使ç¨è¯¥æ¹å·ç颿æç» |
| | | List<QualityTracePickVo> picks = qualityTraceMapper.listPicksByBatchNo(no); |
| | | if (picks.isEmpty()) { |
| | | return result; |
| | | } |
| | | fillPickSource(picks); |
| | | Map<Long, List<QualityTracePickVo>> picksByOrder = picks.stream() |
| | | .filter(p -> p.getProductionOrderId() != null) |
| | | .collect(Collectors.groupingBy(QualityTracePickVo::getProductionOrderId, |
| | | LinkedHashMap::new, Collectors.toList())); |
| | | List<Long> orderIds = new ArrayList<>(picksByOrder.keySet()); |
| | | |
| | | //3.è®¢åæ¥å·¥èç¹ä¸äº§åºæåæ¹å· |
| | | List<QualityTraceReportVo> reports = qualityTraceMapper.listReportsByOrderIds(orderIds); |
| | | Map<Long, List<QualityTraceReportVo>> reportsByOrder = reports.stream() |
| | | .filter(r -> r.getProductionOrderId() != null) |
| | | .collect(Collectors.groupingBy(QualityTraceReportVo::getProductionOrderId, |
| | | LinkedHashMap::new, Collectors.toList())); |
| | | Map<Long, List<QualityTraceFinishedBatchVo>> batchesByOrder = |
| | | qualityTraceMapper.listFinishedBatchesByOrderIds(orderIds).stream() |
| | | .filter(b -> b.getProductionOrderId() != null) |
| | | .collect(Collectors.groupingBy(QualityTraceFinishedBatchVo::getProductionOrderId, |
| | | LinkedHashMap::new, Collectors.toList())); |
| | | |
| | | for (Long orderId : orderIds) { |
| | | QualityTraceReverseOrderVo orderVo = new QualityTraceReverseOrderVo(); |
| | | orderVo.setProductionOrderId(orderId); |
| | | List<QualityTraceReportVo> orderReports = |
| | | reportsByOrder.getOrDefault(orderId, new ArrayList<>()); |
| | | if (!orderReports.isEmpty()) { |
| | | QualityTraceReportVo first = orderReports.get(0); |
| | | orderVo.setNpsNo(first.getNpsNo()); |
| | | orderVo.setFinishedProduct(first.getFinishedProduct()); |
| | | orderVo.setUnit(first.getUnit()); |
| | | orderVo.setPlanQty(first.getPlanQty()); |
| | | orderVo.setCompleteQty(first.getCompleteQty()); |
| | | orderVo.setOrderStatus(first.getOrderStatus()); |
| | | orderVo.setOrderCreateTime(first.getOrderCreateTime()); |
| | | } |
| | | List<QualityTracePickVo> orderPicks = |
| | | picksByOrder.getOrDefault(orderId, new ArrayList<>()); |
| | | orderVo.setPickedQty(orderPicks.stream().map(p -> nvl(p.getQuantity())) |
| | | .reduce(BigDecimal.ZERO, BigDecimal::add)); |
| | | orderVo.setPicks(orderPicks); |
| | | orderVo.setReports(orderReports); |
| | | orderVo.setFinishedBatches(batchesByOrder.getOrDefault(orderId, new ArrayList<>())); |
| | | result.getOrders().add(orderVo); |
| | | } |
| | | return result; |
| | | } |
| | | |
| | | @Override |
| | | public List<QualityTraceForwardExportVo> forwardExportRows(String batchNo) { |
| | | QualityTraceForwardVo trace = forward(batchNo); |
| | | List<QualityTraceForwardExportVo> rows = new ArrayList<>(); |
| | | for (QualityTraceChainVo chain : trace.getChains()) { |
| | | String operations = chain.getReports().stream() |
| | | .map(r -> StringUtils.isBlank(r.getOperationName()) ? r.getWorkOrderNo() : r.getOperationName()) |
| | | .filter(StringUtils::isNotBlank).distinct().collect(Collectors.joining("/")); |
| | | String inspectResults = chain.getInspects().stream() |
| | | .map(i -> (StringUtils.isBlank(i.getInspectTypeName()) ? "" : i.getInspectTypeName() + ":") |
| | | + (StringUtils.isBlank(i.getCheckResult()) ? "æªæäº¤" : i.getCheckResult())) |
| | | .collect(Collectors.joining("/")); |
| | | String unqualifiedResults = chain.getUnqualifiedList().stream() |
| | | .map(u -> (StringUtils.isBlank(u.getDealResult()) ? "å¾
å¤ç" : u.getDealResult()) |
| | | + "x" + nvl(u.getQuantity()).stripTrailingZeros().toPlainString()) |
| | | .collect(Collectors.joining("/")); |
| | | if (chain.getPicks().isEmpty()) { |
| | | QualityTraceForwardExportVo row = newForwardRow(trace.getBatchNo(), chain, operations, |
| | | inspectResults, unqualifiedResults); |
| | | rows.add(row); |
| | | continue; |
| | | } |
| | | for (QualityTracePickVo pick : chain.getPicks()) { |
| | | QualityTraceForwardExportVo row = newForwardRow(trace.getBatchNo(), chain, operations, |
| | | inspectResults, unqualifiedResults); |
| | | row.setMaterialBatchNo(pick.getBatchNo()); |
| | | row.setMaterialName(pick.getMaterialName()); |
| | | row.setMaterialModel(pick.getMaterialModel()); |
| | | row.setPickQty(pick.getQuantity()); |
| | | row.setSupplierName(pick.getSupplierName()); |
| | | row.setMaterialCheckResult(pick.getCheckResult()); |
| | | rows.add(row); |
| | | } |
| | | } |
| | | return rows; |
| | | } |
| | | |
| | | @Override |
| | | public List<QualityTraceReverseExportVo> reverseExportRows(String batchNo) { |
| | | QualityTraceReverseVo trace = reverse(batchNo); |
| | | List<QualityTraceReverseExportVo> rows = new ArrayList<>(); |
| | | QualityTraceMaterialBatchVo material = trace.getMaterial(); |
| | | if (trace.getOrders().isEmpty()) { |
| | | rows.add(newReverseRow(trace, material, null, null)); |
| | | return rows; |
| | | } |
| | | for (QualityTraceReverseOrderVo order : trace.getOrders()) { |
| | | String batchNos = order.getFinishedBatches().stream() |
| | | .map(QualityTraceFinishedBatchVo::getBatchNo) |
| | | .filter(StringUtils::isNotBlank).distinct().collect(Collectors.joining("/")); |
| | | rows.add(newReverseRow(trace, material, order, batchNos)); |
| | | } |
| | | return rows; |
| | | } |
| | | |
| | | private QualityTraceForwardExportVo newForwardRow(String batchNo, QualityTraceChainVo chain, |
| | | String operations, String inspectResults, |
| | | String unqualifiedResults) { |
| | | QualityTraceForwardExportVo row = new QualityTraceForwardExportVo(); |
| | | row.setBatchNo(batchNo); |
| | | row.setNpsNo(chain.getNpsNo()); |
| | | row.setFinishedProduct(chain.getFinishedProduct()); |
| | | row.setCompleteQty(chain.getCompleteQty()); |
| | | row.setOperations(operations); |
| | | row.setInspectResults(inspectResults); |
| | | row.setUnqualifiedResults(unqualifiedResults); |
| | | return row; |
| | | } |
| | | |
| | | private QualityTraceReverseExportVo newReverseRow(QualityTraceReverseVo trace, |
| | | QualityTraceMaterialBatchVo material, |
| | | QualityTraceReverseOrderVo order, String batchNos) { |
| | | QualityTraceReverseExportVo row = new QualityTraceReverseExportVo(); |
| | | row.setBatchNo(trace.getBatchNo()); |
| | | if (material != null) { |
| | | row.setMaterialName(material.getMaterialName()); |
| | | row.setMaterialModel(material.getMaterialModel()); |
| | | row.setUnit(material.getUnit()); |
| | | row.setSupplierName(material.getSupplierName()); |
| | | row.setContractNo(material.getContractNo()); |
| | | row.setEntryDate(material.getEntryDate()); |
| | | row.setMaterialCheckResult(material.getCheckResult()); |
| | | } |
| | | if (order != null) { |
| | | row.setNpsNo(order.getNpsNo()); |
| | | row.setFinishedProduct(order.getFinishedProduct()); |
| | | row.setPickedQty(order.getPickedQty()); |
| | | row.setFinishedBatchNos(batchNos); |
| | | } |
| | | return row; |
| | | } |
| | | |
| | | @Override |
| | | public List<QualityTraceBatchOptionVo> batchOptions(String type, String keyword, Integer limit) { |
| | | String queryType = "material".equals(type) ? "material" : "finished"; |
| | | int size = (limit == null || limit <= 0 || limit > 200) ? 50 : limit; |
| | | return qualityTraceMapper.listBatchOptions(queryType, StringUtils.isBlank(keyword) ? null : keyword.trim(), size); |
| | | } |
| | | |
| | | /** ç¨åææ¹å·å溯å
¥åºæ¥æºï¼è¡¥å
¨é¢æè¡çä¾åºå/åå/æ£éªç»è®º */ |
| | | private void fillPickSource(List<QualityTracePickVo> picks) { |
| | | List<String> batchNos = distinct(picks.stream().map(QualityTracePickVo::getBatchNo) |
| | | .filter(StringUtils::isNotBlank).collect(Collectors.toList())); |
| | | if (batchNos.isEmpty()) { |
| | | return; |
| | | } |
| | | Map<String, QualityTraceMaterialBatchVo> infoByBatch = new LinkedHashMap<>(); |
| | | for (QualityTraceMaterialBatchVo info : qualityTraceMapper.listMaterialBatchInfoByBatches(batchNos)) { |
| | | if (StringUtils.isNotBlank(info.getBatchNo())) { |
| | | infoByBatch.putIfAbsent(info.getBatchNo(), info); |
| | | } |
| | | } |
| | | for (QualityTracePickVo pick : picks) { |
| | | QualityTraceMaterialBatchVo info = infoByBatch.get(pick.getBatchNo()); |
| | | if (info == null) { |
| | | continue; |
| | | } |
| | | pick.setSupplierName(info.getSupplierName()); |
| | | pick.setContractNo(info.getContractNo()); |
| | | pick.setCheckResult(info.getCheckResult()); |
| | | if (StringUtils.isBlank(pick.getMaterialName())) { |
| | | pick.setMaterialName(info.getMaterialName()); |
| | | } |
| | | if (StringUtils.isBlank(pick.getMaterialModel())) { |
| | | pick.setMaterialModel(info.getMaterialModel()); |
| | | } |
| | | if (StringUtils.isBlank(pick.getUnit())) { |
| | | pick.setUnit(info.getUnit()); |
| | | } |
| | | } |
| | | } |
| | | |
| | | private String requireBatchNo(String batchNo) { |
| | | if (StringUtils.isBlank(batchNo)) { |
| | | throw new ServiceException("æ¹å·ä¸è½ä¸ºç©º"); |
| | | } |
| | | return batchNo.trim(); |
| | | } |
| | | |
| | | private <T> List<T> distinct(List<T> ids) { |
| | | return ids.stream().filter(Objects::nonNull).distinct().collect(Collectors.toList()); |
| | | } |
| | | |
| | | private BigDecimal nvl(BigDecimal value) { |
| | | return value == null ? BigDecimal.ZERO : value; |
| | | } |
| | | } |
| | |
| | | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; |
| | | import com.ruoyi.common.enums.StockInQualifiedRecordTypeEnum; |
| | | import com.ruoyi.common.exception.ServiceException; |
| | | import com.ruoyi.common.utils.SecurityUtils; |
| | | import com.ruoyi.common.utils.bean.BeanUtils; |
| | | import com.ruoyi.common.utils.poi.ExcelUtil; |
| | | import com.ruoyi.procurementrecord.utils.StockUtils; |
| | |
| | | import com.ruoyi.stock.service.StockUninventoryService; |
| | | import lombok.AllArgsConstructor; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | |
| | | import jakarta.servlet.http.HttpServletResponse; |
| | | import java.math.BigDecimal; |
| | | import java.time.LocalDate; |
| | | import java.time.format.DateTimeFormatter; |
| | | import java.util.ArrayList; |
| | | import java.util.Arrays; |
| | | import java.util.Date; |
| | | import java.util.HashMap; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public int deal(QualityUnqualified qualityUnqualified) { |
| | | QualityUnqualified unqualified = qualityUnqualifiedMapper.selectById(qualityUnqualified.getId()); |
| | | if (unqualified == null) { |
| | | throw new ServiceException("ä¸åæ ¼è®°å½ä¸åå¨"); |
| | | } |
| | | //å¹çï¼å·²å¤ççä¸å
许éå¤å¤çï¼é²æ¢éå¤å
¥åº/é夿¥å·¥å |
| | | if (Integer.valueOf(1).equals(unqualified.getInspectState())) { |
| | | throw new ServiceException("该ä¸åæ ¼è®°å½å·²å¤çï¼è¯·å¿é夿ä½"); |
| | | } |
| | | if (ObjectUtils.isNull(qualityUnqualified.getDealResult())) { |
| | | throw new ServiceException("è¯·éæ©å¤çç»æ"); |
| | | } |
| | | QualityInspect qualityInspect = qualityInspectService.getById(unqualified.getInspectId()); |
| | | //å¤çç»ææä¸¾æ ¡éªï¼åææä»
æ¥åº/è®©æ¥æ¾è¡ï¼è¿ç¨/åºåæ£é¢å¤æ¯æè¿ä¿®/è¿å·¥ |
| | | List<String> allowedResults = new ArrayList<>(Arrays.asList("æ¥åº", "è®©æ¥æ¾è¡")); |
| | | if (qualityInspect == null || qualityInspect.getInspectType() == null || qualityInspect.getInspectType() != 0) { |
| | | allowedResults.addAll(Arrays.asList("è¿ä¿®", "è¿å·¥")); |
| | | } |
| | | if (!allowedResults.contains(qualityUnqualified.getDealResult())) { |
| | | throw new ServiceException("å¤çç»æä¸åæ³ï¼ä»
æ¯æï¼" + String.join("/", allowedResults)); |
| | | } |
| | | String batchNo = qualityInspect == null ? null |
| | | : resolveProductionBatchNo(qualityInspect.getProductMainId(), qualityInspect.getId(), qualityInspect.getProductModelId()); |
| | | if (ObjectUtils.isNotNull(qualityInspect) && qualityInspect.getInspectType() != 0) { |
| | |
| | | break; |
| | | } |
| | | } |
| | | qualityUnqualified.setInspectState(1); |
| | | return qualityUnqualifiedMapper.updateById(qualityUnqualified); |
| | | //以åºä¸è®°å½ä¸ºåååï¼é²æ¢è¯·æ±ä½ç¯¡æ¹æ°é/ç¶æçåæ®µ |
| | | unqualified.setDealResult(qualityUnqualified.getDealResult()); |
| | | unqualified.setDealName(ObjectUtils.isNotNull(qualityUnqualified.getDealName()) |
| | | ? qualityUnqualified.getDealName() : SecurityUtils.getUsername()); |
| | | unqualified.setDealTime(qualityUnqualified.getDealTime() != null |
| | | ? qualityUnqualified.getDealTime() : new Date()); |
| | | unqualified.setInspectState(1); |
| | | return qualityUnqualifiedMapper.updateById(unqualified); |
| | | } |
| | | |
| | | @Override |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.stock.controller; |
| | | |
| | | import com.baomidou.mybatisplus.core.metadata.IPage; |
| | | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
| | | import com.ruoyi.common.utils.poi.ExcelUtil; |
| | | import com.ruoyi.framework.aspectj.lang.annotation.Log; |
| | | import com.ruoyi.framework.aspectj.lang.enums.BusinessType; |
| | | import com.ruoyi.framework.web.domain.R; |
| | | import com.ruoyi.stock.dto.StockCheckStartDto; |
| | | import com.ruoyi.stock.pojo.StockCheckDetail; |
| | | import com.ruoyi.stock.pojo.StockCheckMain; |
| | | import com.ruoyi.stock.service.StockCheckService; |
| | | import io.swagger.v3.oas.annotations.Operation; |
| | | import io.swagger.v3.oas.annotations.tags.Tag; |
| | | import jakarta.servlet.http.HttpServletResponse; |
| | | import lombok.RequiredArgsConstructor; |
| | | import org.springframework.web.bind.annotation.*; |
| | | |
| | | import java.util.List; |
| | | |
| | | @RestController |
| | | @RequestMapping("/stockCheck") |
| | | @RequiredArgsConstructor |
| | | @Tag(name = "åºåçç¹") |
| | | public class StockCheckController { |
| | | |
| | | private final StockCheckService stockCheckService; |
| | | |
| | | @PostMapping("/start") |
| | | @Log(title = "Start stock check", businessType = BusinessType.INSERT) |
| | | @Operation(summary = "åèµ·çç¹ï¼çæè´¦é¢å¿«ç
§æç»ï¼") |
| | | public R start(@RequestBody StockCheckStartDto dto) { |
| | | return stockCheckService.start(dto, dto.getProductModelIds()); |
| | | } |
| | | |
| | | @GetMapping("/listPage") |
| | | @Operation(summary = "çç¹åå页") |
| | | public R<IPage<StockCheckMain>> listPage(Page<StockCheckMain> page, StockCheckMain query) { |
| | | return R.ok(stockCheckService.listPage(page, query)); |
| | | } |
| | | |
| | | @GetMapping("/{id}") |
| | | @Operation(summary = "çç¹å详æ
(主表)") |
| | | public R<StockCheckMain> getInfo(@PathVariable Long id) { |
| | | return R.ok(stockCheckService.getMain(id)); |
| | | } |
| | | |
| | | @GetMapping("/detailPage") |
| | | @Operation(summary = "çç¹æç»å页(onlyDiff=trueåªçå·²å½å
¥ä¸æå·®å¼)") |
| | | public R<IPage<StockCheckDetail>> detailPage(Page<StockCheckDetail> page, |
| | | @RequestParam Long mainId, |
| | | @RequestParam(required = false) Boolean onlyDiff) { |
| | | return R.ok(stockCheckService.detailPage(page, mainId, onlyDiff)); |
| | | } |
| | | |
| | | @PutMapping("/entry") |
| | | @Log(title = "Stock check entry", businessType = BusinessType.UPDATE) |
| | | @Operation(summary = "å½å
¥å®çæ°é [{id,actualQty,remark}...]") |
| | | public R entry(@RequestBody List<StockCheckDetail> details) { |
| | | return stockCheckService.entry(details); |
| | | } |
| | | |
| | | @PostMapping("/finish") |
| | | @Log(title = "Finish stock check", businessType = BusinessType.UPDATE) |
| | | @Operation(summary = "宿çç¹ï¼å·®å¼çæå¾
å®¡æ ¸è°è´¦åæ®ï¼") |
| | | public R finish(@RequestBody StockCheckMain main) { |
| | | return stockCheckService.finish(main.getId()); |
| | | } |
| | | |
| | | @PostMapping("/cancel") |
| | | @Log(title = "Cancel stock check", businessType = BusinessType.UPDATE) |
| | | @Operation(summary = "åæ¶çç¹ï¼ä»
çç¹ä¸ï¼") |
| | | public R cancel(@RequestBody StockCheckMain main) { |
| | | return stockCheckService.cancel(main.getId()); |
| | | } |
| | | |
| | | @DeleteMapping("/delete") |
| | | @Log(title = "Delete stock check", businessType = BusinessType.DELETE) |
| | | @Operation(summary = "å é¤çç¹åï¼è¿å¸¦å 餿ç»ï¼") |
| | | public R delete(@RequestBody List<Long> ids) { |
| | | return stockCheckService.delete(ids); |
| | | } |
| | | |
| | | @GetMapping("/diffList") |
| | | @Operation(summary = "å·®å¼åæå表") |
| | | public R<List<StockCheckDetail>> diffList(@RequestParam Long mainId) { |
| | | return R.ok(stockCheckService.diffList(mainId)); |
| | | } |
| | | |
| | | @GetMapping("/diffList/export") |
| | | @Log(title = "Export stock check diff", businessType = BusinessType.EXPORT) |
| | | @Operation(summary = "å·®å¼åæå¯¼åº") |
| | | public void diffExport(HttpServletResponse response, @RequestParam Long mainId) { |
| | | List<StockCheckDetail> list = stockCheckService.diffList(mainId); |
| | | ExcelUtil<StockCheckDetail> util = new ExcelUtil<>(StockCheckDetail.class); |
| | | util.exportExcel(response, list, "çç¹å·®å¼åæ"); |
| | | } |
| | | |
| | | @GetMapping("/export") |
| | | @Log(title = "Export stock check", businessType = BusinessType.EXPORT) |
| | | @Operation(summary = "çç¹å导åº") |
| | | public void export(HttpServletResponse response, StockCheckMain query) { |
| | | List<StockCheckMain> list = stockCheckService.listForExport(query); |
| | | ExcelUtil<StockCheckMain> util = new ExcelUtil<>(StockCheckMain.class); |
| | | util.exportExcel(response, list, "åºåçç¹å"); |
| | | } |
| | | |
| | | @GetMapping("/detailExport") |
| | | @Log(title = "Export stock check detail", businessType = BusinessType.EXPORT) |
| | | @Operation(summary = "çç¹æç»å¯¼åº") |
| | | public void detailExport(HttpServletResponse response, @RequestParam Long mainId) { |
| | | List<StockCheckDetail> list = stockCheckService.detailPage(new Page<>(1, -1), mainId, null).getRecords(); |
| | | ExcelUtil<StockCheckDetail> util = new ExcelUtil<>(StockCheckDetail.class); |
| | | util.exportExcel(response, list, "çç¹æç»"); |
| | | } |
| | | } |
| | |
| | | return R.ok(stockInventoryDtoIPage); |
| | | } |
| | | |
| | | @GetMapping("/warnPage") |
| | | @Operation(summary = "åºåé¢è¦å页ï¼å¯ç¨æ°é<=é¢è¦å¼ï¼") |
| | | public R warnPage(Page page, StockInventoryDto stockInventoryDto) { |
| | | stockInventoryDto.setWarnOnly(true); |
| | | return R.ok(stockInventoryService.pagestockInventory(page, stockInventoryDto)); |
| | | } |
| | | |
| | | @GetMapping("/warnExport") |
| | | @Operation(summary = "åºåé¢è¦å¯¼åº") |
| | | public void warnExport(HttpServletResponse response, StockInventoryDto stockInventoryDto) { |
| | | stockInventoryDto.setWarnOnly(true); |
| | | List<StockInventoryDto> list = stockInventoryService.pagestockInventory(new Page<>(1, -1), stockInventoryDto).getRecords(); |
| | | List<StockInventoryExportData> exportList = new ArrayList<>(); |
| | | for (StockInventoryDto item : list) { |
| | | StockInventoryExportData data = new StockInventoryExportData(); |
| | | data.setProductName(item.getProductName()); |
| | | data.setModel(item.getModel()); |
| | | data.setUnit(item.getUnit()); |
| | | data.setBatchNo(item.getBatchNo()); |
| | | data.setQualifiedQuantity(item.getQualitity()); |
| | | data.setWarnNum(item.getWarnNum()); |
| | | data.setQualifiedLockedQuantity(item.getLockedQuantity()); |
| | | data.setRemark(item.getRemark()); |
| | | exportList.add(data); |
| | | } |
| | | ExcelUtil<StockInventoryExportData> util = new ExcelUtil<>(StockInventoryExportData.class); |
| | | util.exportExcel(response, exportList, "åºåé¢è¦"); |
| | | } |
| | | |
| | | /** |
| | | * æ¥è¯¢å¯¹åºæ¹å·åæ°é |
| | | * @param page |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.stock.dto; |
| | | |
| | | import com.ruoyi.stock.pojo.StockCheckMain; |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | import lombok.EqualsAndHashCode; |
| | | |
| | | import java.util.List; |
| | | |
| | | @EqualsAndHashCode(callSuper = true) |
| | | @Data |
| | | @Schema(name = "StockCheckStartDto", description = "åèµ·çç¹åæ°") |
| | | public class StockCheckStartDto extends StockCheckMain { |
| | | |
| | | @Schema(description = "æå®çç¹ç产åè§æ ¼idå表ï¼ä¸ä¼ =å
¨é¨åºå") |
| | | private List<Long> productModelIds; |
| | | } |
| | |
| | | private String unit; |
| | | private String batchNo; |
| | | |
| | | @Schema(description = "true=åªæ¥é¢è¦(å¯ç¨æ°é<=é¢è¦å¼ä¸é¢è¦å¼>0)") |
| | | private Boolean warnOnly; |
| | | |
| | | |
| | | //å
¥åºç±»å |
| | | private String recordType; |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.stock.mapper; |
| | | |
| | | import com.baomidou.mybatisplus.core.mapper.BaseMapper; |
| | | import com.ruoyi.stock.pojo.StockCheckDetail; |
| | | import org.apache.ibatis.annotations.Mapper; |
| | | |
| | | @Mapper |
| | | public interface StockCheckDetailMapper extends BaseMapper<StockCheckDetail> { |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.stock.mapper; |
| | | |
| | | import com.baomidou.mybatisplus.core.mapper.BaseMapper; |
| | | import com.ruoyi.stock.pojo.StockCheckMain; |
| | | import org.apache.ibatis.annotations.Mapper; |
| | | |
| | | @Mapper |
| | | public interface StockCheckMainMapper extends BaseMapper<StockCheckMain> { |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.stock.pojo; |
| | | |
| | | import com.baomidou.mybatisplus.annotation.FieldFill; |
| | | import com.baomidou.mybatisplus.annotation.IdType; |
| | | import com.baomidou.mybatisplus.annotation.TableField; |
| | | import com.baomidou.mybatisplus.annotation.TableId; |
| | | import com.baomidou.mybatisplus.annotation.TableName; |
| | | import com.fasterxml.jackson.annotation.JsonFormat; |
| | | import com.ruoyi.framework.aspectj.lang.annotation.Excel; |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | import org.springframework.format.annotation.DateTimeFormat; |
| | | |
| | | import java.io.Serializable; |
| | | import java.math.BigDecimal; |
| | | import java.time.LocalDateTime; |
| | | |
| | | /** |
| | | * åºåçç¹æç» |
| | | */ |
| | | @Data |
| | | @TableName("stock_check_detail") |
| | | @Schema(name = "StockCheckDetail", description = "åºåçç¹æç»") |
| | | public class StockCheckDetail implements Serializable { |
| | | |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | @TableId(type = IdType.AUTO) |
| | | private Long id; |
| | | |
| | | @Schema(description = "çç¹ä¸»è¡¨id") |
| | | private Long mainId; |
| | | |
| | | @Schema(description = "åºåè¡id") |
| | | private Long inventoryId; |
| | | |
| | | @Schema(description = "产åè§æ ¼id") |
| | | private Long productModelId; |
| | | |
| | | @Excel(name = "产ååç§°") |
| | | @Schema(description = "产ååç§°(åä½)") |
| | | private String productName; |
| | | |
| | | @Excel(name = "è§æ ¼åå·") |
| | | @Schema(description = "è§æ ¼åå·(åä½)") |
| | | private String productModel; |
| | | |
| | | @Excel(name = "åä½") |
| | | @Schema(description = "åä½(åä½)") |
| | | private String unit; |
| | | |
| | | @Excel(name = "æ¹å·") |
| | | @Schema(description = "æ¹å·") |
| | | private String batchNo; |
| | | |
| | | @Excel(name = "è´¦é¢æ°é") |
| | | @Schema(description = "è´¦é¢æ°éå¿«ç
§") |
| | | private BigDecimal bookQty; |
| | | |
| | | @Excel(name = "å®çæ°é") |
| | | @Schema(description = "å®çæ°é") |
| | | private BigDecimal actualQty; |
| | | |
| | | @Excel(name = "差弿°é") |
| | | @Schema(description = "å·®å¼=å®ç-è´¦é¢") |
| | | private BigDecimal diffQty; |
| | | |
| | | @Schema(description = "0æªè°è´¦ 1å·²çæè°è´¦åæ®") |
| | | private Integer adjusted; |
| | | |
| | | @Excel(name = "夿³¨") |
| | | @Schema(description = "夿³¨") |
| | | private String remark; |
| | | |
| | | @TableField(fill = FieldFill.INSERT) |
| | | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") |
| | | @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") |
| | | private LocalDateTime createTime; |
| | | |
| | | @TableField(fill = FieldFill.INSERT) |
| | | private Long createUser; |
| | | |
| | | @TableField(fill = FieldFill.INSERT_UPDATE) |
| | | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") |
| | | @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") |
| | | private LocalDateTime updateTime; |
| | | |
| | | @TableField(fill = FieldFill.INSERT_UPDATE) |
| | | private Long updateUser; |
| | | |
| | | @TableField(fill = FieldFill.INSERT) |
| | | private Long deptId; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.stock.pojo; |
| | | |
| | | import com.baomidou.mybatisplus.annotation.FieldFill; |
| | | import com.baomidou.mybatisplus.annotation.IdType; |
| | | import com.baomidou.mybatisplus.annotation.TableField; |
| | | import com.baomidou.mybatisplus.annotation.TableId; |
| | | import com.baomidou.mybatisplus.annotation.TableName; |
| | | import com.fasterxml.jackson.annotation.JsonFormat; |
| | | import com.ruoyi.framework.aspectj.lang.annotation.Excel; |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | import org.springframework.format.annotation.DateTimeFormat; |
| | | |
| | | import java.io.Serializable; |
| | | import java.time.LocalDate; |
| | | import java.time.LocalDateTime; |
| | | |
| | | /** |
| | | * åºåçç¹ä¸»è¡¨ |
| | | */ |
| | | @Data |
| | | @TableName("stock_check_main") |
| | | @Schema(name = "StockCheckMain", description = "åºåçç¹ä¸»è¡¨") |
| | | public class StockCheckMain implements Serializable { |
| | | |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | @TableId(type = IdType.AUTO) |
| | | private Long id; |
| | | |
| | | @Excel(name = "çç¹åå·") |
| | | @Schema(description = "çç¹åå·") |
| | | private String checkNo; |
| | | |
| | | @Excel(name = "çç¹åç§°") |
| | | @Schema(description = "çç¹åç§°") |
| | | private String checkName; |
| | | |
| | | @Excel(name = "çç¹æ¥æ", width = 30, dateFormat = "yyyy-MM-dd") |
| | | @Schema(description = "çç¹æ¥æ") |
| | | @JsonFormat(pattern = "yyyy-MM-dd") |
| | | @DateTimeFormat(pattern = "yyyy-MM-dd") |
| | | private LocalDate checkDate; |
| | | |
| | | @Excel(name = "çç¹äºº") |
| | | @Schema(description = "çç¹äºº") |
| | | private String checker; |
| | | |
| | | @Excel(name = "ç¶æ", readConverterExp = "0=çç¹ä¸,1=已宿,2=已忶") |
| | | @Schema(description = "ç¶æ 0çç¹ä¸ 1已宿 2已忶") |
| | | private Integer status; |
| | | |
| | | @Excel(name = "çç¹ç§ç±»æ°") |
| | | @Schema(description = "çç¹ç§ç±»æ°") |
| | | private Integer totalKinds; |
| | | |
| | | @Excel(name = "å·®å¼ç§ç±»æ°") |
| | | @Schema(description = "å·®å¼ç§ç±»æ°") |
| | | private Integer diffKinds; |
| | | |
| | | @Excel(name = "夿³¨") |
| | | @Schema(description = "夿³¨") |
| | | private String remark; |
| | | |
| | | @TableField(exist = false) |
| | | @Schema(description = "å建æ¶é´èµ·(æ¥è¯¢åæ°)") |
| | | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") |
| | | @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") |
| | | private LocalDateTime beginTime; |
| | | |
| | | @TableField(exist = false) |
| | | @Schema(description = "å建æ¶é´æ¢(æ¥è¯¢åæ°)") |
| | | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") |
| | | @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") |
| | | private LocalDateTime endTime; |
| | | |
| | | @TableField(fill = FieldFill.INSERT) |
| | | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") |
| | | @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") |
| | | private LocalDateTime createTime; |
| | | |
| | | @TableField(fill = FieldFill.INSERT_UPDATE) |
| | | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") |
| | | @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") |
| | | private LocalDateTime updateTime; |
| | | |
| | | @TableField(fill = FieldFill.INSERT) |
| | | private Long createUser; |
| | | |
| | | @TableField(fill = FieldFill.INSERT_UPDATE) |
| | | private Long updateUser; |
| | | |
| | | @TableField(fill = FieldFill.INSERT) |
| | | private Long deptId; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.stock.service; |
| | | |
| | | import com.baomidou.mybatisplus.core.metadata.IPage; |
| | | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
| | | import com.ruoyi.framework.web.domain.R; |
| | | import com.ruoyi.stock.pojo.StockCheckDetail; |
| | | import com.ruoyi.stock.pojo.StockCheckMain; |
| | | |
| | | import java.util.List; |
| | | |
| | | public interface StockCheckService { |
| | | |
| | | /** |
| | | * åèµ·çç¹ï¼æåºåè¡å¿«ç
§çæçç¹æç»ï¼å¯æäº§åè§æ ¼è¿æ»¤ï¼ |
| | | */ |
| | | R start(StockCheckMain main, List<Long> productModelIds); |
| | | |
| | | IPage<StockCheckMain> listPage(Page<StockCheckMain> page, StockCheckMain query); |
| | | |
| | | StockCheckMain getMain(Long id); |
| | | |
| | | IPage<StockCheckDetail> detailPage(Page<StockCheckDetail> page, Long mainId, Boolean onlyDiff); |
| | | |
| | | /** |
| | | * å½å
¥å®çæ°éï¼[{id, actualQty, remark}...] |
| | | */ |
| | | R entry(List<StockCheckDetail> details); |
| | | |
| | | /** |
| | | * 宿çç¹ï¼å·®å¼çæå¾
å®¡æ ¸åºå
¥åºè°è´¦åæ® |
| | | */ |
| | | R finish(Long id); |
| | | |
| | | R cancel(Long id); |
| | | |
| | | /** |
| | | * å é¤çç¹åï¼è¿å¸¦å 餿ç»ï¼ |
| | | */ |
| | | R delete(List<Long> ids); |
| | | |
| | | /** |
| | | * å·®å¼åæå表ï¼å«æªå½å
¥ï¼ |
| | | */ |
| | | List<StockCheckDetail> diffList(Long mainId); |
| | | |
| | | List<StockCheckMain> listForExport(StockCheckMain query); |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.stock.service.impl; |
| | | |
| | | import com.baomidou.mybatisplus.core.metadata.IPage; |
| | | import com.baomidou.mybatisplus.core.toolkit.Wrappers; |
| | | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
| | | import com.ruoyi.basic.mapper.ProductMapper; |
| | | import com.ruoyi.basic.mapper.ProductModelMapper; |
| | | import com.ruoyi.basic.pojo.Product; |
| | | import com.ruoyi.basic.pojo.ProductModel; |
| | | import com.ruoyi.common.enums.StockInQualifiedRecordTypeEnum; |
| | | import com.ruoyi.common.enums.StockOutQualifiedRecordTypeEnum; |
| | | import com.ruoyi.common.exception.ServiceException; |
| | | import com.ruoyi.framework.web.domain.R; |
| | | import com.ruoyi.stock.dto.StockInventoryDto; |
| | | import com.ruoyi.stock.mapper.StockCheckDetailMapper; |
| | | import com.ruoyi.stock.mapper.StockCheckMainMapper; |
| | | import com.ruoyi.stock.mapper.StockInventoryMapper; |
| | | import com.ruoyi.stock.pojo.StockCheckDetail; |
| | | import com.ruoyi.stock.pojo.StockCheckMain; |
| | | import com.ruoyi.stock.pojo.StockInventory; |
| | | import com.ruoyi.stock.service.StockCheckService; |
| | | import com.ruoyi.stock.service.StockInventoryService; |
| | | import lombok.RequiredArgsConstructor; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.time.LocalDate; |
| | | import java.time.format.DateTimeFormatter; |
| | | import java.util.ArrayList; |
| | | import java.util.HashMap; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.Objects; |
| | | import java.util.stream.Collectors; |
| | | |
| | | @Service |
| | | @RequiredArgsConstructor |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public class StockCheckServiceImpl implements StockCheckService { |
| | | |
| | | private final StockCheckMainMapper stockCheckMainMapper; |
| | | private final StockCheckDetailMapper stockCheckDetailMapper; |
| | | private final StockInventoryMapper stockInventoryMapper; |
| | | private final StockInventoryService stockInventoryService; |
| | | private final ProductModelMapper productModelMapper; |
| | | private final ProductMapper productMapper; |
| | | |
| | | @Override |
| | | public R start(StockCheckMain main, List<Long> productModelIds) { |
| | | if (main.getCheckName() == null || main.getCheckName().trim().isEmpty()) { |
| | | throw new ServiceException("çç¹åç§°ä¸è½ä¸ºç©º"); |
| | | } |
| | | List<StockInventory> inventories = stockInventoryMapper.selectList( |
| | | Wrappers.<StockInventory>lambdaQuery() |
| | | .in(productModelIds != null && !productModelIds.isEmpty(), |
| | | StockInventory::getProductModelId, |
| | | productModelIds == null ? List.of() : productModelIds)); |
| | | if (inventories.isEmpty()) { |
| | | throw new ServiceException("没æå¯çç¹çåºåè®°å½"); |
| | | } |
| | | //åä¸äº§åè§æ ¼ä¸å
è®¸åæ¶å¨ä¸¤å¼ çç¹ä¸ |
| | | List<Long> modelIds = inventories.stream().map(StockInventory::getProductModelId) |
| | | .filter(Objects::nonNull).distinct().collect(Collectors.toList()); |
| | | List<Long> pendingIds = stockCheckDetailMapper.selectList( |
| | | Wrappers.<StockCheckDetail>lambdaQuery() |
| | | .select(StockCheckDetail::getProductModelId) |
| | | .in(StockCheckDetail::getProductModelId, modelIds) |
| | | .eq(StockCheckDetail::getAdjusted, 0)) |
| | | .stream().map(StockCheckDetail::getProductModelId).distinct().collect(Collectors.toList()); |
| | | List<Long> conflictModelIds = new ArrayList<>(); |
| | | if (!pendingIds.isEmpty()) { |
| | | List<StockCheckMain> pendingMains = stockCheckMainMapper.selectList( |
| | | Wrappers.<StockCheckMain>lambdaQuery() |
| | | .select(StockCheckMain::getId) |
| | | .in(StockCheckMain::getStatus, 0)); |
| | | if (!pendingMains.isEmpty()) { |
| | | List<Long> pendingMainIds = pendingMains.stream().map(StockCheckMain::getId).collect(Collectors.toList()); |
| | | conflictModelIds = stockCheckDetailMapper.selectList( |
| | | Wrappers.<StockCheckDetail>lambdaQuery() |
| | | .select(StockCheckDetail::getProductModelId) |
| | | .in(StockCheckDetail::getMainId, pendingMainIds) |
| | | .in(StockCheckDetail::getProductModelId, pendingIds)) |
| | | .stream().map(StockCheckDetail::getProductModelId).distinct().collect(Collectors.toList()); |
| | | } |
| | | } |
| | | if (!conflictModelIds.isEmpty()) { |
| | | throw new ServiceException("以ä¸äº§åè§æ ¼åå¨çç¹ä¸çåæ®ï¼è¯·å
宿æåæ¶ï¼" + joinModels(conflictModelIds)); |
| | | } |
| | | |
| | | main.setCheckNo(generateCheckNo()); |
| | | main.setStatus(0); |
| | | if (main.getCheckDate() == null) { |
| | | main.setCheckDate(LocalDate.now()); |
| | | } |
| | | main.setTotalKinds(inventories.size()); |
| | | main.setDiffKinds(0); |
| | | stockCheckMainMapper.insert(main); |
| | | |
| | | Map<Long, ProductModel> modelMap = loadModels(inventories); |
| | | Map<Long, Product> productMap = loadProducts(modelMap.values()); |
| | | for (StockInventory inv : inventories) { |
| | | StockCheckDetail detail = new StockCheckDetail(); |
| | | detail.setMainId(main.getId()); |
| | | detail.setInventoryId(inv.getId()); |
| | | detail.setProductModelId(inv.getProductModelId()); |
| | | ProductModel pm = modelMap.get(inv.getProductModelId()); |
| | | if (pm != null) { |
| | | detail.setProductModel(pm.getModel()); |
| | | detail.setUnit(pm.getUnit()); |
| | | Product p = productMap.get(pm.getProductId()); |
| | | if (p != null) { |
| | | detail.setProductName(p.getProductName()); |
| | | } |
| | | } |
| | | detail.setBatchNo(inv.getBatchNo()); |
| | | detail.setBookQty(inv.getQualitity()); |
| | | detail.setAdjusted(0); |
| | | stockCheckDetailMapper.insert(detail); |
| | | } |
| | | return R.ok(main.getId()); |
| | | } |
| | | |
| | | @Override |
| | | public IPage<StockCheckMain> listPage(Page<StockCheckMain> page, StockCheckMain query) { |
| | | return stockCheckMainMapper.selectPage(page, Wrappers.<StockCheckMain>lambdaQuery() |
| | | .like(query.getCheckNo() != null && !query.getCheckNo().isEmpty(), |
| | | StockCheckMain::getCheckNo, query.getCheckNo()) |
| | | .like(query.getCheckName() != null && !query.getCheckName().isEmpty(), |
| | | StockCheckMain::getCheckName, query.getCheckName()) |
| | | .eq(query.getStatus() != null, StockCheckMain::getStatus, query.getStatus()) |
| | | .ge(query.getBeginTime() != null, StockCheckMain::getCreateTime, query.getBeginTime()) |
| | | .le(query.getEndTime() != null, StockCheckMain::getCreateTime, query.getEndTime()) |
| | | .orderByDesc(StockCheckMain::getId)); |
| | | } |
| | | |
| | | @Override |
| | | public StockCheckMain getMain(Long id) { |
| | | StockCheckMain main = stockCheckMainMapper.selectById(id); |
| | | if (main == null) { |
| | | throw new ServiceException("çç¹åä¸åå¨"); |
| | | } |
| | | return main; |
| | | } |
| | | |
| | | @Override |
| | | public IPage<StockCheckDetail> detailPage(Page<StockCheckDetail> page, Long mainId, Boolean onlyDiff) { |
| | | getMain(mainId); |
| | | return stockCheckDetailMapper.selectPage(page, Wrappers.<StockCheckDetail>lambdaQuery() |
| | | .eq(StockCheckDetail::getMainId, mainId) |
| | | .isNotNull(Boolean.TRUE.equals(onlyDiff), StockCheckDetail::getActualQty) |
| | | .apply(Boolean.TRUE.equals(onlyDiff), |
| | | "actual_qty is not null and ifnull(actual_qty,0) <> ifnull(book_qty,0)") |
| | | .orderByAsc(StockCheckDetail::getId)); |
| | | } |
| | | |
| | | @Override |
| | | public R entry(List<StockCheckDetail> details) { |
| | | if (details == null || details.isEmpty()) { |
| | | throw new ServiceException("è¯·ä¼ å
¥å®çæ°æ®"); |
| | | } |
| | | for (StockCheckDetail item : details) { |
| | | if (item.getId() == null || item.getActualQty() == null |
| | | || item.getActualQty().compareTo(BigDecimal.ZERO) < 0) { |
| | | throw new ServiceException("å®çæ°æ®é误ï¼idä¸å®çæ°é(>=0)å¿
ä¼ "); |
| | | } |
| | | StockCheckDetail db = stockCheckDetailMapper.selectById(item.getId()); |
| | | if (db == null) { |
| | | throw new ServiceException("çç¹æç»ä¸åå¨ï¼ID=" + item.getId()); |
| | | } |
| | | StockCheckMain main = getMain(db.getMainId()); |
| | | if (!Integer.valueOf(0).equals(main.getStatus())) { |
| | | throw new ServiceException("çç¹å[" + main.getCheckNo() + "]å·²ç»æï¼ä¸è½åå½å
¥"); |
| | | } |
| | | StockCheckDetail update = new StockCheckDetail(); |
| | | update.setId(db.getId()); |
| | | update.setActualQty(item.getActualQty()); |
| | | update.setDiffQty(item.getActualQty().subtract( |
| | | db.getBookQty() == null ? BigDecimal.ZERO : db.getBookQty())); |
| | | if (item.getRemark() != null) { |
| | | update.setRemark(item.getRemark()); |
| | | } |
| | | stockCheckDetailMapper.updateById(update); |
| | | } |
| | | return R.ok(); |
| | | } |
| | | |
| | | @Override |
| | | public R finish(Long id) { |
| | | StockCheckMain main = getMain(id); |
| | | if (!Integer.valueOf(0).equals(main.getStatus())) { |
| | | throw new ServiceException("ä»
çç¹ä¸çåæ®å¯ä»¥å®æ"); |
| | | } |
| | | List<StockCheckDetail> details = stockCheckDetailMapper.selectList( |
| | | Wrappers.<StockCheckDetail>lambdaQuery().eq(StockCheckDetail::getMainId, id)); |
| | | if (details.isEmpty()) { |
| | | throw new ServiceException("çç¹æç»ä¸ºç©º"); |
| | | } |
| | | List<StockCheckDetail> notEntered = details.stream() |
| | | .filter(d -> d.getActualQty() == null).collect(Collectors.toList()); |
| | | if (!notEntered.isEmpty()) { |
| | | throw new ServiceException("è¿æ " + notEntered.size() + " æ¡æç»æªå½å
¥å®çæ°éï¼è¯·å
彿»¡"); |
| | | } |
| | | int diffKinds = 0; |
| | | int adjusted = 0; |
| | | for (StockCheckDetail detail : details) { |
| | | BigDecimal diff = detail.getDiffQty() == null ? BigDecimal.ZERO : detail.getDiffQty(); |
| | | if (diff.compareTo(BigDecimal.ZERO) == 0) { |
| | | continue; |
| | | } |
| | | diffKinds++; |
| | | StockInventoryDto dto = new StockInventoryDto(); |
| | | dto.setRecordId(detail.getId()); |
| | | dto.setProductModelId(detail.getProductModelId()); |
| | | dto.setBatchNo(detail.getBatchNo()); |
| | | dto.setQualitity(diff.abs()); |
| | | dto.setRemark("çç¹è°è´¦ " + main.getCheckNo()); |
| | | if (diff.compareTo(BigDecimal.ZERO) > 0) { |
| | | //ççï¼å
¥åº |
| | | dto.setRecordType(StockInQualifiedRecordTypeEnum.CUSTOMIZATION_STOCK_IN.getCode()); |
| | | stockInventoryService.addStockInRecordOnly(dto); |
| | | } else { |
| | | //çäºï¼åºåºï¼è¶
å¯ç¨åºåä¼è¢«åºåºæ ¡éªæ¦æªï¼ |
| | | dto.setRecordType(StockOutQualifiedRecordTypeEnum.CUSTOMIZATION_STOCK_OUT.getCode()); |
| | | stockInventoryService.addStockOutRecordOnly(dto); |
| | | } |
| | | StockCheckDetail update = new StockCheckDetail(); |
| | | update.setId(detail.getId()); |
| | | update.setAdjusted(1); |
| | | stockCheckDetailMapper.updateById(update); |
| | | adjusted++; |
| | | } |
| | | StockCheckMain update = new StockCheckMain(); |
| | | update.setId(id); |
| | | update.setStatus(1); |
| | | update.setDiffKinds(diffKinds); |
| | | stockCheckMainMapper.updateById(update); |
| | | return R.ok("çç¹å®æï¼å·®å¼ " + diffKinds + " æ¡ï¼å·²çæè°è´¦åæ® " + adjusted |
| | | + " æ¡ï¼å¾
åºå
¥åºè®°å½å®¡æ ¸éè¿åè´¦é¢çæï¼"); |
| | | } |
| | | |
| | | @Override |
| | | public R cancel(Long id) { |
| | | StockCheckMain main = getMain(id); |
| | | if (!Integer.valueOf(0).equals(main.getStatus())) { |
| | | throw new ServiceException("ä»
çç¹ä¸çåæ®å¯ä»¥åæ¶"); |
| | | } |
| | | StockCheckMain update = new StockCheckMain(); |
| | | update.setId(id); |
| | | update.setStatus(2); |
| | | stockCheckMainMapper.updateById(update); |
| | | return R.ok(); |
| | | } |
| | | |
| | | @Override |
| | | public R delete(List<Long> ids) { |
| | | if (ids == null || ids.isEmpty()) { |
| | | throw new ServiceException("è¯·éæ©è³å°ä¸æ¡æ°æ®"); |
| | | } |
| | | stockCheckDetailMapper.delete(Wrappers.<StockCheckDetail>lambdaQuery() |
| | | .in(StockCheckDetail::getMainId, ids)); |
| | | stockCheckMainMapper.deleteBatchIds(ids); |
| | | return R.ok(); |
| | | } |
| | | |
| | | @Override |
| | | public List<StockCheckDetail> diffList(Long mainId) { |
| | | getMain(mainId); |
| | | return stockCheckDetailMapper.selectList(Wrappers.<StockCheckDetail>lambdaQuery() |
| | | .eq(StockCheckDetail::getMainId, mainId) |
| | | .isNotNull(StockCheckDetail::getActualQty) |
| | | .apply("ifnull(actual_qty,0) <> ifnull(book_qty,0)") |
| | | .orderByAsc(StockCheckDetail::getId)); |
| | | } |
| | | |
| | | @Override |
| | | public List<StockCheckMain> listForExport(StockCheckMain query) { |
| | | return stockCheckMainMapper.selectList(Wrappers.<StockCheckMain>lambdaQuery() |
| | | .like(query != null && query.getCheckNo() != null && !query.getCheckNo().isEmpty(), |
| | | StockCheckMain::getCheckNo, query == null ? null : query.getCheckNo()) |
| | | .like(query != null && query.getCheckName() != null && !query.getCheckName().isEmpty(), |
| | | StockCheckMain::getCheckName, query == null ? null : query.getCheckName()) |
| | | .eq(query != null && query.getStatus() != null, |
| | | StockCheckMain::getStatus, query == null ? null : query.getStatus()) |
| | | .orderByDesc(StockCheckMain::getId)); |
| | | } |
| | | |
| | | private String generateCheckNo() { |
| | | String prefix = "PD" + LocalDate.now().format(DateTimeFormatter.BASIC_ISO_DATE); |
| | | StockCheckMain latest = stockCheckMainMapper.selectOne(Wrappers.<StockCheckMain>lambdaQuery() |
| | | .select(StockCheckMain::getCheckNo) |
| | | .likeRight(StockCheckMain::getCheckNo, prefix) |
| | | .orderByDesc(StockCheckMain::getCheckNo) |
| | | .last("limit 1"), false); |
| | | int sequence = 1; |
| | | if (latest != null && latest.getCheckNo() != null && latest.getCheckNo().startsWith(prefix)) { |
| | | try { |
| | | sequence = Integer.parseInt(latest.getCheckNo().substring(prefix.length())) + 1; |
| | | } catch (NumberFormatException ignored) { |
| | | sequence = 1; |
| | | } |
| | | } |
| | | return prefix + String.format("%03d", sequence); |
| | | } |
| | | |
| | | private Map<Long, ProductModel> loadModels(List<StockInventory> inventories) { |
| | | List<Long> ids = inventories.stream().map(StockInventory::getProductModelId) |
| | | .filter(Objects::nonNull).distinct().collect(Collectors.toList()); |
| | | if (ids.isEmpty()) { |
| | | return new HashMap<>(); |
| | | } |
| | | return productModelMapper.selectBatchIds(ids).stream() |
| | | .collect(Collectors.toMap(ProductModel::getId, m -> m, (a, b) -> a)); |
| | | } |
| | | |
| | | private Map<Long, Product> loadProducts(java.util.Collection<ProductModel> models) { |
| | | List<Long> ids = models.stream().map(ProductModel::getProductId) |
| | | .filter(Objects::nonNull).distinct().collect(Collectors.toList()); |
| | | if (ids.isEmpty()) { |
| | | return new HashMap<>(); |
| | | } |
| | | return productMapper.selectBatchIds(ids).stream() |
| | | .collect(Collectors.toMap(Product::getId, p -> p, (a, b) -> a)); |
| | | } |
| | | |
| | | private String joinModels(List<Long> modelIds) { |
| | | Map<Long, ProductModel> modelMap = productModelMapper.selectBatchIds(modelIds).stream() |
| | | .collect(Collectors.toMap(ProductModel::getId, m -> m, (a, b) -> a)); |
| | | return modelIds.stream() |
| | | .map(id -> { |
| | | ProductModel pm = modelMap.get(id); |
| | | return pm == null || pm.getModel() == null ? String.valueOf(id) : pm.getModel(); |
| | | }) |
| | | .collect(Collectors.joining("ã")); |
| | | } |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.technology.bean.dto; |
| | | |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | |
| | | import java.math.BigDecimal; |
| | | |
| | | @Data |
| | | @Schema(description = "BOMé½å¥åæå
¥å") |
| | | public class BomKitCheckDto { |
| | | |
| | | @Schema(description = "BOM id") |
| | | private Long bomId; |
| | | |
| | | @Schema(description = "éæ±æ°éï¼ä»¥BOMæ ¹äº§å为åä½ï¼") |
| | | private BigDecimal demandQty; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.technology.bean.vo; |
| | | |
| | | import com.ruoyi.framework.aspectj.lang.annotation.Excel; |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | |
| | | import java.math.BigDecimal; |
| | | |
| | | @Data |
| | | @Schema(description = "BOMé½å¥åæè¡ç»æ") |
| | | public class BomKitCheckItemVo { |
| | | |
| | | @Schema(description = "产åè§æ ¼id") |
| | | private Long productModelId; |
| | | |
| | | @Excel(name = "产ååç§°") |
| | | @Schema(description = "产ååç§°") |
| | | private String productName; |
| | | |
| | | @Excel(name = "è§æ ¼åå·") |
| | | @Schema(description = "è§æ ¼åå·") |
| | | private String model; |
| | | |
| | | @Excel(name = "åä½") |
| | | @Schema(description = "åä½") |
| | | private String unit; |
| | | |
| | | @Excel(name = "éæ±é") |
| | | @Schema(description = "æBOMå±å¼åçéæ±æ°é") |
| | | private BigDecimal requiredQty; |
| | | |
| | | @Excel(name = "å¯ç¨åºå") |
| | | @Schema(description = "åºåæ°é-é宿°é") |
| | | private BigDecimal availableQty; |
| | | |
| | | @Excel(name = "ç¼ºå£æ°é") |
| | | @Schema(description = "éæ±é-å¯ç¨åºåï¼ä¸è¶³é¨åï¼é½å¥æ¶ä¸º0") |
| | | private BigDecimal shortageQty; |
| | | } |
| | |
| | | import com.ruoyi.framework.aspectj.lang.enums.BusinessType; |
| | | import com.ruoyi.framework.web.domain.R; |
| | | import com.ruoyi.technology.bean.dto.BomImportDto; |
| | | import com.ruoyi.technology.bean.dto.BomKitCheckDto; |
| | | import com.ruoyi.technology.bean.dto.TechnologyBomDto; |
| | | import com.ruoyi.technology.bean.vo.BomKitCheckItemVo; |
| | | import com.ruoyi.technology.bean.vo.TechnologyBomVo; |
| | | import com.ruoyi.technology.pojo.TechnologyBom; |
| | | import com.ruoyi.technology.service.TechnologyBomService; |
| | |
| | | public R copy(@RequestBody TechnologyBom technologyBom) { |
| | | return technologyBomService.copy(technologyBom); |
| | | } |
| | | |
| | | @PostMapping("/kitCheck") |
| | | @Operation(summary = "BOMé½å¥åæï¼éæ±å±å¼+åºåæ¯å¯¹ï¼") |
| | | public R<List<BomKitCheckItemVo>> kitCheck(@RequestBody BomKitCheckDto dto) { |
| | | return R.ok(technologyBomService.kitCheck(dto)); |
| | | } |
| | | |
| | | @PostMapping("/kitCheck/export") |
| | | @Log(title = "Export BOM kit check", businessType = BusinessType.EXPORT) |
| | | @Operation(summary = "BOMé½å¥åæå¯¼åºExcel") |
| | | public void exportKitCheck(HttpServletResponse response, @RequestBody BomKitCheckDto dto) { |
| | | List<BomKitCheckItemVo> list = technologyBomService.kitCheck(dto); |
| | | ExcelUtil<BomKitCheckItemVo> util = new ExcelUtil<>(BomKitCheckItemVo.class); |
| | | util.exportExcel(response, list, "BOMé½å¥åæ"); |
| | | } |
| | | |
| | | @PostMapping("/kitCheck/generateDemand") |
| | | @Log(title = "Generate procurement demand", businessType = BusinessType.INSERT) |
| | | @Operation(summary = "é½å¥ç¼ºå£çæéè´éæ±") |
| | | public R generateDemand(@RequestBody BomKitCheckDto dto) { |
| | | return technologyBomService.generateProcurementDemand(dto); |
| | | } |
| | | |
| | | @PutMapping("/changeStatus") |
| | | @Log(title = "Change BOM status", businessType = BusinessType.UPDATE) |
| | | @Operation(summary = "BOMå¯ç¨/åç¨ï¼å¯ç¨èªå¨åç¨åè§æ ¼å
¶å®çæ¬ï¼") |
| | | public R changeStatus(@RequestBody TechnologyBom technologyBom) { |
| | | return technologyBomService.changeStatus(technologyBom.getId(), technologyBom.getStatus()); |
| | | } |
| | | } |
| | |
| | | @Schema(description = "çæ¬å·") |
| | | private String version; |
| | | |
| | | @Schema(description = "ç¶æ 1å¯ç¨ 0åç¨ï¼åä¸äº§åè§æ ¼ä»
å
许ä¸ä¸ªå¯ç¨çæ¬") |
| | | private Integer status; |
| | | |
| | | @Schema(description = "å建æ¶é´") |
| | | @TableField(fill = FieldFill.INSERT) |
| | | private LocalDateTime createTime; |
| | |
| | | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
| | | import com.baomidou.mybatisplus.extension.service.IService; |
| | | import com.ruoyi.framework.web.domain.R; |
| | | import com.ruoyi.technology.bean.dto.BomKitCheckDto; |
| | | import com.ruoyi.technology.bean.dto.TechnologyBomDto; |
| | | import com.ruoyi.technology.bean.vo.BomKitCheckItemVo; |
| | | import com.ruoyi.technology.bean.vo.TechnologyBomVo; |
| | | import com.ruoyi.technology.pojo.TechnologyBom; |
| | | import jakarta.servlet.http.HttpServletResponse; |
| | |
| | | void exportBom(HttpServletResponse response, Long bomId); |
| | | |
| | | R copy(TechnologyBom technologyBom); |
| | | |
| | | /** |
| | | * BOMé½å¥åæï¼æéæ±æ°éå±å¼BOMï¼æ¯å¯¹å¯ç¨åºåï¼æ°é-éå®éï¼ï¼è¿ååç©æéæ±/å¯ç¨/ç¼ºå£ |
| | | */ |
| | | List<BomKitCheckItemVo> kitCheck(BomKitCheckDto dto); |
| | | |
| | | /** |
| | | * é½å¥ç¼ºå£çæ/ç´¯å éè´éæ±ï¼procurement_demand å¾
å¤çè®°å½ï¼ |
| | | */ |
| | | R generateProcurementDemand(BomKitCheckDto dto); |
| | | |
| | | /** |
| | | * BOMå¯ç¨/åç¨ï¼å¯ç¨æ¶èªå¨åç¨å产åè§æ ¼çå
¶å®çæ¬ |
| | | */ |
| | | R changeStatus(Integer id, Integer status); |
| | | } |
| | |
| | | import com.ruoyi.common.utils.bean.BeanUtils; |
| | | import com.ruoyi.common.utils.poi.ExcelUtil; |
| | | import com.ruoyi.framework.web.domain.R; |
| | | import com.ruoyi.procurementrecord.pojo.ProcurementDemand; |
| | | import com.ruoyi.procurementrecord.service.ProcurementDemandService; |
| | | import com.ruoyi.stock.mapper.StockInventoryMapper; |
| | | import com.ruoyi.stock.pojo.StockInventory; |
| | | import com.ruoyi.technology.bean.dto.BomImportDto; |
| | | import com.ruoyi.technology.bean.dto.BomKitCheckDto; |
| | | import com.ruoyi.technology.bean.dto.TechnologyBomDto; |
| | | import com.ruoyi.technology.bean.dto.TechnologyBomStructureDto; |
| | | import com.ruoyi.technology.bean.vo.BomKitCheckItemVo; |
| | | import com.ruoyi.technology.bean.vo.TechnologyBomStructureVo; |
| | | import com.ruoyi.technology.bean.vo.TechnologyBomVo; |
| | | import com.ruoyi.technology.mapper.TechnologyBomMapper; |
| | |
| | | private final TechnologyRoutingMapper technologyRoutingMapper; |
| | | private final IProductService productService; |
| | | private final TechnologyBomStructureMapper technologyBomStructureMapper; |
| | | private final StockInventoryMapper stockInventoryMapper; |
| | | private final ProcurementDemandService procurementDemandService; |
| | | |
| | | /** |
| | | * å页æ¥è¯¢BOMå表ã |
| | |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public R add(TechnologyBom technologyBom) { |
| | | validateProductModel(technologyBom.getProductModelId()); |
| | | if (technologyBom.getStatus() == null) { |
| | | technologyBom.setStatus(1); |
| | | } |
| | | boolean saved = technologyBomMapper.insert(technologyBom) > 0; |
| | | if (!saved) { |
| | | return R.fail("Add BOM failed"); |
| | | } |
| | | technologyBom.setBomNo("BM." + String.format("%05d", technologyBom.getId())); |
| | | technologyBomMapper.updateById(technologyBom); |
| | | if (Integer.valueOf(1).equals(technologyBom.getStatus())) { |
| | | deactivateOtherVersions(technologyBom.getProductModelId(), technologyBom.getId().longValue()); |
| | | } |
| | | initRootStructure(technologyBom.getId().longValue(), technologyBom.getProductModelId()); |
| | | return R.ok(); |
| | | } |
| | |
| | | technologyBom.setBomNo(oldBom.getBomNo()); |
| | | } |
| | | technologyBomMapper.updateById(technologyBom); |
| | | if (Integer.valueOf(1).equals(technologyBom.getStatus())) { |
| | | deactivateOtherVersions(technologyBom.getProductModelId(), technologyBom.getId().longValue()); |
| | | } |
| | | return R.ok(); |
| | | } |
| | | |
| | | /** |
| | | * åä¸äº§åè§æ ¼åªä¿çä¸ä¸ªå¯ç¨çæ¬ |
| | | */ |
| | | private void deactivateOtherVersions(Long productModelId, Long keepId) { |
| | | if (productModelId == null) { |
| | | return; |
| | | } |
| | | technologyBomMapper.update(null, Wrappers.<TechnologyBom>lambdaUpdate() |
| | | .set(TechnologyBom::getStatus, 0) |
| | | .eq(TechnologyBom::getProductModelId, productModelId) |
| | | .ne(TechnologyBom::getId, keepId) |
| | | .eq(TechnologyBom::getStatus, 1)); |
| | | } |
| | | |
| | | /** |
| | |
| | | newTechnologyBom.setProductModelId(oldTechnologyBom.getProductModelId()); |
| | | newTechnologyBom.setVersion("FZ" + oldTechnologyBom.getVersion()); |
| | | newTechnologyBom.setRemark(oldTechnologyBom.getRemark()); |
| | | newTechnologyBom.setStatus(0); |
| | | boolean saved = technologyBomMapper.insert(newTechnologyBom) > 0; |
| | | if (!saved) { |
| | | return R.fail("Copy BOM failed"); |
| | |
| | | long randomNum = ThreadLocalRandom.current().nextLong(min, max + 1); |
| | | return String.valueOf(randomNum); |
| | | } |
| | | |
| | | /** |
| | | * BOMé½å¥åæï¼éå±å±å¼æ ï¼éæ±é=ç¶éæ±Ãåä½ç¨éï¼ï¼æè§æ ¼æ±æ»åä¸å¯ç¨åºåæ¯å¯¹ã |
| | | * å¯ç¨åºå = Σ(åºåæ°é - é宿°é)ï¼ç¼ºå£ = max(éæ±é - å¯ç¨åºå, 0)ã |
| | | */ |
| | | @Override |
| | | public List<BomKitCheckItemVo> kitCheck(BomKitCheckDto dto) { |
| | | if (dto == null || dto.getBomId() == null || dto.getDemandQty() == null |
| | | || dto.getDemandQty().compareTo(BigDecimal.ZERO) <= 0) { |
| | | throw new ServiceException("è¯·ä¼ å
¥bomIdåéæ±æ°é(须大äº0)"); |
| | | } |
| | | TechnologyBom bom = technologyBomMapper.selectById(dto.getBomId()); |
| | | if (bom == null) { |
| | | throw new ServiceException("BOMä¸åå¨"); |
| | | } |
| | | List<TechnologyBomStructureVo> roots = technologyBomStructureService.listByBomId(dto.getBomId()); |
| | | if (CollUtil.isEmpty(roots)) { |
| | | throw new ServiceException("BOMç»æä¸ºç©ºï¼è¯·å
ç»´æ¤ç©ææ¸
å"); |
| | | } |
| | | |
| | | Map<Long, BigDecimal> requiredMap = new LinkedHashMap<>(); |
| | | for (TechnologyBomStructureVo root : roots) { |
| | | expandRequirements(root, dto.getDemandQty(), requiredMap, true); |
| | | } |
| | | if (requiredMap.isEmpty()) { |
| | | throw new ServiceException("BOM䏿 ç©æèç¹"); |
| | | } |
| | | |
| | | Map<Long, BigDecimal> availMap = new HashMap<>(); |
| | | List<StockInventory> stocks = stockInventoryMapper.selectList(Wrappers.<StockInventory>lambdaQuery() |
| | | .in(StockInventory::getProductModelId, requiredMap.keySet())); |
| | | for (StockInventory s : stocks) { |
| | | BigDecimal avail = s.getQualitity() == null ? BigDecimal.ZERO : s.getQualitity(); |
| | | avail = avail.subtract(s.getLockedQuantity() == null ? BigDecimal.ZERO : s.getLockedQuantity()); |
| | | availMap.merge(s.getProductModelId(), avail, BigDecimal::add); |
| | | } |
| | | |
| | | List<ProductModel> models = productModelService.listByIds(requiredMap.keySet()); |
| | | Map<Long, ProductModel> modelMap = models.stream() |
| | | .collect(Collectors.toMap(ProductModel::getId, m -> m, (a, b) -> a)); |
| | | Map<Long, String> productNameMap = new HashMap<>(); |
| | | Set<Long> productIds = models.stream().map(ProductModel::getProductId) |
| | | .filter(Objects::nonNull).collect(Collectors.toSet()); |
| | | if (!productIds.isEmpty()) { |
| | | productService.listByIds(productIds) |
| | | .forEach(p -> productNameMap.put(p.getId().longValue(), p.getProductName())); |
| | | } |
| | | |
| | | List<BomKitCheckItemVo> result = new ArrayList<>(); |
| | | for (Map.Entry<Long, BigDecimal> entry : requiredMap.entrySet()) { |
| | | BigDecimal required = entry.getValue(); |
| | | BigDecimal available = availMap.getOrDefault(entry.getKey(), BigDecimal.ZERO); |
| | | ProductModel pm = modelMap.get(entry.getKey()); |
| | | BomKitCheckItemVo vo = new BomKitCheckItemVo(); |
| | | vo.setProductModelId(entry.getKey()); |
| | | vo.setProductName(pm == null ? null : productNameMap.get(pm.getProductId())); |
| | | vo.setModel(pm == null ? null : pm.getModel()); |
| | | vo.setUnit(pm == null ? null : pm.getUnit()); |
| | | vo.setRequiredQty(required); |
| | | vo.setAvailableQty(available); |
| | | vo.setShortageQty(required.subtract(available).max(BigDecimal.ZERO)); |
| | | result.add(vo); |
| | | } |
| | | result.sort(Comparator.comparing(BomKitCheckItemVo::getShortageQty).reversed()); |
| | | return result; |
| | | } |
| | | |
| | | private void expandRequirements(TechnologyBomStructureVo node, BigDecimal requiredQty, |
| | | Map<Long, BigDecimal> requiredMap, boolean isRoot) { |
| | | if (!isRoot && node.getProductModelId() != null) { |
| | | requiredMap.merge(node.getProductModelId(), requiredQty, BigDecimal::add); |
| | | } |
| | | if (CollUtil.isNotEmpty(node.getChildren())) { |
| | | for (TechnologyBomStructureVo child : node.getChildren()) { |
| | | BigDecimal unitQty = child.getUnitQuantity() == null ? BigDecimal.ZERO : child.getUnitQuantity(); |
| | | expandRequirements(child, requiredQty.multiply(unitQty), requiredMap, false); |
| | | } |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * å°ç¼ºå£ç©æåå
¥éè´éæ±ï¼åè§æ ¼å·²åå¨å¾
å¤çè®°å½åç´¯å 缺å£ï¼å¦åæ°å¢ã |
| | | */ |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public R generateProcurementDemand(BomKitCheckDto dto) { |
| | | List<BomKitCheckItemVo> items = kitCheck(dto); |
| | | List<BomKitCheckItemVo> shortages = items.stream() |
| | | .filter(item -> item.getShortageQty().compareTo(BigDecimal.ZERO) > 0) |
| | | .collect(Collectors.toList()); |
| | | if (shortages.isEmpty()) { |
| | | return R.ok("åºåé½å¥ï¼æ éçæéè´éæ±"); |
| | | } |
| | | TechnologyBom bom = technologyBomMapper.selectById(dto.getBomId()); |
| | | int created = 0; |
| | | int merged = 0; |
| | | for (BomKitCheckItemVo item : shortages) { |
| | | ProcurementDemand exist = procurementDemandService.getOne(Wrappers.<ProcurementDemand>lambdaQuery() |
| | | .eq(ProcurementDemand::getProductModelId, item.getProductModelId()) |
| | | .eq(ProcurementDemand::getStatus, 0) |
| | | .last("limit 1")); |
| | | if (exist != null) { |
| | | exist.setDemandQuantity(exist.getDemandQuantity().add(item.getShortageQty())); |
| | | exist.setStockQuantity(item.getAvailableQty()); |
| | | exist.setSourceBomId(dto.getBomId()); |
| | | exist.setSourceBomNo(bom == null ? null : bom.getBomNo()); |
| | | procurementDemandService.updateById(exist); |
| | | merged++; |
| | | } else { |
| | | ProcurementDemand demand = new ProcurementDemand(); |
| | | demand.setProductModelId(item.getProductModelId()); |
| | | demand.setProductName(item.getProductName()); |
| | | demand.setProductModel(item.getModel()); |
| | | demand.setUnit(item.getUnit()); |
| | | demand.setDemandQuantity(item.getShortageQty()); |
| | | demand.setStockQuantity(item.getAvailableQty()); |
| | | demand.setSourceBomId(dto.getBomId()); |
| | | demand.setSourceBomNo(bom == null ? null : bom.getBomNo()); |
| | | demand.setStatus(0); |
| | | procurementDemandService.save(demand); |
| | | created++; |
| | | } |
| | | } |
| | | return R.ok(String.format("éè´éæ±çæå®æï¼æ°å¢ %d æ¡ï¼ç´¯å åå¹¶ %d æ¡", created, merged)); |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public R changeStatus(Integer id, Integer status) { |
| | | if (id == null || status == null || (status != 0 && status != 1)) { |
| | | return R.fail("åæ°é误ï¼éä¼ å
¥idåç¶æ(1å¯ç¨/0åç¨)"); |
| | | } |
| | | TechnologyBom bom = technologyBomMapper.selectById(id); |
| | | if (bom == null) { |
| | | return R.fail("BOMä¸åå¨"); |
| | | } |
| | | TechnologyBom update = new TechnologyBom(); |
| | | update.setId(id); |
| | | update.setStatus(status); |
| | | technologyBomMapper.updateById(update); |
| | | if (Integer.valueOf(1).equals(status)) { |
| | | deactivateOtherVersions(bom.getProductModelId(), id.longValue()); |
| | | } |
| | | return R.ok(); |
| | | } |
| | | } |
| | |
| | | druid: |
| | | # ä¸»åºæ°æ®æº |
| | | master: |
| | | url: jdbc:mysql://localhost:3306/product-inventory-management-bdpro?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 |
| | | url: jdbc:mysql://localhost:3306/product-inventory-management-qysj?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 |
| | | username: root |
| | | password: 123456 |
| | | # ä»åºæ°æ®æº |
| | |
| | | <result column="tenant_id" property="tenantId" /> |
| | | <result column="product_name" property="productName" /> |
| | | <result column="product_id" property="productId" /> |
| | | <result column="product_code" property="productCode" /> |
| | | <result column="barcode" property="barcode" /> |
| | | </resultMap> |
| | | |
| | | <resultMap id="ProductModelVoResultMap" type="com.ruoyi.basic.vo.ProductModelVo" extends="BaseResultMap"> |
| | |
| | | <if test="c.model != null and c.model != ''"> |
| | | and pm.model like concat('%',#{c.model},'%') |
| | | </if> |
| | | <if test="c.barcode != null and c.barcode != ''"> |
| | | and pm.barcode like concat('%',#{c.barcode},'%') |
| | | </if> |
| | | <if test="c.productName != null and c.productName != ''"> |
| | | and p.product_name like concat('%',#{c.productName},'%') |
| | | </if> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <?xml version="1.0" encoding="UTF-8"?> |
| | | <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> |
| | | <mapper namespace="com.ruoyi.cost.mapper.CostAccountingMapper"> |
| | | |
| | | <!-- ç»ä¸ç订åç鿡件ï¼po=ç产订åï¼pm/p=订åæåè§æ ¼/产å |
| | | è®¢åæ¥æå create_timeï¼å岿°æ®æªåå¡«æ¶åé start_timeï¼é¿å
çé丢å --> |
| | | <sql id="orderFilter"> |
| | | <if test="startDate != null">and date(coalesce(po.create_time, po.start_time)) >= #{startDate}</if> |
| | | <if test="endDate != null">and date(coalesce(po.create_time, po.start_time)) <= #{endDate}</if> |
| | | <if test="npsNo != null and npsNo != ''">and po.nps_no like concat('%', #{npsNo}, '%')</if> |
| | | <if test="productName != null and productName != ''"> |
| | | and (p.product_name like concat('%', #{productName}, '%') |
| | | or pm.model like concat('%', #{productName}, '%')) |
| | | </if> |
| | | </sql> |
| | | |
| | | <select id="listOrders" resultType="com.ruoyi.cost.bean.vo.CostOrderVo"> |
| | | select po.id as productionOrderId, |
| | | po.nps_no as npsNo, |
| | | po.product_model_id as productModelId, |
| | | concat(ifnull(p.product_name, ''), '/', ifnull(pm.model, '')) as finishedProduct, |
| | | ifnull(p.product_name, '') as productName, |
| | | ifnull(pm.model, '') as productModel, |
| | | pm.unit as unit, |
| | | ifnull(po.complete_quantity, 0) as completeQty, |
| | | ifnull(po.quantity, 0) as planQty, |
| | | coalesce(po.create_time, po.start_time) as createTime |
| | | from production_order po |
| | | left join product_model pm on pm.id = po.product_model_id |
| | | left join product p on p.id = pm.product_id |
| | | <where> |
| | | <include refid="orderFilter"/> |
| | | </where> |
| | | order by po.id desc |
| | | </select> |
| | | |
| | | <select id="listMaterialInputs" resultType="com.ruoyi.cost.bean.vo.CostMaterialInputVo"> |
| | | select pot.production_order_id as productionOrderId, |
| | | ppi.product_model_id as productModelId, |
| | | sum(ifnull(ppi.input_quantity, 0)) as inputQty |
| | | from production_product_input ppi |
| | | join production_product_main ppm on ppm.id = ppi.production_product_main_id |
| | | join production_operation_task pot on pot.id = ppm.production_operation_task_id |
| | | join production_order po on po.id = pot.production_order_id |
| | | left join product_model pm on pm.id = po.product_model_id |
| | | left join product p on p.id = pm.product_id |
| | | <where> |
| | | and ppi.product_model_id is not null |
| | | <include refid="orderFilter"/> |
| | | </where> |
| | | group by pot.production_order_id, ppi.product_model_id |
| | | </select> |
| | | |
| | | <select id="listConsumedMaterials" resultType="com.ruoyi.cost.bean.vo.CostMissingPriceVo"> |
| | | select ppi.product_model_id as productModelId, |
| | | ifnull(pmat.product_name, '') as materialName, |
| | | ifnull(pmm.model, '') as materialModel, |
| | | pmm.unit as unit, |
| | | sum(ifnull(ppi.input_quantity, 0)) as inputQty, |
| | | count(distinct pot.production_order_id) as orderCount, |
| | | max(ppi.create_time) as lastInputTime |
| | | from production_product_input ppi |
| | | join production_product_main ppm on ppm.id = ppi.production_product_main_id |
| | | join production_operation_task pot on pot.id = ppm.production_operation_task_id |
| | | join production_order po on po.id = pot.production_order_id |
| | | left join product_model pm on pm.id = po.product_model_id |
| | | left join product p on p.id = pm.product_id |
| | | left join product_model pmm on pmm.id = ppi.product_model_id |
| | | left join product pmat on pmat.id = pmm.product_id |
| | | <where> |
| | | and ppi.product_model_id is not null |
| | | <include refid="orderFilter"/> |
| | | </where> |
| | | group by ppi.product_model_id, pmat.product_name, pmm.model, pmm.unit |
| | | order by inputQty desc |
| | | </select> |
| | | |
| | | <!-- ç©æåä»·æ¥æºï¼priority è¶å°è¶ä¼å
ï¼ä»·ç®è¡¨ > éè´æç» > éè´å
¥åºè®°å½ > å票ç»è®° --> |
| | | <select id="listMaterialPrices" resultType="com.ruoyi.cost.bean.vo.CostMaterialPriceVo"> |
| | | select pm.id as productModelId, |
| | | ppm_price.base_price as price, |
| | | 'éè´ä»·ç®è¡¨' as priceSource, |
| | | 1 as priority |
| | | from procurement_price_management ppm_price |
| | | join product_model pm on pm.product_code = ppm_price.product_code |
| | | join (select product_code, max(id) as mid |
| | | from procurement_price_management |
| | | group by product_code) latest on latest.mid = ppm_price.id |
| | | where ppm_price.product_code is not null and ppm_price.product_code <> '' |
| | | and ifnull(ppm_price.base_price, 0) > 0 |
| | | union all |
| | | select slp.product_model_id, |
| | | slp.tax_inclusive_unit_price, |
| | | 'éè´æç»', |
| | | 2 |
| | | from sales_ledger_product slp |
| | | join (select product_model_id, max(id) as mid |
| | | from sales_ledger_product |
| | | where type = 2 and product_model_id is not null |
| | | group by product_model_id) latest on latest.mid = slp.id |
| | | where ifnull(slp.tax_inclusive_unit_price, 0) > 0 |
| | | union all |
| | | select prs.product_model_id, |
| | | prs.unit_price, |
| | | 'éè´å
¥åºè®°å½', |
| | | 3 |
| | | from procurement_record_storage prs |
| | | join (select product_model_id, max(id) as mid |
| | | from procurement_record_storage |
| | | where product_model_id is not null |
| | | group by product_model_id) latest on latest.mid = prs.id |
| | | where ifnull(prs.unit_price, 0) > 0 |
| | | union all |
| | | select rec.product_model_id, |
| | | rec.tax_inclusive_unit_price, |
| | | 'éè´å票ç»è®°', |
| | | 4 |
| | | from product_record rec |
| | | join (select product_model_id, max(id) as mid |
| | | from product_record |
| | | where product_model_id is not null |
| | | group by product_model_id) latest on latest.mid = rec.id |
| | | where ifnull(rec.tax_inclusive_unit_price, 0) > 0 |
| | | order by productModelId, priority |
| | | </select> |
| | | |
| | | <select id="listLaborCosts" resultType="com.ruoyi.cost.bean.vo.CostLaborVo"> |
| | | select pot.production_order_id as productionOrderId, |
| | | count(*) as accountRows, |
| | | sum(cast( |
| | | case |
| | | when prc.unit_price is not null |
| | | then ifnull(pa.finished_num, 0) * prc.unit_price |
| | | when poro.type = 0 |
| | | then ifnull(pa.work_hours, 0) * ifnull(ppm.work_hour, 0) |
| | | else ifnull(pa.work_hours, 0) * ifnull(pa.finished_num, 0) |
| | | * ifnull(cast(nullif(substring_index(pm.model, '*', -1), pm.model) as decimal(18, 4)), 0) |
| | | end as decimal(18, 2))) as laborCost, |
| | | sum(case when prc.unit_price is null and ifnull(pa.work_hours, 0) = 0 then 1 else 0 end) as noRateRows |
| | | from production_account pa |
| | | join production_product_main ppm on ppm.id = pa.production_product_main_id |
| | | join production_operation_task pot on pot.id = ppm.production_operation_task_id |
| | | join production_order po on po.id = pot.production_order_id |
| | | left join production_order_routing_operation poro on poro.id = pot.production_order_routing_operation_id |
| | | left join product_model pm on pm.id = po.product_model_id |
| | | left join product p on p.id = pm.product_id |
| | | left join piece_rate_config prc |
| | | on prc.product_model_id = pm.id |
| | | and prc.operation_name = pa.technology_operation_name |
| | | and prc.status = 1 |
| | | <where> |
| | | <include refid="orderFilter"/> |
| | | </where> |
| | | group by pot.production_order_id |
| | | </select> |
| | | |
| | | <select id="listSalePrices" resultType="com.ruoyi.cost.bean.vo.CostSalePriceVo"> |
| | | select po.id as productionOrderId, |
| | | slp.tax_inclusive_unit_price as salePrice |
| | | from production_order po |
| | | join production_plan pp |
| | | on find_in_set(pp.id, replace(replace(replace(po.production_plan_ids, '[', ''), ']', ''), ' ', '')) > 0 |
| | | join sales_ledger_product slp |
| | | on slp.sales_ledger_id = pp.sales_ledger_id |
| | | and slp.product_model_id = po.product_model_id |
| | | and slp.type = 1 |
| | | left join product_model pm on pm.id = po.product_model_id |
| | | left join product p on p.id = pm.product_id |
| | | <where> |
| | | <include refid="orderFilter"/> |
| | | </where> |
| | | order by po.id, slp.id desc |
| | | </select> |
| | | |
| | | <select id="sumEnergyCost" resultType="com.ruoyi.cost.bean.vo.CostEnergyVo"> |
| | | select ifnull(sum(ifnull(eec.sum_num, 0)), 0) as kwh, |
| | | ifnull(sum(ifnull(eec.sum_num, 0) * ifnull(ep.price, 0)), 0) as energyCost |
| | | from equipment_energy_consumption eec |
| | | left join energy_period ep on ep.date = eec.run_date |
| | | <where> |
| | | <if test="startDate != null">and eec.run_date >= #{startDate}</if> |
| | | <if test="endDate != null">and eec.run_date <= #{endDate}</if> |
| | | </where> |
| | | </select> |
| | | </mapper> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <?xml version="1.0" encoding="UTF-8"?> |
| | | <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> |
| | | <mapper namespace="com.ruoyi.production.mapper.MaterialConsumptionMapper"> |
| | | |
| | | <select id="listOrders" resultType="com.ruoyi.production.bean.vo.MaterialConsumptionOrderVo"> |
| | | select po.id as productionOrderId, |
| | | po.nps_no as npsNo, |
| | | po.product_model_id as productModelId, |
| | | concat(ifnull(p.product_name, ''), '/', ifnull(pm.model, '')) as finishedProduct, |
| | | ifnull(po.complete_quantity, 0) as completeQty, |
| | | ifnull(po.quantity, 0) as planQty |
| | | from production_order po |
| | | left join product_model pm on pm.id = po.product_model_id |
| | | left join product p on p.id = pm.product_id |
| | | <where> |
| | | <!-- è®¢åæ¥æå create_timeï¼å岿°æ®æªåå¡«æ¶åé start_timeï¼é¿å
çé丢å --> |
| | | <if test="startDate != null">and date(coalesce(po.create_time, po.start_time)) >= #{startDate}</if> |
| | | <if test="endDate != null">and date(coalesce(po.create_time, po.start_time)) <= #{endDate}</if> |
| | | <if test="npsNo != null and npsNo != ''">and po.nps_no like concat('%', #{npsNo}, '%')</if> |
| | | <if test="productName != null and productName != ''"> |
| | | and (p.product_name like concat('%', #{productName}, '%') |
| | | or pm.model like concat('%', #{productName}, '%')) |
| | | </if> |
| | | </where> |
| | | order by po.id desc |
| | | </select> |
| | | |
| | | <select id="listStructures" resultType="com.ruoyi.production.bean.vo.MaterialConsumptionStructureVo"> |
| | | select pbs.production_order_id as productionOrderId, |
| | | pbs.id as id, |
| | | pbs.parent_id as parentId, |
| | | pbs.product_model_id as productModelId, |
| | | ifnull(pbs.unit_quantity, 0) as unitQuantity |
| | | from production_bom_structure pbs |
| | | where pbs.production_order_id in |
| | | <foreach collection="orderIds" item="id" open="(" separator="," close=")">#{id}</foreach> |
| | | order by pbs.id |
| | | </select> |
| | | |
| | | <select id="listActualInputs" resultType="com.ruoyi.production.bean.vo.MaterialConsumptionActualVo"> |
| | | select pot.production_order_id as productionOrderId, |
| | | ppi.product_model_id as productModelId, |
| | | sum(ifnull(ppi.input_quantity, 0)) as actualQty |
| | | from production_product_input ppi |
| | | join production_product_main ppm on ppm.id = ppi.production_product_main_id |
| | | join production_operation_task pot on pot.id = ppm.production_operation_task_id |
| | | where pot.production_order_id in |
| | | <foreach collection="orderIds" item="id" open="(" separator="," close=")">#{id}</foreach> |
| | | group by pot.production_order_id, ppi.product_model_id |
| | | </select> |
| | | </mapper> |
| | |
| | | <if test="c.productMainId != null"> |
| | | and ppm.id = #{c.productMainId} |
| | | </if> |
| | | <if test="c.deviceId != null"> |
| | | and ppm.device_id = #{c.deviceId} |
| | | </if> |
| | | <if test="c.deviceName != null and c.deviceName != ''"> |
| | | and ppm.device_name like concat('%', #{c.deviceName}, '%') |
| | | </if> |
| | | </where> |
| | | order by pot.work_order_no desc, poro.drag_sort, ppm.product_no desc |
| | | </select> |
| | | |
| | | <select id="wageSummary" resultType="com.ruoyi.production.bean.vo.PieceWageSummaryVo"> |
| | | select pa.scheduling_user_id as userId, |
| | | pa.scheduling_user_name as userName, |
| | | count(distinct pa.production_product_main_id) as workCount, |
| | | sum(ifnull(pa.finished_num, 0)) as quantity, |
| | | sum(ifnull(ppm.work_hour, 0)) as workHour, |
| | | sum(cast(ifnull(prc.unit_price, 0) * ifnull(pa.finished_num, 0) as decimal(18, 2))) as pieceWage, |
| | | sum( |
| | | case |
| | | when prc.unit_price is not null |
| | | then cast(ifnull(pa.finished_num, 0) * prc.unit_price as decimal(18, 2)) |
| | | when poro.type = 0 |
| | | then cast(ifnull(pa.work_hours, 0) * ifnull(ppm.work_hour, 0) as decimal(18, 2)) |
| | | else cast(ifnull(pa.work_hours, 0) * ifnull(pa.finished_num, 0) * |
| | | case |
| | | when substring_index(pm.model, '*', -1) regexp '^[0-9]+(\\.[0-9]+)?$' |
| | | then cast(substring_index(pm.model, '*', -1) as decimal(18, 4)) |
| | | else 1 |
| | | end as decimal(18, 2)) |
| | | end |
| | | ) as wages |
| | | from production_account pa |
| | | join production_product_main ppm on ppm.id = pa.production_product_main_id |
| | | left join production_operation_task pot on ppm.production_operation_task_id = pot.id |
| | | left join production_order po on pot.production_order_id = po.id |
| | | left join production_order_routing_operation poro on pot.production_order_routing_operation_id = poro.id |
| | | left join product_model pm on pm.id = ifnull(poro.product_model_id, po.product_model_id) |
| | | left join piece_rate_config prc on prc.product_model_id = pm.id |
| | | and prc.operation_name = pa.technology_operation_name |
| | | and prc.status = 1 |
| | | <where> |
| | | <if test="startDate != null">and date(pa.scheduling_date) >= #{startDate}</if> |
| | | <if test="endDate != null">and date(pa.scheduling_date) <= #{endDate}</if> |
| | | <if test="userName != null and userName != ''">and pa.scheduling_user_name like concat('%', #{userName}, '%')</if> |
| | | </where> |
| | | group by pa.scheduling_user_id, pa.scheduling_user_name |
| | | order by wages desc |
| | | </select> |
| | | |
| | | <!-- å·¥æ¶/æ¥åºæ¯æ¥å·¥å级æ éï¼ä¸åå¤å·¥åºæ¶ç´æ¥ sum ä¼è¢«è¡æ°æ¾å¤§ï¼æ
ç¨ rn=1 åªå¨å
¶é¦éå·¥åºè¡è®¡å
¥ --> |
| | | <select id="outputStat" resultType="com.ruoyi.production.bean.vo.DeviceOutputStatVo"> |
| | | select |
| | | t.groupName, |
| | | <if test="dimension == 'device'">t.groupId,</if> |
| | | count(distinct t.ppmId) as workCount, |
| | | sum(ifnull(t.finishedNum, 0)) as quantity, |
| | | sum(case when t.rn = 1 then ifnull(t.scrapQty, 0) else 0 end) as scrapQty, |
| | | sum(case when t.rn = 1 then ifnull(t.workHour, 0) else 0 end) as workHour |
| | | from ( |
| | | select |
| | | <choose> |
| | | <when test="dimension == 'operation'">pa.technology_operation_name</when> |
| | | <when test="dimension == 'product'">concat(ifnull(p.product_name, ''), '/', ifnull(pm.model, ''))</when> |
| | | <otherwise>ifnull(ppm.device_name, 'æªæå®è®¾å¤')</otherwise> |
| | | </choose> |
| | | as groupName, |
| | | ppm.device_id as groupId, |
| | | ppm.id as ppmId, |
| | | pa.finished_num as finishedNum, |
| | | ppm.work_hour as workHour, |
| | | ppo.scrap_qty as scrapQty, |
| | | row_number() over (partition by ppm.id order by pa.id) as rn |
| | | from production_account pa |
| | | join production_product_main ppm on ppm.id = pa.production_product_main_id |
| | | left join production_operation_task pot on ppm.production_operation_task_id = pot.id |
| | | left join production_order po on pot.production_order_id = po.id |
| | | left join production_order_routing_operation poro on pot.production_order_routing_operation_id = poro.id |
| | | left join product_model pm on pm.id = ifnull(poro.product_model_id, po.product_model_id) |
| | | left join product p on pm.product_id = p.id |
| | | left join ( |
| | | select production_product_main_id, sum(ifnull(scrap_qty, 0)) as scrap_qty |
| | | from production_product_output |
| | | group by production_product_main_id |
| | | ) ppo on ppo.production_product_main_id = ppm.id |
| | | <where> |
| | | <if test="startDate != null">and date(pa.scheduling_date) >= #{startDate}</if> |
| | | <if test="endDate != null">and date(pa.scheduling_date) <= #{endDate}</if> |
| | | <if test="deviceId != null">and ppm.device_id = #{deviceId}</if> |
| | | </where> |
| | | ) t |
| | | group by t.groupName |
| | | <if test="dimension == 'device'">, t.groupId</if> |
| | | order by quantity desc |
| | | </select> |
| | | |
| | | <select id="getOrderByMainId" resultType="com.ruoyi.production.pojo.ProductionOrder"> |
| | |
| | | cast(ifnull(pa.work_hours, 0) as decimal(18,4)) as workHours, |
| | | cast( |
| | | case |
| | | when prc.unit_price is not null then ifnull(pa.finished_num, 0) * prc.unit_price |
| | | when poro.type = 0 then ifnull(pa.work_hours, 0) * ifnull(ppm.work_hour, 0) |
| | | else ifnull(pa.work_hours, 0) * ifnull(pa.finished_num, 0) * |
| | | case |
| | |
| | | end |
| | | end |
| | | as decimal(18,4) |
| | | ) as wages |
| | | ) as wages, |
| | | case when prc.unit_price is not null then '计件' else '计æ¶' end as wageMode, |
| | | ppm.device_id as deviceId, |
| | | ppm.device_name as deviceName |
| | | from production_account pa |
| | | left join production_product_main ppm on ppm.id = pa.production_product_main_id |
| | | left join production_operation_task pot on ppm.production_operation_task_id = pot.id |
| | |
| | | left join product p on pm.product_id = p.id |
| | | left join product p_parent on p_parent.id = p.parent_id |
| | | left join production_product_output ppo on ppo.production_product_main_id = ppm.id |
| | | left join piece_rate_config prc on prc.product_model_id = pm.id |
| | | and prc.operation_name = pa.technology_operation_name |
| | | and prc.status = 1 |
| | | <where> |
| | | <if test="c != null"> |
| | | <if test="c.productCategory != null and c.productCategory != ''"> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <?xml version="1.0" encoding="UTF-8"?> |
| | | <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> |
| | | <mapper namespace="com.ruoyi.quality.mapper.QualityTraceMapper"> |
| | | |
| | | <!-- æ¥å·¥èç¹å
Œ
±åï¼æ¥å·¥åâå·¥åâç产订åâæå --> |
| | | <sql id="reportColumns"> |
| | | ppm.id as productMainId, |
| | | pot.production_order_id as productionOrderId, |
| | | po.nps_no as npsNo, |
| | | concat(ifnull(p.product_name, ''), '/', ifnull(pmf.model, '')) as finishedProduct, |
| | | pmf.unit as unit, |
| | | ifnull(po.quantity, 0) as planQty, |
| | | ifnull(po.complete_quantity, 0) as completeQty, |
| | | po.status as orderStatus, |
| | | coalesce(po.create_time, po.start_time) as orderCreateTime, |
| | | pot.work_order_no as workOrderNo, |
| | | poro.operation_name as operationName, |
| | | ppm.user_name as userName, |
| | | ppm.device_name as deviceName, |
| | | ifnull(ppo.quantity, 0) as outputQty, |
| | | ifnull(ppo.scrap_qty, 0) as scrapQty, |
| | | ppm.product_no as productNo, |
| | | ppm.create_time as reportTime |
| | | </sql> |
| | | |
| | | <sql id="reportJoins"> |
| | | from production_product_main ppm |
| | | join production_operation_task pot on pot.id = ppm.production_operation_task_id |
| | | join production_order po on po.id = pot.production_order_id |
| | | left join production_order_routing_operation poro on poro.id = pot.production_order_routing_operation_id |
| | | left join product_model pmf on pmf.id = po.product_model_id |
| | | left join product p on p.id = pmf.product_id |
| | | left join production_product_output ppo on ppo.production_product_main_id = ppm.id |
| | | </sql> |
| | | |
| | | <select id="listInboundByFinishedBatch" resultType="com.ruoyi.quality.dto.QualityTraceFinishedBatchVo"> |
| | | select x.productionOrderId, x.productMainId, x.batchNo, x.productModelId, x.qty, x.inTime, x.recordType |
| | | from ( |
| | | select pot.production_order_id as productionOrderId, |
| | | sir.record_id as productMainId, |
| | | sir.batch_no as batchNo, |
| | | sir.product_model_id as productModelId, |
| | | ifnull(sir.stock_in_num, 0) as qty, |
| | | sir.create_time as inTime, |
| | | sir.record_type as recordType |
| | | from stock_in_record sir |
| | | join production_product_main ppm on ppm.id = sir.record_id |
| | | join production_operation_task pot on pot.id = ppm.production_operation_task_id |
| | | where sir.batch_no = #{batchNo} and sir.record_type = '2' |
| | | union all |
| | | select pot.production_order_id, |
| | | qi.product_main_id, |
| | | sir.batch_no, |
| | | sir.product_model_id, |
| | | ifnull(sir.stock_in_num, 0), |
| | | sir.create_time, |
| | | sir.record_type |
| | | from stock_in_record sir |
| | | join quality_inspect qi on qi.id = sir.record_id |
| | | join production_product_main ppm on ppm.id = qi.product_main_id |
| | | join production_operation_task pot on pot.id = ppm.production_operation_task_id |
| | | where sir.batch_no = #{batchNo} and sir.record_type = '6' |
| | | ) x |
| | | order by x.productionOrderId, x.inTime |
| | | </select> |
| | | |
| | | <select id="listReportsByMainIds" resultType="com.ruoyi.quality.dto.QualityTraceReportVo"> |
| | | select <include refid="reportColumns"/> |
| | | <include refid="reportJoins"/> |
| | | where ppm.id in |
| | | <foreach collection="ids" item="id" open="(" separator="," close=")">#{id}</foreach> |
| | | order by pot.production_order_id, poro.drag_sort, ppm.id |
| | | </select> |
| | | |
| | | <select id="listReportsByOrderIds" resultType="com.ruoyi.quality.dto.QualityTraceReportVo"> |
| | | select <include refid="reportColumns"/> |
| | | <include refid="reportJoins"/> |
| | | where pot.production_order_id in |
| | | <foreach collection="ids" item="id" open="(" separator="," close=")">#{id}</foreach> |
| | | order by pot.production_order_id, poro.drag_sort, ppm.id |
| | | </select> |
| | | |
| | | <select id="listInputsByMainIds" resultType="com.ruoyi.quality.dto.QualityTraceInputVo"> |
| | | select ppi.production_product_main_id as productMainId, |
| | | ppi.product_model_id as productModelId, |
| | | ifnull(p.product_name, '') as materialName, |
| | | ifnull(pm.model, '') as materialModel, |
| | | pm.unit as unit, |
| | | ifnull(ppi.input_quantity, 0) as inputQty, |
| | | pot.work_order_no as workOrderNo, |
| | | poro.operation_name as operationName |
| | | from production_product_input ppi |
| | | join production_product_main ppm on ppm.id = ppi.production_product_main_id |
| | | join production_operation_task pot on pot.id = ppm.production_operation_task_id |
| | | left join production_order_routing_operation poro on poro.id = pot.production_order_routing_operation_id |
| | | join product_model pm on pm.id = ppi.product_model_id |
| | | left join product p on p.id = pm.product_id |
| | | where ppi.production_product_main_id in |
| | | <foreach collection="ids" item="id" open="(" separator="," close=")">#{id}</foreach> |
| | | order by ppi.production_product_main_id, ppi.id |
| | | </select> |
| | | |
| | | <sql id="pickColumns"> |
| | | pop.production_order_id as productionOrderId, |
| | | pop.product_model_id as productModelId, |
| | | ifnull(p.product_name, '') as materialName, |
| | | ifnull(pm.model, '') as materialModel, |
| | | pm.unit as unit, |
| | | pop.batch_no as batchNo, |
| | | ifnull(pop.quantity, 0) as quantity, |
| | | pop.operation_name as operationName, |
| | | pop.create_time as pickTime |
| | | </sql> |
| | | |
| | | <select id="listPicksByOrderIds" resultType="com.ruoyi.quality.dto.QualityTracePickVo"> |
| | | select <include refid="pickColumns"/> |
| | | from production_order_pick pop |
| | | join product_model pm on pm.id = pop.product_model_id |
| | | left join product p on p.id = pm.product_id |
| | | where pop.production_order_id in |
| | | <foreach collection="ids" item="id" open="(" separator="," close=")">#{id}</foreach> |
| | | and pop.batch_no is not null and pop.batch_no <> '' |
| | | order by pop.production_order_id, pop.id |
| | | </select> |
| | | |
| | | <select id="listPicksByBatchNo" resultType="com.ruoyi.quality.dto.QualityTracePickVo"> |
| | | select <include refid="pickColumns"/> |
| | | from production_order_pick pop |
| | | join product_model pm on pm.id = pop.product_model_id |
| | | left join product p on p.id = pm.product_id |
| | | where pop.batch_no = #{batchNo} |
| | | order by pop.production_order_id, pop.id |
| | | </select> |
| | | |
| | | <select id="listInspectsByMainIds" resultType="com.ruoyi.quality.dto.QualityTraceInspectVo"> |
| | | select qi.id as inspectId, |
| | | qi.product_main_id as productMainId, |
| | | qi.inspect_type as inspectType, |
| | | case qi.inspect_type when 0 then 'åææ£éª' when 1 then 'è¿ç¨æ£éª' when 2 then 'åºåæ£éª' |
| | | else 'å
¶ä»' end as inspectTypeName, |
| | | qi.process as process, |
| | | qi.check_name as checkName, |
| | | qi.product_name as productName, |
| | | qi.model as model, |
| | | qi.unit as unit, |
| | | ifnull(qi.quantity, 0) as quantity, |
| | | ifnull(qi.qualified_quantity, 0) as qualifiedQuantity, |
| | | ifnull(qi.unqualified_quantity, 0) as unqualifiedQuantity, |
| | | qi.check_result as checkResult, |
| | | qi.check_time as checkTime, |
| | | qi.inspect_state as inspectState, |
| | | qi.defective_phenomena as defectivePhenomena |
| | | from quality_inspect qi |
| | | where qi.product_main_id in |
| | | <foreach collection="ids" item="id" open="(" separator="," close=")">#{id}</foreach> |
| | | order by qi.id |
| | | </select> |
| | | |
| | | <select id="listUnqualifiedByInspectIds" resultType="com.ruoyi.quality.dto.QualityTraceUnqualifiedVo"> |
| | | select qu.id as id, |
| | | qu.inspect_id as inspectId, |
| | | qu.product_name as productName, |
| | | qu.model as model, |
| | | qu.unit as unit, |
| | | ifnull(qu.quantity, 0) as quantity, |
| | | qu.defective_phenomena as defectivePhenomena, |
| | | qu.deal_result as dealResult, |
| | | qu.deal_name as dealName, |
| | | qu.deal_time as dealTime, |
| | | qu.inspect_state as inspectState, |
| | | qu.check_time as checkTime |
| | | from quality_unqualified qu |
| | | where qu.inspect_id in |
| | | <foreach collection="ids" item="id" open="(" separator="," close=")">#{id}</foreach> |
| | | order by qu.id |
| | | </select> |
| | | |
| | | <select id="listOutboundByBatch" resultType="com.ruoyi.quality.dto.QualityTraceOutboundVo"> |
| | | select sor.id as id, |
| | | sor.batch_no as batchNo, |
| | | ifnull(p.product_name, '') as productName, |
| | | ifnull(pm.model, '') as productModel, |
| | | pm.unit as unit, |
| | | ifnull(sor.stock_out_num, 0) as qty, |
| | | sor.record_type as recordType, |
| | | sor.create_time as outTime, |
| | | sor.remark as remark |
| | | from stock_out_record sor |
| | | join product_model pm on pm.id = sor.product_model_id |
| | | left join product p on p.id = pm.product_id |
| | | where sor.batch_no = #{batchNo} |
| | | order by sor.id |
| | | </select> |
| | | |
| | | <select id="listFinishedBatchesByOrderIds" resultType="com.ruoyi.quality.dto.QualityTraceFinishedBatchVo"> |
| | | select x.productionOrderId, x.productMainId, x.batchNo, x.productModelId, x.qty, x.inTime, x.recordType |
| | | from ( |
| | | select pot.production_order_id as productionOrderId, |
| | | sir.record_id as productMainId, |
| | | sir.batch_no as batchNo, |
| | | sir.product_model_id as productModelId, |
| | | ifnull(sir.stock_in_num, 0) as qty, |
| | | sir.create_time as inTime, |
| | | sir.record_type as recordType |
| | | from stock_in_record sir |
| | | join production_product_main ppm on ppm.id = sir.record_id |
| | | join production_operation_task pot on pot.id = ppm.production_operation_task_id |
| | | join production_order po on po.id = pot.production_order_id |
| | | where sir.record_type = '2' and sir.batch_no is not null and sir.batch_no <> '' |
| | | and sir.product_model_id = po.product_model_id |
| | | and pot.production_order_id in |
| | | <foreach collection="ids" item="id" open="(" separator="," close=")">#{id}</foreach> |
| | | union all |
| | | select pot.production_order_id, |
| | | qi.product_main_id, |
| | | sir.batch_no, |
| | | sir.product_model_id, |
| | | ifnull(sir.stock_in_num, 0), |
| | | sir.create_time, |
| | | sir.record_type |
| | | from stock_in_record sir |
| | | join quality_inspect qi on qi.id = sir.record_id |
| | | join production_product_main ppm on ppm.id = qi.product_main_id |
| | | join production_operation_task pot on pot.id = ppm.production_operation_task_id |
| | | join production_order po on po.id = pot.production_order_id |
| | | where sir.record_type = '6' and sir.batch_no is not null and sir.batch_no <> '' |
| | | and sir.product_model_id = po.product_model_id |
| | | and pot.production_order_id in |
| | | <foreach collection="ids" item="id" open="(" separator="," close=")">#{id}</foreach> |
| | | ) x |
| | | order by x.productionOrderId, x.inTime |
| | | </select> |
| | | |
| | | <select id="listMaterialBatchInfoByBatches" resultType="com.ruoyi.quality.dto.QualityTraceMaterialBatchVo"> |
| | | select sir.id as inRecordId, |
| | | sir.batch_no as batchNo, |
| | | sir.product_model_id as productModelId, |
| | | ifnull(p.product_name, '') as materialName, |
| | | ifnull(pm.model, '') as materialModel, |
| | | pm.unit as unit, |
| | | ifnull(sir.stock_in_num, 0) as qty, |
| | | sir.create_time as inTime, |
| | | sir.record_type as recordType, |
| | | qi.id as inspectId, |
| | | ifnull(qi.quantity, 0) as inspectQty, |
| | | ifnull(qi.qualified_quantity, 0) as qualifiedQty, |
| | | ifnull(qi.unqualified_quantity, 0) as unqualifiedQty, |
| | | qi.check_result as checkResult, |
| | | qi.check_time as checkTime, |
| | | coalesce(pl.supplier_name, pl_direct.supplier_name, qi.supplier) as supplierName, |
| | | coalesce(pl.purchase_contract_number, pl_direct.purchase_contract_number) as contractNo, |
| | | coalesce(pl.entry_date, pl_direct.entry_date) as entryDate |
| | | from stock_in_record sir |
| | | join product_model pm on pm.id = sir.product_model_id |
| | | left join product p on p.id = pm.product_id |
| | | left join quality_inspect qi on qi.id = sir.record_id and sir.record_type in ('6', '10') |
| | | left join purchase_ledger pl on pl.id = qi.purchase_ledger_id |
| | | left join purchase_ledger pl_direct on pl_direct.id = sir.record_id and sir.record_type = '7' |
| | | where sir.batch_no in |
| | | <foreach collection="batchNos" item="bn" open="(" separator="," close=")">#{bn}</foreach> |
| | | order by sir.id |
| | | </select> |
| | | |
| | | <select id="listBatchOptions" resultType="com.ruoyi.quality.dto.QualityTraceBatchOptionVo"> |
| | | <choose> |
| | | <when test="type == 'material'"> |
| | | select pop.batch_no as batchNo, |
| | | ifnull(p.product_name, '') as productName, |
| | | ifnull(pm.model, '') as productModel, |
| | | pm.unit as unit, |
| | | ifnull(pop.quantity, 0) as qty, |
| | | pop.create_time as inTime, |
| | | po.nps_no as npsNo |
| | | from production_order_pick pop |
| | | join product_model pm on pm.id = pop.product_model_id |
| | | left join product p on p.id = pm.product_id |
| | | left join production_order po on po.id = pop.production_order_id |
| | | where pop.batch_no is not null and pop.batch_no <> '' |
| | | </when> |
| | | <otherwise> |
| | | select sir.batch_no as batchNo, |
| | | ifnull(p.product_name, '') as productName, |
| | | ifnull(pm.model, '') as productModel, |
| | | pm.unit as unit, |
| | | ifnull(sir.stock_in_num, 0) as qty, |
| | | sir.create_time as inTime, |
| | | po.nps_no as npsNo |
| | | from stock_in_record sir |
| | | join product_model pm on pm.id = sir.product_model_id |
| | | left join product p on p.id = pm.product_id |
| | | left join quality_inspect qi on qi.id = sir.record_id and sir.record_type = '6' |
| | | left join production_product_main ppm |
| | | on ppm.id = case when sir.record_type = '2' then sir.record_id else qi.product_main_id end |
| | | left join production_operation_task pot on pot.id = ppm.production_operation_task_id |
| | | left join production_order po on po.id = pot.production_order_id |
| | | where sir.record_type in ('2', '6') and sir.batch_no is not null and sir.batch_no <> '' |
| | | </otherwise> |
| | | </choose> |
| | | <if test="keyword != null and keyword != ''"> |
| | | and ( |
| | | <choose> |
| | | <when test="type == 'material'">pop</when> |
| | | <otherwise>sir</otherwise> |
| | | </choose> |
| | | .batch_no like concat('%', #{keyword}, '%') |
| | | or p.product_name like concat('%', #{keyword}, '%') |
| | | or pm.model like concat('%', #{keyword}, '%') |
| | | ) |
| | | </if> |
| | | order by inTime desc |
| | | limit #{limit} |
| | | </select> |
| | | </mapper> |
| | |
| | | <if test="ew.productName != null and ew.productName !=''"> |
| | | and p.product_name like concat('%',#{ew.productName},'%') |
| | | </if> |
| | | <if test="ew.warnOnly != null and ew.warnOnly"> |
| | | and COALESCE(si.warn_num, 0) > 0 |
| | | and (si.qualitity - COALESCE(si.locked_quantity, 0)) <= si.warn_num |
| | | </if> |
| | | </select> |
| | | |
| | | <select id="pageListCombinedStockInventory" resultType="com.ruoyi.stock.dto.StockInventoryDto"> |