Merge remote-tracking branch 'origin/dev_新疆_塔河种业' into dev_新疆_塔河种业
已修改124个文件
已添加46个文件
已删除4个文件
| | |
| | | ### Claude Code ### |
| | | .claude/settings.local.json |
| | | .claude/worktrees/ |
| | | .claude/scheduled_tasks.json |
| | | .claude/scheduled_tasks.json |
| | | |
| | | .export_tmp/ |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | # ä¸è¢ä¸ç é¦é¡µæ¹ç(å
¨é¾è·¯é©¾é©¶è±) â å端èè°æ¹æ¡ |
| | | |
| | | ## èæ¯ |
| | | |
| | | å° `/bagcode-home` é¦é¡µä»"åºç¡æ°æ® + ä¸è¢ä¸ç ç产"çå±é¨ç»è®¡é¡µ,éæä¸ºè¦ç**宿´ä»·å¼é¾**ç驾驶è±:åç§ â 产线/æ¹æ¬¡ â è¢ç /æç â éå®åºåº â æµéæ«ç â é²çªæº¯æº,并串èä»å¨åºåãè´¨éé¢è¦ãå¿«æ·å
¥å£ãæ´ä½è§è§å¯¹é½ç»å½é¡µç**åä¸ç¿ 绿ç»ç**飿 ¼ã |
| | | |
| | | ## æ¶åé¡µé¢ |
| | | |
| | | - é¦é¡µ(驾驶è±):`src/views/dashboard/bagCodeHome/index.vue` ââ å
¨é¾è·¯éæ |
| | | - å
³è跳转页é¢:åºç¡æ°æ®ãä¸è¢ä¸ç ç产ãåºåºæµéãé²ä¼ªé²çªè´§ã溯æºåæãä»å¨ç©æµãè´¨é管ç ä¸çåä¸å¡é¡µ |
| | | |
| | | ## æ¥å£åæ´ |
| | | |
| | | ### 1. æ©å±æ±æ»æ¥å£(è¿åæ°å¢å段) |
| | | |
| | | `GET /mes/bag-code-home-statistics/summary` |
| | | |
| | | æ°å¢ååºå段(å `Long`,æ é»è®¤å¼æ¶è¿å 0): |
| | | |
| | | | åæ®µ | 说æ | æ°æ®æ¥æºè¡¨ | |
| | | |------|------|-----------| |
| | | | `salesNoticeCount` | åè´§éç¥åæ° | `mes_wm_sales_notice` | |
| | | | `productSalesCount` | éå®åºåºåæ° | `mes_wm_product_sales` | |
| | | | `returnSalesCount` | éå®éè´§åæ° | `mes_wm_return_sales` | |
| | | | `stockWarningPendingCount` | æªå¤çåºåé¢è¦æ°(`status=10`) | `mes_wm_stock_warning` | |
| | | | `ncrPendingCount` | å¾
è¯å®¡ä¸åæ ¼ååæ°(`status=0`) | `mes_qc_ncr` | |
| | | |
| | | åæå段(`mdmItemCount/mesItemCount/itemTypeCount/unitMeasureCount/lineCount/batchCount/bagCodeCount/palletCount/batchStatusList/bagCodeStatusList`)ä¿æä¸åã |
| | | |
| | | ### 2. å¤ç¨å·²æç»è®¡æ¥å£(æ éæ¹å¨) |
| | | |
| | | | æ¥å£ | ç¨é | å端 API | |
| | | |------|------|---------| |
| | | | `GET /mes/trace-cross-region/summary` | çªè´§é¢è¦æ±æ»(`total/pending/handled/falseAlarm/crossProvince/crossCity`) | `api/mes/trace-cross-region`(æ°å¢) | |
| | | | `GET /mes/trace-consumer-scan/summary` | 累计æ«ç /æå/失败/æ¶åæ¹æ¬¡ | å·²æ | |
| | | | `GET /mes/trace-consumer-scan/distribution?groupBy=province` | æ¶è´¹è
æ«ç å°åºåå¸ | å·²æ | |
| | | |
| | | ## å端修æ¹ç¹ |
| | | |
| | | ### 1. é¦é¡µç»æ(index.vue) |
| | | |
| | | | åºå | ç»ä»¶ | æ°æ® | |
| | | |------|------|------| |
| | | | ä¸å¡å
¨é¾è·¯ | `modules/business-flow.vue` | summary + æ«ç æ»æ° + çªè´§æ»æ° | |
| | | | å
¨é¾è·¯ KPI æ»è§(8 å¡) | `modules/kpi-cards.vue` | summary + æ«ç æ»æ° | |
| | | | è¢ç çæè¶å¿ | `modules/trend-chart.vue`(å¤ç¨) | `summary/trend` | |
| | | | æ¶è´¹è
æ«ç å°åºåå¸ | `modules/scan-region-chart.vue`(æ°å¢) | `distribution/groupBy=province` | |
| | | | æ¹æ¬¡ç¶æåå¸ / è¢ç ç¶æåå¸ | `batch-status-chart.vue` / `bag-code-status-chart.vue`(å¤ç¨) | summary ç¶æå表 | |
| | | | å¾
åä¸é¢è¦ | `modules/alert-panel.vue`(æ°å¢) | summary + çªè´§æ±æ» | |
| | | | åç»å¿«æ·å
¥å£ | `modules/shortcuts.vue`(éå为åç») | éæè·¯ç±é
ç½® | |
| | | |
| | | ### 2. æ°å¢/å 餿件 |
| | | |
| | | - æ°å¢:`api/mes/trace-cross-region/index.ts` |
| | | - æ°å¢:é¦é¡µ `modules/business-flow.vue`ã`kpi-cards.vue`ã`scan-region-chart.vue`ã`alert-panel.vue` |
| | | - éå:é¦é¡µ `index.vue`ã`modules/shortcuts.vue` |
| | | - æ´æ°:`api/mes/bag-code-home/index.ts`(Summary å 5 åæ®µ)ã`data.ts`ã`chart-options.ts` |
| | | - å é¤:`modules/basic-cards.vue`ã`modules/bag-code-cards.vue`(ä¸å使ç¨) |
| | | |
| | | ### 3. æ ·å¼ä¸»é¢ |
| | | |
| | | - é¦é¡µå
容åºç»ä¸"åä¸ç¿ 绿ç»ç"主é¢:æµ
è²ç¿ 绿æ¸åèæ¯(æ èæ¯å¾)ãç½è²ç£¨ç ç»çå¡çãèè·ç½/墨绿æåã |
| | | - å¾è¡¨ç»ä¸ç¿ 绿主è²(`#10b981`)å¹¶éé
æµ
åºæåè²ã |
| | | - 䏻颿 ·å¼éä¸å¨ `index.vue` çé scoped `<style>` ä¸(`.agri-dashboard` 容å¨ä¸ºä½ç¨å),åå¡çç»ä»¶ä½¿ç¨å¯¹åºç»çç±»ã |
| | | |
| | | ## åæ®µå±ç¤ºè§å |
| | | |
| | | | åæ®µ | å±ç¤ºä½ç½® | 说æ | |
| | | |------|----------|------| |
| | | | åç§æ»æ° | KPI + ä¸å¡é¾è·¯ | ç¹æè·³è½¬ `MdmItem` | |
| | | | çäº§æ¹æ¬¡ | KPI + ä¸å¡é¾è·¯ | 跳转 `MesProBatch` | |
| | | | è¢ç / æçç | KPI + ä¸å¡é¾è·¯ | 跳转 `MesProBagCode` / `MesProPallet` | |
| | | | éå®åºåºåæ° | KPI + ä¸å¡é¾è·¯ | 跳转 `MesWmProductSales` | |
| | | | 累计æ«ç | KPI + ä¸å¡é¾è·¯ | æ¥èª `trace-consumer-scan/summary`,跳转 `MesConsumerScanStatistics` | |
| | | | çªè´§é¢è¦æ»æ° | ä¸å¡é¾è·¯(é²çª/溯æº) | æ¥èª `trace-cross-region/summary`,跳转 `MesTraceCrossRegion` | |
| | | | åºåé¢è¦(æªå¤ç) | KPI + å¾
åé¢è¦ | 跳转 `MesWmStockWarning` | |
| | | | å¾
è¯å®¡ä¸åæ ¼ | KPI + å¾
åé¢è¦ | 跳转 `MesQcNcr` | |
| | | |
| | | ## 注æäºé¡¹ |
| | | |
| | | - æ°å¢ç 5 ä¸ªæ±æ»å段éè¦**åç«¯éæ°ç¼è¯å¹¶éå¯**åæä¼è¿å;éå¯åå端已å `?? 0` å
åº,ç¸å
³å¡ç/èç¹æ¾ç¤º 0,ä¸å½±åå
¶å®æ°æ®ã |
| | | - è·¯ç±è·³è½¬ä½¿ç¨**è·¯ç± name**(å·²ä¸èå `component_name` 对é½),æªå è½½çèåæ²¿ç¨ `message.warning('å½åèåå°æªå è½½...')` å
åºã |
| | | - æ¶è´¹è
æ«ç /çªè´§æ ç»çº¬åº¦å段,ä»
æ¯æç/叿æ¬åå¸å¾,䏿¯æå°å¾åæ ã |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | # æ¹æ¬¡è¿½æº¯ç»ä¸èåæ¥å£ - å端èè°æ¹æ¡ |
| | | |
| | | ## æ¶åé¡µé¢ |
| | | |
| | | - MES â è´¨æ£ â æ¹æ¬¡è¿½æº¯ï¼`/qc/batch-trace`ï¼ |
| | | - æ¹æ¬¡è¿½æº¯è¯¦æ
|
| | | - æ¹æ¬¡ç ãæçç ãè¢ç æ«ç 追溯å
¥å£ |
| | | |
| | | ## ä¸å¡æµç¨ä¸æ°æ®å¸¦å
¥ |
| | | |
| | | 1. 卿¹æ¬¡è¿½æº¯å表è¾å
¥çäº§æ¹æ¬¡ç ãä¸´æ¶æ¹æ¬¡ç ãè¢ç ææçç ã |
| | | 2. 页é¢è°ç¨ç»ä¸è¯¦æ
æ¥å£ï¼å端å°å
¥å£ç è§£æå°çäº§æ¹æ¬¡ï¼å¹¶èåç产ãè´¨æ£ãä»å¨ãéå®åé²ä¼ªä¿¡æ¯ã |
| | | 3. 详æ
页以çäº§æ¹æ¬¡ä¸ºæ ¹å±ç¤ºå
¨é¾è·¯æ°æ®ï¼è¢ç åæçä¿¡æ¯æ¥èªç产èµç æ°æ®ï¼ä»å¨ä¸éå®ä¿¡æ¯æ¥èªä»å¨ä¸å¡æ°æ®ã |
| | | 4. åå追溯å±ç¤ºå½åæ¹æ¬¡äº§åºç䏿¸¸æ¹æ¬¡ï¼åå追溯å±ç¤ºå½åæ¹æ¬¡æ¶èç䏿¸¸æ¹æ¬¡ã |
| | | 5. æ¶é´çº¿ãé¶æ®µè§å¾åå³çæè¦å使ç¨å䏿¬¡èåååºï¼é¿å
æå¼è¯¦æ
åéå¤è¯·æ±å¤ä¸ªæ§æ¥å£ã |
| | | |
| | | ## API |
| | | |
| | | | æ¹æ³ | è·¯å¾ | 说æ | |
| | | |---|---|---| |
| | | | GET | `/mes/trace/batch/detail` | æ¥è¯¢ç»ä¸æ¹æ¬¡è¿½æº¯è¯¦æ
| |
| | | |
| | | ### 请æ±åæ° |
| | | |
| | | | åæ° | ç±»å | å¿
å¡« | 说æ | |
| | | |---|---|---|---| |
| | | | `code` | String | æ¯ | çäº§æ¹æ¬¡ç ãä¸´æ¶æ¹æ¬¡ç ãè¢ç ææçç | |
| | | |
| | | 示ä¾ï¼`code=BAG-202608280001` |
| | | |
| | | ### ååºä¸»è¦å段 |
| | | |
| | | | åæ®µ | ç±»å | 说æ | |
| | | |---|---|---| |
| | | | `sourceType` | String | å
¥å£ç±»åï¼`BAG`ã`PALLET`ã`BATCH` | |
| | | | `requestCode` | String | åå§è¾å
¥ç | |
| | | | `itemCode` / `itemName` | String | åç§ç¼ç ãåç§° | |
| | | | `itemSpecification` | String | åç§è§æ ¼ | |
| | | | `batchCode` / `tempCode` | String | æ£å¼æ¹æ¬¡å·ãä¸´æ¶æ¹æ¬¡ç | |
| | | | `batchStatusName` | String | æ¹æ¬¡ç¶æåç§° | |
| | | | `produceDate` | DateTime | çäº§æ¥æ | |
| | | | `lineCode` / `lineName` | String | 产线ç¼ç ãåç§° | |
| | | | `ownerUserName` | String | ç产责任人 | |
| | | | `planQuantity` | Decimal | è®¡åæ°é | |
| | | | `bagQuantity` / `palletQuantity` | Integer | è¢ç æ°éãæçæ°é | |
| | | | `workers` | Array | ç产人å | |
| | | | `pallets` | Array | æçæè¦ | |
| | | | `bagTotal` / `bags` | Long / Array | è¢ç æ»æ°åæå¤ 100 æ¡æç» | |
| | | | `inbound` | Object | ææ°å
¥åºäºä»¶ | |
| | | | `quality` | Object | ç§åè´¨éæ£éªä¸ææ | |
| | | | `antiFake` | Object | å½åè¿½æº¯ç æ«ç 次æ°ã馿¬¡åæè¿æ«ç æ¶é´ | |
| | | | `purchaseSources` | Array | éè´æ¥æºãä¾åºåå IQC ä¿¡æ¯ | |
| | | | `salesTargets` | Array | éå®åºåºã客æ·å OQC ä¿¡æ¯ | |
| | | | `processTraces` | Array | å·¥åºæå
¥ãäº§åºæµè½¬ä¿¡æ¯ | |
| | | |
| | | ### ååºç¤ºä¾ |
| | | |
| | | ```json |
| | | { |
| | | "code": 0, |
| | | "data": { |
| | | "sourceType": "BAG", |
| | | "requestCode": "BAG-202608280001", |
| | | "batchCode": "B20260828001", |
| | | "itemName": "示ä¾åç§", |
| | | "batchStatusName": "已宿", |
| | | "workers": [], |
| | | "pallets": [], |
| | | "bags": [], |
| | | "purchaseSources": [], |
| | | "salesTargets": [], |
| | | "processTraces": [] |
| | | } |
| | | } |
| | | ``` |
| | | |
| | | ## 页é¢å±ç¤ºè§å |
| | | |
| | | | è§å¾ | å±ç¤ºå
容 | |
| | | |---|---| |
| | | | é¶æ®µæ»è§ | æ¥æºãç产ãè´¨æ£ãèµç ãå
¥åºãéå®ãæ¶è´¹ãé²ä¼ªå
«ä¸ªé¶æ®µçç¶æåæ°é | |
| | | | å
¨é¾è·¯æ¶é´çº¿ | ææ¶é´å±ç¤ºéè´ãç产ãè´¨æ£ãèµç ãå
¥åºãåºåºåæ«ç äºä»¶ï¼å¼å¸¸ç¶æä¼å
é«äº® | |
| | | | æµå¨å¾è°± | ä»¥æ¹æ¬¡ãå·¥åºãä»åºãæçãè¢ç ãéå®åå客æ·ä¸ºèç¹ï¼é»è®¤å±ç¤ºæ¹æ¬¡çº§å
³ç³» | |
| | | | å³çåæ | å±ç¤ºè´¨éç»è®ºãåºåæ°éãéå®å»åãé²ä¼ªæ«ç 次æ°åçªè´§é£é© | |
| | | | éè´æ¥æº | å±ç¤ºéè´å
¥åºãä¾åºåãéè´è®¢åãIQC åå·åæ£éªç»è®º | |
| | | | éå®å»å | å±ç¤ºéå®åºåºã客æ·ãéå®è®¢åãOQC åå·åè´¨éç¶æ | |
| | | | å·¥åºæµè½¬ | `IN` æ¾ç¤ºä¸ºæå
¥ï¼`OUT` æ¾ç¤ºä¸ºäº§åº | |
| | | |
| | | ## ä¸å¡è§å |
| | | |
| | | - è¾å
¥è¢ç ææçç æ¶ï¼è¯¦æ
ä»ä»¥å
¶æå±çäº§æ¹æ¬¡ä¸ºæ ¹è¿è¡èåã |
| | | - å½åæ¥å£è¿åçè¢ç æç»æå¤ 100 æ¡ï¼`bagTotal` ç¨äºå±ç¤ºå®æ´æ°éï¼å¤§æ¹æ¬¡ä¸å¾ææç»æ°é夿æ»éã |
| | | - 空æ°ç»è¡¨ç¤ºè¯¥ä¸å¡é¶æ®µææ è®°å½ï¼`quality`ã`inbound`ã`antiFake` ä¸ºç©ºè¡¨ç¤ºææ å¯¹åºä¿¡æ¯ã |
| | | - é²ä¼ªæ«ç ç»è®¡ä»
ç¨äºå±ç¤ºï¼ä¸è½æ¿ä»£è´¨éæ£éªç»è®ºæåºåºç¶æã |
| | | - 客æ·ãä¾åºåãæä½äººçåç§°åºä»¥æ¥å£è¿åå¼ä¸ºåï¼ä¸å¨å端é夿¥è¯¢æ§æ¹æ¬¡æ¥å£ã |
| | | |
| | | ## 注æäºé¡¹ |
| | | |
| | | - 管ç端æ¥å£éè¦æ¹æ¬¡è¿½æº¯æ¥è¯¢æéï¼`mes:trace-batch:query`ã |
| | | - æ§ç `/mes/wm/batch/*` æ¥å£ç»§ç»ä¾ä»å¨æ¹æ¬¡é¡µé¢ä½¿ç¨ï¼æ¹æ¬¡è¿½æº¯é¡µé¢åæ¢åä¸åºåå¹¶è¡è¯·æ±æ§çäºä¸ªè¯¦æ
æ¥å£ã |
| | | - åç»æ©å±æ¶é´çº¿åå¾è°±æ¶ï¼å»ºè®®å端å¢å å页ä¸èç¹å±çº§åæ°ï¼é¿å
䏿¬¡æ§å è½½å
¨é¨è¢ç ã |
| | | - å±ç¤ºæ¶è´¹è
æ«ç ä¿¡æ¯æ¶ä¸å¾å±ç¤º IP å°åå User-Agent åæã |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | # H5 溯æºãåç§ä¿¡æ¯å¸¦è®¡éåä½ã- å端èè°è¯´æ |
| | | |
| | | ## èæ¯ |
| | | |
| | | H5 æ«ç 溯æºé¡µï¼`mes.trace-base-url` æåç `trace.html`ï¼ã追溯æ¥è¯¢ãåºåçåç§ä¿¡æ¯éè¦å¸¦ä¸è®¡éåä½ã |
| | | |
| | | åç§ä¸»è®¡éåä½åå¨å¨ `mdm_item.unit_measure_id`ï¼åä½ç¼å·ï¼ï¼é¡µé¢éè¦çåä½åç§°ç±å端éè¿ |
| | | `MdmUnitMeasureApi.getUnitMeasure(id)` è§£æåéååºè¿åï¼å端ä¸éè¦ååç¬è¯·æ±å使¥å£ã |
| | | |
| | | åæ¶æéæ±ç²¾ç®ã追溯æ¥è¯¢ãåºåï¼å»æã责任人ããè´¨æ£ç»è®ºã两è¡ï¼è¿ä¸¤é¡¹æ°æ®å¨æå çãè´¨æ£ä¿¡æ¯ãåºåä¸ä»ç¶å¯æ¥ï¼æªä¸¢å¤±ï¼ã |
| | | |
| | | ## æ¶åæ¥å£ |
| | | |
| | | | æ¹æ³ | è·¯å¾ | 说æ | |
| | | |------|------|------| |
| | | | GET | /public/mes/trace/query?code={追溯ç } | H5 æº¯æºæ¥è¯¢ï¼å
ç»å½ï¼ï¼ååºåç§åºåæ°å¢ `itemUnitMeasureName` | |
| | | |
| | | **ååºæ°å¢å段ï¼åç§ä¿¡æ¯åºåï¼ä½äº `itemSpecification` ä¹åï¼ï¼** |
| | | |
| | | | åæ®µ | ç±»å | 说æ | |
| | | |------|------|------| |
| | | | itemUnitMeasureName | String | åç§ä¸»è®¡éåä½åç§°ï¼å¦ `48åå
`ï¼ï¼ç©ææªé
ç½®å使¶è¿å `null` | |
| | | |
| | | **ååºç¤ºä¾ï¼åç§ç¸å
³ç段ï¼ï¼** |
| | | |
| | | ```json |
| | | { |
| | | "code": 0, |
| | | "data": { |
| | | "itemCode": "ITEM_20260917002", |
| | | "itemName": "æµè¯", |
| | | "itemSpecification": "ä¸çº§", |
| | | "itemUnitMeasureName": "48åå
" |
| | | } |
| | | } |
| | | ``` |
| | | |
| | | ## 页é¢å±ç¤ºè§å |
| | | |
| | | ã追溯æ¥è¯¢ãåºååæ®µé¡ºåºï¼ |
| | | |
| | | | åæ®µ | åå¼ | 说æ | |
| | | |------|------|------| |
| | | | åç§åç§° | `itemName` + `itemSpecification` | 两è
ä»¥ç©ºæ ¼æ¼æ¥ï¼ä¸ºç©ºçä¸å䏿¼æ¥ | |
| | | | 计éåä½ | `itemUnitMeasureName` | æªé
ç½®å使¶å±ç¤º `-` | |
| | | | ç产ç»è¥è
| 页é¢å¸¸é `COMPANY_NAME` | éæä¿¡æ¯ | |
| | | | åå
è¯å«ä»£ç | `requestCode` â `batchCode` â `tempCode` 便¬¡åé | â | |
| | | | 追溯ç½å | 页é¢å¸¸é `TRACE_URL` | å¤ç½è®¿é®å°åï¼ä¸å
è£
/äºç»´ç å°å¶ä¸è´ | |
| | | | 追溯类å | `sourceType` | è¢ç / æçç / æ¹æ¬¡ç | |
| | | | æ¹æ¬¡å· | `batchCode` | â | |
| | | | çäº§æ¥æ | `produceDate` | â | |
| | | | 产线 | `lineName`ï¼ä¸ºç©ºåé `lineCode` | â | |
| | | |
| | | **æ¬æ¬¡ç§»é¤çå±ç¤ºé¡¹ï¼** |
| | | |
| | | | åæ®µ | åå±ç¤ºä½ç½® | 说æ | |
| | | |------|-----------|------| |
| | | | 责任人 | 追溯æ¥è¯¢åºå | 已移é¤ï¼`ownerUserName` åæ®µä»å¨ååºä¸ | |
| | | | è´¨æ£ç»è®º | 追溯æ¥è¯¢åºå | 已移é¤ï¼è´¨æ£ç»è®ºä»å¨ååº `quality.resultName` ä¸ï¼å¯å¨æå çãè´¨æ£ä¿¡æ¯ãåºåæ¥ç | |
| | | |
| | | ## 注æäºé¡¹ |
| | | |
| | | - `itemUnitMeasureName` åçæ¯åä½**åç§°**ï¼`mdm_unit_measure.name`ï¼ï¼ä¸æ¯åä½ç±»åï¼`type`ï¼å¦ 48åå
/100åå
/å¨ï¼ãç©ææªé
置主计éå使¶è¯¥å段为 `null`ï¼é¡µé¢å±ç¤º `-`ã |
| | | - åä½å称为空å符串æ¶å端ç»ä¸è½¬æ `null` è¿åã |
| | | - è¯¥åæ®µä¸ºçº¯å±ç¤ºå段ï¼å岿°æ®æ éå¤çï¼æ¥å£å
¶ä½å段ä¸ç»æä¿æä¸åï¼ååå
¼å®¹ã |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | # H5 溯æºãæªç»å®æ¹æ¬¡ä¹å¯æ«ç ã- å端èè°è¯´æ |
| | | |
| | | ## èæ¯ |
| | | |
| | | è¢ç / æçç å¨çæåãå½å
¥çäº§æ¹æ¬¡åï¼æ¯ä¸ä¸ªãå·²å°å¶ãæªæäº§ãçä¸é´æãæ¤åè¯¥ç¶æä¸è°ç¨æº¯æºæ¥è¯¢æ¥å£ä¼ç´æ¥è¿åé误ç `1040760000`ï¼æªæ¥è¯¢å°è¯¥è¿½æº¯ç ï¼ï¼æ¶è´¹è
æ«å°è¿ç±»å
è£
æ¶æ æ³æ¥çä»»ä½ä¿¡æ¯ã |
| | | |
| | | æ¬æ¬¡è°æ´ï¼**æªç»å®æ¹æ¬¡çè¢ç / æçç åæ ·å¯ä»¥æ«ç æå**ï¼æ¥å£æ£å¸¸è¿å该ç 对åºç**åç§ä¿¡æ¯**ï¼å¹¶æ°å¢ `batchBound` åæ®µæ è¯æ¹æ¬¡æ¯å¦å·²å½å
¥ï¼ç±å端æç¤ºãå°æªç»å®æ¹æ¬¡ããè¿½æº¯ç æ¬èº«ä¸å卿¶ï¼è¡ä¸ºä¸åï¼ä»è¿å `1040760000`ã |
| | | |
| | | ## æ¶åæ¥å£ |
| | | |
| | | | æ¹æ³ | è·¯å¾ | 说æ | |
| | | |------|------|------| |
| | | | GET | /public/mes/trace/query?code={追溯ç } | H5 æº¯æºæ¥è¯¢ï¼å
ç»å½ï¼ | |
| | | |
| | | ## ååºæ°å¢å段 |
| | | |
| | | | åæ®µ | ç±»å | 说æ | |
| | | |------|------|------| |
| | | | batchBound | Boolean | æ¯å¦å·²å½å
¥çäº§æ¹æ¬¡ã`true` å·²ç»å®ï¼æ¹æ¬¡åºååæ®µæ£å¸¸è¿åï¼ï¼`false` æªç»å®ï¼æ¤æ¶**ä»
** `itemCode` / `itemName` / `itemSpecification` / `itemUnitMeasureName`ã`sourceType`ã`requestCode`ã`antiFake`ã`timeline`ã`decision` æå¼ï¼å
¶ä½æ¹æ¬¡ç¸å
³å段å
¨é¨ä¸º `null` | |
| | | |
| | | **åæ®µä½ç½®ï¼** `requestCode` ä¹åï¼`itemCode` ä¹åã |
| | | |
| | | ## åæ´ååå¯¹æ¯ |
| | | |
| | | | åºæ¯ | åæ´å | åæ´å | |
| | | |------|--------|--------| |
| | | | è¢ç å·²çæãæªå½å
¥æ¹æ¬¡ | `code=1040760000`ï¼`data=null`ï¼æ æ³å±ç¤ºä»»ä½ä¿¡æ¯ | `code=0`ï¼`batchBound=false`ï¼è¿ååç§ä¿¡æ¯ï¼å端æç¤ºæªç»å®æ¹æ¬¡ | |
| | | | æçå·²çæãæªå½å
¥æ¹æ¬¡ | åä¸ | åä¸ï¼åç§åæçå
**ä»»ä¸è¢ç **çåç§ | |
| | | | 追溯ç ä¸åå¨ | `code=1040760000` | ä¸å | |
| | | |
| | | ## ååºç¤ºä¾ï¼æªç»å®æ¹æ¬¡ï¼ |
| | | |
| | | ```json |
| | | { |
| | | "code": 0, |
| | | "data": { |
| | | "sourceType": "BAG", |
| | | "requestCode": "BAG-00000153", |
| | | "batchBound": false, |
| | | "itemCode": "ITEM_20260917003", |
| | | "itemName": "å¨", |
| | | "itemSpecification": null, |
| | | "itemUnitMeasureName": "å¨è¢å", |
| | | "batchCode": null, |
| | | "tempCode": null, |
| | | "batchStatus": null, |
| | | "batchStatusName": null, |
| | | "produceDate": null, |
| | | "lineCode": null, |
| | | "lineName": null, |
| | | "ownerUserId": null, |
| | | "ownerUserName": null, |
| | | "planQuantity": null, |
| | | "bagQuantity": null, |
| | | "palletQuantity": null, |
| | | "inboundTime": null, |
| | | "remark": null, |
| | | "workers": null, |
| | | "palletCount": null, |
| | | "pallets": null, |
| | | "bagTotal": null, |
| | | "bags": null, |
| | | "inbound": null, |
| | | "quality": null, |
| | | "antiFake": { |
| | | "scanCount": 0, |
| | | "firstScanTime": null, |
| | | "lastScanTime": null |
| | | }, |
| | | "purchaseSources": null, |
| | | "salesTargets": null, |
| | | "seedFlows": null, |
| | | "processTraces": null, |
| | | "timeline": [], |
| | | "decision": { |
| | | "qualityRisk": false, |
| | | "inboundQuantity": null, |
| | | "salesTargetCount": 0, |
| | | "consumerScanCount": 0, |
| | | "riskLevel": "NORMAL" |
| | | } |
| | | } |
| | | } |
| | | ``` |
| | | |
| | | ## 页é¢å±ç¤ºè§å |
| | | |
| | | ### 追溯æ¥è¯¢åºå |
| | | |
| | | | åæ®µ | ç»å®æ¹æ¬¡ï¼`batchBound=true`ï¼ | æªç»å®æ¹æ¬¡ï¼`batchBound=false`ï¼ | |
| | | |------|------------------------------|--------------------------------| |
| | | | åç§åç§° | `itemName` + `itemSpecification` ç©ºæ ¼æ¼æ¥ | åå·¦ | |
| | | | 计éåä½ | `itemUnitMeasureName` | åå·¦ | |
| | | | ç产ç»è¥è
| 页é¢å¸¸é `COMPANY_NAME` | åå·¦ | |
| | | | åå
è¯å«ä»£ç | `requestCode` â `batchCode` â `tempCode` 便¬¡åé | `requestCode` | |
| | | | 追溯ç½å | 页é¢å¸¸é `TRACE_URL` | åå·¦ | |
| | | | 追溯类å | `sourceType` | åå·¦ | |
| | | | æ¹æ¬¡å· | `batchCode` | **ä¸å±ç¤º**ï¼æ¿æ¢ä¸ºæç¤ºææ¡ | |
| | | | çäº§æ¥æ | `produceDate` | **ä¸å±ç¤º** | |
| | | | 产线 | `lineName`ï¼ä¸ºç©ºåé `lineCode` | **ä¸å±ç¤º** | |
| | | |
| | | **æªç»å®æ¹æ¬¡æ¶çæç¤ºææ¡ï¼æ¿ä»£æ¹æ¬¡å· / çäº§æ¥æ / 产线ä¸è¡ï¼ï¼** |
| | | |
| | | > 该追溯ç å°æªå½å
¥çäº§æ¹æ¬¡ï¼æ¹æ¬¡å·ãçäº§æ¥æã产线çä¿¡æ¯å¾
å®åï¼å½åå±ç¤ºè¯¥ç 对åºçåç§ä¿¡æ¯ã |
| | | |
| | | ### é²ä¼ªæ¥è¯¢åºå |
| | | |
| | | - `batchCode` æå¼æ¶ï¼`å¯¹åºæ¹æ¬¡` è¡å±ç¤ºæ¹æ¬¡å·ã |
| | | - `batchCode` 为空ï¼å³æªç»å®æ¹æ¬¡ï¼æ¶ï¼`å¯¹åºæ¹æ¬¡` è¡å±ç¤ºãå°æªç»å®æ¹æ¬¡ãï¼å¹¶ä»¥å¼±å / è¦ç¤ºæ ·å¼åºåï¼é¿å
è¢«è¯¯è¯»ä¸ºãæ æ°æ®ãã |
| | | |
| | | ## 注æäºé¡¹ |
| | | |
| | | - `batchBound` æ¯**å¯ä¸**å¤ææ¹æ¬¡æ¯å¦å·²å½å
¥çåæ®µï¼å端ä¸è¦ç¨ `batchCode == null` æ¨æï¼å岿°æ®ä¸åæ ·å卿¹æ¬¡å·ä¸ºç©ºä½æ¹æ¬¡å·²ç»å®çè¾¹çæ
åµï¼ã |
| | | - æªç»å®æ¹æ¬¡æ¶ï¼`bags` / `pallets` / `workers` / `quality` çåºåå为 `null`ï¼ä¸æ¯ç©ºæ°ç»ï¼ï¼å端渲æåéå¤ç©ºã |
| | | - æªç»å®æ¹æ¬¡çæ«ç **åæ ·ä¼**计å
¥é²ä¼ªæ¥è¯¢æ¬¡æ°ï¼`antiFake.scanCount`ï¼ä¸æ¶è´¹è
æ«ç äºä»¶ï¼é»è¾ä¸æ£å¸¸æ«ç ä¸è´ã |
| | | - æççåç§åãæçå
ä»»ä¸è¢ç ãçåç§ãç论ä¸å䏿ççè¢ç åç§ä¸è´ï¼è¥åºç°ä¸ä¸è´ï¼æ°æ®å¼å¸¸ï¼ï¼å±ç¤ºçåç§å¯è½ä¸å®é
ä¸ç¬¦ï¼å±å¯æ¥åçé级表ç°ã |
| | | - è¿½æº¯ç æ¬èº«ä¸å卿¶ä»è¿å `code=1040760000`ï¼å端沿ç¨åæé误æç¤ºï¼ä¸éè¦æ¹å¨ã |
| | | - æ¬æ¬¡ä¸º**æ¾å®½**æ ¡éªï¼ä¸å½±åå·²ç»å®æ¹æ¬¡çå岿°æ®ï¼æ¥å£ååå
¼å®¹ã |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | # åç§ç®¡ç廿ãåç§åç±»ããéè´ä»·ã - å端èè°æ¹æ¡ |
| | | |
| | | ## èæ¯ |
| | | |
| | | åºç¡æ°æ®-åç§ç®¡çä¸åç»´æ¤ãåç§åç±»ãåãéè´ä»·ãä¸¤ä¸ªåæ®µï¼ |
| | | |
| | | - æ°æ®åºå `mdm_item.category_id`ã`mdm_item.purchase_price` ä¿çï¼å岿°æ®ä¸å ï¼ï¼ä½æ¥å£å±ä¸åæ¥æ¶åè¿åã |
| | | - MDMâMES 忥ä¸åä¼ åç§åç±»ï¼åæ¥çæç MES ç©æãç©æåç±»ã为空ï¼å¯å¨ MES ç©æäº§åé¡µé¢æå·¥è¡¥å¡«ã |
| | | - MESâMDM åå忥ï¼MES ç©æå¾éãåæ¥å° MDMãåååç±»ï¼ä¿æä¸åã |
| | | |
| | | ## API åå |
| | | |
| | | | æ¹æ³ | è·¯å¾ | åå | |
| | | |------|------|------| |
| | | | POST | /mdm/item/create | 请æ±ä½ä¸åæ¥æ¶ `categoryId`ã`purchasePrice`ï¼ä¼ å
¥å°è¢«å¿½ç¥ï¼ | |
| | | | PUT | /mdm/item/update | åä¸ | |
| | | | GET | /mdm/item/get | ååºä¸åè¿å `categoryId`ã`categoryName`ã`purchasePrice` | |
| | | | GET | /mdm/item/page | ååºä¸åè¿åä¸è¿°ä¸å段ï¼ä¸åæ¯æ `categoryId` æ¥è¯¢åæ° | |
| | | | GET | /mdm/item/simple-list | ååºä¸åè¿åä¸è¿°ä¸å段 | |
| | | | GET | /mdm/item/list-by-ids | ååºä¸åè¿åä¸è¿°ä¸å段 | |
| | | |
| | | **ååºç¤ºä¾ï¼èéï¼ï¼** |
| | | |
| | | ```json |
| | | { |
| | | "code": 0, |
| | | "data": { |
| | | "list": [ |
| | | { |
| | | "id": 1, |
| | | "code": "PZ0001", |
| | | "name": "水稻åç§A", |
| | | "specification": "500g/è¢", |
| | | "unitMeasureId": 2, |
| | | "unitMeasureName": "è¢", |
| | | "salesPrice": 15.00, |
| | | "syncedMes": true |
| | | } |
| | | ], |
| | | "total": 1 |
| | | } |
| | | } |
| | | ``` |
| | | |
| | | ## å端修æ¹ç¹ï¼æ¬æ¹å·²åæ¥ä¿®æ¹ï¼ä¾å端å¢é夿 ¸ï¼ |
| | | |
| | | ### 1. åç§ç®¡ç页é¢ï¼src/views/basicData/mdm/ï¼ |
| | | |
| | | | æä»¶ | ä¿®æ¹å
容 | |
| | | |------|----------| |
| | | | data.ts | å é¤è¡¨åãåç§åç±»ãTreeSelectããéè´ä»·ãInputNumberï¼å é¤å表ãåç§åç±»ããéè´ä»·ãåï¼å é¤ `buildCategoryTree` å MES ç©æåç±»æ¥å£ import | |
| | | | index.vue | å é¤åç±»å表ç¼åãåç±»åç§°/é¢è²å·¥å
·å½æ°ã`#categoryName` ææ§½ååç±»å è½½é»è¾ | |
| | | | modules/form.vue | å 餿å¼è¡¨åæ¶å è½½åç±»æ çé»è¾ | |
| | | | components/data.ts | åç§éæ©å¼¹çªå é¤ãåç§åç±»ãæç´¢é¡¹ä¸å | |
| | | | components/select-dialog.vue | å é¤åç±»ç¼åãåç§°/é¢è²å½æ°ã`#categoryId` ææ§½ååç±»å è½½é»è¾ | |
| | | |
| | | ### 2. API ç±»åï¼src/api/mdm/item/index.tsï¼ |
| | | |
| | | - `MdmItemApi.Item` å é¤ `categoryId`ã`categoryName`ã`purchasePrice`ã |
| | | - `MdmItemApi.PageParams` å é¤ `categoryId`ã |
| | | |
| | | ### 3. ä¾èµéè´ä»·èªå¨ç®ä»·ç忮页ï¼è¡ä¸ºååï¼éç¹å¤æ ¸ï¼ |
| | | |
| | | åç§ä¸åæéè´ä»·ï¼ä»¥ä¸ä¸¤å¤éååãåä»·ãä¸åèªå¨å¸¦å
¥ï¼æ¹ä¸ºé»è®¤ 0ãç±ç¨æ·æå·¥å¡«åï¼ |
| | | |
| | | | æä»¶ | ä¿®æ¹å
容 | |
| | | |------|----------| |
| | | | src/views/erp/purchase/order/modules/item-form.vue | éæ©åç§å `productPrice` ä¸ååéè´ä»·ï¼ç½® 0 æå·¥å¡«å | |
| | | | src/views/erp/purchase/request/modules/item-form.vue | åä¸ | |
| | | |
| | | å
¶ä½åæ®ï¼éå®ãåºåçï¼ä½¿ç¨çæ¯ ERP 产åï¼`erp_product`ï¼èªèº«ä»·æ ¼æéå®ä»·ï¼ä¸åå½±åã |
| | | |
| | | ## ä¸å¡è§å说æ |
| | | |
| | | | åºæ¯ | è§å | |
| | | |------|------| |
| | | | æ°å¢/ç¼è¾åç§ | æ åç±»ãæ éè´ä»·å段ï¼ä¿åæ¥å£å¿½ç¥è¿ä¸¤ä¸ªå
¥å | |
| | | | ç¼è¾åå²åç§ | åå²å·²å¡«çåç±»/éè´ä»·å¨æ´æ°æ¶ä¸ä¼è¢«æ¸
空ï¼ä»
ä¸ååæ¾ï¼ï¼ä¹ä¸ä¼è¢«è¦ç | |
| | | | åç§åæ¥å° MES | çæç MES ç©æäº§åãç©æåç±»ã为空ï¼MES ç©æäº§å页é¢ä»å¯æå·¥è¡¥å¡«åç±» | |
| | | | MES ç©æå¾éåæ¥å° MDM | åç±»åå `mdm_item.category_id` ä¿æåé»è¾ï¼åç§ç®¡ç页é¢ä¸å±ç¤ºè¯¥å¼ï¼ | |
| | | | åç§åç±»ç®¡çæ¨¡å | 䏿¹å¨ï¼åç±»æ°æ®ä»ä¾ MES ç©æåç±»çåºæ¯ä½¿ç¨ | |
| | | |
| | | ## 注æäºé¡¹ |
| | | |
| | | - éå®ä»·ãææ¬ä»·æªä¸çº¿ï¼è¡¨åä¸åè¡¨ä¿æåæ ·ã |
| | | - å表å é¤ä¸¤ååå宽èªè¡å¾®è°ã |
| | | - åç§éæ©å¼¹çªï¼MdmItemSelect/MdmItemSelectDialogï¼è¢«éè´ãåºåçå¤å¤ä¸å¡é¡µå¤ç¨ï¼å é¤åç±»åå请åå½éªè¯éå带å
¥ï¼ç¼ç /åç§°/åä½/æ¡ç ï¼æ¯å¦æ£å¸¸ã |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | # MDM 计éå使°å¢ãç±»åãåæ®µ - å端èè°æ¹æ¡ |
| | | |
| | | ## æ¶åé¡µé¢ |
| | | |
| | | - åºç¡æ°æ® > MDM > 计éåä½ï¼åè¡¨ãæ°å¢/ç¼è¾å¼¹çªï¼ |
| | | |
| | | ## API |
| | | |
| | | æ¥å£è·¯å¾ä¸åï¼ä»
请æ±/ååºä½æ°å¢ `type` åæ®µã |
| | | |
| | | | æ¹æ³ | è·¯å¾ | 说æ | |
| | | |------|------|------| |
| | | | POST | /mdm/unit/create | å建计éåä½ï¼è¯·æ±ä½æ°å¢ typeï¼ | |
| | | | PUT | /mdm/unit/update | æ´æ°è®¡éåä½ï¼è¯·æ±ä½æ°å¢ typeï¼ | |
| | | | GET | /mdm/unit/get | è·å¾è®¡éåä½ï¼ååºæ°å¢ typeï¼ | |
| | | | GET | /mdm/unit/page | è·å¾è®¡éåä½å页ï¼ååºæ°å¢ typeï¼ | |
| | | | GET | /mdm/unit/list | è·å¾è®¡éåä½å表ï¼ååºæ°å¢ typeï¼ | |
| | | |
| | | **请æ±åæ°ï¼æ°å¢ï¼ï¼** |
| | | |
| | | | åæ° | ç±»å | å¿
å¡« | 说æ | |
| | | |------|------|------|------| |
| | | | type | String | æ¯ | ç±»åï¼åéï¼å¯éå¼åºå®ä¸ºï¼`48åå
`ã`100åå
`ã`å¨`ï¼ä¸éä¸ï¼ç´æ¥åææ¬ï¼å端 `@NotBlank` æ ¡éªï¼ | |
| | | |
| | | **ååºåæ®µï¼æ°å¢ï¼ï¼** |
| | | |
| | | | åæ®µ | ç±»å | 说æ | |
| | | |------|------|------| |
| | | | type | String | ç±»åï¼å岿°æ®ä¸º null | |
| | | |
| | | **ååºç¤ºä¾ï¼** |
| | | |
| | | ```json |
| | | { |
| | | "code": 0, |
| | | "data": { |
| | | "id": 1, |
| | | "code": "BAG", |
| | | "name": "è¢", |
| | | "type": "48åå
", |
| | | "status": 0 |
| | | } |
| | | } |
| | | ``` |
| | | |
| | | ## å端修æ¹ç¹è¯´æï¼å·²éæ¬æ¬¡å端æ¹å¨ä¸å¹¶å®æï¼ä¾æ ¸å¯¹ï¼ |
| | | |
| | | | ä½ç½® | è¦æ± | |
| | | |------|------| |
| | | | æ°å¢/ç¼è¾å¼¹çªè¡¨å | å¢å ãç±»åã䏿鿩ï¼é项åºå®ä¸é¡¹ï¼48åå
/ 100åå
/ å¨ï¼åéãå¿
å¡« | |
| | | | åè¡¨è¡¨æ ¼ | å¢å ãç±»åãåå±ç¤ºï¼ç©ºå¼æ¾ç¤ºä¸º `-` | |
| | | | æ¥è¯¢è¡¨å | æä¸æä¾ç±»åçéï¼å端å页æ¥å£æªå è¯¥è¿æ»¤æ¡ä»¶ï¼ | |
| | | |
| | | ## ä¸å¡è§å说æ |
| | | |
| | | | åºæ¯ | è§å | |
| | | |------|------| |
| | | | åéæ°æ® | èè®°å½ `type` 为空ï¼å表å±ç¤º `-`ï¼ç¼è¾èè®°å½æ¶å¿
须补éç±»ååæè½ä¿åï¼åç«¯å¼ºæ ¡éªï¼ | |
| | | | éé¡¹æ¥æº | é项为åç«¯åæ»ä¸é¡¹ææ¬ï¼ä¸å»ºæ°æ®åå
¸ï¼æäº¤ç value å³ä¸æææ¬æ¬èº« | |
| | | | åç«¯æ ¡éª | `@NotBlank` å¿
å¡«æ ¡éªï¼åå¼èå´ä¸éå¶ï¼åç«¯ä¸æéä¿è¯åªä¼æäº¤ä¸ä¸ªåºå®å¼ | |
| | | |
| | | ## 注æäºé¡¹ |
| | | |
| | | - `type` ä¸ºææ¬åæ®µï¼VARCHAR(20)ï¼ï¼ä¿åæ¶ä¼ 䏿åæï¼ä¸è¦ä¼ ç¼ç ææ°åã |
| | | - è¯¥åæ®µå¿
å¡«ï¼ä¸ºç©ºæ¶æ¥å£è¿ååæ°æ ¡éªé误ãç±»åä¸è½ä¸ºç©ºãã |
| | | - 计éåä½è¢«ç©æå¼ç¨åä»å¯ä¿®æ¹ç±»åï¼æ 级èéå¶ã |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | # ä¸è¢ä¸ç ç产é»è¾æ¹é - å端èè°æ¹æ¡ |
| | | |
| | | > é
å¥éæ±æ¹æ¡ï¼`docs/mes_bag_code_package_refactor_requirements.md`ãæ¬æ¹æ¡è¦çæ¥å£åæ´ä¸é¡µé¢æ°æ®å¸¦å
¥ï¼åç«¯ä¸»ä½æ¹å¨å·²éæ¬æ¬¡æ¹é 忥宿ï¼ä¾èè°åå½ä½¿ç¨ã |
| | | |
| | | ## æ¶åé¡µé¢ |
| | | |
| | | - èµç 管çï¼è¢ç ï¼ï¼çææ°æ®å
å¼¹çªãçæåå§è¢ç å¼¹çªãè¢ç å表ãå½å
¥æ¹æ¬¡ãç»å®æçãè¿½æº¯å¼¹çª |
| | | - çäº§æ¹æ¬¡ï¼æ°å¢/ç¼è¾/è¡¥å½è¡¨åï¼æ°å¢ãç»å®æçãå¤éï¼ãå表ãæç´¢åº |
| | | - æç管çï¼é¢çæå¼¹çªãå表ãç»å®æ¹æ¬¡å¼¹çª |
| | | - å
Œ
± H5 溯æºé¡µãæ«ç 追溯弹çªï¼åå½ï¼ |
| | | |
| | | ## ä¸å¡æµç¨ä¸æ°æ®å¸¦å
¥ |
| | | |
| | | 1. çææ°æ®å
ï¼éåç§ â å端æåç§ä¸»è®¡éåä½ç±»åèå¨ï¼æ¥ `/mdm/item/get` å `unitMeasureId`ï¼åæ¥ `/mdm/unit/get?id=` å `type`ï¼ï¼ |
| | | - `48åå
`/`100åå
` â è¾å
¥**æçæ°**ï¼é¢è§ãæ¯æ N è¢ Ã æçæ° = è¢ç æ°ã |
| | | - `å¨` â è¾å
¥**è¢ç æ°**ï¼æ æçï¼ |
| | | - ç±»åæªé
ç½® â æç¤ºåå¾ã计éåä½ãç»´æ¤ï¼æäº¤æ¶å端ä¹ä¼å
åºæ¥é |
| | | 2. çæç»æï¼åä¸ uuid è¢ç ç» + èªå¨çæçä¸´æ¶æçï¼PL-åºå·ï¼ï¼è¢ç 已带åç§ãå·²ç»æçã |
| | | 3. å½å
¥æ¹æ¬¡ï¼å¾éè¢ç â éçäº§æ¹æ¬¡ãå端级èï¼ä¸´æ¶æç忣å¼ç ï¼æ¹æ¬¡å·-Påºå·ï¼å¹¶ç»æ¹æ¬¡ãååè¢ç å使çç ãæ··åç§ä¼è¢«æ¦æªã |
| | | 4. æ¹æ¬¡ä¸åå½å
¥/å±ç¤ºåç§ï¼åç§ä¿¡æ¯å
¨é¨ç±è¢ç æ°æ®å
æºå¸¦ã |
| | | 5. æ°å¢/è¡¥å½/ç¼è¾æ¹æ¬¡æ¶åå¯éãç»å®æçãï¼å¤éãéå¿
å¡«ï¼æ°æ®æº `GET /mes/pro/pallet/unbound-list`ï¼å±ç¤ºä¸´æ¶æçç +å·²è£
è¢æ°ï¼ï¼å¾éåæ¹æ¬¡ç¶æç´æ¥ä¸º**ç产ä¸**ï¼å端åäºå¡å¤ç¨æçç»å®æ¹æ¬¡é»è¾ï¼æç忣å¼ç ãæçä¸è¢ç 级èå½å
¥ï¼ï¼ä»»ä¸æ ¡éªå¤±è´¥æ´ä½åæ»ï¼ç¼è¾æ¶ä»
éå¾éæ¬æ¬¡æ°å¢çæçï¼å·²ç»å®æçä¸å¨ä¸æä¸ãä¸å¯è§£ç»ï¼ã |
| | | |
| | | ## API |
| | | |
| | | | æ¹æ³ | è·¯å¾ | åæ´ | |
| | | |------|------|------| |
| | | | POST | /mes/pro/bag-code/generate | 请æ±/ååºç»æåæ´ï¼è§ä¸ï¼ | |
| | | | POST | /mes/pro/bag-code/raw-generate | **æ°å¢**ï¼çæåå§è¢ç ï¼è¯·æ± `{ itemId, count, remark? }`ï¼ä»
ææ°éçæã䏿¢ç®è®¡éåä½ç±»åãä¸çææçï¼ååºç»æå generateï¼`type/perPallet` 为空ã`palletIds` 空æ°ç»ï¼ | |
| | | | PUT | /mes/pro/bag-code/bind-batch | è·¯å¾ä¸åï¼æ°å¢åç§ä¸è´æ ¡éªãæç级èç»å®ï¼å·²å¯¼åºå°å·ï¼PRINTEDï¼è¢ç ä¹å
许å½å
¥æ¹æ¬¡ | |
| | | | PUT | /mes/pro/pallet/bind-batch | è·¯å¾ä¸åï¼æçç»å®æ¹æ¬¡æ¶ï¼æç䏿ªç»æ¹æ¬¡çè¢ç èªå¨çº§èå½å
¥å䏿¹æ¬¡ï¼åç§ä¸è´æ ¡éªãååæ¹æ¬¡è¢æ°ï¼ | |
| | | | DELETE | /mes/pro/bag-code/delete-by-uuid | è·¯å¾ä¸åï¼çº§èå 餿¬ç»èªå¨çææç | |
| | | | POST | /mes/pro/bag-code/replace | ä¸åï¼æ°è¢ç èªå¨ç»§æ¿ååç§ | |
| | | | GET | /mes/pro/bag-code/pageãlist-by-uuidãget-by-code | ååºæ°å¢åç§å段ï¼page æ°å¢å¯éæ¥è¯¢åæ° `itemId`ï¼åç§ï¼çå¼å¹é
ï¼å¯¼åº Excel åå£å¾ï¼ | |
| | | | POST | /mes/pro/pallet/batch-createãpre-generate | 请æ±å»æ capacity | |
| | | | GET | /mes/pro/pallet/page | ååºå»æ capacityï¼ä¿ç autoGenerated | |
| | | | POST/PUT | /mes/pro/batch/createãupdateãfill-info | 请æ±å»æ itemIdï¼ä¸è
åæ°å¢å¯é `palletIds`ï¼ç»å®æ¶æ¹æ¬¡è¿å
¥ç产ä¸ï¼ | |
| | | | GET | /mes/pro/pallet/unbound-list | **æ°å¢**ï¼æªç»å®æ¹æ¬¡çä¸´æ¶æçåè¡¨ï¼æé mes:pro-pallet:queryï¼ï¼ä¾æ¹æ¬¡æ°å¢/è¡¥å½ç»å®æç䏿 | |
| | | | GET | /mes/pro/batch/pageãgetãsimple-list | ååºå»æ itemId/itemCode/itemName/itemSpecification | |
| | | |
| | | **çææ°æ®å
请æ±åæ°ï¼** |
| | | |
| | | | åæ° | ç±»å | å¿
å¡« | 说æ | |
| | | |------|------|------|------| |
| | | | itemId | Long | æ¯ | åç§ç¼å· | |
| | | | palletCount | Integer | æ¡ä»¶å¿
å¡« | æçæ°ï¼ç±»å=Nåå
ï¼ | |
| | | | bagCount | Integer | æ¡ä»¶å¿
å¡« | è¢ç æ°ï¼ç±»å=å¨ï¼ | |
| | | | remark | String | å¦ | 夿³¨ | |
| | | |
| | | **çææ°æ®å
ååºç¤ºä¾ï¼** |
| | | |
| | | ```json |
| | | { |
| | | "code": 0, |
| | | "data": { |
| | | "uuid": "çæç»UUID", |
| | | "type": "48åå
", |
| | | "perPallet": 48, |
| | | "totalCount": 96, |
| | | "palletIds": [101, 102] |
| | | } |
| | | } |
| | | ``` |
| | | |
| | | ## åæ®µå±ç¤ºè§å |
| | | |
| | | | åæ®µ | å±ç¤ºä½ç½® | 说æ | |
| | | |------|----------|------| |
| | | | åç§ç¼ç /åç§°ï¼itemCode/itemNameï¼ | è¢ç å表ã追溯ãå¯¼åº Excel | çææ¶ç»å®å¨è¢ç ä¸ | |
| | | | autoGenerated | æçå表ãèªå¨çæãTag | æ°æ®å
èªå¨å建çæçæ è¯ | |
| | | | åç§ï¼æ¹æ¬¡é¡µï¼ | ä¸åå±ç¤º | 表å/å表/æç´¢åå·²ç§»é¤ | |
| | | |
| | | ## ä¸å¡è§å说æ |
| | | |
| | | | åºæ¯ | è§å | |
| | | |------|------| |
| | | | ç±»å=Nåå
çæ | è¢ç æ° = N à æçæ°ï¼èªå¨å»º N 个æçå¹¶ååç»å® | |
| | | | ç±»å=å¨ çæ | æ æçï¼è¢ç ä»
ç»æ¹æ¬¡ | |
| | | | çæåå§è¢ç | ä»
éåç§+æ°éï¼è¢ç 带åç§ãä¸ç»æ¹æ¬¡/æçï¼åç»å½å
¥æ¹æ¬¡ãç»æçã导åºå°å·ãå é¤ç»ä¸æ°æ®å
è¢ç å®å
¨ä¸è´ï¼ä¸æ ¡éªåç§è®¡éåä½ç±»å | |
| | | | å½å
¥æ¹æ¬¡æ··åç§ | æ¥éãå½å
¥æ¹æ¬¡çè¢ç å¿
é¡»å±äºåä¸åç§ãï¼ä¸æ¹æ¬¡å·²æè¢ç ä¸å¹¶æ ¡éªï¼ | |
| | | | æçç»å®æ¹æ¬¡ | æç䏿ªç»æ¹æ¬¡çè¢ç ï¼å·²çæ/已导åºå°å·ï¼èªå¨éæçå½å
¥å䏿¹æ¬¡ï¼è¢ç å使çç åæ¥æ´æ°ä¸ºæ£å¼ç | |
| | | | æ¹æ¬¡æ°å¢/è¡¥å½/ç¼è¾ç»å®æç | palletIds éç©ºæ¶æ¹æ¬¡ç¶æç´æ¥ç½®ãç产ä¸ãï¼åäºå¡å¤ç¨æçç»å®æ¹æ¬¡é»è¾ï¼æ£å¼ç +è¢ç 级è+åç§ä¸è´æ ¡éªï¼ï¼å¤±è´¥æ´ä½åæ»ï¼æ°å¢/è¡¥å½æªå¾éåç»´æè稿ï¼ç¼è¾åæ¶å¾éä¸åéç¶æãå·²ç»å®æçä¸å¯è§£ç» | |
| | | | ç»æç容é | æ ä¸éï¼èªå¨æçå¯ç»§ç»æå¨ç»å
¥ | |
| | | | å 餿°æ®å
| ç»å
æçå·²ç»æ¹æ¬¡æææ£å¼ç åä¸å¯å ï¼å¦å级èå èªå¨æç | |
| | | | 追溯åç§ | ä¼å
è¢ç åç§ï¼åå²è¢ç åéæ¹æ¬¡åç§ï¼å
Œ
± H5 åæ¥æ¯æï¼ | |
| | | | æ¹æ¬¡å· | PC + yyyyMMdd + 产线ç¼ç + æµæ°´å·ï¼ä¸åå«åç§ç¼ç ï¼ | |
| | | |
| | | ## 注æäºé¡¹ |
| | | |
| | | - `generate` æ§åæ° `count` å·²åºå¼ï¼åªä¼ `palletCount` æ `bagCount`ï¼æåç§ç±»åäºéä¸ï¼ã |
| | | - æ¹æ¬¡ `itemId` ç¸å
³åæ®µå·²ä»æ¥å£ç§»é¤ï¼å¿åå¼ç¨ï¼æ¹æ¬¡è¿½æº¯è§å¾ `get-by-code` çåç§å段ä¿çï¼å¯è½ä¸ºç©º=æ°æ¹æ¬¡ï¼ã |
| | | - æç追溯è§å¾ï¼PalletTrace/qr-trace-modalï¼ä»è¿å `capacity` ä¾å岿°æ®å±ç¤ºï¼æ°æç为空ã |
| | | - èæ°æ®ï¼åå²ç©ºç½è¢ç ï¼åç§ä¸ºç©ºå±æ£å¸¸ï¼è¿½æº¯èµ°æ¹æ¬¡åéã |
| | | - `palletIds` å¨ create/update/fill-info åçæï¼ä¸ææ¯æ¬¡æå¼å¼¹çªéæ°æå `unbound-list`ï¼è¥æäº¤æ¶æéæç已被ä»äººç»å®ï¼å端æ´ä½æ¥éåæ»ï¼æ¬æ¬¡æ¹æ¬¡æä½ä¸çæï¼ï¼æç¤ºç¨æ·å·æ°éè¯ã |
| | | - è¢ç å页ï¼`/page`ï¼å端已æ¹ä¸º**å建æ¶é´ååº**ï¼åç§å
æç¼å·ååºï¼ï¼å端æ éåä¼ æåºåæ°ï¼å¯¼åº Excel åå£å¾ã |
| | | - åå§è¢ç 䏿°æ®å
è¢ç å表åè§åï¼uuid æç»ã坿´ç»å é¤ï¼ï¼å表页éè¿çæç» UUID åºåæ¥æºã |
| | | - å表æç´¢åºæ°å¢ãåç§ãæ¡ä»¶ï¼å¤ç¨ `MdmItemSelect`ï¼å¯æ¸
空ï¼ï¼ä¼ `itemId` çå¼è¿æ»¤ï¼å¯¼åº Excel æºå¸¦å䏿¥è¯¢æ¡ä»¶åå£å¾çæãåå²ç©ºç½è¢ç åç§ä¸ºç©ºï¼æåç§çéä¸ä¼å½ä¸ã |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | # ä¸è¢ä¸ç ç产é»è¾æ¹é - éæ±æ¹æ¡ |
| | | |
| | | > ç¶æï¼å·²ç¡®è®¤å¹¶å®æå®æ½ï¼2026-09-17ï¼ãå³çç¹å®ç¨¿è§ææ«ã6. 确认ç»è®ºãã |
| | | |
| | | ## 1. éæ±èæ¯ |
| | | |
| | | ä¸è¢ä¸ç çç产é»è¾è°æ´ï¼ |
| | | |
| | | - æ¹æ¬¡ç产管ç**ä¸åç»å®åç§**ï¼åç§ä¸æ²å°ãèµç 管çãçæ°æ®å
ä¸ã |
| | | - çææ°æ®å
æ¶éæ©**åç§**å¹¶è¾å
¥**æçæ°**ï¼ç³»ç»æåç§ä¸»è®¡éåä½çãç±»åãèªå¨è®¡ç®è¢ç æ°éå¹¶çæè¢ç ã |
| | | - ææçæ°**èªå¨çææçå¹¶èªå¨ç»å®**è¢ç ï¼æçä¸åéè¦ãå¯è£
è¢æ°ãã |
| | | - åç§ä¸ºãå¨ãæ¶æ æçï¼æ¹ä¸ºç´æ¥è¾å
¥**è¢ç æ°**ï¼è¢ç åªç»çäº§æ¹æ¬¡ãä¸ç»æçç ã |
| | | |
| | | ## 2. ç°ç¶è¦ç¹ |
| | | |
| | | | 对象 | ç°ç¶ | |
| | | |------|------| |
| | | | æ°æ®å
çæ | `POST /mes/pro/bag-code/generate` ä»
ä¼ `count`ï¼çæç©ºç½è¢ç ï¼æ åç§/æ¹æ¬¡/æçï¼ | |
| | | | æ¹æ¬¡ | `mes_pro_batch.itemId` ç»å®åç§ï¼æ¹æ¬¡å· = PC + æ¥æ + 产线ç¼ç + åç§ç¼ç + æµæ°´å· | |
| | | | æç | æå¨åå»ºï¼æ¹éçæ/é¢çæï¼ï¼å建æ¶å¡« `capacity å¯è£
è¢æ°`ï¼è¢ç æå¨ç»æçå¹¶æ ¡éªå®¹é | |
| | | | åç§âåä½ | `mdm_item.unitMeasureId â mdm_unit_measure.type`ï¼ç±»åé项ï¼48åå
/100åå
/å¨ï¼æ¬æ¬¡å·²å ï¼ | |
| | | | 追溯 | æ«ç 追溯çåç§ä¿¡æ¯åèªæ¹æ¬¡ `batch.itemId` | |
| | | |
| | | ## 3. æ¹é æ¹æ¡ |
| | | |
| | | ### 3.1 çææ°æ®å
ï¼èµç 管çï¼æ ¸å¿æ¹å¨ï¼ |
| | | |
| | | **æ¢ç®è§å**ï¼å端计ç®ï¼ä¸ä¿¡ä»»åç«¯ä¼ å¼ï¼ï¼ |
| | | |
| | | | åç§ä¸»åä½ç±»å | è¾å
¥ | çæç»æ | |
| | | |------|------|------| |
| | | | 48åå
| æçæ° P | è¢ç 48 à P 个ï¼èªå¨çæ P 个æçï¼æ¯æç»å® 48 个è¢ç | |
| | | | 100åå
| æçæ° P | è¢ç 100 à P 个ï¼èªå¨çæ P 个æçï¼æ¯æç»å® 100 个è¢ç | |
| | | | å¨ | è¢ç æ° N | è¢ç N 个ï¼ä¸çææçï¼è¢ç ä¸ç»æç | |
| | | | ç±»å为空/æ æ³è§£æ | - | æ¥éï¼åç§ä¸»è®¡éå使ªé
置类åï¼48åå
/100åå
/å¨ï¼ | |
| | | |
| | | **æ¥å£åæ´** `POST /mes/pro/bag-code/generate`ï¼ |
| | | |
| | | | åæ° | ç±»å | å¿
å¡« | 说æ | |
| | | |------|------|------|------| |
| | | | itemId | Long | æ¯ | åç§ï¼mdm_item ç¼å·ï¼ | |
| | | | palletCount | Integer | æ¡ä»¶å¿
å¡« | æçæ°ï¼ç±»å为 Nåå
æ¶å¿
å¡«ï¼ | |
| | | | bagCount | Integer | æ¡ä»¶å¿
å¡« | è¢ç æ°ï¼ç±»å为 å¨ æ¶å¿
å¡«ï¼ | |
| | | | remark | String | å¦ | 夿³¨ | |
| | | |
| | | ååºæ°å¢ï¼`uuidãtypeãperPalletï¼æ¯æè¢æ°ï¼ãtotalCountï¼çæè¢ç æ°ï¼ãpalletIdsï¼èªå¨çæçæçï¼`ã |
| | | |
| | | **äºå¡é»è¾**ï¼ä¸æ¬¡çæ = åä¸ uuid çè¢ç ç» + åæ¹èªå¨çæçæçï¼æçå
以**临æ¶ç ï¼PL-åºå·ï¼**è½åºå¹¶å®æè¢ç ç»å®ï¼æ£å¼æçç å¨ãå½å
¥æ¹æ¬¡ãæ¶çæã |
| | | |
| | | **çææ°æ®å
å¼¹çªï¼å端ï¼**ï¼éæ©åç§ï¼æ²¿ç¨åç§éæ©ç»ä»¶ï¼â 读å该åç§ä¸»åä½ç±»åï¼åç«¯æ¥ `mdm_unit_measure`ï¼ç±»åä¸ºç©ºç»æç¤ºï¼â æç±»å忢è¾å
¥ãæçæ°ãæãè¢ç æ°ãâ 宿¶é¢è§"å°çæ è¢ç X 个 / æç Y 个"ã |
| | | |
| | | ### 3.2 å½å
¥æ¹æ¬¡ï¼ä¿æåå½å
¥ï¼æ©å±çº§èï¼ |
| | | |
| | | `PUT /mes/pro/bag-code/bind-batch` æµç¨ä¸åï¼æ°å¢çº§èï¼ |
| | | |
| | | 1. è¢ç ç»å®æ¹æ¬¡ï¼ç°ç¶ï¼ã |
| | | 2. 该ç»è¢ç æç»å®çä¸´æ¶æçèªå¨ç»å®å䏿¹æ¬¡ï¼å¹¶åé
æ£å¼æçç `æ¹æ¬¡å·-Påºå·`ï¼ååæ¹æ¬¡æçæ°ã |
| | | 3. æ°å¢æ ¡éªï¼å䏿°æ®å
ï¼åæ¹ç»å®è¢ç ï¼åç§å¿
é¡»ä¸è´ï¼çææ¶å¤©ç¶ä¸è´ï¼é²æå¨æ··éï¼ã |
| | | |
| | | ### 3.3 è¢ç æ°æ®æ¨¡å |
| | | |
| | | `mes_pro_bag_code` æ°å¢ï¼`item_id`ã`item_code`ã`item_name`ï¼åä½ï¼ã |
| | | |
| | | - å表/æ¥è¯¢ï¼æ¾ç¤ºåç§åï¼ç¼ç /åç§°å¯æ£ç´¢æ¬æä¸åï¼ä»
å±ç¤ºï¼ã |
| | | - å 餿°æ®å
ï¼delete-by-uuidï¼ï¼çº§èå 餿¬ç»**èªå¨çæ**çæçï¼åæä»æ¯å
¨é¨æªç»æ¹æ¬¡ï¼å·²å½æ¹æ¬¡ç»´æç°ç¶ä¸å¯å ï¼ã |
| | | - è¢ç ä¸å¼ºå¶æçï¼`pallet_id` ä¿æå¯ç©ºï¼å¨ç±»åï¼ã |
| | | |
| | | ### 3.4 æ¹æ¬¡ç产管ç |
| | | |
| | | - **廿åç§å段**ï¼å建/ç¼è¾è¡¨åãå表åãæ¥è¯¢æ¡ä»¶ãSave/Resp/Page VO åç§»é¤ `itemId`ï¼DO 䏿°æ®åºå `mes_pro_batch.item_id` ä¿çï¼å岿°æ®ã追溯åéç¨ï¼ï¼æ³¨éæ è®°"å·²åºå¼"ã |
| | | - **æ¹æ¬¡å·è§åæ¹ä¸º** `PC + yyyyMMdd + 产线ç¼ç + æµæ°´å·`ï¼`generateBatchCode` ä¸åæ¼åç§ç¼ç ï¼èªå¨ç¼ç è§åé
ç½®æ éæ¹ï¼ã |
| | | - ç¼è¾æ¹æ¬¡ä¸åå åç§ååéæ°çææ¹æ¬¡å·ã |
| | | |
| | | ### 3.5 æç管ç |
| | | |
| | | - æ¹éçæ/é¢çææ¥å£å»æ `capacity` å
¥åï¼è¡¨å廿ãå¯è£
è¢æ°ãåæ®µï¼åè¡¨å»æè¯¥åãDB åä¿çå
¼å®¹åå²ã |
| | | - è¢ç æå¨ç»æçå»æå®¹éæ ¡éªï¼`capacity` å¤ç©ºé»è¾å¤©ç¶è·³è¿ï¼å é¤ç¸å
³æ ¡éªä»£ç ï¼ã |
| | | - æçå表为èªå¨çææçææ è¯ï¼å¤ç¨ `auto_generated` åæ®µ = trueï¼ã |
| | | |
| | | ### 3.6 追溯/æ«ç /çæ¿ï¼åå½é¡¹ï¼ |
| | | |
| | | - è¢ç 追溯ï¼`/get-by-code`ãTraceRespVOï¼ï¼åç§æ¹ä¸º**ä¼å
åè¢ç item_idï¼åå²è¢ç åéæ¹æ¬¡ itemId**ã |
| | | - æ¹æ¬¡è¿½æº¯è§å¾ï¼MesProBatchTraceRespVOï¼ï¼ä¿çåç§è¿åä½å¯è½ä¸ºç©ºï¼å岿¹æ¬¡æå¼ï¼ã |
| | | - æ«ç å
¥åºãéå®åºåºãè¢ç é¦é¡µçæ¿ï¼ä¸ç´æ¥ä¾èµæ¹æ¬¡åç§çé»è¾ä¸å¨ï¼æ¶åå¤åå½éªè¯ã |
| | | |
| | | ## 4. æ°æ®åºåæ´ï¼mom-thzyï¼ |
| | | |
| | | ```sql |
| | | ALTER TABLE mes_pro_bag_code ADD COLUMN item_id BIGINT NULL COMMENT 'åç§ï¼ç©æï¼ç¼å·' AFTER pallet_code; |
| | | ALTER TABLE mes_pro_bag_code ADD COLUMN item_code VARCHAR(64) NULL COMMENT 'åç§ç¼ç ï¼åä½ï¼' AFTER item_id; |
| | | ALTER TABLE mes_pro_bag_code ADD COLUMN item_name VARCHAR(255) NULL COMMENT 'åç§åç§°ï¼åä½ï¼' AFTER item_code; |
| | | -- mes_pro_batch.item_id ä¿çä¸å ï¼Java æ³¨éæ è®°åºå¼ |
| | | ``` |
| | | |
| | | ## 5. åå端æ¹å¨æ¸
å |
| | | |
| | | | å± | æä»¶ | æ¹å¨ | |
| | | |----|------|------| |
| | | | DB | mes_pro_bag_code | +item_id/item_code/item_name | |
| | | | å端 | MesProBagCodeGenerateReqVO/RespVOãServiceImpl | æ°åæ°ãç±»åæ¢ç®ãèªå¨å»ºæçãäºå¡ | |
| | | | å端 | MesProBagCodeDO/RespVO/Mapper | +åç§å段 | |
| | | | å端 | bind-batch æµç¨ | 级èæçç»æ¹æ¬¡ãåç§ä¸è´æ§æ ¡éª | |
| | | | å端 | MesProBatchServiceImpl/VO | å»åç§ãæ¹æ¬¡å·è§åãç¼è¾é»è¾ | |
| | | | å端 | MesProPalletServiceImpl/VO | å» capacity å
¥å䏿 ¡éª | |
| | | | å端 | delete-by-uuid | 级èå èªå¨æç | |
| | | | å端 | 追溯 VO | åç§ä¼å
è¢ç ãåéæ¹æ¬¡ | |
| | | | å端 | pro/bagCode generate-form | åç§+æçæ°/è¢ç æ°è¡¨å | |
| | | | å端 | pro/bagCode å表 | +åç§å | |
| | | | å端 | pro/batch form/list/search | ç§»é¤åç§ | |
| | | | å端 | pro/pallet form/list | ç§»é¤å¯è£
è¢æ° | |
| | | |
| | | ## 6. 确认ç»è®ºï¼å®ç¨¿ï¼ |
| | | |
| | | 1. **æ··åç§**ï¼è¦ã䏿¬¡ bind-batch å¾éçè¢ç åç§å¿
é¡»ä¸è´ï¼å¦åæ¥éãå½å
¥æ¹æ¬¡çè¢ç å¿
é¡»å±äºåä¸åç§ãï¼åå²ç©ºç½è¢ç ä¸å䏿 ¡éªï¼ã |
| | | 2. **èªå¨æçå¯å¦åæå¨å¢ç»**ï¼æ 容éä¸éï¼è£
满åä»å¯ç»§ç»æå¨ç»å
¥è¢ç ã |
| | | 3. **æ¹æ¬¡å表å岿°æ®**ï¼èæ¹æ¬¡ itemId ç´æ¥ä¸å±ç¤ºå³å¯ï¼æ æ°æ®è¿ç§»ï¼è¿½æº¯è§å¾ä¿çæ¹æ¬¡åç§ååå²åéã |
| | | 4. **æµç¨ä¸æ¹æ¬¡å·**ï¼ä¿æãå
çææ°æ®å
ãåå½å
¥æ¹æ¬¡ãï¼æ¹æ¬¡å·è§åæ¹ä¸º `PC + yyyyMMdd + 产线ç¼ç + æµæ°´å·`ã |
| | | |
| | | ## 7. 宿½è®°å½ï¼2026-09-17ï¼ |
| | | |
| | | - DBï¼mom-thzyï¼ï¼`mes_pro_bag_code` æ°å¢ `item_id/item_code/item_name`ï¼`mdm_unit_measure.type`ï¼48åå
/100åå
/å¨ï¼ï¼`mes_pro_batch.item_id` ä¿çæ åºå¼ã |
| | | - å端ï¼`generate` éåï¼ç±»åæ¢ç®+èªå¨ä¸´æ¶æçï¼ã`bind-batch` 级èæçæ£å¼ç +åç§ä¸è´æ ¡éªã`delete-by-uuid` 级èå èªå¨æçã`replace` ç»§æ¿åç§ãæçåå»ºå» `capacity` å
¥åãè¢ç ç»æçå»å®¹éæ ¡éªãæ¹æ¬¡ VO/Service å»åç§ãæ¹æ¬¡å·å产线è¦ç´ ãè¢ç /å
Œ
±è¿½æº¯ä¸äºç»´ç æ ç¾åç§ãè¢ç ä¼å
ãæ¹æ¬¡åéãã |
| | | - å端ï¼è¢ç çæå¼¹çªï¼åç§+æçæ°/è¢ç æ°å¨æ+é¢è§ï¼ãå表åç§åï¼æ¹æ¬¡è¡¨å/å表/æç´¢å»åç§ï¼æç表å/å表å»å¯è£
è¢æ°ãå表å ãèªå¨çæãæ è¯ãç»æç䏿å»å®¹éæç¤ºã |
| | | - ç¼è¯ï¼`mvn compile -pl yudao-module-mes -am -q` éè¿ã |
| | | |
| | | ## 8. è¡¥å
éæ±ï¼æ¹æ¬¡æä½ç»å®æçï¼2026-09-17ï¼ |
| | | |
| | | - æ¹æ¬¡æ°å¢/è¡¥å½/ç¼è¾åå¯éãç»å®æçãï¼å¤éãéå¿
å¡«ï¼ï¼å¾éåæ¹æ¬¡ç¶æç´æ¥ç½®**ç产ä¸**ï¼åäºå¡å¤ç¨æçç»å®æ¹æ¬¡é»è¾ï¼æ£å¼æçç ãæçä¸è¢ç 级èå½å
¥ãåç§ä¸è´æ ¡éªï¼ï¼ä»»ä¸æ¥å¤±è´¥æ´ä½åæ»ã |
| | | - ç¼è¾æ¶ä»
ä¼ æ¬æ¬¡æ°å¢å¾éçæçï¼å·²ç»å®æçä¸å¨ä¸æä¸ï¼unbound-list å·²è¿æ»¤ï¼ï¼ä¸æ¯æè§£ç»ï¼æªå¾é䏿¹ç¶æã䏿ªæåéã |
| | | - æ°æ¥å£ `GET /mes/pro/pallet/unbound-list`ï¼batch_id ä¸ºç©ºãæ æ£å¼æçç 䏿ªä½åºçä¸´æ¶æçã |
| | | - å端èè°ç»åè§ `docs/mes_bag_code_package_refactor_integration.md`ã |
| | | |
| | | ## 9. è¡¥å
éæ±ï¼åå§è¢ç ä¸å表æåºï¼2026-09-17ï¼ |
| | | |
| | | - æ°å¢ `POST /mes/pro/bag-code/raw-generate`ï¼ä»
éåç§+è¢ç æ°éå³çæå¯¹åºæ°éè¢ç ï¼å¸¦åç§åä½ãuuid æç»ï¼ï¼**䏿 ¡éªè®¡éåä½ç±»åãä¸çææç**ï¼åç»å½å
¥æ¹æ¬¡/ç»æç/å°å·/å é¤ä¸æ°æ®å
è¢ç ä¸è´ãèµç 管ç页工å
·æ å ãçæåå§è¢ç ãå¼¹çªå
¥å£ã |
| | | - è¢ç å页æ¥è¯¢æ¹ä¸ºæ**å建æ¶é´ååº**ï¼åç§æç¼å·ååºï¼ï¼åãè¢åºå·ååºãåºå¼ã |
| | | - ç¼è¯ `mvn compile -pl yudao-module-mes -am -q` éè¿ãåç«¯ç±»åæ£æ¥æ¹å¨æä»¶é¶é误ã |
| | | |
| | | ## 10. è¡¥å
éæ±ï¼è¢ç å表åç§æ¥è¯¢ï¼2026-09-17ï¼ |
| | | |
| | | - èµç 管çå表æç´¢åºæ°å¢ãåç§ãæ¡ä»¶ï¼å¤ç¨ `MdmItemSelect` éæ©ç»ä»¶ï¼ï¼æ `mes_pro_bag_code.item_id` çå¼è¿æ»¤ï¼å页ä¸å¯¼åº Excel åå£å¾çæã |
| | | - åå²ç©ºç½è¢ç `item_id` 为空ï¼éæ©åç§åä¸ä¼å½ä¸ï¼å±æ£å¸¸ï¼ã§3.3 åãç¼ç /åç§°å¯æ£ç´¢æ¬æä¸åï¼ä»
å±ç¤ºãå°±æ¤å级为æåç§ç¼å·æ£ç´¢ã |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | # æ¹æ¬¡ç产管çï¼éè产线ç¼ç ãåæ®µæ¹åãæ°å¢å å·¥çç» - å端èè°æ¹æ¡ |
| | | |
| | | ## èæ¯ |
| | | |
| | | æ¹æ¬¡ç产管ç页é¢ï¼/mes/pro/batchï¼è°æ´ï¼ |
| | | |
| | | - éèã产线ç¼ç ãï¼å表åãæç´¢é¡¹ãExcel 导åºåä¸åå±ç¤ºï¼æ¥å£ä»è¿å `lineCode`ï¼ã |
| | | - ã产线åç§°ãå±ç¤ºææ¡ç»ä¸æ¹ä¸ºãå å·¥åä½ãï¼æ°æ®ä»ä¸º `lineName`ï¼æ¥æºäº§çº¿ä¸»æ°æ®ï¼ã |
| | | - ãè®¡åæ°éãå±ç¤ºææ¡æ¹ä¸ºãå å·¥æ°éãï¼æ°æ®ä»ä¸º `planQuantity`ï¼2026-09-17 ç±ãä»·æ ¼æ°éã忬¡æ´åï¼ã |
| | | - æ°å¢ãå å·¥çç»ãåæ®µï¼æå·¥å¡«åææ¬ï¼æé¿ 64 å符ï¼ä½ç½®å¨ãå å·¥åä½ãä¹åã |
| | | |
| | | ## API åå |
| | | |
| | | | æ¹æ³ | è·¯å¾ | åå | |
| | | |------|------|------| |
| | | | POST | /mes/pro/batch/create | 请æ±ä½æ°å¢ `processingTeam`ï¼å¯éï¼ | |
| | | | PUT | /mes/pro/batch/update | åä¸ | |
| | | | PUT | /mes/pro/batch/fill-info | åä¸ï¼ä¸´æ¶æ¹æ¬¡è¡¥å½ï¼ | |
| | | | GET | /mes/pro/batch/get | ååºæ°å¢ `processingTeam` | |
| | | | GET | /mes/pro/batch/page | ååºæ°å¢ `processingTeam`ï¼æ°å¢æ¥è¯¢åæ° `processingTeam`ï¼æ¨¡ç³å¹é
ï¼ | |
| | | |
| | | **åæ®µè¯´æï¼** |
| | | |
| | | | åæ®µ | ç±»å | å¿
å¡« | 说æ | |
| | | |------|------|------|------| |
| | | | processingTeam | String(64) | å¦ | å å·¥çç»ï¼æå·¥å¡«åï¼ä¸é产线ä¹å¯å¡« | |
| | | |
| | | **ååºç¤ºä¾ï¼èéï¼ï¼** |
| | | |
| | | ```json |
| | | { |
| | | "code": 0, |
| | | "data": { |
| | | "list": [ |
| | | { |
| | | "id": 1, |
| | | "code": "PC20260917L01NY001", |
| | | "lineName": "å
è£
ä¸çº¿", |
| | | "processingTeam": "ä¸å·å å·¥çç»", |
| | | "planQuantity": 1000, |
| | | "ownerUserName": "å¼ ä¸" |
| | | } |
| | | ], |
| | | "total": 1 |
| | | } |
| | | } |
| | | ``` |
| | | |
| | | ## ä¸å¡è§å说æ |
| | | |
| | | | åºæ¯ | è§å | |
| | | |------|------| |
| | | | æ°å¢/è¡¥å½/ç¼è¾æ¹æ¬¡ | ãå å·¥çç»ã为å¯éææ¬è¾å
¥ï¼ç¼è¾æ¶ä¸ä¼ ä¸ä¼æ¸
空åå²å¼ | |
| | | | å å·¥åä½ | ä»ç±éæ©äº§çº¿ï¼`lineId`ï¼åå¡« `lineName`ï¼ä»
å±ç¤ºææ¡åå | |
| | | | å å·¥æ°é | ä»
å±ç¤ºææ¡ååï¼åæ®µä¸æ ¡éªé»è¾ä¸å | |
| | | | 产线ç¼ç | æ¥å£ä¿ç `lineCode`ï¼æ«ç ãæ¹æ¬¡å·çæçä»ä¾èµï¼ï¼é¡µé¢ä¸å¯¼åºéè | |
| | | | å¯¼åº Excel | å忥ååï¼å»æã产线ç¼ç ãï¼ã产线åç§°âå å·¥åä½ãï¼æ°å¢ãå å·¥çç»ãï¼ãè®¡åæ°éâå å·¥æ°éã | |
| | | |
| | | ## æ°æ®åºåæ´ |
| | | |
| | | `mes_pro_batch` æ°å¢å `processing_team VARCHAR(64) NULL COMMENT 'å å·¥çç»'`ï¼èæ¬ï¼`docs/sql/pro_batch_processing_team.sql`ï¼ã |
| | | |
| | | ## 注æäºé¡¹ |
| | | |
| | | - æ«ç 追溯弹çªï¼qr-trace-modalï¼ãæ¹æ¬¡è¿½æº¯é¡µï¼qc/batchtraceï¼æ¬æ¬¡æªè¦æ±è°æ´ï¼ä»å±ç¤ºäº§çº¿ç¼ç /åç§°ä¸è®¡åæ°éææ¡ï¼å¦éç»ä¸å¦è¡å¤çã |
| | | - æ¬æ¹åç«¯å·²åæ¥ä¿®æ¹å端 `src/views/mes/pro/batch/`ï¼åãæç´¢è¡¨åãç¼è¾è¡¨åï¼ä¸ `src/api/mes/pro/batch/index.ts` ç±»åï¼ä¾å端å¢é夿 ¸ã |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | # åºåè¢ç æç»èè°æ¹æ¡ |
| | | |
| | | ## ä¸å¡æµç¨ |
| | | |
| | | ç§åè´¨æ£ä»¥è¢ç æäº¤ãè´¨æ£åæ ¼æ¶ï¼æååºåæ±æ»æ°éåå° 1ï¼åæ ¼åºåæ±æ»æ°éå¢å 1ï¼åæ¶è¯¥è¢ç æç»è¿ç§»å°åæ ¼ä»ï¼è´¨æ£ä¸åæ ¼æ¶ï¼æååºåæ±æ»æ°éåå° 1ï¼è¢ç æç»æ 记为æ¥åºãå
¶ä»è¢ç ä¸åå½±åã |
| | | |
| | | åºåå°è´¦ç»§ç»æç©æãæ¹æ¬¡ãä»åºãåºåºãåºä½åä¾åºåæ±æ»ï¼è¢ç æç»ç¨äºè®°å½æ¯ä¸ªè¢ç çå
·ä½ç¶æåä½ç½®ã |
| | | |
| | | ## è¢ç æç»çå½å¨æï¼ç»ä¸æå¡æç®¡ï¼ |
| | | |
| | | ææå¸¦è¢ç çåºååå¨ç»ä¸éè¿åºåäºå¡æå¡å¨åä¸äºå¡å
åæ¥ç»´æ¤ **æ±æ»åºå + è¢ç æç» + åºåæµæ°´** ä¸è
ä¸è´ï¼åä¸å¡å
¥å£æ éåèªå®ç°è¢ç é»è¾ãçå½å¨æï¼ |
| | | |
| | | | é¶æ®µ | å¨ä½ | è¢ç æç»åå | |
| | | |------|------|--------------| |
| | | | åè¢æ«ç å
¥åº | ç产æ«ç å
¥åºï¼æ«ç ç±»å BAGï¼ | å»ºç«æ´»å¨æç»ï¼æååºï¼ | |
| | | | ç§åè´¨æ£åæ ¼ | æååºåº + åæ ¼å
¥åº | æç»ç±æååºè¿ç§»å°åæ ¼åº | |
| | | | ç§åè´¨æ£ä¸åæ ¼ | æååºåº | æç»æ¥åº | |
| | | | éå®åºåºå®æ | åºåºæ£å | æç»ç½®ä¸ºå·²åºåº | |
| | | | æ´ä½ç§»åº | è°æ¨ç§»åº + ç§»å
¥ | æç»ä½ç½®è¿ç§»å°ç®æ åºä½ | |
| | | |
| | | 说æï¼ |
| | | - æçï¼PALLETï¼/æ¹æ¬¡ï¼BATCHï¼æ´æ¹å
¥åºãéè´/æé¡¹/éè´§çæè¡ææ°éå
¥åºçåºå
¥å£ï¼ä¸ºæ¹éæ±æ»ï¼ä¸éè¢å»ºç«æç»ï¼è¿äºè¢ç å¨é¦æ¬¡ç§åè´¨æ£æ¶éè¿ææ¹æ¬¡å®ä½æååºå补建æç»ã |
| | | - äºå¡æµæ°´ DTO å¢å `bagCodeId`/`bagCode` åæ®µï¼åºåº/ç§»å
¥æè¢ç èªå¨æ´æ°è¢ç æç»ã |
| | | - æ¯ç¬å¸¦è¢ç çå
¥åºãåºåºãç§»åºãè´¨æ£é½ä¼çæå¯¹åºç `mes_wm_transaction` æµæ°´å¹¶åå¡«è¢ç ï¼ä¾¿äºå¨åºåæµæ°´é¡µé¢æè¢ç çé追溯ã |
| | | |
| | | |
| | | ## API |
| | | |
| | | | æ¹æ³ | è·¯å¾ | 说æ | |
| | | |------|------|------| |
| | | | GET | `/mes/wm/material-stock/page` | åºåæ±æ»å页ï¼ååºå¢å è¢ç ç»è®¡å段 | |
| | | | GET | `/mes/wm/material-stock/bag-details` | æ¥è¯¢æå®åºåæ±æ»è®°å½ä¸çå¨åºè¢ç æç» | |
| | | | GET | `/mes/wm/transaction/page` | åºåäºå¡æµæ°´ï¼æ¯æ `bagCode` çéå¹¶è¿åè¢ç | |
| | | |
| | | ### è¢ç æç»æ¥è¯¢ |
| | | |
| | | 请æ±åæ°ï¼ |
| | | |
| | | | åæ° | ç±»å | å¿
å¡« | 说æ | |
| | | |------|------|------|------| |
| | | | materialStockId | Long | æ¯ | åºåæ±æ»è®°å½ ID | |
| | | | bagCode | String | å¦ | è¢ç æ¨¡ç³æ¥è¯¢ | |
| | | | pageNo | Integer | æ¯ | 页ç | |
| | | | pageSize | Integer | æ¯ | æ¯é¡µæ¡æ° | |
| | | |
| | | ååºå段å
æ¬ `bagCode`ã`batchCode`ã`stockState`ã`status`ã`quantity`ã`warehouseId`ã`locationId`ã`areaId`ã`inboundTime` å `outboundTime`ã |
| | | |
| | | åºåæ±æ»å页ååºæ°å¢ï¼ |
| | | |
| | | | åæ®µ | ç±»å | 说æ | |
| | | |------|------|------| |
| | | | bagCount | Long | å½åå¨åºè¢ç æç»æ°é | |
| | | | bagDetailSupported | Boolean | æ¯å¦åå¨è¢ç æç»ï¼å岿 æ³è¿åè¢ç çåºå为 false | |
| | | |
| | | ## å端è°ç¨æ¶åº |
| | | |
| | | 1. è°ç¨åºåå°è´¦å页æ¥å£è·åæ±æ»è®°å½ã |
| | | 2. 对 `bagDetailSupported=true` çè®°å½æ¾ç¤ºâæ¥çè¢ç âã |
| | | 3. ç¹å»åè°ç¨ `/mes/wm/material-stock/bag-details`ï¼ä¼ å
¥å½åè¡ `id` ä½ä¸º `materialStockId`ã |
| | | 4. è¢ç æç»ä¸ç `bagCode` å¯ç»§ç»è°ç¨æ¹æ¬¡/è¢ç 追溯æ¥å£æ¥çè´¨æ£åç产信æ¯ã |
| | | 5. åºåæµæ°´é¡µé¢ä½¿ç¨ `bagCode` çéæ¶ï¼å±ç¤ºè´¨æ£è¿ç§»äº§ççè¢ç çº§æµæ°´ã |
| | | |
| | | ## ä¸å¡è§å |
| | | |
| | | - åä¸è¢ç åªè½åå¨ä¸æ¡åºåè¢ç æç»ã |
| | | - è´¨æ£æå®é
è¢ç å®ä½æååºåï¼ä¸ææ¹æ¬¡éæºæ£åã |
| | | - æ¥åºè¢ç ä¸è®¡å
¥å¨åºæç»æ¥è¯¢ï¼ä½ä¿çæç»è®°å½ç¨äºè¿½æº¯ã |
| | | - æ æ³ä»å岿±æ»åºåè¿åè¢ç æ¶ï¼ä¸ä¼ªé è¢ç æç»ã |
| | | - SQL èæ¬ä¸å
å« `tenant_id` åæ®µã |
| | |
| | | |
| | | **注æï¼** æ£è´§æç»éè¦æå¨æ·»å |
| | | |
| | | ## åè´§éç¥è¡ç©ææ ¡éª |
| | | |
| | | æ°å¢æä¿®æ¹åè´§éç¥è¡æ¶ï¼ç©æå¿
é¡»å
³èæ¹æ¬¡ï¼ä¸è¯¥ç©ææ¹æ¬¡å¿
é¡»å卿£å¼åºåºåãæ£å¼åºæåºåç¶æä¸ºåæ ¼åºï¼`stockState = 20`ï¼çåºåè®°å½ã |
| | | |
| | | | æ ¡éªé¡¹ | è§å | |
| | | |--------|------| |
| | | | ç©æ | å¿
é¡»åå¨ä¸å¯ç¨ | |
| | | | æ¹æ¬¡ | `batchId` æ `batchCode` å¿
é¡»è½å¹é
æææ¹æ¬¡ï¼ä¸æ¹æ¬¡å±äºæéç©æ | |
| | | | æ£å¼åºå | ä»
ç»è®¡åæ ¼åºåºåï¼ä¸ç»è®¡æååºåºå | |
| | | | æ°é | åä¸ç©æãæ¹æ¬¡çåæ ¼åºåºåå计å¿
é¡»ä¸å°äºåè´§æ°é | |
| | | | åºååæ´ | ä¿ååè´§éç¥è¡æ¶ä¸æ£åãä¸é¢å åºåï¼å®é
åºåºæ¶åæ¬¡æ ¡éª | |
| | | |
| | | åºåä¸è¶³æ¶ï¼å端åºç´æ¥å±ç¤ºå端è¿åçâåºåæ°éä¸è¶³âä¸å¡æç¤ºï¼å¹¶ä¿çç¨æ·å¡«åç表åå
容ã |
| | | |
| | | ## åæ®µæ å°è¡¨ |
| | | |
| | | ### ä¸»è¡¨åæ®µæ å° |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | # ç产线æ«ç å
¥åºï¼æ¯æè¢ç /æçç /æ¹æ¬¡ç + å»æè®¾å¤ç¼ç - å端èè°æ¹æ¡ |
| | | |
| | | ## æ¶åé¡µé¢ |
| | | |
| | | - ç产线æ«ç å
¥åºï¼`src/views/mes/pro/scan-in/index.vue`ï¼ |
| | | |
| | | ## ä¸å¡åæ´ |
| | | |
| | | 1. **å»æè®¾å¤ç¼ç **ï¼æ«ç å
¥åºä¸åå½å
¥/å±ç¤ºè®¾å¤ç¼ç ï¼æ¥å£ `deviceCode` æ¹ä¸ºéå¿
å¡«ï¼å端ä¸åä¼ ã |
| | | 2. **产线ãåºåºãåºä½æ¹ä¸ºä¸æéæ©**ï¼æ°æ®æºä¸ºç°æç²¾ç®å表æ¥å£ï¼ä¸åæå¡«ç¼å·ã |
| | | 3. **çå¾
æ«ç åºå¢å "æ«ç ç±»å"éæ©**ï¼è¢ç / æçç / æ¹æ¬¡ç ä¸éä¸ï¼æ«ç æ¡éç±»åæäº¤å¯¹åºç å¼ã |
| | | |
| | | ## API |
| | | |
| | | ### 主æ¥å£ï¼è¿½æº¯ç æ«ç å
¥åº |
| | | |
| | | | æ¹æ³ | è·¯å¾ | 说æ | |
| | | |------|------|------| |
| | | | POST | /mes/pro/scan-in/inbound | è¿½æº¯ç æ«ç å
¥åºï¼è¢ç /æçç /æ¹æ¬¡ç ï¼ | |
| | | |
| | | **请æ±åæ°ï¼æ¬æ¬¡åæ´ï¼ï¼** |
| | | |
| | | | åæ° | ç±»å | å¿
å¡« | åæ´ | 说æ | |
| | | |------|------|------|------|------| |
| | | | scanType | String | å¦ | æ°å¢ | æ«ç ç±»åï¼`BAG` è¢ç / `PALLET` æçç / `BATCH` æ¹æ¬¡ç ï¼ä¸ä¼ é»è®¤ `BAG` | |
| | | | deviceCode | String | å¦ | æ¹ä¸ºéå¿
å¡« | 设å¤ç¼ç ï¼å端ä¸åä¼ | |
| | | | bagCode | String | æ¯ | è¯ä¹æ©å± | æ«ç å
容ï¼è¢ç /æçç /æ¹æ¬¡ç çç å¼ï¼å«ä¸´æ¶ç ï¼ | |
| | | | eventId | String | æ¯ | - | äºä»¶å·ï¼å»ºè®®ç¨ `{scanType}-{æ¶é´æ³}` ä¿è¯å¯ä¸ï¼ | |
| | | | quantity | Number | æ¯ | - | è¢ç åºæ¯ä¼ 1ï¼æç/æ¹æ¬¡åºæ¯å端忽ç¥è¯¥å¼ï¼æå·²è£
è¢æ°/æ¹æ¬¡è¢æ°è®¡ç® | |
| | | | lineCode | String | å¦ | - | 产线ç¼ç ï¼åç«¯ä¸æéæ©ï¼ | |
| | | | locationId | Long | æ¯ | - | WIP æååºåºç¼å·ï¼åç«¯ä¸æéæ©ï¼ | |
| | | | areaId | Long | æ¯ | - | WIP æååºä½ç¼å·ï¼åç«¯ä¸æéæ©ï¼ | |
| | | |
| | | **ååºæ°å¢å段ï¼** |
| | | |
| | | | åæ®µ | ç±»å | 说æ | |
| | | |------|------|------| |
| | | | scanType | String | æ¬æ¬¡æ«ç ç±»åï¼BAG/PALLET/BATCHï¼ | |
| | | |
| | | **å
¥åºæ°éå£å¾ï¼** |
| | | |
| | | | scanType | æ°é | 说æ | |
| | | |----------|------|------| |
| | | | BAG | åç«¯ä¼ 1 | åè¢å
¥åº | |
| | | | PALLET | æçå·²è£
è¢æ° `bag_count` | æ´æä¸æ¬¡æ§å
¥æååº | |
| | | | BATCH | æ¹æ¬¡è¢æ° `bag_quantity` | æ´æ¹ä¸æ¬¡æ§å
¥æååº | |
| | | |
| | | **å
¥åºå»éï¼** è¢ç ãæçç ãæ¹æ¬¡ç å以åèª `inbound_event_id` 夿æ¯å¦å·²å
¥åºï¼é夿«ç è¿å对åº"å·²å
¥åº"é误ç ï¼ä¸ä¼éå¤åå
¥åºåäºå¡ã |
| | | |
| | | ### ä¸ææ°æ®æºï¼å¤ç¨ç°ææ¥å£ï¼æ æ°å¢ï¼ |
| | | |
| | | | ç¨é | æ¹æ³ | è·¯å¾ | 说æ | |
| | | |------|------|------|------| |
| | | | 产线 | GET | /mes/pro/line/simple-list | è¿åå¯ç¨äº§çº¿ `{id, code, name}` | |
| | | | åºåº | GET | /mes/wm/warehouse-location/simple-list | è¿ååºåº `{id, code, name}`ï¼éåºåºåèå¨å è½½å
¶ä¸åºä½ | |
| | | | åºä½ | GET | /mes/wm/warehouse-area/simple-list?locationId= | è¿ååºä½ `{id, code, name}` | |
| | | |
| | | ## æ°æ®å¸¦å
¥è¯´æ |
| | | |
| | | - 产线/åºåº/åºä½ï¼ä¸æéæ©ï¼é¡µé¢ `onMounted` 䏿¬¡æ§å 载产线ãåºåºï¼éæ©åºåºåæ `locationId` èå¨å è½½åºä½ã |
| | | - æ«ç æäº¤ï¼`locationId`ã`areaId`ã`scanType`ã`bagCode` ä¸å¹¶å¸¦å
¥å
¥åºæ¥å£ï¼äº§çº¿ `lineCode` æå¼æä¼ ã |
| | | - äºä»¶å表/çæ¿ï¼ä»¥ `scanType` åºå追溯ç ç±»åå±ç¤ºï¼å岿 ç±»åçæ°æ®é»è®¤æ¾ç¤º"è¢ç "ï¼ã |
| | | |
| | | ## åæ®µå±ç¤ºè§å |
| | | |
| | | | åæ®µ | å±ç¤ºä½ç½® | 说æ | |
| | | |------|----------|------| |
| | | | æ«ç ç±»å | çå¾
æ«ç åºä¸æ | ä¸éä¸ï¼è¢ç /æçç /æ¹æ¬¡ç | |
| | | | ç产产线 | æ«ç å¡é
ç½®åº + ç¶æå¡ | 䏿鿩ï¼å¯æ¸
空 | |
| | | | WIP æååºåº/åºä½ | æ«ç å¡é
ç½®åº + ç¶æå¡ | 䏿鿩ï¼åºä½éåºåºèå¨ç¦ç¨/å¯ç¨ | |
| | | | æè¿å
¥åºè¿½æº¯ç | ç»è®¡å¡ | å±ç¤ºææ°ä¸æ¡æ«ç å
容 | |
| | | | 追溯ç /ç±»å/产线 | æè¿æ«ç äºä»¶è¡¨ | è¡¨æ ¼æ°å¢"ç±»å"åï¼å"设å¤/产线"åæ¹ä¸º"产线" | |
| | | | æè¿æ«ç ç±»å | ç¶æå¡ | å±ç¤ºææ°äºä»¶æ«ç ç±»å | |
| | | |
| | | ## 注æäºé¡¹ |
| | | |
| | | 1. å端é**æ§è¡ SQL èæ¬** `sql/mysql/mes_pro_scan_event_scan_type.sql`ï¼`mes_pro_scan_event` å¢å `scan_type` åï¼`mes_pro_pallet` å¢å `inbound_event_id`/`inbound_time` åï¼ï¼å**éæ°ç¼è¯å¹¶éå¯**ã |
| | | 2. éå¯åæ§æ¥å£ä¼å¿½ç¥ `scanType`ï¼æè¢ç å¤çï¼ï¼æç/æ¹æ¬¡ç æ«ç ä¼è¿å"è¢ç ä¸åå¨"ï¼å端类å䏿ç
§å¸¸å¯éï¼åè½é级为ä»
è¢ç ã |
| | | 3. 产线/åºåº/åºä½ä¸æè¥æ¥å£ 404ï¼å端æªéå¯ï¼ï¼ä¸æä¸ºç©ºï¼éå
ä¿éå端å¯ç¨ã |
| | | 4. æçãæ¹æ¬¡æ´æ/æ´æ¹å
¥åºä¼åæ¥æå
¶ä¸æªå
¥åºè¢ç æ 记为已å
¥åºï¼é¿å
åç»åè¢æ«ç éå¤å
¥åºã |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | # ç§åæµåä¿¡æ¯ï¼éå®åºåºåºå
¥åºæµæ°´ï¼ - H5 溯æºèè°è¯´æ |
| | | |
| | | ## èæ¯ |
| | | |
| | | H5 æ«ç 溯æºé¡µï¼`mes.trace-base-url` æåç `trace.html`ï¼æ°å¢ãç§åæµåä¿¡æ¯ãåºåï¼ |
| | | æ**æ¹æ¬¡å
¨æµæ°´**å±ç¤ºè¯¥æ¹æ¬¡çå
¥åºä¸åºåºè®°å½ï¼æ°æ®æºä¸ºéå®åºåº `/sales-outbound/product-sales` 模å对åºçåºåäºå¡ï¼ã |
| | | |
| | | åæ¶ä¿®å¤æ¢æãéå®å»åãæ°æ®é¾è·¯ï¼ç§åéå®åºåºæè¢ç /æçæ«ç æ£è´§æ¶ï¼æ¹æ¬¡å·åªåå
¥åºåº**æç»è¡¨** |
| | | ï¼`mes_wm_product_sales_detail.batch_code`ï¼ï¼åæ¥è¯¢åªå¹é
åºåº**è¡è¡¨**æ¹æ¬¡å·ï¼å¯¼è´æº¯æºæ°¸è¿æ¥ä¸å°éå®åºåºä¿¡æ¯ã |
| | | |
| | | ## æ¶åæ¥å£ |
| | | |
| | | | æ¹æ³ | è·¯å¾ | 说æ | |
| | | |------|------|------| |
| | | | GET | /public/mes/trace/query?code={追溯ç } | H5 æº¯æºæ¥è¯¢ï¼å
ç»å½ï¼ï¼ååºæ°å¢ `seedFlows` åºå | |
| | | |
| | | **ååºæ°å¢å段 `seedFlows`ï¼æ¹æ¬¡åºå
¥åºæµæ°´ï¼æäºå¡æ¶é´ååºï¼ï¼** |
| | | |
| | | | åæ®µ | ç±»å | 说æ | |
| | | |------|------|------| |
| | | | type | Integer | äºå¡æ¹åï¼1-å
¥åº 2-åºåº | |
| | | | bizType | Integer | ä¸å¡ç±»åï¼118-ç产å
¥åºã119-éå®åºåºã124-产å产åºã120-éå®éè´§å
¥åºçï¼è§ MesBizTypeConstantsï¼ | |
| | | | bizCode | String | æ¥æºä¸å¡åå·ï¼å¦éå®åºåºåå· SL_xxxï¼ | |
| | | | quantity | BigDecimal | å卿°éï¼åºåºä¸ºè´æ°ï¼å±ç¤ºæ¶åç»å¯¹å¼ï¼ | |
| | | | transactionTime | LocalDateTime | äºå¡åçæ¶é´ | |
| | | | warehouseName | String | ä»åºåç§° | |
| | | | locationName | String | åºåºåç§° | |
| | | | areaName | String | åºä½åç§° | |
| | | | clientName | String | 客æ·åç§°ï¼ä»
éå®åºåºæµæ°´å¸¦åºï¼æ¥èªåºåºåå¿«ç
§ï¼ | |
| | | |
| | | **`salesTargets` åæ®µååï¼åæ¥å£ï¼ååå
¼å®¹ï¼ï¼** |
| | | |
| | | - æ¥è¯¢å£å¾æ©å±ï¼æ¹æ¬¡å·é¤å¹é
åºåºè¡å¤ï¼åæ¶æåºåºæç»èåå¹é
ï¼æé¤å·²åæ¶åæ®ï¼ã |
| | | - æ°å¢å¡«å
`clientName`ï¼å®¢æ·åç§°å¿«ç
§ï¼ã`clientCode` ä¸åï¼æ¤åæä¸º nullã |
| | | |
| | | ## H5 页é¢å±ç¤ºè§å |
| | | |
| | | | åºå | å±ç¤ºæ¡ä»¶ | å | |
| | | |------|----------|----| |
| | | | ç§åæµåä¿¡æ¯ | `seedFlows` é空ï¼ä¼å
ï¼ | æ¹åï¼å
¥åº/åºåºå¾½æ ï¼ãä¸å¡ãæ¥æºåå·ã客æ·ãæ°éãæ¶é´ãä»åº/åºåº | |
| | | | ç§åæµåä¿¡æ¯ï¼åéï¼ | `seedFlows` ä¸ºç©ºä½ `salesTargets` é空 | éå®åºåºåã客æ·ãæ°éãæ¥æ | |
| | | |
| | | ## é¨ç½²æ³¨æäºé¡¹ |
| | | |
| | | 1. `trace.html` 为 `yudao-server` éæèµæºï¼`src/main/resources/static/trace.html`ï¼ï¼é**éæ°æå
åå¸å端**ï¼ |
| | | è¥ç产 nginx ç `/prod/trace.html`ï¼å¦ `http://47.97.181.254:9008/prod/trace.html`ï¼æ¯ç¬ç«æ·è´é¨ç½²çï¼éåæ¥æ¿æ¢è¯¥æä»¶ã |
| | | 2. éå®åºåºæµæ°´ç客æ·åç§°å `mes_wm_product_sales.client_name` å¿«ç
§å段ï¼è¦æ±ç¯å¢åºå
å«è¯¥åï¼ |
| | | ç»ææ¥ `mom-thzy` åºå·²æï¼**`mom-xgdl` åºç¼ºå¤± `client_name` / `outbound_time` / `outbound_user_id` å**ï¼è½åäºä»£ç ï¼ï¼ä½¿ç¨ local ç¯å¢æ¶éå
è¡¥åã |
| | | 3. åå²åºåºåä¸ä¼è¡¥çææµæ°´ï¼ä»
æ°åºåºå¯çå°å®æ´å
¥+åºè®°å½ï¼æ æµæ°´æ¶åéå±ç¤ºéå®åºåºåã |
| | | |
| | | ## éªè¯æ°æ®ï¼mom-thzyï¼ |
| | | |
| | | æ¹æ¬¡ `PC20260819twoITEM_001`ï¼å
¥åº 100ï¼äº§å产åºï¼èæçº¿è¾¹ä»åºï¼â åºåº 1ï¼éå®åºåº SL_20260901002ï¼æååæ ¼åºï¼åé客æ·ï¼ã |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | # ç§åè´¨æ£æè¢ç ç²åº¦æµè½¬åºå - å端èè°æ¹æ¡ |
| | | |
| | | ## èæ¯ |
| | | |
| | | ç§åè´¨æ£åé»è¾ï¼è´¨æ£åæ ¼å**æ´æ¹**å°ä»åºæ¹æ¬¡åºå仿ååº(10)è½¬ä¸ºåæ ¼åº(20)ï¼ä¸è¢åæ ¼å³æ´æ¹æ¾è¡ï¼é¢ç²åº¦è¿ç²ã |
| | | |
| | | æ¬æ¬¡æ¹é 为**æè¢ç ç²åº¦**ï¼è´¨æ£åªé对被æ«çé£ä¸è¢ï¼åæ ¼ä»
å°è¯¥è¢å¯¹åºåºå仿ååºè½¬å
¥åæ ¼åºï¼åæ¹æ¬¡å
¶ä»è¢ä¿ææååºå¾
æ£ï¼åæ¶ç»æ¯è¢æä¸è´¨æ£æ è®°ï¼`qc_status`ï¼ï¼éå®åºåºæ«è¢ç /æçæ¶æ ¡éªå·²è´¨æ£åæ ¼æå
许åºåºã |
| | | |
| | | ## æ¶åé¡µé¢ |
| | | |
| | | - è´¨é管ç-ç§åè´¨æ£ï¼æäº¤è´¨æ£è¡¨åï¼ |
| | | - éå®åºåº-æ«ç æ£è´§ï¼æ«è¢ç /æçï¼ |
| | | - åºåå°è´¦ï¼`mes_wm_material_stock` å页ï¼åæ¹æ¬¡å¯è½åæ¶åºç°æååºä¸åæ ¼åºä¸¤æ¡è®°å½ï¼ç¶æåå·²æåå
¸å±ç¤ºæåï¼ |
| | | |
| | | ## API |
| | | |
| | | æ¬æ¬¡**æ æ°å¢/ä¿®æ¹æ¥å£**ï¼åä¸ºæ¢ææ¥å£çæ ¡éªè¯ä¹ä¸æ°æ®æµè½¬ååã |
| | | |
| | | ### 1. æäº¤ç§åè´¨æ£ |
| | | |
| | | | æ¹æ³ | è·¯å¾ | 说æ | |
| | | |------|------|------| |
| | | | POST | `/mes/qc/seed-quality/submit` | æäº¤ç§åè´¨æ£ï¼æè¢ç ï¼ | |
| | | |
| | | **请æ±åæ°ï¼ä¸åï¼ï¼** |
| | | |
| | | | åæ° | ç±»å | å¿
å¡« | 说æ | |
| | | |------|------|------|------| |
| | | | code | String | æ¯ | è¢ç ï¼æ«ç å
容ï¼ï¼**å¿
须为ææè¢ç ** | |
| | | | batchCode | String | å¦ | çäº§æ¹æ¬¡å·ï¼å
¼å®¹é¢çï¼ | |
| | | | indicators | Array | æ¯ | åé¡¹ææ ï¼purity/cleanliness/germination_rate/moistureï¼ | |
| | | | reason | String | å¦ | 夿³¨ | |
| | | |
| | | **ååºï¼ä¸åï¼ï¼** `{ "code": 0, "data": è´¨æ£è®°å½ID }` |
| | | |
| | | ### 2. æ«ç æ£è´§ |
| | | |
| | | | æ¹æ³ | è·¯å¾ | 说æ | |
| | | |------|------|------| |
| | | | POST | `/mes/wm/product-sales/scan` | æ«ç æ£è´§ï¼è¢ç /æçï¼ | |
| | | |
| | | **请æ±åæ°ï¼ä¸åï¼ï¼** |
| | | |
| | | | åæ° | ç±»å | å¿
å¡« | 说æ | |
| | | |------|------|------|------| |
| | | | salesId | Long | æ¯ | éå®åºåºåID | |
| | | | scanContent | String | æ¯ | è¢ç ææçç | |
| | | | quantity | BigDecimal | å¦ | åºåºæ°éï¼ç¼ºçç¨è¡æ°éï¼ | |
| | | |
| | | **ååºï¼ä¸åï¼ï¼** æ²¿ç¨ `MesWmProductSalesScanRespVO`ï¼`availableQuantity`/`outboundQuantity` ååºäº**åæ ¼åº**åºå计ç®ã |
| | | |
| | | ## ä¸å¡è§ååå |
| | | |
| | | | åºæ¯ | åè¡ä¸º | æ°è¡ä¸º | |
| | | |------|--------|--------| |
| | | | ç§åè´¨æ£æäº¤éè¢ç | å
¼å®¹æ¹æ¬¡ç æäº¤ | æ¥éãæªè§£æå°ææè¢ç ï¼ç§åè´¨æ£å¿
须以è¢ç æäº¤ã | |
| | | | è´¨æ£åæ ¼ | æ´æ¹æååºâåæ ¼åº | ä»
该è¢ï¼æååº -1ãåæ ¼åº +1ï¼åæ¹æ¬¡å
¶ä»è¢ä»ä¸ºæååºï¼ï¼è¢ç qc_status=20 | |
| | | | è´¨æ£ä¸åæ ¼ | æ åºååå | 该è¢ä»æååºåæ¸
é¤ï¼æ¥åºï¼ï¼è¢ç qc_status=30 | |
| | | | éå®åºåºæ«è¢ç | 䏿 ¡éªè´¨æ£ | qc_status å¿
须为 20ï¼å¦åæ¥ã该è¢ç æªè´¨æ£åæ ¼ï¼ç¦æ¢åºåºã | |
| | | | éå®åºåºæ«æç | 䏿 ¡éªè´¨æ£ | æç䏿æè¢ç qc_status å¿
须为 20ï¼å¦åæ¥ãæçä¸å卿ªè´¨æ£è¢ç ï¼ç¦æ¢æ´æåºåºã | |
| | | | éå®åºåºéåºå | å¯è½é䏿ååºè®°å½ | ä»
ä»åæ ¼åº(20)è®°å½ä¸éæ°éè¶³å¤ç | |
| | | |
| | | ## åºåè¯ä¹è¯´æ |
| | | |
| | | å䏿¬¡ï¼å
¥åºä»ææ¹æ¬¡èåï¼è´¨æ£åæ ¼åï¼åæ¹æ¬¡ `mes_wm_material_stock` ä¼åæ¶åå¨ä¸¤æ¡è®°å½ï¼ |
| | | |
| | | | è®°å½ | stock_state | å«ä¹ | æ¯å¦å¯åºåº | |
| | | |------|-------------|------|-----------| |
| | | | æååº | 10 | è¯¥æ¹æ¬¡æªè´¨æ£çå©ä½è¢æ° | å¦ | |
| | | | åæ ¼åº | 20 | 已质æ£åæ ¼ãå¯éå®çè¢æ° | æ¯ | |
| | | |
| | | 示ä¾ï¼æ¹æ¬¡å
¥åº 3 è¢ï¼quantity=3ãæååºï¼ãè´¨æ£åæ ¼ 1 è¢å â æååº quantity=2 + åæ ¼åº quantity=1ã |
| | | |
| | | ## åæ®µå±ç¤ºè§å |
| | | |
| | | | åæ®µ | å±ç¤ºä½ç½® | 说æ | |
| | | |------|----------|------| |
| | | | è´¨æ£ç¶æï¼qc_statusï¼ | ç§åè´¨æ£æäº¤ç»æåé¦ | å端æ éå±ç¤ºï¼å端å¨ç¬¬äºæ¬¡æäº¤åä¸è¢ç æ¶æ¥ã该è¢ç 已质æ£ï¼ç¦æ¢éå¤æäº¤ã | |
| | | | åºåç¶æ | åºåå°è´¦å表 | åä¸ç©æ/æ¹æ¬¡å¯è½åºç°ä¸¤æ¡ä¸åç¶æè®°å½ï¼å为æ£å¸¸ç°è±¡ | |
| | | | å¯åºåºæ°é | æ«ç æ£è´§ç»æ | 以 `availableQuantity` 为åï¼åªåæ åæ ¼åºåºå | |
| | | |
| | | ## 注æäºé¡¹ |
| | | |
| | | 1. **ç§åè´¨æ£æäº¤å¿
é¡»ä¼ è¢ç **ï¼`code` åæ®µç°å¨å¿
é¡»æ¯ç³»ç»ä¸åå¨çææè¢ç ï¼ä»
ä¼ æ¹æ¬¡å·ä¸å被æ¥åã |
| | | 2. **è´¨æ£æåååºåæ»æ°ä¸å**ï¼æååº -1 ä¸åæ ¼åº +1 忥åçï¼ç©æå¨åºæ»æ°å®æï¼åªæ¯ä»"å¾
æ£"å为"å¯å®"ã |
| | | 3. **åæ¹æ¬¡åç¶æå¹¶å**ï¼æååºä¸åæ ¼åºè®°å½åæ¶å卿¯é¢æè¡ä¸ºï¼å端å¨åºåå°è´¦ãåºåºéåºåæ¶åºè½æ¥ååä¸ç©æ/æ¹æ¬¡åºç°å¤è¡ã |
| | | 4. **åºåºæ°éæç¤º**ï¼è¥ææ¹æ¬¡ä»
é¨åè¢è´¨æ£åæ ¼ï¼æ«ç æ£è´§å¯åºåºæ°éåªå
å«åæ ¼è¢ï¼å端æç¤ºåºä»¥æ¥å£è¿åç `availableQuantity` 为åã |
| | | 5. **ä¸åæ ¼è¢æ¥åº**ï¼è´¨æ£ä¸åæ ¼çè¢ä¼ä»æååºå䏿£é¤ï¼ä¸è¯¥è¢ç qc_status=30ï¼ç¦æ¢åºåºã |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | -- æ¹æ¬¡ç产管çï¼æ°å¢ãå å·¥çç»ãåæ®µ |
| | | -- æ§è¡åºï¼mom-thzyï¼localï¼ |
| | | ALTER TABLE mes_pro_batch ADD COLUMN processing_team VARCHAR(64) NULL COMMENT 'å å·¥çç»ï¼æå·¥å¡«åï¼' AFTER line_name; |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | -- æ¹æ¬¡è¿½æº¯æ°æ®æ¨¡å补强 |
| | | -- 说æï¼å段å
å
许为空ï¼å岿°æ®å填宿ååè¯ä¼°æ¯å¦æ¶ç´§çº¦æã |
| | | -- 注æï¼é¡¹ç®ä¸ä½¿ç¨ tenant_idï¼æ§è¡åè¯·ç¡®è®¤åæ®µåç´¢å¼ä¸åå¨ã |
| | | |
| | | ALTER TABLE mes_wm_batch |
| | | ADD COLUMN pro_batch_id BIGINT NULL COMMENT '对åºçäº§æ¹æ¬¡ID' AFTER id; |
| | | ALTER TABLE mes_wm_batch |
| | | ADD INDEX idx_mes_wm_batch_pro_batch_id (pro_batch_id); |
| | | |
| | | ALTER TABLE mes_wm_sn |
| | | ADD COLUMN pro_batch_id BIGINT NULL COMMENT 'çäº§æ¹æ¬¡ID' AFTER id; |
| | | ALTER TABLE mes_wm_sn |
| | | ADD COLUMN bag_code_id BIGINT NULL COMMENT 'è¢ç ID' AFTER pro_batch_id; |
| | | ALTER TABLE mes_wm_sn |
| | | ADD COLUMN pallet_id BIGINT NULL COMMENT 'æçID' AFTER bag_code_id; |
| | | ALTER TABLE mes_wm_sn |
| | | ADD COLUMN sales_id BIGINT NULL COMMENT 'éå®åºåºåID' AFTER pallet_id; |
| | | ALTER TABLE mes_wm_sn |
| | | ADD INDEX idx_mes_wm_sn_pro_batch_id (pro_batch_id); |
| | | ALTER TABLE mes_wm_sn |
| | | ADD INDEX idx_mes_wm_sn_bag_code_id (bag_code_id); |
| | | |
| | | ALTER TABLE mes_qc_seed_quality |
| | | ADD COLUMN batch_id BIGINT NULL COMMENT 'çäº§æ¹æ¬¡ID' AFTER item_id; |
| | | ALTER TABLE mes_qc_seed_quality |
| | | ADD INDEX idx_mes_qc_seed_quality_batch_id (batch_id); |
| | | |
| | | CREATE TABLE mes_trace_event ( |
| | | id BIGINT NOT NULL AUTO_INCREMENT COMMENT '主é®', |
| | | event_no VARCHAR(64) NOT NULL COMMENT 'äºä»¶ç¼å·', |
| | | event_type VARCHAR(32) NOT NULL COMMENT 'äºä»¶ç±»å', |
| | | event_category VARCHAR(32) NULL COMMENT 'äºä»¶åç±»', |
| | | event_time DATETIME NOT NULL COMMENT 'äºä»¶æ¶é´', |
| | | pro_batch_id BIGINT NULL COMMENT 'çäº§æ¹æ¬¡ID', |
| | | wm_batch_id BIGINT NULL COMMENT 'ä»å¨æ¹æ¬¡ID', |
| | | bag_code_id BIGINT NULL COMMENT 'è¢ç ID', |
| | | pallet_id BIGINT NULL COMMENT 'æçID', |
| | | sn_id BIGINT NULL COMMENT 'SN ID', |
| | | item_id BIGINT NULL COMMENT 'ç©æID', |
| | | biz_type VARCHAR(32) NULL COMMENT 'ä¸å¡ç±»å', |
| | | biz_id BIGINT NULL COMMENT 'ä¸å¡ID', |
| | | biz_code VARCHAR(100) NULL COMMENT 'ä¸å¡ç¼ç ', |
| | | biz_line_id BIGINT NULL COMMENT 'ä¸å¡æç»ID', |
| | | from_node_type VARCHAR(32) NULL COMMENT 'æ¥æºèç¹ç±»å', |
| | | from_node_id BIGINT NULL COMMENT 'æ¥æºèç¹ID', |
| | | from_node_code VARCHAR(100) NULL COMMENT 'æ¥æºèç¹ç¼ç ', |
| | | to_node_type VARCHAR(32) NULL COMMENT 'ç®æ èç¹ç±»å', |
| | | to_node_id BIGINT NULL COMMENT 'ç®æ èç¹ID', |
| | | to_node_code VARCHAR(100) NULL COMMENT 'ç®æ èç¹ç¼ç ', |
| | | quantity DECIMAL(18, 6) NULL COMMENT 'æ°é', |
| | | warehouse_id BIGINT NULL COMMENT 'ä»åºID', |
| | | location_id BIGINT NULL COMMENT 'åºåºID', |
| | | area_id BIGINT NULL COMMENT 'åºä½ID', |
| | | line_id BIGINT NULL COMMENT '产线ID', |
| | | work_order_id BIGINT NULL COMMENT 'å·¥åID', |
| | | process_id BIGINT NULL COMMENT 'å·¥åºID', |
| | | sales_id BIGINT NULL COMMENT 'éå®åºåºåID', |
| | | quality_id BIGINT NULL COMMENT 'è´¨æ£è®°å½ID', |
| | | operator_id BIGINT NULL COMMENT 'æä½äººID', |
| | | payload_json JSON NULL COMMENT 'äºä»¶æ©å±æ°æ®', |
| | | content_hash VARCHAR(64) NULL COMMENT 'äºä»¶å
容SHA-256æè¦', |
| | | prev_hash VARCHAR(64) NULL COMMENT 'åä¸äºä»¶æè¦', |
| | | creator VARCHAR(64) NULL DEFAULT '' COMMENT 'å建è
', |
| | | create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'å建æ¶é´', |
| | | updater VARCHAR(64) NULL DEFAULT '' COMMENT 'æ´æ°è
', |
| | | update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'æ´æ°æ¶é´', |
| | | deleted BIT(1) NOT NULL DEFAULT b'0' COMMENT 'æ¯å¦å é¤', |
| | | PRIMARY KEY (id), |
| | | UNIQUE KEY uk_mes_trace_event_no (event_no), |
| | | KEY idx_mes_trace_event_batch_time (pro_batch_id, event_time), |
| | | KEY idx_mes_trace_event_biz (biz_type, biz_id, biz_line_id), |
| | | KEY idx_mes_trace_event_nodes (from_node_id, to_node_id) |
| | | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='MESç»ä¸è¿½æº¯äºä»¶'; |
| | | |
| | | -- å岿°æ®å填示ä¾ï¼ç¡®è®¤æ°æ®è´¨éåæ§è¡ï¼ |
| | | -- UPDATE mes_wm_batch w JOIN mes_pro_batch p ON p.code = w.code AND p.deleted = b'0' |
| | | -- SET w.pro_batch_id = p.id WHERE w.pro_batch_id IS NULL AND w.deleted = b'0'; |
| | | -- UPDATE mes_qc_seed_quality q JOIN mes_pro_batch p ON p.code = q.batch_code AND p.deleted = b'0' |
| | | -- SET q.batch_id = p.id WHERE q.batch_id IS NULL AND q.deleted = b'0'; |
| | |
| | | | æ¹æ³ | è·¯å¾ | 说æ | |
| | | |------|------|------| |
| | | | GET | /mes/wm/transaction/page | å页æ¥è¯¢åºåäºå¡æµæ°´ | |
| | | | GET | /mes/pro/batch/get-by-code | ç¹å»æ¹æ¬¡å·æ¥è¯¢çäº§æ¹æ¬¡ãæçåè¢ç ä¿¡æ¯ | |
| | | |
| | | ### 请æ±åæ° |
| | | |
| | |
| | | | bizType | Integer | å¦ | ä¸å¡ç±»å | |
| | | | bizCode | String | å¦ | ä¸å¡åå·ï¼æ¨¡ç³å¹é
| |
| | | | materialStockId | Long | å¦ | åºåè®°å½ID | |
| | | | bagCode | String | å¦ | è¢ç ï¼æ¨¡ç³å¹é
ï¼è´¨æ£ãéå®åºåºçè¢ç çº§æµæ°´ï¼ | |
| | | | startTime | String | å¦ | å¼å§æ¶é´ï¼æ ¼å¼ï¼yyyy-MM-dd HH:mm:ssï¼ | |
| | | | endTime | String | å¦ | ç»ææ¶é´ï¼æ ¼å¼ï¼yyyy-MM-dd HH:mm:ssï¼ | |
| | | | pageNo | Integer | æ¯ | 页ç ï¼é»è®¤1 | |
| | | | pageSize | Integer | æ¯ | æ¯é¡µæ¡æ°ï¼é»è®¤10 | |
| | | |
| | | ### æ¹æ¬¡è¿½æº¯æ¥è¯¢ |
| | | |
| | | ç¹å»æµæ°´å表ä¸çæ¹æ¬¡å·æ¶ï¼ä½¿ç¨å½åè¡ç `batchCode` è°ç¨ä»¥ä¸æ¥å£ï¼ |
| | | |
| | | | åæ° | ç±»å | å¿
å¡« | 说æ | |
| | | |------|------|------|------| |
| | | | code | String | æ¯ | æ¹æ¬¡å·ææ¹æ¬¡äºç»´ç å
容 | |
| | | |
| | | 请æ±ç¤ºä¾ï¼`GET /mes/pro/batch/get-by-code?code={batchCode}` |
| | | |
| | | æ¥å£è¿åçéç¹åæ®µï¼ |
| | | |
| | | | åæ®µ | ç±»å | 说æ | |
| | | |------|------|------| |
| | | | id | Long | çäº§æ¹æ¬¡ID | |
| | | | code | String | æ£å¼æ¹æ¬¡å· | |
| | | | tempCode | String | ä¸´æ¶æ¹æ¬¡ç | |
| | | | itemCode | String | ç©æç¼ç | |
| | | | itemName | String | ç©æåç§° | |
| | | | workers | Array | æ¹æ¬¡äººåé
ç½® | |
| | | | pallets | Array | æ¹æ¬¡ä¸çæçå表 | |
| | | | bagTotal | Integer | è¢ç æ»æ° | |
| | | | bags | Array | æ¹æ¬¡ä¸çè¢ç å表 | |
| | | |
| | | 该æ¥å£åæ¶æ¯ææ£å¼æ¹æ¬¡å·åä¸´æ¶æ¹æ¬¡ç ãè¥æ¹æ¬¡å·ä¸ºç©ºï¼ä¸æ¾ç¤ºç¹å»å
¥å£ï¼è¥æ¥è¯¢ä¸å°çäº§æ¹æ¬¡ï¼ææ¥å£è¿åçä¸å¡é误æç¤ºç¨æ·ã |
| | | |
| | | ### ååºå段 |
| | | |
| | |
| | | | quantity | BigDecimal | å卿°éï¼æ£æ°=å
¥åºï¼è´æ°=åºåºï¼ | |
| | | | batchId | Long | æ¹æ¬¡ID | |
| | | | batchCode | String | æ¹æ¬¡å· | |
| | | | bagCodeId | Long | è¢ç IDï¼è¢ç çº§æµæ°´éç©ºï¼ | |
| | | | bagCode | String | è¢ç ï¼è¢ç çº§æµæ°´é空ï¼å¦è´¨æ£ãéå®åºåºãç§»åºï¼ | |
| | | | warehouseId | Long | ä»åºID | |
| | | | warehouseName | String | ä»åºåç§° | |
| | | | locationId | Long | åºåºID | |
| | |
| | | | 121 | å¤ååæ | å¤ååæ | |
| | | | 122 | å¤åå
¥åº | å¤åå
¥åº | |
| | | |
| | | ## è°ç¨æ¶åº |
| | | |
| | | 1. è¿å
¥åºåäºå¡æµæ°´é¡µé¢æ¶ï¼è°ç¨ `/mes/wm/transaction/page` è·åæµæ°´å表ã |
| | | 2. å表ä¸å±ç¤º `batchCode`ï¼æ¹æ¬¡å·é空æ¶å
许ç¹å»ã |
| | | 3. ç¹å»æ¹æ¬¡å·åï¼å°å½åè¡ç `batchCode` ä½ä¸º `code` è°ç¨ `/mes/pro/batch/get-by-code`ã |
| | | 4. æ ¹æ®è¿åç»æå±ç¤ºçäº§æ¹æ¬¡ä¿¡æ¯ãæçå表åè¢ç å表ï¼`bagTotal` ç¨äºæ¾ç¤ºè¢ç æ»æ°ï¼`bags` ç¨äºå±ç¤ºè¢ç æç»ã |
| | | |
| | | ## åæ®µå±ç¤ºè§å |
| | | |
| | | | åæ®µ | å±ç¤ºä½ç½® | 说æ | |
| | | |------|----------|------| |
| | | | batchCode | åºåæµæ°´å表 | æ¹æ¬¡å·é空æ¶ä½ä¸ºå¯ç¹å»å
¥å£ | |
| | | | code | æ¹æ¬¡è¯¦æ
| æ£å¼æ¹æ¬¡å· | |
| | | | tempCode | æ¹æ¬¡è¯¦æ
| ä¸´æ¶æ¹æ¬¡ç ï¼æå¼æ¶å±ç¤º | |
| | | | bagTotal | æ¹æ¬¡è¯¦æ
| å±ç¤ºè¯¥æ¹æ¬¡è¢ç æ»æ° | |
| | | | bags[].code | æ¹æ¬¡è¯¦æ
| å±ç¤ºè¢ç æç» | |
| | | | pallets | æ¹æ¬¡è¯¦æ
| å±ç¤ºè¯¥æ¹æ¬¡å
³èçæçä¿¡æ¯ | |
| | | |
| | | ## æç´¢æ¡ä»¶ |
| | | |
| | | | æ¡ä»¶å段 | ç»ä»¶ç±»å | 说æ | |
| | |
| | | | åºåº | locationName | 100 | - | |
| | | | åºä½ | areaName | 100 | - | |
| | | | äºå¡æ¶é´ | transactionTime | 160 | æ ¼å¼ï¼yyyy-MM-dd HH:mm:ss | |
| | | | è¢ç | bagCode | 150 | è¢ç çº§æµæ°´çè¢ç ï¼æ¹æ¬¡/è¢ç å¯ç»§ç»è¿½æº¯ | |
| | | |
| | | ## ä¸å¡è§å说æ |
| | | |
| | |
| | | | æ°éæ¾ç¤º | quantity > 0 æ¾ç¤ºç»¿è²ï¼quantity < 0 æ¾ç¤ºçº¢è² | |
| | | | ç±»åæ ç¾ | å
¥åºæ¾ç¤ºç»¿è² success æ ç¾ï¼åºåºæ¾ç¤ºçº¢è² danger æ ç¾ | |
| | | | ä¸å¡åå·è·³è½¬ | ç¹å» bizCode å¯è·³è½¬å°å¯¹åºä¸å¡åæ®è¯¦æ
页 | |
| | | | è¢ç çé | ä¼ bagCode 坿¥çæå®è¢ç ç宿´æµè½¬ï¼è´¨æ£æååºåº/åæ ¼å
¥åº/éå®åºåºçï¼ | |
| | | |
| | | ## æéé
ç½® |
| | | |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | -- ========================================= |
| | | -- è¢ç è´¨æ£ç¶æï¼æ¯æç§åè´¨æ£æè¢ç ç²åº¦æµè½¬åºå |
| | | -- qc_statusï¼10 æªè´¨æ£ / 20 è´¨æ£åæ ¼ / 30 è´¨æ£ä¸åæ ¼ |
| | | -- æ°å¢åç¨äºè®°å½æ¯è¢çè´¨æ£ç»æï¼éå®åºåºæ«è¢ç æ¶æ ¡éªè¯¥è¢å·²è´¨æ£åæ ¼ã |
| | | -- ========================================= |
| | | |
| | | ALTER TABLE `mes_pro_bag_code` |
| | | ADD COLUMN `qc_status` TINYINT NOT NULL DEFAULT 10 COMMENT 'è´¨æ£ç¶æï¼10æªè´¨æ£ 20è´¨æ£åæ ¼ 30è´¨æ£ä¸åæ ¼ï¼' AFTER `status`; |
| | | |
| | | -- åå¡«åéæ°æ®ï¼æå·²æç§åè´¨æ£è®°å½åæ¥è¢ç è´¨æ£ç¶æ |
| | | UPDATE `mes_pro_bag_code` b |
| | | JOIN `mes_qc_seed_quality` q ON b.code = q.code AND b.deleted = 0 |
| | | SET b.qc_status = IF(q.result = 1, 20, 30), b.update_time = NOW(); |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | -- ç产线æ«ç å
¥åºï¼æ¯æè¢ç /æçç /æ¹æ¬¡ç ä¸ç§æ«ç ç±»åï¼å¹¶å»æè®¾å¤ç¼ç å¿
å¡« |
| | | -- 说æï¼ |
| | | -- 1. mes_pro_scan_event å¢å scan_type åï¼æ è®°æ«ç ç±»åï¼BAG è¢ç / PALLET æçç / BATCH æ¹æ¬¡ç ï¼ï¼åå²è¢ç æ°æ®åå¡« BAG |
| | | -- 2. mes_pro_pallet å¢å å
¥åºæ è®°åï¼æçåå
æ å
¥åºæ è®°åæ®µï¼æ´æå
¥åºéå»éï¼é²æ¢å䏿çé夿«ç å
¥åºï¼ |
| | | |
| | | ALTER TABLE mes_pro_scan_event ADD COLUMN scan_type VARCHAR(16) NULL COMMENT 'æ«ç ç±»åï¼BAGè¢ç /PALLETæçç /BATCHæ¹æ¬¡ç ï¼' AFTER bag_code; |
| | | |
| | | -- 设å¤ç¼ç ä¸åå¿
å¡«ï¼åç«¯å»æè®¾å¤ç¼ç ï¼åå²åä¿æå
¼å®¹ï¼ |
| | | ALTER TABLE mes_pro_scan_event MODIFY COLUMN device_code VARCHAR(64) NULL DEFAULT NULL COMMENT '设å¤ç¼ç ï¼ä¸åå¿
å¡«ï¼'; |
| | | |
| | | ALTER TABLE mes_pro_pallet ADD COLUMN inbound_event_id BIGINT NULL COMMENT 'æè¿å
¥åºæ«ç äºä»¶ç¼å·' AFTER bag_count; |
| | | ALTER TABLE mes_pro_pallet ADD COLUMN inbound_time DATETIME NULL COMMENT 'æè¿å
¥åºæ¶é´' AFTER inbound_event_id; |
| | | |
| | | UPDATE mes_pro_scan_event SET scan_type = 'BAG' WHERE scan_type IS NULL; |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | -- ============================================= |
| | | -- ç§åè´¨æ£è®°å½ç¬ç«èå |
| | | -- å°è´¨æ£è®°å½ä»ãç§åè´¨æ£ã页(æäº¤+è®°å½åä¸)æåºï¼ç¬ç«æèåé¡µé¢ |
| | | -- 说æï¼ |
| | | -- 1. ç§åè´¨æ£æäº¤é¡µï¼seed-quality -> mes/qc/seedQuality/indexï¼ä»
æäº¤ï¼ |
| | | -- 2. è´¨æ£è®°å½é¡µï¼seed-quality-record -> mes/qc/seedQuality/recordï¼ä»
è®°å½æ¥è¯¢ï¼ |
| | | -- æå¨ãè´¨é管çã(5500) ç®å½ä¸ï¼å¹çï¼å¯é夿§è¡ï¼æ ç§æ·å段ã |
| | | -- ============================================= |
| | | |
| | | INSERT INTO system_menu |
| | | (id, name, parent_id, type, sort, status, path, icon, component, component_name, permission, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) |
| | | SELECT 1065224, 'è´¨æ£è®°å½', 5500, 2, 95, 0, 'seed-quality-record', 'ep:list', 'mes/qc/seedQuality/record', 'MesQcSeedQualityRecord', '', b'1', b'1', b'1', '1', NOW(), '1', NOW(), b'0' |
| | | FROM DUAL |
| | | WHERE NOT EXISTS (SELECT 1 FROM system_menu WHERE id = 1065224 AND deleted = b'0'); |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | CREATE TABLE mes_wm_material_stock_bag ( |
| | | id BIGINT NOT NULL AUTO_INCREMENT COMMENT 'ç¼å·', |
| | | material_stock_id BIGINT NOT NULL COMMENT 'åºåæ±æ»è®°å½ID', |
| | | bag_code_id BIGINT NOT NULL COMMENT 'ç产è¢ç ID', |
| | | bag_code VARCHAR(64) NOT NULL COMMENT 'è¢ç ', |
| | | item_id BIGINT NOT NULL COMMENT 'ç©æID', |
| | | batch_id BIGINT NULL COMMENT 'ä»åºæ¹æ¬¡ID', |
| | | batch_code VARCHAR(64) NULL COMMENT 'æ¹æ¬¡å·', |
| | | vendor_id BIGINT NULL COMMENT 'ä¾åºåID', |
| | | warehouse_id BIGINT NOT NULL COMMENT 'ä»åºID', |
| | | location_id BIGINT NULL COMMENT 'åºåºID', |
| | | area_id BIGINT NULL COMMENT 'åºä½ID', |
| | | stock_state TINYINT NOT NULL COMMENT 'åºåç¶æï¼10æåï¼20åæ ¼ï¼30å·²åºåºï¼40æ¥åº', |
| | | status TINYINT NOT NULL DEFAULT 1 COMMENT 'æç»ç¶æï¼1å¨åºï¼2å·²åºåºï¼3å·²æ¥åº', |
| | | quantity DECIMAL(18, 6) NOT NULL DEFAULT 1 COMMENT 'è¢ç åºåæ°é', |
| | | frozen BIT NOT NULL DEFAULT 0 COMMENT 'æ¯å¦å»ç»', |
| | | last_transaction_id BIGINT NULL COMMENT 'æè¿åºåäºå¡ID', |
| | | inbound_time DATETIME NULL COMMENT 'å
¥åºæ¶é´', |
| | | outbound_time DATETIME NULL COMMENT 'åºåºæ¶é´', |
| | | creator VARCHAR(64) DEFAULT '' COMMENT 'å建è
', |
| | | create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'å建æ¶é´', |
| | | updater VARCHAR(64) DEFAULT '' COMMENT 'æ´æ°è
', |
| | | update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'æ´æ°æ¶é´', |
| | | deleted BIT NOT NULL DEFAULT 0 COMMENT 'æ¯å¦å é¤', |
| | | PRIMARY KEY (id), |
| | | UNIQUE KEY uk_bag_code (bag_code), |
| | | KEY idx_material_stock (material_stock_id), |
| | | KEY idx_batch_state (batch_id, stock_state, status), |
| | | KEY idx_location_state (warehouse_id, location_id, area_id, stock_state, status), |
| | | KEY idx_bag_code_id (bag_code_id) |
| | | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='MESåºåè¢ç æç»'; |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | -- MES éå®åºåºåè¡¨ç»æä¿®æ¹ |
| | | -- æ ¹æ® MesWmProductSalesDO è¡¥å
ç¼ºå¤±åæ®µ |
| | | -- 说æï¼ä¿®å¤æ¥è¯¢æ¥é Unknown column 'client_name'ï¼åæ¶è¡¥å
outbound_timeãoutbound_user_id |
| | | |
| | | -- 1. ç»éååç§°å¿«ç
§ |
| | | ALTER TABLE mes_wm_product_sales ADD COLUMN client_name VARCHAR(128) DEFAULT NULL COMMENT 'ç»éååç§°å¿«ç
§' AFTER client_id; |
| | | |
| | | -- 2. å®é
åºåºæ¶é´ |
| | | ALTER TABLE mes_wm_product_sales ADD COLUMN outbound_time DATETIME DEFAULT NULL COMMENT 'å®é
åºåºæ¶é´'; |
| | | |
| | | -- 3. æ§è¡åºåºæä½äººID |
| | | ALTER TABLE mes_wm_product_sales ADD COLUMN outbound_user_id BIGINT DEFAULT NULL COMMENT 'æ§è¡åºåºæä½äººID'; |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | -- ===================================================================== |
| | | -- æ°å»ºåæ ¼ä»åº + ä»åºç±»å + è´¨æ£å
¥åæ ¼åºæ¹é |
| | | -- |
| | | -- 1) mes_wm_warehouse å¢å type åæ®µï¼10 æååº / 20 åæ ¼åºï¼ |
| | | -- 2) ç°æä»åºåç±»ï¼èæçº¿è¾¹ä»åº=10ï¼æååºï¼ï¼äº§ååº/ç©æåº=20ï¼åæ ¼åºï¼ |
| | | -- 3) æ°å»º"æååæ ¼åº"(type=20) + ä¸ä¸ªåºåº + ä¸ä¸ªåºä½ |
| | | -- 4) èæä»åºä¸ stock_state=20 çåæ ¼åºåè¿ç§»å°æ°åæ ¼åº |
| | | -- |
| | | -- 说æï¼æ¬èæ¬å¹çï¼å¯é夿§è¡ï¼æ ç§æ·å段ã |
| | | -- ===================================================================== |
| | | |
| | | -- 1) å¢å ä»åºç±»ååæ®µï¼MySQL 䏿¯æ ALTER ADD COLUMN IF NOT EXISTSï¼å
æ¥å卿§ï¼ |
| | | SET @type_exists = ( |
| | | SELECT COUNT(*) |
| | | FROM information_schema.columns |
| | | WHERE table_schema = DATABASE() |
| | | AND table_name = 'mes_wm_warehouse' |
| | | AND column_name = 'type' |
| | | ); |
| | | SET @type_sql = IF( |
| | | @type_exists = 0, |
| | | 'ALTER TABLE mes_wm_warehouse ADD COLUMN type tinyint NOT NULL DEFAULT 10 COMMENT ''ä»åºç±»åï¼10æååºï¼20åæ ¼åº'' AFTER frozen', |
| | | 'SELECT 1' |
| | | ); |
| | | PREPARE type_stmt FROM @type_sql; |
| | | EXECUTE type_stmt; |
| | | DEALLOCATE PREPARE type_stmt; |
| | | |
| | | -- 2) ç°æä»åºåç±» |
| | | UPDATE mes_wm_warehouse SET type = 10 WHERE code = 'WIP_VIRTUAL_WAREHOUSE' AND deleted = 0; |
| | | UPDATE mes_wm_warehouse SET type = 20 WHERE code IN ('1212', 'WHS000001') AND deleted = 0; |
| | | |
| | | -- 3) æ°å»º"æååæ ¼åº"ï¼type=20ï¼ |
| | | SET @wh_exists = ( |
| | | SELECT COUNT(*) FROM mes_wm_warehouse WHERE code = 'FG_QUALIFIED_WH' AND deleted = 0 |
| | | ); |
| | | INSERT INTO mes_wm_warehouse (code, name, frozen, type, remark) |
| | | SELECT 'FG_QUALIFIED_WH', 'æååæ ¼åº', 0, 20, 'è´¨æ£åæ ¼ç´æ¥å
¥åºçç®æ ä»åºï¼type=20 åæ ¼åºï¼' |
| | | WHERE @wh_exists = 0; |
| | | SET @wh_id = (SELECT id FROM mes_wm_warehouse WHERE code = 'FG_QUALIFIED_WH' AND deleted = 0 LIMIT 1); |
| | | |
| | | -- æ°å»º"æååæ ¼åºåº" |
| | | SET @loc_exists = ( |
| | | SELECT COUNT(*) FROM mes_wm_warehouse_location WHERE code = 'FG_QUALIFIED_WH_LOC' AND deleted = 0 |
| | | ); |
| | | INSERT INTO mes_wm_warehouse_location (code, name, warehouse_id, frozen, remark) |
| | | SELECT 'FG_QUALIFIED_WH_LOC', 'æååæ ¼åºåº', @wh_id, 0, 'è´¨æ£åæ ¼å
¥åºé»è®¤åºåº' |
| | | WHERE @loc_exists = 0; |
| | | SET @loc_id = (SELECT id FROM mes_wm_warehouse_location WHERE code = 'FG_QUALIFIED_WH_LOC' AND deleted = 0 LIMIT 1); |
| | | |
| | | -- æ°å»º"æååæ ¼åºä½" |
| | | SET @area_exists = ( |
| | | SELECT COUNT(*) FROM mes_wm_warehouse_area WHERE code = 'FG_QUALIFIED_WH_AREA' AND deleted = 0 |
| | | ); |
| | | INSERT INTO mes_wm_warehouse_area (code, name, location_id, frozen, remark) |
| | | SELECT 'FG_QUALIFIED_WH_AREA', 'æååæ ¼åºä½', @loc_id, 0, 'è´¨æ£åæ ¼å
¥åºé»è®¤åºä½' |
| | | WHERE @area_exists = 0; |
| | | SET @area_id = (SELECT id FROM mes_wm_warehouse_area WHERE code = 'FG_QUALIFIED_WH_AREA' AND deleted = 0 LIMIT 1); |
| | | |
| | | -- 4) è¿ç§»èæä»åºåæ ¼åºåå°æ°åæ ¼åº |
| | | -- 4.1 è¥æ°åæ ¼åºå·²åå¨å (item_id, batch_id, vendor_id) ç state=20 è®°å½ï¼å
æ°éç´¯å åå¹¶ |
| | | UPDATE mes_wm_material_stock t |
| | | JOIN mes_wm_material_stock s |
| | | ON s.warehouse_id = 3 AND s.stock_state = 20 AND s.deleted = 0 |
| | | AND t.warehouse_id = @wh_id AND t.stock_state = 20 AND t.deleted = 0 |
| | | AND t.item_id = s.item_id |
| | | AND IFNULL(t.batch_id, 0) = IFNULL(s.batch_id, 0) |
| | | AND IFNULL(t.vendor_id, 0) = IFNULL(s.vendor_id, 0) |
| | | SET t.quantity = t.quantity + s.quantity, |
| | | t.reserved_quantity = t.reserved_quantity + s.reserved_quantity, |
| | | t.frozen_quantity = t.frozen_quantity + s.frozen_quantity; |
| | | |
| | | -- 4.2 å é¤å·²åå¹¶å°æ°åæ ¼åºçæºè®°å½ï¼èæä»åºä¸ï¼ |
| | | DELETE s FROM mes_wm_material_stock s |
| | | JOIN mes_wm_material_stock t |
| | | ON s.warehouse_id = 3 AND s.stock_state = 20 AND s.deleted = 0 |
| | | AND t.warehouse_id = @wh_id AND t.stock_state = 20 AND t.deleted = 0 |
| | | AND t.item_id = s.item_id |
| | | AND IFNULL(t.batch_id, 0) = IFNULL(s.batch_id, 0) |
| | | AND IFNULL(t.vendor_id, 0) = IFNULL(s.vendor_id, 0); |
| | | |
| | | -- 4.3 å
¶ä½åæ ¼åºåç´æ¥æ¹ä»åº/åºåº/åºä½ |
| | | UPDATE mes_wm_material_stock |
| | | SET warehouse_id = @wh_id, location_id = @loc_id, area_id = @area_id |
| | | WHERE warehouse_id = 3 AND stock_state = 20 AND deleted = 0; |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | SET @exists_bag_code_id = (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'mes_wm_transaction' AND column_name = 'bag_code_id'); |
| | | SET @sql_bag_code_id = IF(@exists_bag_code_id = 0, 'ALTER TABLE mes_wm_transaction ADD COLUMN bag_code_id BIGINT NULL COMMENT ''ç产è¢ç ID'' AFTER material_stock_id', 'SELECT 1'); |
| | | PREPARE stmt FROM @sql_bag_code_id; |
| | | EXECUTE stmt; |
| | | DEALLOCATE PREPARE stmt; |
| | | |
| | | SET @exists_bag_code = (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'mes_wm_transaction' AND column_name = 'bag_code'); |
| | | SET @sql_bag_code = IF(@exists_bag_code = 0, 'ALTER TABLE mes_wm_transaction ADD COLUMN bag_code VARCHAR(64) NULL COMMENT ''è¢ç '' AFTER bag_code_id', 'SELECT 1'); |
| | | PREPARE stmt FROM @sql_bag_code; |
| | | EXECUTE stmt; |
| | | DEALLOCATE PREPARE stmt; |
| | | |
| | | SET @exists_bag_code_index = (SELECT COUNT(*) FROM information_schema.statistics WHERE table_schema = DATABASE() AND table_name = 'mes_wm_transaction' AND index_name = 'idx_bag_code'); |
| | | SET @sql_bag_code_index = IF(@exists_bag_code_index = 0, 'ALTER TABLE mes_wm_transaction ADD KEY idx_bag_code (bag_code)', 'SELECT 1'); |
| | | PREPARE stmt FROM @sql_bag_code_index; |
| | | EXECUTE stmt; |
| | | DEALLOCATE PREPARE stmt; |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | -- ============================================================ |
| | | -- ä¸å¡æ°æ®æ¸
çåå¨è¿ç¨ï¼ç®æ åºï¼mom-thzyï¼ |
| | | -- |
| | | -- ç¨éï¼æ¸
空åä¸å¡æ¨¡åçæµæ°´/äºå¡æ°æ®ï¼ä¿çç¨æ·ãè§è²ãèåã |
| | | -- åå
¸ãæµç¨å®ä¹ãåºç¡é
ç½®ä¸ä¸»æ°æ®æ¡£æ¡ã |
| | | -- |
| | | -- 注æï¼ |
| | | -- 1. TRUNCATE 为 DDL éå¼æäº¤ï¼æ æ³åæ»ï¼æ§è¡å请å
å¤ä»½ã |
| | | -- 2. æ§è¡æ¹å¼ï¼mysql -uroot -p mom-thzy < sp_clean_business_data.sql |
| | | -- æå¨å®¢æ·ç«¯ä¸æ´ä½æ§è¡æ¬èæ¬ï¼å« DELIMITERï¼ã |
| | | -- 3. æ§è¡æ¸
çï¼CALL sp_clean_business_data(); |
| | | -- ============================================================ |
| | | |
| | | DROP PROCEDURE IF EXISTS `sp_clean_business_data`; |
| | | |
| | | DELIMITER $$ |
| | | |
| | | CREATE DEFINER=`root`@`%` PROCEDURE `sp_clean_business_data`() |
| | | BEGIN |
| | | SET FOREIGN_KEY_CHECKS = 0; |
| | | |
| | | -- ============================================================ |
| | | -- 1. ç³»ç»è¿è¡æ°æ®ï¼æ¥å¿ / Token / éªè¯ç / ç«å
ä¿¡ / 社交ç»å®ï¼ |
| | | -- ============================================================ |
| | | TRUNCATE TABLE system_login_log; |
| | | TRUNCATE TABLE system_operate_log; |
| | | TRUNCATE TABLE system_notify_message; |
| | | TRUNCATE TABLE system_oauth2_access_token; |
| | | TRUNCATE TABLE system_oauth2_refresh_token; |
| | | TRUNCATE TABLE system_oauth2_code; |
| | | TRUNCATE TABLE system_oauth2_approve; |
| | | TRUNCATE TABLE system_sms_code; |
| | | TRUNCATE TABLE system_sms_log; |
| | | TRUNCATE TABLE system_mail_log; |
| | | TRUNCATE TABLE system_social_user; |
| | | TRUNCATE TABLE system_social_user_bind; |
| | | TRUNCATE TABLE infra_api_access_log; |
| | | TRUNCATE TABLE infra_api_error_log; |
| | | TRUNCATE TABLE infra_job_log; |
| | | |
| | | -- å é¤ä¸æ¬é¡¹ç®æ å
³çæ¡æ¶èªå¸¦å®æ¶ä»»å¡ï¼pay/mall/iot/demoï¼ï¼ |
| | | -- ä¿çæ¥å¿æ¸
çä¸ä»¶å¥ï¼accessLogCleanJob / errorLogCleanJob / jobLogCleanJob |
| | | DELETE FROM infra_job |
| | | WHERE handler_name IN ( |
| | | 'payNotifyJob', 'payOrderSyncJob', 'payOrderExpireJob', |
| | | 'payRefundSyncJob', 'payTransferSyncJob', |
| | | 'tradeOrderAutoCancelJob', 'tradeOrderAutoReceiveJob', 'tradeOrderAutoCommentJob', |
| | | 'brokerageRecordUnfreezeJob', 'combinationRecordExpireJob', |
| | | 'couponExpireJob', 'productStatisticsJob', |
| | | 'iotDeviceOfflineCheckJob', 'iotOtaUpgradeJob', |
| | | 'demoJob' |
| | | ); |
| | | |
| | | -- Quartz è°åº¦è¿è¡æ¶æ°æ®ï¼qrtz_locks ä¿çéè¡ï¼æ¸
空ä¼å¯¼è´è°åº¦å¨å 鿥éï¼ |
| | | -- æ¸
çåå¦éæ¢å¤ä¿çä»»å¡çè°åº¦æ³¨åï¼å¨ãåºç¡è®¾æ½-宿¶ä»»å¡ã页é¢ç¹"忥"æè°ç¨ |
| | | -- POST /admin-api/infra/job/sync ä» infra_job é建触åå¨ |
| | | TRUNCATE TABLE qrtz_blob_triggers; |
| | | TRUNCATE TABLE qrtz_calendars; |
| | | TRUNCATE TABLE qrtz_cron_triggers; |
| | | TRUNCATE TABLE qrtz_fired_triggers; |
| | | TRUNCATE TABLE qrtz_job_details; |
| | | TRUNCATE TABLE qrtz_paused_trigger_grps; |
| | | TRUNCATE TABLE qrtz_scheduler_state; |
| | | TRUNCATE TABLE qrtz_simple_triggers; |
| | | TRUNCATE TABLE qrtz_simprop_triggers; |
| | | TRUNCATE TABLE qrtz_triggers; |
| | | |
| | | -- ============================================================ |
| | | -- 2. æä»¶ä¸éä»¶ |
| | | -- ============================================================ |
| | | TRUNCATE TABLE system_storage_attachment; |
| | | TRUNCATE TABLE system_storage_blob; |
| | | TRUNCATE TABLE storage_attachment; |
| | | TRUNCATE TABLE storage_blob; |
| | | TRUNCATE TABLE infra_file; |
| | | TRUNCATE TABLE infra_file_content; |
| | | |
| | | -- ============================================================ |
| | | -- 3. BPM æµç¨å®ä¾ä¸å®¡æ¹åå² |
| | | -- ä¿çï¼æµç¨å®ä¹/表å/åç±»/表达å¼/çå¬å¨/ç¨æ·ç»/ä¸å¡éä»¶é
ç½® |
| | | -- ä¿çï¼act_re_* / act_ge_* / act_id_* / act_procdef_infoï¼å®ä¹ä¸é¨ç½²èµæºï¼ |
| | | -- ============================================================ |
| | | TRUNCATE TABLE bpm_oa_leave; |
| | | TRUNCATE TABLE bpm_process_instance_copy; |
| | | TRUNCATE TABLE act_hi_procinst; |
| | | TRUNCATE TABLE act_hi_taskinst; |
| | | TRUNCATE TABLE act_hi_actinst; |
| | | TRUNCATE TABLE act_hi_varinst; |
| | | TRUNCATE TABLE act_hi_identitylink; |
| | | TRUNCATE TABLE act_hi_comment; |
| | | TRUNCATE TABLE act_hi_detail; |
| | | TRUNCATE TABLE act_hi_attachment; |
| | | TRUNCATE TABLE act_hi_entitylink; |
| | | TRUNCATE TABLE act_hi_tsk_log; |
| | | TRUNCATE TABLE act_ru_task; |
| | | TRUNCATE TABLE act_ru_execution; |
| | | TRUNCATE TABLE act_ru_actinst; |
| | | TRUNCATE TABLE act_ru_variable; |
| | | TRUNCATE TABLE act_ru_identitylink; |
| | | TRUNCATE TABLE act_ru_job; |
| | | TRUNCATE TABLE act_ru_timer_job; |
| | | TRUNCATE TABLE act_ru_deadletter_job; |
| | | TRUNCATE TABLE act_ru_suspended_job; |
| | | TRUNCATE TABLE act_ru_external_job; |
| | | TRUNCATE TABLE act_ru_history_job; |
| | | TRUNCATE TABLE act_ru_event_subscr; |
| | | TRUNCATE TABLE act_ru_entitylink; |
| | | TRUNCATE TABLE act_evt_log; |
| | | -- Flowable æ¹æ¬¡è¿è¡æ¶ï¼multi-instance æ¹å¤çï¼åèæ¬éæ¼ï¼ |
| | | TRUNCATE TABLE flw_ru_batch; |
| | | TRUNCATE TABLE flw_ru_batch_part; |
| | | |
| | | -- ============================================================ |
| | | -- 4. MES ç产模å â ä¸å¡æ°æ® |
| | | -- ä¿çï¼mes_pro_process / mes_pro_route*ï¼å·¥èºä¸è·¯çº¿å®ä¹ï¼ |
| | | -- ============================================================ |
| | | TRUNCATE TABLE mes_pro_work_order_param_record_detail; |
| | | TRUNCATE TABLE mes_pro_work_order_param_record; |
| | | TRUNCATE TABLE mes_pro_work_order_process; |
| | | TRUNCATE TABLE mes_pro_work_order_bom; |
| | | TRUNCATE TABLE mes_pro_work_order; |
| | | TRUNCATE TABLE mes_pro_task_issue; |
| | | TRUNCATE TABLE mes_pro_task; |
| | | TRUNCATE TABLE mes_pro_task_pause_record; -- ç产任å¡å工记å½ï¼åèæ¬éæ¼ï¼ |
| | | TRUNCATE TABLE mes_pro_feedback; |
| | | TRUNCATE TABLE mes_pro_mps_merge_item; |
| | | TRUNCATE TABLE mes_pro_mps; |
| | | TRUNCATE TABLE mes_pro_card_process; |
| | | TRUNCATE TABLE mes_pro_card; |
| | | TRUNCATE TABLE mes_pro_work_record_log; |
| | | TRUNCATE TABLE mes_pro_work_record; |
| | | TRUNCATE TABLE mes_pro_andon_record; |
| | | TRUNCATE TABLE mes_pro_scan_event; -- è¢ç æ«ç å
¥åºäºä»¶ï¼åèæ¬éæ¼ï¼ |
| | | |
| | | -- ============================================================ |
| | | -- 5. MES ä»å¨æ¨¡å â ä¸å¡æ°æ® |
| | | -- ä¿çï¼mes_wm_warehouse / _area / _location / _barcode_configï¼ä»å¨é
ç½®ï¼ |
| | | -- ============================================================ |
| | | TRUNCATE TABLE mes_wm_transaction; |
| | | TRUNCATE TABLE mes_wm_stock_reserve; |
| | | TRUNCATE TABLE mes_wm_material_stock; |
| | | TRUNCATE TABLE mes_wm_material_stock_bag; -- åºåè¢ç æç»ï¼åèæ¬éæ¼ï¼ |
| | | TRUNCATE TABLE mes_wm_stock_warning; -- åºåé¢è¦è®°å½ï¼åèæ¬éæ¼ï¼ |
| | | TRUNCATE TABLE mes_wm_sn; |
| | | TRUNCATE TABLE mes_wm_batch; |
| | | TRUNCATE TABLE mes_wm_barcode; |
| | | TRUNCATE TABLE mes_wm_stock_taking_task_result; |
| | | TRUNCATE TABLE mes_wm_stock_taking_task_line; |
| | | TRUNCATE TABLE mes_wm_stock_taking_task; |
| | | TRUNCATE TABLE mes_wm_stock_taking_plan_param; |
| | | TRUNCATE TABLE mes_wm_stock_taking_plan; |
| | | TRUNCATE TABLE mes_wm_package_line; |
| | | TRUNCATE TABLE mes_wm_package; |
| | | TRUNCATE TABLE mes_wm_item_receipt_detail; |
| | | TRUNCATE TABLE mes_wm_item_receipt_line; |
| | | TRUNCATE TABLE mes_wm_item_receipt; |
| | | TRUNCATE TABLE mes_wm_item_consume_detail; |
| | | TRUNCATE TABLE mes_wm_item_consume_line; |
| | | TRUNCATE TABLE mes_wm_item_consume; |
| | | TRUNCATE TABLE mes_wm_product_produce_detail; |
| | | TRUNCATE TABLE mes_wm_product_produce_line; |
| | | TRUNCATE TABLE mes_wm_product_produce; |
| | | TRUNCATE TABLE mes_wm_product_issue_detail; |
| | | TRUNCATE TABLE mes_wm_product_issue_line; |
| | | TRUNCATE TABLE mes_wm_product_issue; |
| | | TRUNCATE TABLE mes_wm_product_receipt_detail; |
| | | TRUNCATE TABLE mes_wm_product_receipt_line; |
| | | TRUNCATE TABLE mes_wm_product_receipt; |
| | | TRUNCATE TABLE mes_wm_product_sales_detail; |
| | | TRUNCATE TABLE mes_wm_product_sales_line; |
| | | TRUNCATE TABLE mes_wm_product_sales; |
| | | TRUNCATE TABLE mes_wm_misc_receipt_detail; |
| | | TRUNCATE TABLE mes_wm_misc_receipt_line; |
| | | TRUNCATE TABLE mes_wm_misc_receipt; |
| | | TRUNCATE TABLE mes_wm_misc_issue_detail; |
| | | TRUNCATE TABLE mes_wm_misc_issue_line; |
| | | TRUNCATE TABLE mes_wm_misc_issue; |
| | | TRUNCATE TABLE mes_wm_outsource_receipt_detail; |
| | | TRUNCATE TABLE mes_wm_outsource_receipt_line; |
| | | TRUNCATE TABLE mes_wm_outsource_receipt; |
| | | TRUNCATE TABLE mes_wm_outsource_issue_detail; |
| | | TRUNCATE TABLE mes_wm_outsource_issue_line; |
| | | TRUNCATE TABLE mes_wm_outsource_issue; |
| | | TRUNCATE TABLE mes_wm_return_vendor_detail; |
| | | TRUNCATE TABLE mes_wm_return_vendor_line; |
| | | TRUNCATE TABLE mes_wm_return_vendor; |
| | | TRUNCATE TABLE mes_wm_return_issue_detail; |
| | | TRUNCATE TABLE mes_wm_return_issue_line; |
| | | TRUNCATE TABLE mes_wm_return_issue; |
| | | TRUNCATE TABLE mes_wm_return_sales_detail; |
| | | TRUNCATE TABLE mes_wm_return_sales_line; |
| | | TRUNCATE TABLE mes_wm_return_sales; |
| | | TRUNCATE TABLE mes_wm_sales_notice_line; |
| | | TRUNCATE TABLE mes_wm_sales_notice; |
| | | TRUNCATE TABLE mes_wm_transfer_detail; |
| | | TRUNCATE TABLE mes_wm_transfer_line; |
| | | TRUNCATE TABLE mes_wm_transfer; |
| | | TRUNCATE TABLE mes_wm_arrival_notice_line; |
| | | TRUNCATE TABLE mes_wm_arrival_notice; |
| | | |
| | | -- ============================================================ |
| | | -- 6. MES è´¨æ£æ¨¡å â ä¸å¡æ°æ® |
| | | -- ä¿çï¼mes_qc_template(_indicator/_item) / _indicator / _defectï¼è´¨æ£é
ç½®ä¸åå
¸ï¼ |
| | | -- ============================================================ |
| | | TRUNCATE TABLE mes_qc_indicator_result_detail; |
| | | TRUNCATE TABLE mes_qc_indicator_result; |
| | | TRUNCATE TABLE mes_qc_defect_record; |
| | | TRUNCATE TABLE mes_qc_ncr; |
| | | TRUNCATE TABLE mes_qc_iqc_line; |
| | | TRUNCATE TABLE mes_qc_iqc; |
| | | TRUNCATE TABLE mes_qc_ipqc_line; |
| | | TRUNCATE TABLE mes_qc_ipqc; |
| | | TRUNCATE TABLE mes_qc_oqc_line; |
| | | TRUNCATE TABLE mes_qc_oqc; |
| | | TRUNCATE TABLE mes_qc_rqc_line; |
| | | TRUNCATE TABLE mes_qc_rqc; |
| | | -- ç§åè´¨æ£è®°å½ï¼åèæ¬éæ¼ï¼ |
| | | TRUNCATE TABLE mes_qc_seed_quality_indicator; |
| | | TRUNCATE TABLE mes_qc_seed_quality_source; |
| | | TRUNCATE TABLE mes_qc_seed_quality; |
| | | |
| | | -- ============================================================ |
| | | -- 7. MES 追溯模å â äºä»¶ä¸é¢è¦è®°å½ï¼åèæ¬éæ¼ï¼ |
| | | -- ä¿çï¼mes_trace_anti_configï¼é²ä¼ªçªé
ç½®ï¼ |
| | | -- ============================================================ |
| | | TRUNCATE TABLE mes_trace_consumer_scan_event; |
| | | TRUNCATE TABLE mes_trace_cross_region_warning; |
| | | TRUNCATE TABLE mes_trace_integrity_record; |
| | | TRUNCATE TABLE mes_trace_event; |
| | | |
| | | -- ============================================================ |
| | | -- 8. MES è®¾å¤æ¨¡å â ç¹æ£/ä¿å
»/ç»´ä¿®/è®¡éæ£æµè®°å½ |
| | | -- ä¿çï¼mes_dv_machinery(_type) / _check_plan* / _subject / _meteringï¼å°è´¦ä¸è®¡åï¼ |
| | | -- ============================================================ |
| | | TRUNCATE TABLE mes_dv_check_record_line; |
| | | TRUNCATE TABLE mes_dv_check_record; |
| | | TRUNCATE TABLE mes_dv_mainten_record_line; |
| | | TRUNCATE TABLE mes_dv_mainten_record; |
| | | TRUNCATE TABLE mes_dv_repair_line; |
| | | TRUNCATE TABLE mes_dv_repair; |
| | | TRUNCATE TABLE mes_dv_metering_check; |
| | | |
| | | -- ============================================================ |
| | | -- 9. MES å·¥èº/设计模å â ä¸å¡æ°æ®ï¼ç¼ç çæè®°å½ä¸ºæµæ°´æ°æ®ï¼ |
| | | -- ä¿çï¼mes_pd_process_param(_template/_detail)ï¼å·¥èºåæ°å®ä¹ï¼ |
| | | -- / mes_md_auto_code_rule / _partï¼ç¼ç è§åï¼ |
| | | -- ============================================================ |
| | | TRUNCATE TABLE mes_pd_archive; |
| | | TRUNCATE TABLE mes_pd_document_audit; |
| | | TRUNCATE TABLE mes_pd_document; |
| | | TRUNCATE TABLE mes_pd_project; |
| | | TRUNCATE TABLE mes_md_auto_code_record; |
| | | |
| | | -- ============================================================ |
| | | -- 10. CRM 模å â ä¸å¡æ°æ® |
| | | -- ä¿çï¼crm_customer / crm_contact / crm_business_status(_type) |
| | | -- / crm_contract_config / crm_customer_limit_config / crm_customer_pool_config |
| | | -- ============================================================ |
| | | TRUNCATE TABLE crm_receivable_plan; |
| | | TRUNCATE TABLE crm_receivable; |
| | | TRUNCATE TABLE crm_contract_product; |
| | | TRUNCATE TABLE crm_contract; |
| | | TRUNCATE TABLE crm_sale_quotation_product; |
| | | TRUNCATE TABLE crm_sale_quotation; |
| | | TRUNCATE TABLE crm_business_product; |
| | | TRUNCATE TABLE crm_contact_business; |
| | | TRUNCATE TABLE crm_business; |
| | | TRUNCATE TABLE crm_clue; |
| | | TRUNCATE TABLE crm_follow_up_record; |
| | | TRUNCATE TABLE crm_invoice; |
| | | TRUNCATE TABLE crm_sales_target; |
| | | TRUNCATE TABLE crm_permission; |
| | | |
| | | -- ============================================================ |
| | | -- 11. å®å模å â ä¸å¡æ°æ® |
| | | -- ============================================================ |
| | | TRUNCATE TABLE after_sale_return_item; |
| | | TRUNCATE TABLE after_sale_return; |
| | | TRUNCATE TABLE after_sale_ticket_item; |
| | | TRUNCATE TABLE after_sale_ticket; |
| | | TRUNCATE TABLE after_sale_repair; |
| | | TRUNCATE TABLE after_sale_permission; |
| | | |
| | | -- ============================================================ |
| | | -- 12. ERP 模å â ä¸å¡æ°æ® |
| | | -- ä¿çï¼erp_supplier / erp_account |
| | | -- ============================================================ |
| | | TRUNCATE TABLE erp_finance_payment_item; |
| | | TRUNCATE TABLE erp_finance_payment; |
| | | TRUNCATE TABLE erp_finance_receipt_item; |
| | | TRUNCATE TABLE erp_finance_receipt; |
| | | TRUNCATE TABLE erp_purchase_order_items; |
| | | TRUNCATE TABLE erp_purchase_order; |
| | | TRUNCATE TABLE erp_purchase_request_items; |
| | | TRUNCATE TABLE erp_purchase_request; |
| | | TRUNCATE TABLE erp_sale_order_items; |
| | | TRUNCATE TABLE erp_sale_order; |
| | | TRUNCATE TABLE erp_purchase_invoice; |
| | | |
| | | -- ============================================================ |
| | | -- 13. SRM 模å â ä¸å¡æ°æ® |
| | | -- ä¿çï¼srm_supplier / srm_supplier_contact / srm_supplier_category |
| | | -- / srm_tender_config |
| | | -- ============================================================ |
| | | TRUNCATE TABLE srm_bid_award; |
| | | TRUNCATE TABLE srm_bid_evaluation; |
| | | TRUNCATE TABLE srm_bid_open; |
| | | TRUNCATE TABLE srm_tender_bid; |
| | | TRUNCATE TABLE srm_tender_material; |
| | | TRUNCATE TABLE srm_tender_project; |
| | | TRUNCATE TABLE srm_delivery_plan; |
| | | TRUNCATE TABLE srm_purchase_collaboration; |
| | | TRUNCATE TABLE srm_supplier_quote; |
| | | TRUNCATE TABLE srm_supplier_evaluation; |
| | | TRUNCATE TABLE srm_supplier_certificate; |
| | | TRUNCATE TABLE srm_supplier_apply; |
| | | |
| | | -- ============================================================ |
| | | -- 14. HRM 模å â ä¸å¡æ°æ® |
| | | -- ä¿çï¼hrm_employee åæ¡£æ¡åè¡¨ï¼æè²/å·¥ä½ç»å/ç´§æ¥è系人/ |
| | | -- 社ä¿å
¬ç§¯é/èªé
¬æ¡£æ¡/ååï¼ãèå¤è忥/è§åã请åç±»åé
ç½®ã |
| | | -- èªé
¬ç»æã社ä¿å
¬ç§¯éæ¹æ¡ã个ç¨ç¨çé
ç½® |
| | | -- ============================================================ |
| | | TRUNCATE TABLE hrm_salary_payment_detail; |
| | | TRUNCATE TABLE hrm_salary_payment; |
| | | TRUNCATE TABLE hrm_salary_calculation; |
| | | TRUNCATE TABLE hrm_attendance_summary; |
| | | TRUNCATE TABLE hrm_attendance_record; |
| | | TRUNCATE TABLE hrm_attendance_exception; |
| | | TRUNCATE TABLE hrm_leave_application; |
| | | TRUNCATE TABLE hrm_resignation_application; |
| | | TRUNCATE TABLE hrm_transfer_application; |
| | | |
| | | -- ============================================================ |
| | | -- 15. AI 模å â 对è¯ä¸çæå
容 |
| | | -- ä¿çï¼ai_api_key / ai_model / ai_tool / ai_chat_role |
| | | -- / ai_knowledge(_document/_segment) / ai_workflow |
| | | -- ============================================================ |
| | | TRUNCATE TABLE ai_chat_message; |
| | | TRUNCATE TABLE ai_chat_conversation; |
| | | TRUNCATE TABLE ai_image; |
| | | TRUNCATE TABLE ai_mind_map; |
| | | TRUNCATE TABLE ai_music; |
| | | TRUNCATE TABLE ai_write; |
| | | |
| | | -- ============================================================ |
| | | -- 16. IM 模å â ä¼è¯ä¸æ¶æ¯ |
| | | -- ä¿çï¼im_sensitive_word / im_face_pack / im_face_pack_item |
| | | -- ============================================================ |
| | | TRUNCATE TABLE im_group_message_receipt; |
| | | TRUNCATE TABLE im_group_message; |
| | | TRUNCATE TABLE im_private_message; |
| | | TRUNCATE TABLE im_message_file; |
| | | TRUNCATE TABLE im_group_request; |
| | | TRUNCATE TABLE im_group_member; |
| | | TRUNCATE TABLE im_group; |
| | | TRUNCATE TABLE im_friend_request; |
| | | TRUNCATE TABLE im_friend; |
| | | TRUNCATE TABLE im_conversation_read; |
| | | TRUNCATE TABLE im_conversation; |
| | | TRUNCATE TABLE im_channel_message; |
| | | TRUNCATE TABLE im_channel_material; |
| | | TRUNCATE TABLE im_channel; |
| | | TRUNCATE TABLE im_rtc_participant; |
| | | TRUNCATE TABLE im_rtc_call; |
| | | TRUNCATE TABLE im_user_online; |
| | | TRUNCATE TABLE im_face_user_item; |
| | | |
| | | -- ============================================================ |
| | | -- 17. OA 已读/æå®äººå
³èï¼ä¿çéç¥å
¬åå
容 oa_notice / system_noticeï¼ |
| | | -- ============================================================ |
| | | TRUNCATE TABLE oa_notice_read; |
| | | TRUNCATE TABLE oa_notice_user; |
| | | |
| | | -- ============================================================ |
| | | -- 18. ç¤ºä¾æ°æ® |
| | | -- ============================================================ |
| | | TRUNCATE TABLE yudao_demo01_contact; |
| | | TRUNCATE TABLE yudao_demo02_category; |
| | | TRUNCATE TABLE yudao_demo03_course; |
| | | TRUNCATE TABLE yudao_demo03_grade; |
| | | TRUNCATE TABLE yudao_demo03_student; |
| | | |
| | | -- ============================================================ |
| | | -- 19. åºç¡æ°æ®ä¸ä¸è¢ä¸ç 管ç |
| | | -- åºç¡æ°æ®ï¼ç©æç®¡ç / ç©æåç±» / 计éåä½ / åç / SKU |
| | | -- ä¸è¢ä¸ç ï¼äº§çº¿ç»´æ¤ / æ¹æ¬¡ç产管ç / èµç 管ç / æçç 管ç |
| | | -- åç§æ°æ®æºï¼mes_md_itemï¼ä¸ mdm_item åæ¥ï¼æ¹æ¬¡/è¢ç éåç§ä½¿ç¨ï¼ |
| | | -- ä¿çï¼mes_md_vendorï¼ä¾åºåï¼ä¸ erp_supplier çç¥ä¸è´ï¼ |
| | | -- / mdm_warehouseï¼ä»åºï¼ä¸ mes_wm_warehouse çç¥ä¸è´ï¼ |
| | | -- / mes_md_workshop / mes_md_workstation*ï¼è½¦é´å·¥ä½ç«é
ç½®ï¼ |
| | | -- ============================================================ |
| | | -- ä¸è¢ä¸ç ï¼å
æ¸
å¼ç¨æ¹æ¬¡çæç»ï¼åæ¸
æ¹æ¬¡ä¸äº§çº¿ |
| | | TRUNCATE TABLE mes_pro_batch_worker; |
| | | TRUNCATE TABLE mes_pro_bag_code_replace; -- è¢ç æ¿æ¢è®°å½ï¼åèæ¬éæ¼ï¼ |
| | | TRUNCATE TABLE mes_pro_bag_code; |
| | | TRUNCATE TABLE mes_pro_pallet; |
| | | TRUNCATE TABLE mes_pro_batch; |
| | | TRUNCATE TABLE mes_pro_line; |
| | | -- åç§æ°æ®æºï¼MES ç©æäº§åå
³èé
ç½®ï¼ |
| | | TRUNCATE TABLE mes_md_product_bom; |
| | | TRUNCATE TABLE mes_md_product_sop; |
| | | TRUNCATE TABLE mes_md_product_sip; |
| | | TRUNCATE TABLE mes_md_item_batch_config; |
| | | TRUNCATE TABLE mes_md_unit_measure; -- MES 计éåä½ï¼åèæ¬éæ¼ï¼ |
| | | TRUNCATE TABLE mes_md_item; |
| | | -- åºç¡æ°æ®ï¼MDM ç©æä¸»æ°æ® / åç±» / 计éåä½ / åç / SKUï¼ |
| | | TRUNCATE TABLE mdm_item_batch_config; |
| | | TRUNCATE TABLE mdm_item_sku; -- ç©æ SKUï¼mdm_item å表ï¼åèæ¬éæ¼ï¼ |
| | | TRUNCATE TABLE mdm_item; |
| | | TRUNCATE TABLE mdm_item_category; -- ç©æåç±»ï¼åèæ¬éæ¼ï¼ |
| | | TRUNCATE TABLE mdm_brand; -- åçï¼åèæ¬éæ¼ï¼ |
| | | TRUNCATE TABLE mes_md_item_type; |
| | | TRUNCATE TABLE mdm_unit_measure; |
| | | -- ç©æè¿ç§»æ å°è¡¨ï¼å¦æ¸
çåéä» ERP éæ°è¿ç§»ç©æï¼è¯·æ¾å¼ä¸é¢ä¸è¡ |
| | | -- TRUNCATE TABLE mdm_item_migration_map; |
| | | |
| | | SET FOREIGN_KEY_CHECKS = 1; |
| | | |
| | | -- ============================================================ |
| | | -- æ¸
çç»ææ ¡éªï¼ä»£è¡¨è¡¨è¡æ°åºå
¨é¨ä¸º 0ï¼ |
| | | -- ============================================================ |
| | | SELECT |
| | | (SELECT COUNT(*) FROM mes_pro_work_order) AS work_order_cnt, |
| | | (SELECT COUNT(*) FROM mes_wm_material_stock) AS stock_cnt, |
| | | (SELECT COUNT(*) FROM mes_qc_iqc) AS iqc_cnt, |
| | | (SELECT COUNT(*) FROM crm_contract) AS contract_cnt, |
| | | (SELECT COUNT(*) FROM erp_sale_order) AS sale_order_cnt, |
| | | (SELECT COUNT(*) FROM mdm_item) AS mdm_item_cnt, |
| | | (SELECT COUNT(*) FROM system_operate_log) AS operate_log_cnt; |
| | | |
| | | SELECT 'ä¸å¡æ°æ®æ¸
ç宿' AS result; |
| | | END $$ |
| | | |
| | | DELIMITER ; |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | -- ============================================= |
| | | -- åºåºæµé管çèåæåèæ¬ |
| | | -- å°"éå®ä»åº"(602479) æå为ä¸çº§èå"åºåºæµé管ç" |
| | | -- åç»æï¼ä»å¨ç©æµ(5780) -> éå®ä»åº(602479) -> åè´§éç¥/éå®åºåº/éå®éè´§ |
| | | -- ============================================= |
| | | |
| | | -- 1. æå为ä¸çº§èå |
| | | -- 说æï¼é¡¶çº§"è¥é管ç"(2617) å·²å ç¨ path=saleï¼æ
æ¹ç¨ sales-outbound é¿å
è·¯ç±å²çª |
| | | UPDATE system_menu SET |
| | | parent_id = 0, |
| | | name = 'åºåºæµé管ç', |
| | | path = 'sales-outbound', |
| | | sort = 10 -- æ¾å¨ä»å¨ç©æµ(sort=9)ä¹å |
| | | WHERE id = 602479 AND deleted = b'0'; |
| | | |
| | | -- ============================================= |
| | | -- 说æï¼ |
| | | -- 1. åèå(åè´§éç¥ 5867 / éå®åºåº 5970 / éå®éè´§ 5847) æ éæ¹å¨ï¼ |
| | | -- åç«¯å¨æè·¯ç±ä¼èªå¨æ¼æ¥ä¸º /sales-outbound/sales-notice çè·¯å¾ |
| | | -- 2. 顶级ç®å½èåç±å端èªå¨æ¸²æä¸º BasicLayoutï¼component åæ®µæ éå¡«å |
| | | -- 3. å¦éæ¢å¤ï¼æ§è¡ä»¥ä¸ååèæ¬ï¼ |
| | | -- ============================================= |
| | | |
| | | -- ååèæ¬ï¼å¦éæ¢å¤ï¼ï¼ |
| | | -- UPDATE system_menu SET parent_id = 5780, name = 'éå®ä»åº', path = 'sale', sort = 5 WHERE id = 602479; |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.framework.common.util.number; |
| | | |
| | | import java.util.concurrent.ThreadLocalRandom; |
| | | |
| | | /** |
| | | * ä¸å¡ç¼ç ï¼åæ®å· / ä¸»æ°æ®ç¼ç ï¼çæçå
Œ
±çº¦å®ã |
| | | * |
| | | * <p>éæ±ï¼ç³»ç»ä¸ææèªå¨çæçä¸å¡ç¼ç ç»ä¸ä¸ºã16 ä½çº¯æ°åãï¼ä¸**éæºçæãä¸ä½¿ç¨èªå¢/顺åº**ï¼ |
| | | * åæ¶ä¿è¯å
¨ç³»ç»å¯ä¸ï¼ä»»æä¸¤æ¡ç¼ç é½ä¸éå¤ï¼ã |
| | | * |
| | | * <p>å®ç°çº¦å®ï¼ |
| | | * <ul> |
| | | * <li>ç¼ç = éæº 16 使°åï¼èå´ 0 ~ 10^16-1ï¼å·¦ä¾§è¡¥ '0'ï¼ï¼</li> |
| | | * <li>å¯ä¸æ§ç± Redis éå {@link #USED_SET_KEY} æ¥éä¿è¯ï¼éæºçæååå
¥éåï¼ |
| | | * åæåï¼è¿å 1ï¼è¯´ææ²¡ç¨è¿æéç¨ï¼å¦åéè¯ï¼</li> |
| | | * <li>åçæç¹ï¼è§ {@link #randomCode()} ä¸ {@link #MAX_RETRY}ã</li> |
| | | * </ul> |
| | | * |
| | | * <p>注æï¼Redis éå丢失åï¼åå²ç¼ç å¯è½è¢«éæ°éæºå½ä¸ï¼åºç¨å¯å¨æ¶ä¼å°åºå
å·²æç¼ç |
| | | * éæ°è½½å
¥éåï¼è§ yudao-server çå¯å¨å
åºï¼ã |
| | | */ |
| | | public class BizNoUtils { |
| | | |
| | | /** |
| | | * 已使ç¨ä¸å¡ç¼ç ç Redis éå KEYï¼ç¨äºéæºç¼ç æ¥éï¼ä¿è¯å
¨ç³»ç»å¯ä¸ã |
| | | */ |
| | | public static final String USED_SET_KEY = "biz:code:used"; |
| | | |
| | | /** |
| | | * ä¸å¡ç¼ç çæ»é¿åº¦ï¼16 ä½ |
| | | */ |
| | | public static final int CODE_LENGTH = 16; |
| | | |
| | | /** |
| | | * éæºç¼ç ç空é´ä¸éï¼ä¸å«ï¼ï¼10^16 |
| | | */ |
| | | private static final long CODE_SPACE = 10_000_000_000_000_000L; |
| | | |
| | | /** |
| | | * çæéæºç¼ç æ¶çæå¤§éè¯æ¬¡æ°ï¼å½ä¸å·²ç¨ç¼ç æ¶éè¯ï¼ |
| | | */ |
| | | public static final int MAX_RETRY = 10; |
| | | |
| | | /** |
| | | * çæä¸ä¸ªéæº 16 ä½çº¯æ°åç¼ç ï¼å·¦ä¾§è¡¥ '0'ï¼ï¼**ä¸åæ¥é**ã |
| | | * |
| | | * <p>è°ç¨æ¹éèªè¡ç¨ {@link #USED_SET_KEY} æ¥éï¼å½ä¸åéè¯ã |
| | | * |
| | | * @return éæº 16 ä½çº¯æ°åç¼ç |
| | | */ |
| | | public static String randomCode() { |
| | | return String.format("%0" + CODE_LENGTH + "d", ThreadLocalRandom.current().nextLong(CODE_SPACE)); |
| | | } |
| | | |
| | | } |
| | |
| | | package cn.iocoder.yudao.module.aftersales.dal.redis.no; |
| | | |
| | | import cn.hutool.core.date.DatePattern; |
| | | import cn.hutool.core.date.DateUtil; |
| | | import cn.iocoder.yudao.module.aftersales.dal.redis.RedisKeyConstants; |
| | | import cn.iocoder.yudao.framework.common.util.number.BizNoUtils; |
| | | import jakarta.annotation.Resource; |
| | | import org.springframework.data.redis.core.StringRedisTemplate; |
| | | import org.springframework.stereotype.Repository; |
| | | |
| | | import java.time.Duration; |
| | | import java.time.LocalDateTime; |
| | | |
| | | /** |
| | | * å®å模ååå· Redis DAO |
| | |
| | | private StringRedisTemplate stringRedisTemplate; |
| | | |
| | | /** |
| | | * çæåºå·ï¼ä½¿ç¨å½åæ¥æï¼æ ¼å¼ä¸º {PREFIX} + yyyyMMdd + 6 ä½èªå¢ |
| | | * çæ 16 ä½çº¯æ°åä¸å¡ç¼ç ï¼å
¨ç³»ç»å¯ä¸ï¼ã |
| | | * |
| | | * @param prefix åç¼ |
| | | * @return åºå· |
| | | * <p>为å
¼å®¹æ¢æè°ç¨æ¹ï¼ä¿ç {@code prefix} å
¥åï¼ä½ä¸ååä¸ç¼ç æ¼æ¥ã |
| | | * |
| | | * @param prefix åæ®ç±»ååç¼ï¼å·²ä¸ååä¸ç¼ç æ¼æ¥ï¼ |
| | | * @return 16 ä½çº¯æ°åç¼ç |
| | | */ |
| | | public String generate(String prefix) { |
| | | String noPrefix = prefix + DateUtil.format(LocalDateTime.now(), DatePattern.PURE_DATE_PATTERN); |
| | | String key = RedisKeyConstants.NO + noPrefix; |
| | | Long no = stringRedisTemplate.opsForValue().increment(key); |
| | | stringRedisTemplate.expire(key, Duration.ofDays(1L)); |
| | | return noPrefix + String.format("%06d", no); |
| | | // å
¨ç³»ç»å
±ç¨åä¸èªå¢åºåï¼ä¿è¯ç¼ç ã16 ä½çº¯æ°åãä¸å
¨ç³»ç»å¯ä¸ |
| | | // éæºçæ 16 ä½çº¯æ°åç¼ç ï¼å¹¶ç¨ Redis é忥éï¼ä¿è¯å
¨ç³»ç»å¯ä¸ï¼ä¸ä½¿ç¨èªå¢/顺åºï¼ |
| | | for (int i = 0; i < BizNoUtils.MAX_RETRY; i++) { |
| | | String code = BizNoUtils.randomCode(); |
| | | Long added = stringRedisTemplate.opsForSet().add(BizNoUtils.USED_SET_KEY, code); |
| | | if (added != null && added > 0) { |
| | | return code; |
| | | } |
| | | } |
| | | throw new IllegalStateException("çæå¯ä¸ä¸å¡ç¼ç 失败ï¼è¯·éè¯"); |
| | | } |
| | | |
| | | } |
| | |
| | | MesWmReturnSalesCreateReqDTO mesReqDTO = new MesWmReturnSalesCreateReqDTO(); |
| | | mesReqDTO.setCode(returnDO.getNo()); |
| | | mesReqDTO.setName("å®åéè´§-" + returnDO.getNo()); |
| | | mesReqDTO.setSaleOrderId(returnDO.getSaleOrderId()); |
| | | mesReqDTO.setSalesOrderCode(ticket != null ? ticket.getSaleOrderNo() : null); |
| | | mesReqDTO.setClientId(returnDO.getCustomerId()); |
| | | mesReqDTO.setReturnDate(LocalDate.now()); |
| | | mesReqDTO.setReturnReason(returnDO.getReturnReason()); |
| | |
| | | package cn.iocoder.yudao.module.bpm.dal.redis; |
| | | |
| | | import cn.hutool.core.date.DateUtil; |
| | | import cn.hutool.core.util.StrUtil; |
| | | import cn.iocoder.yudao.framework.common.util.number.BizNoUtils; |
| | | import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.BpmModelMetaInfoVO; |
| | | import jakarta.annotation.Resource; |
| | | import org.springframework.data.redis.core.StringRedisTemplate; |
| | | import org.springframework.stereotype.Repository; |
| | | |
| | | import java.time.Duration; |
| | | import java.time.LocalDateTime; |
| | | |
| | | import static cn.hutool.core.date.DatePattern.*; |
| | | |
| | | /** |
| | | * BPM æµç¨ Id ç¼ç ç Redis DAO |
| | |
| | | private StringRedisTemplate stringRedisTemplate; |
| | | |
| | | /** |
| | | * çæåºå·ï¼ä½¿ç¨å®ä¹ç processIdRule è§åçæ |
| | | * çæ 16 ä½çº¯æ°åä¸å¡ç¼ç ï¼å
¨ç³»ç»å¯ä¸ï¼ã |
| | | * |
| | | * @param processIdRule è§å |
| | | * @return åºå· |
| | | * <p>为å
¼å®¹æ¢æè°ç¨æ¹ï¼ä¿ç {@code processIdRule} å
¥åï¼ä½ä¸ååä¸ç¼ç æ¼æ¥ã |
| | | * |
| | | * @param processIdRule æµç¨ Id è§åï¼å·²ä¸ååä¸ç¼ç æ¼æ¥ï¼ |
| | | * @return 16 ä½çº¯æ°åç¼ç |
| | | */ |
| | | public String generate(BpmModelMetaInfoVO.ProcessIdRule processIdRule) { |
| | | // çææ¥æåç¼ |
| | | String infix = ""; |
| | | switch (processIdRule.getInfix()) { |
| | | case "DAY": |
| | | infix = DateUtil.format(LocalDateTime.now(), PURE_DATE_PATTERN); |
| | | break; |
| | | case "HOUR": |
| | | infix = DateUtil.format(LocalDateTime.now(), PURE_DATE_PATTERN + "HH"); |
| | | break; |
| | | case "MINUTE": |
| | | infix = DateUtil.format(LocalDateTime.now(), PURE_DATE_PATTERN + "HHmm"); |
| | | break; |
| | | case "SECOND": |
| | | infix = DateUtil.format(LocalDateTime.now(), PURE_DATETIME_PATTERN); |
| | | break; |
| | | // å
¨ç³»ç»å
±ç¨åä¸èªå¢åºåï¼ä¿è¯ç¼ç ã16 ä½çº¯æ°åãä¸å
¨ç³»ç»å¯ä¸ |
| | | // éæºçæ 16 ä½çº¯æ°åç¼ç ï¼å¹¶ç¨ Redis é忥éï¼ä¿è¯å
¨ç³»ç»å¯ä¸ï¼ä¸ä½¿ç¨èªå¢/顺åºï¼ |
| | | for (int i = 0; i < BizNoUtils.MAX_RETRY; i++) { |
| | | String code = BizNoUtils.randomCode(); |
| | | Long added = stringRedisTemplate.opsForSet().add(BizNoUtils.USED_SET_KEY, code); |
| | | if (added != null && added > 0) { |
| | | return code; |
| | | } |
| | | } |
| | | |
| | | // çæåºå· |
| | | String noPrefix = processIdRule.getPrefix() + infix + processIdRule.getPostfix(); |
| | | String key = RedisKeyConstants.BPM_PROCESS_ID + noPrefix; |
| | | Long no = stringRedisTemplate.opsForValue().increment(key); |
| | | if (StrUtil.isEmpty(infix)) { |
| | | // ç¹æ®ï¼æ²¡æåç¼ï¼åä¸è½è¿æï¼ä¸è½æ¯æ¬¡é½æ¯ä» 0 å¼å§ãå¯è§ https://t.zsxq.com/MU1E2 讨论 |
| | | stringRedisTemplate.expire(key, Duration.ofDays(1L)); |
| | | } |
| | | return noPrefix + String.format("%0" + processIdRule.getLength() + "d", no); |
| | | throw new IllegalStateException("çæå¯ä¸ä¸å¡ç¼ç 失败ï¼è¯·éè¯"); |
| | | } |
| | | |
| | | } |
| | |
| | | package cn.iocoder.yudao.module.crm.dal.redis.no; |
| | | |
| | | import cn.hutool.core.date.DatePattern; |
| | | import cn.hutool.core.date.DateUtil; |
| | | import cn.iocoder.yudao.module.crm.dal.redis.RedisKeyConstants; |
| | | import cn.iocoder.yudao.framework.common.util.number.BizNoUtils; |
| | | import jakarta.annotation.Resource; |
| | | import org.springframework.data.redis.core.StringRedisTemplate; |
| | | import org.springframework.stereotype.Repository; |
| | | |
| | | import java.time.Duration; |
| | | import java.time.LocalDateTime; |
| | | |
| | | |
| | | /** |
| | |
| | | private StringRedisTemplate stringRedisTemplate; |
| | | |
| | | /** |
| | | * çæåºå·ï¼ä½¿ç¨å½åæ¥æï¼æ ¼å¼ä¸º {PREFIX} + yyyyMMdd + 6 ä½èªå¢ |
| | | * ä¾å¦è¯´ï¼QTRK 202109 000001 ï¼æ²¡æä¸é´ç©ºæ ¼ï¼ |
| | | * çæ 16 ä½çº¯æ°åä¸å¡ç¼ç ï¼å
¨ç³»ç»å¯ä¸ï¼ã |
| | | * |
| | | * @param prefix åç¼ |
| | | * @return åºå· |
| | | * <p>为å
¼å®¹æ¢æè°ç¨æ¹ï¼ä¿ç {@code prefix} å
¥åï¼ä½ä¸ååä¸ç¼ç æ¼æ¥ã |
| | | * |
| | | * @param prefix åæ®ç±»ååç¼ï¼å·²ä¸ååä¸ç¼ç æ¼æ¥ï¼ |
| | | * @return 16 ä½çº¯æ°åç¼ç |
| | | */ |
| | | public String generate(String prefix) { |
| | | // éå¢åºå· |
| | | String noPrefix = prefix + DateUtil.format(LocalDateTime.now(), DatePattern.PURE_DATE_PATTERN); |
| | | String key = RedisKeyConstants.NO + noPrefix; |
| | | Long no = stringRedisTemplate.opsForValue().increment(key); |
| | | // è®¾ç½®è¿ææ¶é´ |
| | | stringRedisTemplate.expire(key, Duration.ofDays(1L)); |
| | | return noPrefix + String.format("%06d", no); |
| | | // å
¨ç³»ç»å
±ç¨åä¸èªå¢åºåï¼ä¿è¯ç¼ç ã16 ä½çº¯æ°åãä¸å
¨ç³»ç»å¯ä¸ |
| | | // éæºçæ 16 ä½çº¯æ°åç¼ç ï¼å¹¶ç¨ Redis é忥éï¼ä¿è¯å
¨ç³»ç»å¯ä¸ï¼ä¸ä½¿ç¨èªå¢/顺åºï¼ |
| | | for (int i = 0; i < BizNoUtils.MAX_RETRY; i++) { |
| | | String code = BizNoUtils.randomCode(); |
| | | Long added = stringRedisTemplate.opsForSet().add(BizNoUtils.USED_SET_KEY, code); |
| | | if (added != null && added > 0) { |
| | | return code; |
| | | } |
| | | } |
| | | throw new IllegalStateException("çæå¯ä¸ä¸å¡ç¼ç 失败ï¼è¯·éè¯"); |
| | | } |
| | | |
| | | } |
| | |
| | | import cn.iocoder.yudao.module.mdm.api.item.dto.MdmItemRespDTO; |
| | | import cn.iocoder.yudao.module.mdm.api.unit.MdmUnitMeasureApi; |
| | | import cn.iocoder.yudao.module.mdm.api.unit.dto.MdmUnitMeasureRespDTO; |
| | | import cn.iocoder.yudao.module.mes.api.mps.MesProMpsApi; |
| | | import cn.iocoder.yudao.module.mes.api.productsales.MesWmProductSalesLineApi; |
| | | import cn.iocoder.yudao.module.mes.api.salesnotice.MesWmSalesNoticeApi; |
| | | import cn.iocoder.yudao.module.mes.api.wms.MesWmStockApi; |
| | | import cn.iocoder.yudao.module.system.api.storage.StorageAttachmentApi; |
| | | import cn.iocoder.yudao.module.system.api.user.AdminUserApi; |
| | |
| | | private MdmItemApi mdmItemApi; |
| | | @Resource |
| | | private AdminUserApi adminUserApi; |
| | | @Resource |
| | | private MesWmSalesNoticeApi salesNoticeApi; |
| | | @Resource |
| | | private MesWmProductSalesLineApi productSalesLineApi; |
| | | @Resource |
| | | private MesProMpsApi mpsApi; |
| | | @Resource |
| | | private StorageAttachmentApi storageAttachmentApi; |
| | | @Resource |
| | |
| | | // 2. æ¹éæ¥è¯¢å
³èæ°æ® |
| | | Map<Long, MdmItemRespDTO> itemMap = mdmItemApi.getItemMap( |
| | | convertSet(saleOrderItemList, ErpSaleOrderItemDO::getProductId)); |
| | | Map<Long, String> batchCodeMap = productSalesLineApi.getBatchCodesBySaleOrderItemIds( |
| | | convertSet(saleOrderItemList, ErpSaleOrderItemDO::getId)); |
| | | Map<Long, MdmUnitMeasureRespDTO> unitMeasureMap = mdmUnitMeasureApi.getUnitMeasureMap( |
| | | convertSet(saleOrderItemList, ErpSaleOrderItemDO::getProductUnitId)); |
| | | // 3. 转æ¢è®¢å项 |
| | | List<ErpSaleOrderRespVO.Item> itemVOList = BeanUtils.toBean(saleOrderItemList, ErpSaleOrderRespVO.Item.class, item -> { |
| | | item.setStockCount(mesWmStockApi.getStockQuantity(item.getProductId())); |
| | | item.setBatchCode(batchCodeMap.get(item.getId())); |
| | | MapUtils.findAndThen(itemMap, item.getProductId(), mdmItem -> |
| | | item.setProductName(mdmItem.getName()).setProductBarCode(mdmItem.getBarCode()) |
| | | .setProductSpecification(mdmItem.getSpecification())); |
| | |
| | | // 1.4 管çåä¿¡æ¯ |
| | | Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap( |
| | | convertSet(pageResult.getList(), saleOrder -> Long.parseLong(saleOrder.getCreator()))); |
| | | // 1.5 åè´§éç¥åä¿¡æ¯ |
| | | Map<Long, Boolean> salesNoticeMap = salesNoticeApi.checkSalesNoticeBySaleOrderIds( |
| | | convertSet(pageResult.getList(), ErpSaleOrderDO::getId)); |
| | | // 1.6 åºåºæ¹å· |
| | | Map<Long, String> batchCodeMap = productSalesLineApi.getBatchCodesBySaleOrderItemIds( |
| | | convertSet(saleOrderItemList, ErpSaleOrderItemDO::getId)); |
| | | // 1.7 计éåä½ |
| | | // 1.5 计éåä½ |
| | | Map<Long, MdmUnitMeasureRespDTO> unitMeasureMap = mdmUnitMeasureApi.getUnitMeasureMap( |
| | | convertSet(saleOrderItemList, ErpSaleOrderItemDO::getProductUnitId)); |
| | | // 1.8 æ£æ¥æ¯å¦å¯ä»¥çæåè´§éç¥åï¼éè¦ç产çæç»å¯¹åºç MPS æ¯å¦å·²å®æï¼ |
| | | // çéåºéè¦ç产çæç»ID |
| | | List<Long> needProductionItemIds = saleOrderItemList.stream() |
| | | .filter(item -> item.getNeedProduction() != null && item.getNeedProduction() == 1) |
| | | .map(ErpSaleOrderItemDO::getId) |
| | | .toList(); |
| | | Map<Long, Boolean> canCreateSalesNoticeMap = new java.util.HashMap<>(); |
| | | if (!needProductionItemIds.isEmpty()) { |
| | | // æè®¢ååç»æç»ID |
| | | Map<Long, List<Long>> orderItemIdsMap = new java.util.HashMap<>(); |
| | | for (ErpSaleOrderItemDO item : saleOrderItemList) { |
| | | orderItemIdsMap.computeIfAbsent(item.getOrderId(), k -> new java.util.ArrayList<>()) |
| | | .add(item.getId()); |
| | | } |
| | | // æ£æ¥æ¯ä¸ªè®¢å |
| | | for (Map.Entry<Long, List<Long>> entry : orderItemIdsMap.entrySet()) { |
| | | List<Long> itemIds = entry.getValue().stream() |
| | | .filter(id -> { |
| | | ErpSaleOrderItemDO item = saleOrderItemList.stream() |
| | | .filter(i -> i.getId().equals(id)) |
| | | .findFirst().orElse(null); |
| | | return item != null && item.getNeedProduction() != null && item.getNeedProduction() == 1; |
| | | } |
| | | ).toList(); |
| | | if (itemIds.isEmpty()) { |
| | | canCreateSalesNoticeMap.put(entry.getKey(), true); |
| | | } else { |
| | | canCreateSalesNoticeMap.put(entry.getKey(), mpsApi.checkCanCreateSalesNotice(itemIds)); |
| | | } |
| | | } |
| | | } else { |
| | | // 没æéè¦ç产çæç»ï¼é½å¯ä»¥çæåè´§éç¥å |
| | | pageResult.getList().forEach(order -> canCreateSalesNoticeMap.put(order.getId(), true)); |
| | | } |
| | | // 2. å¼å§æ¼æ¥ |
| | | return BeanUtils.toBean(pageResult, ErpSaleOrderRespVO.class, saleOrder -> { |
| | | saleOrder.setItems(BeanUtils.toBean(saleOrderItemMap.get(saleOrder.getId()), ErpSaleOrderRespVO.Item.class, |
| | | item -> { |
| | | item.setBatchCode(batchCodeMap.get(item.getId())); |
| | | MapUtils.findAndThen(itemMap, item.getProductId(), mdmItem -> |
| | | item.setProductName(mdmItem.getName()).setProductBarCode(mdmItem.getBarCode()) |
| | | .setProductSpecification(mdmItem.getSpecification())); |
| | |
| | | saleOrder.setProductNames(CollUtil.join(saleOrder.getItems(), "ï¼", ErpSaleOrderRespVO.Item::getProductName)); |
| | | MapUtils.findAndThen(customerMap, saleOrder.getCustomerId(), supplier -> saleOrder.setCustomerName(supplier.getName())); |
| | | MapUtils.findAndThen(userMap, Long.parseLong(saleOrder.getCreator()), user -> saleOrder.setCreatorName(user.getNickname())); |
| | | // 设置æ¯å¦å·²çæåè´§éç¥å |
| | | saleOrder.setHasSalesNotice(salesNoticeMap.getOrDefault(saleOrder.getId(), false)); |
| | | // 设置æ¯å¦å¯ä»¥çæåè´§éç¥åï¼å·²çæåè´§éç¥åæ¶ä¸æ¾ç¤ºæé® |
| | | saleOrder.setCanCreateSalesNotice(!saleOrder.getHasSalesNotice() && canCreateSalesNoticeMap.getOrDefault(saleOrder.getId(), true)); |
| | | // 设置æ¯å¦æéè¦ç产çæç» |
| | | boolean hasNeedProduction = saleOrder.getItems().stream() |
| | | .anyMatch(item -> item.getNeedProduction() != null && item.getNeedProduction() == 1); |
| | |
| | | @Schema(description = "åºåºç¶æ", example = "0") |
| | | private Integer outStatus; |
| | | |
| | | // ========== åè´§éç¥ ========== |
| | | |
| | | @Schema(description = "æ¯å¦å·²çæåè´§éç¥å", example = "false") |
| | | private Boolean hasSalesNotice; |
| | | |
| | | @Schema(description = "æ¯å¦å¯ä»¥çæåè´§éç¥åï¼æéè¦çäº§ä¸æªå®æçæç»æ¶ä¸º falseï¼", example = "true") |
| | | private Boolean canCreateSalesNotice; |
| | | // ========== ç产å
³è ========== |
| | | |
| | | @Schema(description = "æ¯å¦æéè¦ç产çæç»ï¼0=å¦ 1=æ¯ï¼", example = "1") |
| | | private Integer needProduction; |
| | | |
| | | // ========== ç产å
³è ========== |
| | | |
| | | @Schema(description = "çäº§ç¶æï¼0-æªå®æï¼1-已宿", example = "1") |
| | | private Integer productionStatus; |
| | |
| | | |
| | | @Schema(description = "å
³èç MPS ç¼å·", example = "1024") |
| | | private Long mpsId; |
| | | |
| | | // ========== åºåºæ¹å· ========== |
| | | |
| | | @Schema(description = "åºåºæ¹å·", example = "B2026001ãB2026002") |
| | | private String batchCode; |
| | | |
| | | // ========== å
³èåæ®µ ========== |
| | | |
| | |
| | | package cn.iocoder.yudao.module.erp.dal.redis.no; |
| | | |
| | | import cn.hutool.core.date.DatePattern; |
| | | import cn.hutool.core.date.DateUtil; |
| | | import cn.iocoder.yudao.module.erp.dal.redis.RedisKeyConstants; |
| | | import cn.iocoder.yudao.framework.common.util.number.BizNoUtils; |
| | | import jakarta.annotation.Resource; |
| | | import org.springframework.data.redis.core.StringRedisTemplate; |
| | | import org.springframework.stereotype.Repository; |
| | | |
| | | import java.time.Duration; |
| | | import java.time.LocalDateTime; |
| | | |
| | | |
| | | /** |
| | |
| | | private StringRedisTemplate stringRedisTemplate; |
| | | |
| | | /** |
| | | * çæåºå·ï¼ä½¿ç¨å½åæ¥æï¼æ ¼å¼ä¸º {PREFIX} + yyyyMMdd + 6 ä½èªå¢ |
| | | * ä¾å¦è¯´ï¼CGDD 202109 000001 ï¼æ²¡æä¸é´ç©ºæ ¼ï¼ |
| | | * çæ 16 ä½çº¯æ°åä¸å¡ç¼ç ï¼å
¨ç³»ç»å¯ä¸ï¼ã |
| | | * |
| | | * @param prefix åç¼ |
| | | * @return åºå· |
| | | * <p>为å
¼å®¹æ¢æè°ç¨æ¹ï¼ä¿ç {@code prefix} å
¥åï¼ä½ä¸ååä¸ç¼ç æ¼æ¥ã |
| | | * |
| | | * @param prefix åæ®ç±»ååç¼ï¼å·²ä¸ååä¸ç¼ç æ¼æ¥ï¼ |
| | | * @return 16 ä½çº¯æ°åç¼ç |
| | | */ |
| | | public String generate(String prefix) { |
| | | // éå¢åºå· |
| | | String noPrefix = prefix + DateUtil.format(LocalDateTime.now(), DatePattern.PURE_DATE_PATTERN); |
| | | String key = RedisKeyConstants.NO + noPrefix; |
| | | Long no = stringRedisTemplate.opsForValue().increment(key); |
| | | // è®¾ç½®è¿ææ¶é´ |
| | | stringRedisTemplate.expire(key, Duration.ofDays(1L)); |
| | | return noPrefix + String.format("%06d", no); |
| | | // å
¨ç³»ç»å
±ç¨åä¸èªå¢åºåï¼ä¿è¯ç¼ç ã16 ä½çº¯æ°åãä¸å
¨ç³»ç»å¯ä¸ |
| | | // éæºçæ 16 ä½çº¯æ°åç¼ç ï¼å¹¶ç¨ Redis é忥éï¼ä¿è¯å
¨ç³»ç»å¯ä¸ï¼ä¸ä½¿ç¨èªå¢/顺åºï¼ |
| | | for (int i = 0; i < BizNoUtils.MAX_RETRY; i++) { |
| | | String code = BizNoUtils.randomCode(); |
| | | Long added = stringRedisTemplate.opsForSet().add(BizNoUtils.USED_SET_KEY, code); |
| | | if (added != null && added > 0) { |
| | | return code; |
| | | } |
| | | } |
| | | throw new IllegalStateException("çæå¯ä¸ä¸å¡ç¼ç 失败ï¼è¯·éè¯"); |
| | | } |
| | | |
| | | } |
| | |
| | | package cn.iocoder.yudao.module.hrm.dal.redis; |
| | | |
| | | import cn.hutool.core.date.DatePattern; |
| | | import cn.hutool.core.date.DateUtil; |
| | | import cn.iocoder.yudao.framework.common.util.number.BizNoUtils; |
| | | import jakarta.annotation.Resource; |
| | | import org.springframework.data.redis.core.StringRedisTemplate; |
| | | import org.springframework.stereotype.Repository; |
| | | |
| | | import java.time.Duration; |
| | | import java.time.LocalDateTime; |
| | | |
| | | /** |
| | | * HRM ç¼å·çæç Redis DAO |
| | |
| | | } |
| | | |
| | | /** |
| | | * çæç¼å· |
| | | * çæ 16 ä½çº¯æ°åä¸å¡ç¼ç ï¼å
¨ç³»ç»å¯ä¸ï¼ã |
| | | * |
| | | * @param prefix åç¼ |
| | | * @param digits 使° |
| | | * @return ç¼å· |
| | | * <p>为å
¼å®¹æ¢æè°ç¨æ¹ï¼ä¿çå
¥åï¼ä½ä¸ååä¸ç¼ç æ¼æ¥ã |
| | | * |
| | | * @return 16 ä½çº¯æ°åç¼ç |
| | | */ |
| | | public String generate(String prefix, int digits) { |
| | | String noPrefix = prefix + DateUtil.format(LocalDateTime.now(), DatePattern.PURE_DATE_PATTERN); |
| | | String key = HrmRedisKeyConstants.NO + noPrefix; |
| | | Long no = stringRedisTemplate.opsForValue().increment(key); |
| | | // è®¾ç½®è¿ææ¶é´ 1 天 |
| | | stringRedisTemplate.expire(key, Duration.ofDays(1L)); |
| | | return noPrefix + String.format("%0" + digits + "d", no); |
| | | // å
¨ç³»ç»å
±ç¨åä¸èªå¢åºåï¼ä¿è¯ç¼ç ã16 ä½çº¯æ°åãä¸å
¨ç³»ç»å¯ä¸ |
| | | // éæºçæ 16 ä½çº¯æ°åç¼ç ï¼å¹¶ç¨ Redis é忥éï¼ä¿è¯å
¨ç³»ç»å¯ä¸ï¼ä¸ä½¿ç¨èªå¢/顺åºï¼ |
| | | for (int i = 0; i < BizNoUtils.MAX_RETRY; i++) { |
| | | String code = BizNoUtils.randomCode(); |
| | | Long added = stringRedisTemplate.opsForSet().add(BizNoUtils.USED_SET_KEY, code); |
| | | if (added != null && added > 0) { |
| | | return code; |
| | | } |
| | | } |
| | | throw new IllegalStateException("çæå¯ä¸ä¸å¡ç¼ç 失败ï¼è¯·éè¯"); |
| | | } |
| | | |
| | | } |
| | |
| | | @Schema(description = "åä½åç§°", requiredMode = Schema.RequiredMode.REQUIRED, example = "个") |
| | | private String name; |
| | | |
| | | @Schema(description = "ç±»åï¼48åå
/100åå
/å¨ï¼", example = "48åå
") |
| | | private String type; |
| | | |
| | | @Schema(description = "æ¯å¦ä¸»åä½", example = "true") |
| | | private Boolean primaryFlag; |
| | | |
| | |
| | | import cn.iocoder.yudao.module.mdm.controller.admin.item.vo.MdmItemSaveReqVO; |
| | | import cn.iocoder.yudao.module.mdm.controller.admin.item.vo.MdmItemStatusUpdateReqVO; |
| | | import cn.iocoder.yudao.module.mdm.controller.admin.item.vo.MdmItemSyncUpdateReqVO; |
| | | import cn.iocoder.yudao.module.mdm.dal.dataobject.category.MdmItemCategoryDO; |
| | | import cn.iocoder.yudao.module.mdm.dal.dataobject.item.MdmItemBatchConfigDO; |
| | | import cn.iocoder.yudao.module.mdm.dal.dataobject.item.MdmItemDO; |
| | | import cn.iocoder.yudao.module.mdm.dal.dataobject.unit.MdmUnitMeasureDO; |
| | | import cn.iocoder.yudao.module.mdm.service.brand.MdmBrandService; |
| | | import cn.iocoder.yudao.module.mdm.service.category.MdmItemCategoryService; |
| | | import cn.iocoder.yudao.module.mdm.service.item.MdmItemBatchConfigService; |
| | | import cn.iocoder.yudao.module.mdm.service.item.MdmItemService; |
| | | import cn.iocoder.yudao.module.mdm.service.unit.MdmUnitMeasureService; |
| | |
| | | @Resource |
| | | private MesMdItemApi mesMdItemApi; |
| | | |
| | | @Resource |
| | | private MdmItemCategoryService itemCategoryService; |
| | | @Resource |
| | | private MdmUnitMeasureService unitMeasureService; |
| | | @Resource |
| | |
| | | @PreAuthorize("@ss.hasPermission('mdm:item:query')") |
| | | public CommonResult<PageResult<MdmItemRespVO>> getItemPage(@Valid MdmItemPageReqVO pageReqVO) { |
| | | PageResult<MdmItemDO> pageResult = itemService.getItemPage(pageReqVO); |
| | | // å
³èæ¥è¯¢åç±»åç§° |
| | | Map<Long, MdmItemCategoryDO> categoryMap = itemCategoryService.getItemCategoryMap( |
| | | convertSet(pageResult.getList(), MdmItemDO::getCategoryId)); |
| | | // å
³èæ¥è¯¢è®¡éåä½åç§° |
| | | Map<Long, MdmUnitMeasureDO> unitMap = unitMeasureService.getUnitMeasureMap( |
| | | convertSet(pageResult.getList(), MdmItemDO::getUnitMeasureId)); |
| | |
| | | .collect(Collectors.toMap(MesWmWarehouseRespDTO::getId, w -> w)); |
| | | // èµå¼ |
| | | respList.forEach(resp -> { |
| | | // åç±»åç§° |
| | | MdmItemCategoryDO category = categoryMap.get(resp.getCategoryId()); |
| | | if (category != null) { |
| | | resp.setCategoryName(category.getName()); |
| | | } |
| | | MdmUnitMeasureDO unit = unitMap.get(resp.getUnitMeasureId()); |
| | | if (unit != null) { |
| | | resp.setUnitMeasureName(unit.getName()); |
| | |
| | | * å¡«å
ç©æååº VO çå
³èåç§°ï¼åç±»ã主åä½ãè¾
åä½ãä»åºåç§°ï¼ |
| | | */ |
| | | private void enrichItemRespVO(MdmItemRespVO resp) { |
| | | // åç±»åç§° |
| | | if (resp.getCategoryId() != null) { |
| | | MdmItemCategoryDO category = itemCategoryService.getItemCategory(resp.getCategoryId()); |
| | | if (category != null) { |
| | | resp.setCategoryName(category.getName()); |
| | | } |
| | | } |
| | | // 主åä½åç§° |
| | | if (resp.getUnitMeasureId() != null) { |
| | | MdmUnitMeasureDO unit = unitMeasureService.getUnitMeasure(resp.getUnitMeasureId()); |
| | |
| | | @Schema(description = "ç©ææ¡ç ", example = "12345678") |
| | | private String barCode; |
| | | |
| | | @Schema(description = "ç©æåç±»ç¼å·", example = "1") |
| | | private Long categoryId; |
| | | |
| | | @Schema(description = "ç©æç±»å", example = "1") |
| | | private Integer itemType; |
| | | |
| | |
| | | @Schema(description = "è§æ ¼åå·", example = "M8*20") |
| | | private String specification; |
| | | |
| | | @Schema(description = "ç©æåç±»ç¼å·", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") |
| | | private Long categoryId; |
| | | |
| | | @Schema(description = "ç©æåç±»åç§°", example = "äºéé
ä»¶") |
| | | private String categoryName; |
| | | |
| | | @Schema(description = "计éåä½ç¼å·", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") |
| | | private Long unitMeasureId; |
| | | |
| | |
| | | |
| | | @Schema(description = "ç¶æ", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") |
| | | private Integer status; |
| | | |
| | | @Schema(description = "éè´ä»·æ ¼", example = "10.00") |
| | | private BigDecimal purchasePrice; |
| | | |
| | | @Schema(description = "éå®ä»·æ ¼", example = "15.00") |
| | | private BigDecimal salesPrice; |
| | |
| | | @Schema(description = "è§æ ¼åå·", example = "M8*20") |
| | | private String specification; |
| | | |
| | | @Schema(description = "ç©æåç±»ç¼å·ï¼å
³è MES ç©æåç±» mes_md_item_typeï¼", example = "1") |
| | | private Long categoryId; |
| | | |
| | | @Schema(description = "计éåä½ç¼å·", example = "1") |
| | | private Long unitMeasureId; |
| | | |
| | |
| | | |
| | | @Schema(description = "ç¶æ", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") |
| | | private Integer status; |
| | | |
| | | @Schema(description = "éè´ä»·æ ¼", example = "10.00") |
| | | private BigDecimal purchasePrice; |
| | | |
| | | @Schema(description = "éå®ä»·æ ¼", example = "15.00") |
| | | private BigDecimal salesPrice; |
| | |
| | | package cn.iocoder.yudao.module.mdm.controller.admin.unit.vo; |
| | | |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import jakarta.validation.constraints.NotBlank; |
| | | import lombok.Data; |
| | | |
| | | import java.math.BigDecimal; |
| | |
| | | @Schema(description = "åä½åç§°", requiredMode = Schema.RequiredMode.REQUIRED, example = "个") |
| | | private String name; |
| | | |
| | | @Schema(description = "ç±»å", requiredMode = Schema.RequiredMode.REQUIRED, example = "48åå
") |
| | | @NotBlank(message = "ç±»åä¸è½ä¸ºç©º") |
| | | private String type; |
| | | |
| | | @Schema(description = "æ¯å¦ä¸»åä½", example = "true") |
| | | private Boolean primaryFlag; |
| | | |
| | |
| | | private String name; |
| | | |
| | | /** |
| | | * ç±»å |
| | | * |
| | | * å¯éå¼ï¼48åå
ã100åå
ãå¨ |
| | | */ |
| | | private String type; |
| | | |
| | | /** |
| | | * æ¯å¦ä¸»åä½ |
| | | */ |
| | | private Boolean primaryFlag; |
| | |
| | | |
| | | import cn.hutool.core.collection.CollUtil; |
| | | import cn.hutool.core.util.ObjUtil; |
| | | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| | | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| | | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| | | import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; |
| | | import cn.iocoder.yudao.module.mdm.controller.admin.item.vo.MdmItemPageReqVO; |
| | | import cn.iocoder.yudao.module.mdm.controller.admin.item.vo.MdmItemSaveReqVO; |
| | | import cn.iocoder.yudao.module.mdm.dal.dataobject.category.MdmItemCategoryDO; |
| | | import cn.iocoder.yudao.module.mdm.dal.dataobject.item.MdmItemBatchConfigDO; |
| | | import cn.iocoder.yudao.module.mdm.dal.dataobject.item.MdmItemDO; |
| | | import cn.iocoder.yudao.module.mdm.dal.dataobject.unit.MdmUnitMeasureDO; |
| | | import cn.iocoder.yudao.module.mdm.dal.mysql.item.MdmItemBatchConfigMapper; |
| | | import cn.iocoder.yudao.module.mdm.dal.mysql.item.MdmItemMapper; |
| | | import cn.iocoder.yudao.module.mdm.service.brand.MdmBrandService; |
| | | import cn.iocoder.yudao.module.mdm.service.category.MdmItemCategoryService; |
| | | import cn.iocoder.yudao.module.mdm.service.unit.MdmUnitMeasureService; |
| | | import cn.iocoder.yudao.module.mes.api.item.MesMdItemApi; |
| | | import cn.iocoder.yudao.module.mes.api.item.MesMdItemTypeApi; |
| | | import cn.iocoder.yudao.module.mes.api.item.dto.MesMdItemSyncReqDTO; |
| | | import cn.iocoder.yudao.module.mes.api.item.dto.MesMdItemTypeRespDTO; |
| | | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
| | | import jakarta.annotation.Resource; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.context.annotation.Lazy; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | |
| | | import java.util.stream.Collectors; |
| | | |
| | | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| | | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; |
| | | import static cn.iocoder.yudao.module.mdm.enums.ErrorCodeConstants.*; |
| | | |
| | | /** |
| | |
| | | private MdmItemMapper itemMapper; |
| | | |
| | | @Resource |
| | | private MdmItemCategoryService itemCategoryService; |
| | | @Resource |
| | | private MdmUnitMeasureService unitMeasureService; |
| | | @Resource |
| | | private MdmBrandService brandService; |
| | |
| | | private MesMdItemApi mesMdItemApi; |
| | | @Resource |
| | | private MdmItemBatchConfigMapper itemBatchConfigMapper; |
| | | |
| | | @Resource |
| | | private MesMdItemTypeApi mesMdItemTypeApi; |
| | | |
| | | |
| | | @Override |
| | |
| | | } |
| | | |
| | | /** |
| | | * åæ¥ç©æå° MESï¼åä½/åç±»æ code æ å°ï¼ |
| | | * åæ¥ç©æå° MESï¼å使 code æ å°ï¼ |
| | | * |
| | | * MDM ç unitMeasureId/categoryId ä¸ MES ç unitMeasureId/itemTypeId åå±ä¸¤å¥ä¸»æ°æ®ï¼ |
| | | * è¿éå
å¨ MDM ä¾§è§£æåº codeï¼åäº¤ç± MesMdItemApi å¨ MES ä¾§è§£æä¸ºå¯¹åº idã |
| | | * åç§ç®¡ç已廿ãåç§åç±»ãåæ®µï¼åæ¥ä¸åä¼ é MES ç©æåç±»ï¼item_type_id ç空ï¼å¯å¨ MES 侧补填ï¼ã |
| | | * åæ¥å¤±è´¥å°æåºå¼å¸¸ï¼è§¦åå¤å± @Transactional æ´ä½åæ»ï¼MDM æä½ä¸å¹¶åæ»ï¼ã |
| | | */ |
| | | private void syncItemToMes(MdmItemSaveReqVO reqVO) { |
| | |
| | | } |
| | | unitCode = unitMeasure.getCode(); |
| | | } |
| | | // è§£æåç±» id -> codeï¼ä½¿ç¨ MDM æ¬å°åç±»æå¡ï¼ |
| | | String itemTypeCode = null; |
| | | if (reqVO.getCategoryId() != null) { |
| | | CommonResult<MesMdItemTypeRespDTO> itemType = mesMdItemTypeApi.getItemType(reqVO.getCategoryId()); |
| | | itemTypeCode = itemType.getData().getCode(); |
| | | } |
| | | // ç»è£
忥 DTO |
| | | MesMdItemSyncReqDTO syncReqDTO = new MesMdItemSyncReqDTO(); |
| | | syncReqDTO.setCode(reqVO.getCode()); |
| | |
| | | syncReqDTO.setName(reqVO.getName()); |
| | | syncReqDTO.setSpecification(reqVO.getSpecification()); |
| | | syncReqDTO.setUnitCode(unitCode); |
| | | syncReqDTO.setItemTypeCode(itemTypeCode); |
| | | syncReqDTO.setSafeStockFlag(Boolean.TRUE); // ä¿ç MDM ç minStock/maxStockï¼é¿å
被 MES æ¸
é¶ |
| | | syncReqDTO.setMinStock(reqVO.getMinStock()); |
| | | syncReqDTO.setMaxStock(reqVO.getMaxStock()); |
| | |
| | | } |
| | | } |
| | | |
| | | private void validateCategoryExists(Long categoryId) { |
| | | if (categoryId == null) { |
| | | return; |
| | | } |
| | | // ä½¿ç¨ MDM æ¬å°åç±»æå¡æ ¡éª |
| | | MdmItemCategoryDO category = itemCategoryService.getItemCategory(categoryId); |
| | | if (category == null) { |
| | | throw exception(MDM_ITEM_CATEGORY_NOT_EXISTS); |
| | | } |
| | | } |
| | | |
| | | private void validateUnitMeasureExists(Long unitMeasureId) { |
| | | if (unitMeasureService.getUnitMeasure(unitMeasureId) == null) { |
| | | throw exception(MDM_UNIT_MEASURE_NOT_EXISTS); |
| | |
| | | |
| | | @Override |
| | | public PageResult<MdmItemDO> getItemPage(MdmItemPageReqVO pageReqVO) { |
| | | // æ¥æ¾æ¶ï¼å¦ææ¥æ¾æä¸ªåç±»ç¼å·ï¼åå
å«å®çååç±» |
| | | Set<Long> categoryIds = null; |
| | | if (pageReqVO.getCategoryId() != null) { |
| | | categoryIds = new HashSet<>(); |
| | | categoryIds.add(pageReqVO.getCategoryId()); |
| | | List<cn.iocoder.yudao.module.mdm.dal.dataobject.category.MdmItemCategoryDO> children = |
| | | itemCategoryService.getItemCategoryChildrenList(pageReqVO.getCategoryId()); |
| | | categoryIds.addAll(convertSet(children, cn.iocoder.yudao.module.mdm.dal.dataobject.category.MdmItemCategoryDO::getId)); |
| | | } |
| | | // å页æ¥è¯¢ |
| | | return itemMapper.selectPage(pageReqVO, categoryIds); |
| | | return itemMapper.selectPage(pageReqVO, (Collection<Long>) null); |
| | | } |
| | | |
| | | @Override |
| | |
| | | @Schema(description = "计éåä½ç¼ç ", requiredMode = Schema.RequiredMode.REQUIRED, example = "PCS") |
| | | private String unitCode; |
| | | |
| | | @Schema(description = "ç©æåç±»ç¼ç ", requiredMode = Schema.RequiredMode.REQUIRED, example = "TYPE001") |
| | | private String itemTypeCode; |
| | | |
| | | @Schema(description = "æ¯å¦å¯ç¨å®å
¨åºå", example = "false") |
| | | private Boolean safeStockFlag; |
| | | |
| | |
| | | @Schema(description = "éè´§ååç§°", requiredMode = Schema.RequiredMode.REQUIRED, example = "å®åéè´§") |
| | | private String name; |
| | | |
| | | @Schema(description = "éå®è®¢å ID", example = "1") |
| | | private Long saleOrderId; |
| | | |
| | | @Schema(description = "éå®è®¢åç¼å·", example = "SO202603010001") |
| | | private String salesOrderCode; |
| | | |
| | | @Schema(description = "å®¢æ· ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") |
| | | private Long clientId; |
| | | |
| | |
| | | import cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.MesMdItemSaveReqVO; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.batchconfig.MesMdItemBatchConfigSaveReqVO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemTypeDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.md.unitmeasure.MesMdUnitMeasureDO; |
| | | import cn.iocoder.yudao.module.mes.dal.mysql.md.item.MesMdItemMapper; |
| | | import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemBatchConfigService; |
| | | import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService; |
| | | import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemTypeService; |
| | | import cn.iocoder.yudao.module.mes.service.md.unitmeasure.MesMdUnitMeasureService; |
| | | import jakarta.annotation.Resource; |
| | | import lombok.extern.slf4j.Slf4j; |
| | |
| | | * MES ç©æäº§å API å®ç°ç±» |
| | | * |
| | | * ä¾ MDM çæ¨¡ååæ¥ç©æä¸»æ°æ®å° MES 使ç¨ã |
| | | * åä½ãåç±»æ code å¨ MES ä¾§è§£æä¸ºå¯¹åº idã |
| | | * å使 code å¨ MES ä¾§è§£æä¸ºå¯¹åº idã |
| | | * |
| | | * @author è¶
级管çå |
| | | */ |
| | |
| | | private MesMdItemService itemService; |
| | | @Resource |
| | | private MesMdItemMapper itemMapper; |
| | | @Resource |
| | | private MesMdItemTypeService itemTypeService; |
| | | @Resource |
| | | private MesMdUnitMeasureService unitMeasureService; |
| | | @Resource |
| | |
| | | } |
| | | |
| | | /** |
| | | * å°åæ¥ DTO 转æ¢ä¸º MES ç©æäº§å SaveReqVOï¼å¹¶æ code è§£æåä½/åç±» id |
| | | * å°åæ¥ DTO 转æ¢ä¸º MES ç©æäº§å SaveReqVOï¼å¹¶æ code è§£æåä½ id |
| | | * |
| | | * MDM åç§ç®¡ç已廿ãåç§åç±»ãï¼åæ¥ä¸åè®¾ç½®ç©æåç±»ï¼item_type_id ç空ï¼å¯å¨ MES ä¾§æå·¥è¡¥å¡«ï¼ |
| | | */ |
| | | private MesMdItemSaveReqVO buildSaveReqVO(MesMdItemSyncReqDTO syncReqDTO) { |
| | | // è§£æè®¡éåä½ code -> id |
| | |
| | | if (unitMeasure == null) { |
| | | throw exception(MD_UNIT_MEASURE_NOT_EXISTS); |
| | | } |
| | | // è§£æç©æåç±» code -> id |
| | | MesMdItemTypeDO itemType = itemTypeService.getItemTypeByCode(syncReqDTO.getItemTypeCode()); |
| | | if (itemType == null) { |
| | | throw exception(MD_ITEM_TYPE_NOT_EXISTS); |
| | | } |
| | | // ç»è£
ï¼code/name/specification/safeStockFlag/minStock/maxStock/highValue/batchFlag/remark ååæ·è´ï¼ |
| | | MesMdItemSaveReqVO saveReqVO = BeanUtils.toBean(syncReqDTO, MesMdItemSaveReqVO.class); |
| | | saveReqVO.setUnitMeasureId(unitMeasure.getId()); |
| | | saveReqVO.setItemTypeId(itemType.getId()); |
| | | return saveReqVO; |
| | | } |
| | | |
| | |
| | | @Schema(description = "æçç æ»æ°", requiredMode = Schema.RequiredMode.REQUIRED, example = "800") |
| | | private Long palletCount; |
| | | |
| | | // ========== åºåºæµé ========== |
| | | |
| | | @Schema(description = "åè´§éç¥åæ°ï¼mes_wm_sales_noticeï¼", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") |
| | | private Long salesNoticeCount; |
| | | |
| | | @Schema(description = "éå®åºåºåæ°ï¼mes_wm_product_salesï¼", requiredMode = Schema.RequiredMode.REQUIRED, example = "20") |
| | | private Long productSalesCount; |
| | | |
| | | @Schema(description = "éå®éè´§åæ°ï¼mes_wm_return_salesï¼", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") |
| | | private Long returnSalesCount; |
| | | |
| | | // ========== ä»å¨é¢è¦ / è´¨é ========== |
| | | |
| | | @Schema(description = "æªå¤çåºåé¢è¦æ°ï¼mes_wm_stock_warning.status=10ï¼", requiredMode = Schema.RequiredMode.REQUIRED, example = "3") |
| | | private Long stockWarningPendingCount; |
| | | |
| | | @Schema(description = "å¾
è¯å®¡ä¸åæ ¼ååæ°ï¼mes_qc_ncr.status=0ï¼", requiredMode = Schema.RequiredMode.REQUIRED, example = "5") |
| | | private Long ncrPendingCount; |
| | | |
| | | // ========== ç¶æåå¸ ========== |
| | | |
| | | @Schema(description = "æ¹æ¬¡ç¶æåå¸") |
| | |
| | | @NotNull(message = "计éåä½ä¸è½ä¸ºç©º") |
| | | private Long unitMeasureId; |
| | | |
| | | @Schema(description = "ç©æåç±»ç¼å·", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") |
| | | @NotNull(message = "ç©æåç±»ç¼å·ä¸è½ä¸ºç©º") |
| | | @Schema(description = "ç©æåç±»ç¼å·", example = "1") |
| | | private Long itemTypeId; |
| | | |
| | | @Schema(description = "æ¯å¦å¯ç¨å®å
¨åºå", example = "false") |
| | |
| | | import cn.iocoder.yudao.module.mes.controller.admin.pro.bagcode.vo.MesProBagCodeGenerateRespVO; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.pro.bagcode.vo.MesProBagCodeGenerateReqVO; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.pro.bagcode.vo.MesProBagCodePageReqVO; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.pro.bagcode.vo.MesProBagCodeRawGenerateReqVO; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.pro.bagcode.vo.MesProBagCodeReplaceReqVO; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.pro.bagcode.vo.MesProBagCodeReplaceRespVO; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.pro.bagcode.vo.MesProBagCodeRespVO; |
| | |
| | | @PreAuthorize("@ss.hasPermission('mes:pro-bag-code:create')") |
| | | public CommonResult<MesProBagCodeGenerateRespVO> generateBagCodes(@Valid @RequestBody MesProBagCodeGenerateReqVO generateReqVO) { |
| | | return success(bagCodeService.generateBagCodes(generateReqVO)); |
| | | } |
| | | |
| | | @PostMapping("/raw-generate") |
| | | @Operation(summary = "çæåå§è¢ç ï¼ä»
éåç§ä¸è¢ç æ°éï¼ä¸å
³è计éåä½ç±»åãä¸çææçï¼") |
| | | @PreAuthorize("@ss.hasPermission('mes:pro-bag-code:create')") |
| | | public CommonResult<MesProBagCodeGenerateRespVO> generateRawBagCodes( |
| | | @Valid @RequestBody MesProBagCodeRawGenerateReqVO rawGenerateReqVO) { |
| | | return success(bagCodeService.generateRawBagCodes(rawGenerateReqVO)); |
| | | } |
| | | |
| | | @PostMapping("/replace") |
| | |
| | | .setProduceDate(batch.getProduceDate()) |
| | | .setLineCode(batch.getLineCode()) |
| | | .setLineName(batch.getLineName()) |
| | | .setOwnerUserId(batch.getOwnerUserId()) |
| | | .setItemId(batch.getItemId()); |
| | | .setOwnerUserId(batch.getOwnerUserId()); |
| | | // 责任人 |
| | | if (batch.getOwnerUserId() != null) { |
| | | AdminUserRespDTO user = adminUserApi.getUser(batch.getOwnerUserId()); |
| | |
| | | respVO.setOwnerUserName(user.getNickname()); |
| | | } |
| | | } |
| | | // åç§ä¿¡æ¯ |
| | | if (batch.getItemId() != null) { |
| | | MesMdmItemDO item = mdmItemService.getItem(batch.getItemId()); |
| | | if (item != null) { |
| | | respVO.setItemCode(item.getCode()) |
| | | .setItemName(item.getName()) |
| | | .setItemSpecification(item.getSpecification()); |
| | | } |
| | | } |
| | | // åç§ä¿¡æ¯ï¼ä¼å
åè¢ç ä¸çåç§ï¼æ°æ®å
çææ¶ç»å®ï¼ï¼åå²è¢ç åéæ¹æ¬¡åç§ |
| | | Long itemId = bagCode.getItemId() != null ? bagCode.getItemId() |
| | | : (batch == null ? null : batch.getItemId()); |
| | | if (itemId != null) { |
| | | MesMdmItemDO item = mdmItemService.getItem(itemId); |
| | | if (item != null) { |
| | | respVO.setItemId(itemId) |
| | | .setItemCode(item.getCode()) |
| | | .setItemName(item.getName()) |
| | | .setItemSpecification(item.getSpecification()); |
| | | } |
| | | } |
| | | return respVO; |
| | |
| | | * æå»ºè¢ç äºç»´ç æ ç¾å表ï¼äºç»´ç ç¼ç 纯ç å¼ï¼å¾çå å å
³é®ä¿¡æ¯æåï¼ |
| | | */ |
| | | private List<QrLabelInfo> buildBagCodeQrLabels(List<MesProBagCodeDO> list) { |
| | | // 1. è·å¾å
³èæ°æ®ï¼æ¹æ¬¡ãåç§ãè´£ä»»äººï¼ |
| | | // 1. è·å¾å
³èæ°æ®ï¼æ¹æ¬¡ãåç§ã责任人ï¼ï¼åç§éåå«è¢ç èªèº«åç§ä¸å岿¹æ¬¡åç§ |
| | | Map<Long, MesProBatchDO> batchMap = convertMap( |
| | | batchService.getBatchList(convertSet(list, MesProBagCodeDO::getBatchId)), MesProBatchDO::getId); |
| | | Map<Long, MesMdmItemDO> itemMap = mdmItemService.getItemMap( |
| | | convertSet(batchMap.values(), MesProBatchDO::getItemId)); |
| | | Set<Long> itemIds = convertSet(list, MesProBagCodeDO::getItemId); |
| | | itemIds.addAll(convertSet(batchMap.values(), MesProBatchDO::getItemId)); |
| | | Map<Long, MesMdmItemDO> itemMap = mdmItemService.getItemMap(itemIds); |
| | | Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap( |
| | | convertSet(batchMap.values(), MesProBatchDO::getOwnerUserId)); |
| | | // 2. æå»ºæ ç¾ |
| | |
| | | @Data |
| | | public class MesProBagCodeGenerateReqVO { |
| | | |
| | | @Schema(description = "çæè¢æ°ï¼æ¬æ¬¡çæçè¢ç æ°éï¼", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") |
| | | @NotNull(message = "çæè¢æ°ä¸è½ä¸ºç©º") |
| | | @Positive(message = "çæè¢æ°å¿
é¡»å¤§äº 0") |
| | | private Integer count; |
| | | @Schema(description = "åç§ï¼ç©æï¼ç¼å·", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") |
| | | @NotNull(message = "åç§ä¸è½ä¸ºç©º") |
| | | private Long itemId; |
| | | |
| | | @Schema(description = "æçæ°ï¼åç§ä¸»åä½ç±»å为 48åå
/100åå
æ¶å¿
å¡«ï¼è¢ç æ° = æ¯æè¢æ° à æçæ°ï¼", example = "5") |
| | | @Positive(message = "æçæ°å¿
é¡»å¤§äº 0") |
| | | private Integer palletCount; |
| | | |
| | | @Schema(description = "è¢ç æ°ï¼åç§ä¸»åä½ç±»å为 å¨ æ¶å¿
å¡«ï¼ä¸çææçï¼", example = "100") |
| | | @Positive(message = "è¢ç æ°å¿
é¡»å¤§äº 0") |
| | | private Integer bagCount; |
| | | |
| | | @Schema(description = "夿³¨") |
| | | private String remark; |
| | |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | |
| | | import java.util.List; |
| | | |
| | | @Schema(description = "管çåå° - MES è¢ç çæååº") |
| | | @Data |
| | | public class MesProBagCodeGenerateRespVO { |
| | | |
| | | @Schema(description = "çæç» UUID") |
| | | private String uuid; |
| | | |
| | | @Schema(description = "åç§ä¸»åä½ç±»å", example = "48åå
") |
| | | private String type; |
| | | |
| | | @Schema(description = "æ¯æçè¢æ°ï¼ç±»å为 å¨ æ¶ä¸º 0ï¼", example = "48") |
| | | private Integer perPallet; |
| | | |
| | | @Schema(description = "æ¬æ¬¡çæçè¢ç æ»æ°", example = "240") |
| | | private Integer totalCount; |
| | | |
| | | @Schema(description = "èªå¨çæçæçç¼å·å表ï¼ç±»å为 å¨ æ¶ä¸ºç©ºï¼") |
| | | private List<Long> palletIds; |
| | | } |
| | |
| | | @Schema(description = "ç»å®æçç¼å·", example = "1024") |
| | | private Long palletId; |
| | | |
| | | @Schema(description = "åç§ï¼ç©æï¼ç¼å·", example = "1024") |
| | | private Long itemId; |
| | | |
| | | @Schema(description = "ç¶æï¼åå
¸ mes_pro_bag_code_statusï¼", example = "10") |
| | | private Integer status; |
| | | |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.mes.controller.admin.pro.bagcode.vo; |
| | | |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import jakarta.validation.constraints.NotNull; |
| | | import jakarta.validation.constraints.Positive; |
| | | import lombok.Data; |
| | | |
| | | @Schema(description = "管çåå° - MES åå§è¢ç çæ Request VOï¼ä»
åç§+æ°éï¼ä¸å
³è计éåä½ç±»åãä¸çææçï¼") |
| | | @Data |
| | | public class MesProBagCodeRawGenerateReqVO { |
| | | |
| | | @Schema(description = "åç§ï¼ç©æï¼ç¼å·", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") |
| | | @NotNull(message = "åç§ä¸è½ä¸ºç©º") |
| | | private Long itemId; |
| | | |
| | | @Schema(description = "è¢ç æ°é", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") |
| | | @NotNull(message = "è¢ç æ°éä¸è½ä¸ºç©º") |
| | | @Positive(message = "è¢ç æ°éå¿
é¡»å¤§äº 0") |
| | | private Integer count; |
| | | |
| | | @Schema(description = "夿³¨") |
| | | private String remark; |
| | | |
| | | } |
| | |
| | | @ColumnWidth(30) |
| | | private String palletCode; |
| | | |
| | | @Schema(description = "åç§ç¼å·", example = "1") |
| | | @ExcelIgnore |
| | | private Long itemId; |
| | | |
| | | @Schema(description = "åç§ç¼ç ") |
| | | @ExcelProperty("åç§ç¼ç ") |
| | | @ColumnWidth(20) |
| | | private String itemCode; |
| | | |
| | | @Schema(description = "åç§åç§°") |
| | | @ExcelProperty("åç§åç§°") |
| | | @ColumnWidth(20) |
| | | private String itemName; |
| | | |
| | | @Schema(description = "ç¶æï¼åå
¸ mes_pro_bag_code_statusï¼", example = "10") |
| | | @ExcelProperty(value = "ç¶æ", converter = DictConvert.class) |
| | | @DictFormat(DictTypeConstants.MES_PRO_BAG_CODE_STATUS) |
| | |
| | | if (CollUtil.isEmpty(list)) { |
| | | return Collections.emptyList(); |
| | | } |
| | | // 1. è·å¾å
³èæ°æ®ï¼è´£ä»»äººãåç§ç©æï¼ |
| | | // 1. è·å¾å
³èæ°æ®ï¼è´£ä»»äººï¼ï¼åç§å·²ä¸æ²å°è¢ç æ°æ®å
ï¼æ¹æ¬¡å表ä¸åå±ç¤º |
| | | Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap( |
| | | convertSet(list, MesProBatchDO::getOwnerUserId)); |
| | | Map<Long, MesMdmItemDO> itemMap = mdmItemService.getItemMap( |
| | | convertSet(list, MesProBatchDO::getItemId)); |
| | | // 2. æå»ºç»æ |
| | | return BeanUtils.toBean(list, MesProBatchRespVO.class, vo -> { |
| | | MapUtils.findAndThen(userMap, vo.getOwnerUserId(), user -> |
| | | vo.setOwnerUserName(user.getNickname())); |
| | | MapUtils.findAndThen(itemMap, vo.getItemId(), item -> { |
| | | vo.setItemCode(item.getCode()); |
| | | vo.setItemName(item.getName()); |
| | | vo.setItemSpecification(item.getSpecification()); |
| | | }); |
| | | }); |
| | | return BeanUtils.toBean(list, MesProBatchRespVO.class, vo -> |
| | | MapUtils.findAndThen(userMap, vo.getOwnerUserId(), user -> |
| | | vo.setOwnerUserName(user.getNickname()))); |
| | | } |
| | | |
| | | private List<MesProBatchWorkerRespVO> buildWorkerRespVOList(List<MesProBatchWorkerDO> workers) { |
| | |
| | | @Schema(description = "ä¸´æ¶æ¹æ¬¡ç ", example = "PB-00000001") |
| | | private String tempCode; |
| | | |
| | | @Schema(description = "åç§ï¼äº§åç©æï¼ç¼å·", example = "1") |
| | | private Long itemId; |
| | | |
| | | @Schema(description = "产线ç¼å·", example = "1") |
| | | private Long lineId; |
| | | |
| | | @Schema(description = "产线ç¼ç ", example = "L01") |
| | | private String lineCode; |
| | | |
| | | @Schema(description = "产线åç§°", example = "å
è£
ä¸çº¿") |
| | | @Schema(description = "产线åç§°ï¼é¡µé¢å±ç¤ºä¸ºãå å·¥åä½ãï¼", example = "å
è£
ä¸çº¿") |
| | | private String lineName; |
| | | |
| | | @Schema(description = "å å·¥çç»", example = "ä¸å·å å·¥çç»") |
| | | private String processingTeam; |
| | | |
| | | @Schema(description = "è´£ä»»äººç¨æ·ç¼å·", example = "1") |
| | | private Long ownerUserId; |
| | | |
| | |
| | | @ExcelIgnore |
| | | private String tempCode; |
| | | |
| | | @Schema(description = "åç§ï¼äº§åç©æï¼ç¼å·", example = "1") |
| | | @ExcelIgnore |
| | | private Long itemId; |
| | | |
| | | @Schema(description = "åç§ç¼ç ") |
| | | @ExcelProperty("åç§ç¼ç ") |
| | | private String itemCode; |
| | | |
| | | @Schema(description = "åç§åç§°") |
| | | @ExcelProperty("åç§åç§°") |
| | | private String itemName; |
| | | |
| | | @Schema(description = "åç§è§æ ¼") |
| | | @ExcelProperty("åç§è§æ ¼") |
| | | private String itemSpecification; |
| | | |
| | | @Schema(description = "产线ç¼å·", example = "1") |
| | | @ExcelIgnore |
| | | private Long lineId; |
| | | |
| | | @Schema(description = "产线ç¼ç ", example = "L01") |
| | | @ExcelProperty("产线ç¼ç ") |
| | | @Schema(description = "产线ç¼ç ï¼é¡µé¢å·²éèï¼ä»
æ¥å£è¿åï¼", example = "L01") |
| | | @ExcelIgnore |
| | | private String lineCode; |
| | | |
| | | @Schema(description = "产线åç§°", example = "å
è£
ä¸çº¿") |
| | | @ExcelProperty("产线åç§°") |
| | | @Schema(description = "产线åç§°ï¼é¡µé¢å±ç¤ºä¸ºãå å·¥åä½ãï¼", example = "å
è£
ä¸çº¿") |
| | | @ExcelProperty("å å·¥åä½") |
| | | private String lineName; |
| | | |
| | | @Schema(description = "å å·¥çç»", example = "ä¸å·å å·¥çç»") |
| | | @ExcelProperty("å å·¥çç»") |
| | | private String processingTeam; |
| | | |
| | | @Schema(description = "çäº§æ¥æ") |
| | | @ExcelProperty("çäº§æ¥æ") |
| | | @ColumnWidth(20) |
| | | private LocalDateTime produceDate; |
| | | |
| | | @Schema(description = "è®¡åæ°é", example = "1000") |
| | | @ExcelProperty("è®¡åæ°é") |
| | | @Schema(description = "å å·¥æ°éï¼åè®¡åæ°éï¼é¡µé¢å±ç¤ºä¸ºãå å·¥æ°éãï¼", example = "1000") |
| | | @ExcelProperty("å å·¥æ°é") |
| | | private BigDecimal planQuantity; |
| | | |
| | | @Schema(description = "è´£ä»»äººç¨æ·ç¼å·", example = "1") |
| | |
| | | import jakarta.validation.Valid; |
| | | import jakarta.validation.constraints.NotEmpty; |
| | | import jakarta.validation.constraints.NotNull; |
| | | import jakarta.validation.constraints.Size; |
| | | import lombok.Data; |
| | | import org.springframework.format.annotation.DateTimeFormat; |
| | | |
| | |
| | | @Schema(description = "ç¼å·", example = "1024") |
| | | private Long id; |
| | | |
| | | @Schema(description = "åç§ï¼äº§åç©æï¼ç¼å·", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") |
| | | @NotNull(message = "åç§ä¸è½ä¸ºç©º") |
| | | private Long itemId; |
| | | |
| | | @Schema(description = "产线ç¼å·", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") |
| | | @NotNull(message = "产线ä¸è½ä¸ºç©º") |
| | | @Schema(description = "产线ç¼å·ï¼é¡µé¢å±ç¤ºä¸ºãå å·¥åä½ãï¼", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") |
| | | @NotNull(message = "å å·¥åä½ä¸è½ä¸ºç©º") |
| | | private Long lineId; |
| | | |
| | | @Schema(description = "å å·¥çç»ï¼æå·¥å¡«åï¼", example = "ä¸å·å å·¥çç»") |
| | | @Size(max = 64, message = "å å·¥çç»é¿åº¦ä¸è½è¶
è¿ 64") |
| | | private String processingTeam; |
| | | |
| | | @Schema(description = "çäº§æ¥æ", requiredMode = Schema.RequiredMode.REQUIRED) |
| | | @NotNull(message = "çäº§æ¥æä¸è½ä¸ºç©º") |
| | | @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) |
| | | private LocalDateTime produceDate; |
| | | |
| | | @Schema(description = "è®¡åæ°é", example = "1000") |
| | | @Schema(description = "å å·¥æ°éï¼åè®¡åæ°éï¼é¡µé¢å±ç¤ºä¸ºãå å·¥æ°éãï¼", example = "1000") |
| | | private BigDecimal planQuantity; |
| | | |
| | | @Schema(description = "è´£ä»»äººç¨æ·ç¼å·ï¼è´£ä»»è½å®å°äººï¼", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") |
| | |
| | | @Valid |
| | | private List<Worker> workers; |
| | | |
| | | @Schema(description = "ç»å®æçç¼å·å表ï¼å¯éï¼ç»å®æ¶æ¹æ¬¡ç´æ¥è¿å
¥ç产ä¸ï¼æçä¸è¢ç 级èå½å
¥æ¬æ¹æ¬¡ï¼æ°å¢/è¡¥å½/ç¼è¾åå¯ä¼ å
¥ï¼ç¼è¾æ¶ä»
éä¼ æ¬æ¬¡æ°å¢å¾éçæçï¼") |
| | | private List<Long> palletIds; |
| | | |
| | | @Schema(description = "ç产人åé
ç½®") |
| | | @Data |
| | | public static class Worker { |
| | |
| | | return success(BeanUtils.toBean(list, MesProPalletRespVO.class)); |
| | | } |
| | | |
| | | @GetMapping("/unbound-list") |
| | | @Operation(summary = "è·å¾æªç»å®æ¹æ¬¡çä¸´æ¶æçå表ï¼ä¾æ¹æ¬¡æ°å¢/è¡¥å½ç»å®æçä¸æä½¿ç¨ï¼") |
| | | @PreAuthorize("@ss.hasPermission('mes:pro-pallet:query')") |
| | | public CommonResult<List<MesProPalletRespVO>> getUnboundPalletList() { |
| | | List<MesProPalletDO> list = palletService.getUnboundPalletList(); |
| | | return success(BeanUtils.toBean(list, MesProPalletRespVO.class)); |
| | | } |
| | | |
| | | @GetMapping("/export-excel") |
| | | @Operation(summary = "å¯¼åºæçç Excel") |
| | | @PreAuthorize("@ss.hasPermission('mes:pro-pallet:export')") |
| | |
| | | @Positive(message = "çææ°éå¿
é¡»å¤§äº 0") |
| | | private Integer count; |
| | | |
| | | @Schema(description = "å¯è£
è¢æ°ï¼è¢/æçï¼", example = "25") |
| | | @Positive(message = "å¯è£
è¢æ°å¿
é¡»å¤§äº 0") |
| | | private Integer capacity; |
| | | |
| | | @Schema(description = "夿³¨") |
| | | private String remark; |
| | | |
| | |
| | | @Positive(message = "çææ°éå¿
é¡»å¤§äº 0") |
| | | private Integer count; |
| | | |
| | | @Schema(description = "å¯è£
è¢æ°ï¼è¢/æçï¼", example = "25") |
| | | @Positive(message = "å¯è£
è¢æ°å¿
é¡»å¤§äº 0") |
| | | private Integer capacity; |
| | | |
| | | @Schema(description = "夿³¨") |
| | | private String remark; |
| | | |
| | |
| | | @ExcelProperty("æçåºå·") |
| | | private Integer palletNo; |
| | | |
| | | @Schema(description = "å¯è£
è¢æ°ï¼è¢/æçï¼", example = "25") |
| | | @ExcelProperty("å¯è£
è¢æ°") |
| | | private Integer capacity; |
| | | |
| | | @Schema(description = "å·²ç»å®è¢ç æ°é", example = "10") |
| | | @ExcelProperty("å·²è£
è¢æ°") |
| | | private Integer bagCount; |
| | |
| | | @RestController @RequestMapping("/mes/pro/scan-in") |
| | | public class MesProScanEventController { |
| | | @Resource private MesProScanEventService service; |
| | | @PostMapping("/inbound") @PreAuthorize("@ss.hasPermission('mes:pro-scan-in:inbound')") @Operation(summary = "è¢ç æ«ç å
¥åº") |
| | | @PostMapping("/inbound") @PreAuthorize("@ss.hasPermission('mes:pro-scan-in:inbound')") @Operation(summary = "è¿½æº¯ç æ«ç å
¥åºï¼è¢ç /æçç /æ¹æ¬¡ç ï¼") |
| | | public CommonResult<MesProScanEventRespVO> inbound(@Valid @RequestBody MesProScanEventCreateReqVO req) { |
| | | return success(BeanUtils.toBean(service.createInbound(req), MesProScanEventRespVO.class)); |
| | | } |
| | |
| | | @Data |
| | | public class MesProScanEventCreateReqVO { |
| | | @NotBlank private String eventId; |
| | | /** |
| | | * æ«ç å
容ï¼è¢ç / æçç / æ¹æ¬¡ç çç å¼ï¼å«ä¸´æ¶ç ï¼ |
| | | */ |
| | | @NotBlank private String bagCode; |
| | | /** |
| | | * æ«ç ç±»åï¼BAG è¢ç / PALLET æçç / BATCH æ¹æ¬¡ç ï¼é»è®¤ BAG |
| | | */ |
| | | private String scanType; |
| | | @NotNull @DecimalMin("0.000001") private BigDecimal quantity; |
| | | @NotBlank private String deviceCode; |
| | | /** |
| | | * 设å¤ç¼ç ï¼ä¸åå¿
å¡«ï¼äº§çº¿æ«ç 以产线+åºåºåºä½å®ä½ï¼ |
| | | */ |
| | | @Size(max = 64) private String deviceCode; |
| | | private String lineCode; |
| | | @NotNull private Long locationId; |
| | | @NotNull private Long areaId; |
| | |
| | | private Long id; |
| | | private String eventId; |
| | | private String bagCode; |
| | | private String scanType; |
| | | private String batchCode; |
| | | private BigDecimal quantity; |
| | | private String deviceCode; |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.mes.controller.admin.pro.trace; |
| | | |
| | | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| | | import cn.iocoder.yudao.module.mes.service.pro.bagcode.MesProBagCodeService; |
| | | import cn.iocoder.yudao.module.mes.service.pro.batch.MesProBatchService; |
| | | import cn.iocoder.yudao.module.mes.service.pro.pallet.MesProPalletService; |
| | | import io.swagger.v3.oas.annotations.Operation; |
| | | import io.swagger.v3.oas.annotations.Parameter; |
| | | import io.swagger.v3.oas.annotations.tags.Tag; |
| | | import jakarta.annotation.Resource; |
| | | import org.springframework.security.access.prepost.PreAuthorize; |
| | | import org.springframework.validation.annotation.Validated; |
| | | import org.springframework.web.bind.annotation.*; |
| | | |
| | | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; |
| | | |
| | | /** |
| | | * MES æ«ç 追溯 - ç¼ç ç±»åè§£æã |
| | | * |
| | | * <p>ç¼ç ç»ä¸ä¸ºã16 ä½çº¯æ°åãåï¼æ æ³åæåç¼å¤æç±»åï¼BAG-/PL-/PB- çåç¼å·²åæ¶ï¼ï¼ |
| | | * å端æ«ç åå
è°ç¨æ¬æ¥å£æç¼ç 忥å
¶æå±ç±»åï¼åè°ç¨å¯¹åºç±»åç追溯æ¥å£ã |
| | | */ |
| | | @Tag(name = "管çåå° - MES æ«ç 溯æºï¼ç±»åè§£æï¼") |
| | | @RestController |
| | | @RequestMapping("/mes/pro/trace") |
| | | @Validated |
| | | public class MesProTraceResolveController { |
| | | |
| | | @Resource |
| | | private MesProBagCodeService bagCodeService; |
| | | @Resource |
| | | private MesProPalletService palletService; |
| | | @Resource |
| | | private MesProBatchService batchService; |
| | | |
| | | @GetMapping("/resolve-type") |
| | | @Operation(summary = "æ ¹æ®ç¼ç è§£ææº¯æºç±»åï¼bag / pallet / batchï¼åä¸å¹é
è¿å空") |
| | | @Parameter(name = "code", description = "ç¼ç ï¼äºç»´ç å
容ï¼", required = true) |
| | | @PreAuthorize("@ss.hasPermission('mes:pro-bag-code:query')") |
| | | public CommonResult<String> resolveType(@RequestParam("code") String code) { |
| | | if (bagCodeService.getBagCodeByCode(code) != null) { |
| | | return success("bag"); |
| | | } |
| | | if (palletService.getPalletByCode(code) != null) { |
| | | return success("pallet"); |
| | | } |
| | | if (batchService.getBatchByCode(code) != null) { |
| | | return success("batch"); |
| | | } |
| | | return success(null); |
| | | } |
| | | |
| | | } |
| | |
| | | package cn.iocoder.yudao.module.mes.controller.admin.qc.seedquality; |
| | | |
| | | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| | | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| | | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.qc.seedquality.vo.MesQcSeedQualityPageReqVO; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.qc.seedquality.vo.MesQcSeedQualityRespVO; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.qc.seedquality.vo.MesQcSeedQualitySubmitReqVO; |
| | | import cn.iocoder.yudao.module.mes.service.qc.seedquality.MesQcSeedQualityService; |
| | | import io.swagger.v3.oas.annotations.Operation; |
| | |
| | | @RestController @RequestMapping("/mes/qc/seed-quality") @Validated |
| | | public class MesQcSeedQualityController { |
| | | @Resource private MesQcSeedQualityService service; |
| | | @GetMapping("/page") |
| | | @Operation(summary = "è·å¾ç§åè´¨æ£è®°å½å页") |
| | | @PreAuthorize("@ss.hasPermission('mes:qc-seed-quality:query')") |
| | | public CommonResult<PageResult<MesQcSeedQualityRespVO>> getQualityPage(@Valid MesQcSeedQualityPageReqVO pageReqVO) { |
| | | return success(BeanUtils.toBean(service.getQualityPage(pageReqVO), MesQcSeedQualityRespVO.class)); |
| | | } |
| | | |
| | | @PostMapping("/submit") @Operation(summary = "æäº¤ç§åè´¨æ£") |
| | | @PreAuthorize("@ss.hasPermission('mes:qc-seed-quality:submit')") |
| | | public CommonResult<Long> submit(@Valid @RequestBody MesQcSeedQualitySubmitReqVO reqVO) { return success(service.submit(reqVO)); } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.mes.controller.admin.qc.seedquality.vo; |
| | | |
| | | import cn.iocoder.yudao.framework.common.pojo.PageParam; |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | import lombok.EqualsAndHashCode; |
| | | |
| | | @Schema(description = "管çåå° - MES ç§åè´¨æ£è®°å½å页 Request VO") |
| | | @Data |
| | | @EqualsAndHashCode(callSuper = true) |
| | | public class MesQcSeedQualityPageReqVO extends PageParam { |
| | | |
| | | @Schema(description = "è´¨æ£è¢ç ") |
| | | private String code; |
| | | |
| | | @Schema(description = "çäº§æ¹æ¬¡") |
| | | private String batchCode; |
| | | |
| | | @Schema(description = "æ£éªç»æï¼1åæ ¼ 2ä¸åæ ¼") |
| | | private Integer result; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.mes.controller.admin.qc.seedquality.vo; |
| | | |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | |
| | | import java.time.LocalDateTime; |
| | | |
| | | @Schema(description = "管çåå° - MES ç§åè´¨æ£è®°å½ Response VO") |
| | | @Data |
| | | public class MesQcSeedQualityRespVO { |
| | | |
| | | private Long id; |
| | | private String code; |
| | | private Long itemId; |
| | | private Long batchId; |
| | | private String batchCode; |
| | | private Integer result; |
| | | private String reason; |
| | | private Long inspectorId; |
| | | private LocalDateTime inspectedAt; |
| | | private LocalDateTime createTime; |
| | | } |
| | |
| | | @Data |
| | | public class MesQcSeedQualitySubmitReqVO { |
| | | @NotBlank private String code; |
| | | @NotNull private Long itemId; |
| | | private String batchCode; |
| | | @NotEmpty @Valid private List<Indicator> indicators; |
| | | private String reason; |
| | | /** ç®æ åæ ¼åºç¼å·ï¼è´¨æ£åæ ¼åå
¥è¯¥ä»åºï¼ï¼å¿
é¡»æ¯ä»åºç±»åä¸ºåæ ¼åº(20)çä»åº */ |
| | | @NotNull private Long qualifiedWarehouseId; |
| | | @Data public static class Indicator { |
| | | @NotBlank private String code; |
| | | @NotNull @DecimalMin("0") private BigDecimal value; |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.mes.controller.admin.trace.batch; |
| | | |
| | | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| | | import cn.iocoder.yudao.module.mes.controller.pub.trace.vo.MesProTracePublicRespVO; |
| | | import cn.iocoder.yudao.module.mes.service.trace.MesProTracePublicService; |
| | | import io.swagger.v3.oas.annotations.Operation; |
| | | import io.swagger.v3.oas.annotations.Parameter; |
| | | import io.swagger.v3.oas.annotations.tags.Tag; |
| | | import jakarta.annotation.Resource; |
| | | import jakarta.validation.constraints.NotBlank; |
| | | import org.springframework.security.access.prepost.PreAuthorize; |
| | | import org.springframework.validation.annotation.Validated; |
| | | import org.springframework.web.bind.annotation.GetMapping; |
| | | import org.springframework.web.bind.annotation.RequestMapping; |
| | | import org.springframework.web.bind.annotation.RequestParam; |
| | | import org.springframework.web.bind.annotation.RestController; |
| | | |
| | | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; |
| | | |
| | | @Tag(name = "管çåå° - MES æ¹æ¬¡è¿½æº¯") |
| | | @RestController |
| | | @RequestMapping("/mes/trace/batch") |
| | | @Validated |
| | | public class MesTraceBatchController { |
| | | |
| | | @Resource |
| | | private MesProTracePublicService traceService; |
| | | |
| | | @GetMapping("/detail") |
| | | @Operation(summary = "æ¥è¯¢ç»ä¸æ¹æ¬¡è¿½æº¯è¯¦æ
") |
| | | @Parameter(name = "code", description = "æ¹æ¬¡ç ãä¸´æ¶æ¹æ¬¡ç ãè¢ç ææçç ", required = true, |
| | | example = "BAG-202608280001") |
| | | @PreAuthorize("@ss.hasPermission('mes:trace-batch:query')") |
| | | public CommonResult<MesProTracePublicRespVO> getBatchTraceDetail( |
| | | @RequestParam("code") @NotBlank(message = "追溯ç ä¸è½ä¸ºç©º") String code) { |
| | | return success(traceService.queryTrace(code)); |
| | | } |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo; |
| | | |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.time.LocalDateTime; |
| | | |
| | | @Schema(description = "管çåå° - MES æ¹æ¬¡åºå
¥åºæµæ°´ï¼ç§åæµåï¼Response VO") |
| | | @Data |
| | | public class MesWmBatchFlowRespVO { |
| | | |
| | | @Schema(description = "äºå¡ç±»åï¼1-å
¥åº 2-åºåº", example = "2") |
| | | private Integer type; |
| | | |
| | | @Schema(description = "ä¸å¡ç±»åï¼è§ MesBizTypeConstantsï¼å¦ 119-éå®åºåºã124-产å产åºï¼", example = "119") |
| | | private Integer bizType; |
| | | |
| | | @Schema(description = "æ¥æºä¸å¡åå·", example = "SL_20260901002") |
| | | private String bizCode; |
| | | |
| | | @Schema(description = "æ¬æ¬¡å卿°éï¼åºåºä¸ºè´æ°ï¼", example = "-1") |
| | | private BigDecimal quantity; |
| | | |
| | | @Schema(description = "äºå¡åçæ¶é´") |
| | | private LocalDateTime transactionTime; |
| | | |
| | | @Schema(description = "ä»åºåç§°", example = "æååæ ¼åº") |
| | | private String warehouseName; |
| | | |
| | | @Schema(description = "åºåºåç§°", example = "æååæ ¼åºåº") |
| | | private String locationName; |
| | | |
| | | @Schema(description = "åºä½åç§°", example = "æååæ ¼åºä½") |
| | | private String areaName; |
| | | |
| | | @Schema(description = "客æ·åç§°ï¼éå®åºåº/éå®éè´§æ¶ï¼", example = "客æ·A") |
| | | private String clientName; |
| | | |
| | | } |
| | |
| | | import cn.iocoder.yudao.module.mes.controller.admin.wm.materialstock.vo.MesWmMaterialStockPageReqVO; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.wm.materialstock.vo.MesWmMaterialStockRespVO; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.wm.materialstock.vo.MesWmMaterialStockListReqVO; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.wm.materialstock.vo.MesWmMaterialStockBagPageReqVO; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.wm.materialstock.vo.MesWmMaterialStockBagRespVO; |
| | | import cn.iocoder.yudao.module.mes.dal.mysql.wm.materialstockbag.MesWmMaterialStockBagMapper; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.wm.materialstock.vo.MesWmStockSummaryRespVO; |
| | | import cn.iocoder.yudao.module.srm.api.supplier.SrmSupplierApi; |
| | | import cn.iocoder.yudao.module.srm.api.supplier.dto.SrmSupplierRespDTO; |
| | |
| | | import cn.iocoder.yudao.module.mdm.api.item.dto.MdmItemRespDTO; |
| | | |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.materialstock.MesWmMaterialStockDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.materialstockbag.MesWmMaterialStockBagDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseAreaDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseLocationDO; |
| | |
| | | private MesWmWarehouseAreaService areaService; |
| | | @Resource |
| | | private SrmSupplierApi srmSupplierApi; |
| | | @Resource |
| | | private MesWmMaterialStockBagMapper materialStockBagMapper; |
| | | |
| | | @GetMapping("/get") |
| | | @Operation(summary = "è·å¾åºåè®°å½") |
| | |
| | | @Valid MesWmMaterialStockPageReqVO pageReqVO) { |
| | | PageResult<MesWmMaterialStockDO> pageResult = materialStockService.getMaterialStockPage(pageReqVO); |
| | | return success(new PageResult<>(buildRespVOList(pageResult.getList()), pageResult.getTotal())); |
| | | } |
| | | |
| | | @GetMapping("/bag-details") |
| | | @Operation(summary = "æ¥è¯¢åºåè¢ç æç»") |
| | | @PreAuthorize("@ss.hasPermission('mes:wm-material-stock:query')") |
| | | public CommonResult<PageResult<MesWmMaterialStockBagRespVO>> getMaterialStockBagDetails( |
| | | @Valid MesWmMaterialStockBagPageReqVO pageReqVO) { |
| | | PageResult<MesWmMaterialStockBagRespVO> result = new PageResult<>(); |
| | | PageResult<cn.iocoder.yudao.module.mes.dal.dataobject.wm.materialstockbag.MesWmMaterialStockBagDO> page = |
| | | materialStockBagMapper.selectPage(pageReqVO); |
| | | return success(new PageResult<>(BeanUtils.toBean(page.getList(), MesWmMaterialStockBagRespVO.class), page.getTotal())); |
| | | } |
| | | |
| | | @PutMapping("/update-frozen") |
| | |
| | | convertSet(list, MesWmMaterialStockDO::getLocationId)); |
| | | Map<Long, MesWmWarehouseAreaDO> areaMap = areaService.getWarehouseAreaMap( |
| | | convertSet(list, MesWmMaterialStockDO::getAreaId)); |
| | | Map<Long, Long> bagCountMap = materialStockBagMapper.selectListByMaterialStockIds( |
| | | convertSet(list, MesWmMaterialStockDO::getId)).stream() |
| | | .collect(Collectors.groupingBy(MesWmMaterialStockBagDO::getMaterialStockId, Collectors.counting())); |
| | | Map<Long, SrmSupplierRespDTO> vendorMap = srmSupplierApi.getSupplierList( |
| | | convertSet(list, MesWmMaterialStockDO::getVendorId)).getCheckedData().stream() |
| | | .collect(Collectors.toMap(SrmSupplierRespDTO::getId, s -> s)); |
| | |
| | | area -> vo.setAreaName(area.getName())); |
| | | MapUtils.findAndThen(vendorMap, vo.getVendorId(), |
| | | vendor -> vo.setVendorName(vendor.getName())); |
| | | vo.setBagCount(bagCountMap.getOrDefault(vo.getId(), 0L)); |
| | | vo.setBagDetailSupported(bagCountMap.containsKey(vo.getId())); |
| | | // 计ç®å¯ç¨é = å¨åºæ°é - å»ç»æ°é - å ç¨é |
| | | BigDecimal quantity = vo.getQuantity() != null ? vo.getQuantity() : BigDecimal.ZERO; |
| | | BigDecimal frozenQty = vo.getFrozenQuantity() != null ? vo.getFrozenQuantity() : BigDecimal.ZERO; |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.mes.controller.admin.wm.materialstock.vo; |
| | | |
| | | import cn.iocoder.yudao.framework.common.pojo.PageParam; |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | import lombok.EqualsAndHashCode; |
| | | |
| | | @Schema(description = "管çåå° - åºåè¢ç æç»å页 Request VO") |
| | | @Data |
| | | @EqualsAndHashCode(callSuper = true) |
| | | public class MesWmMaterialStockBagPageReqVO extends PageParam { |
| | | |
| | | @Schema(description = "åºåæ±æ»è®°å½ID", requiredMode = Schema.RequiredMode.REQUIRED) |
| | | private Long materialStockId; |
| | | |
| | | @Schema(description = "è¢ç ") |
| | | private String bagCode; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.mes.controller.admin.wm.materialstock.vo; |
| | | |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.materialstockbag.MesWmMaterialStockBagDO; |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.time.LocalDateTime; |
| | | |
| | | @Schema(description = "管çåå° - åºåè¢ç æç» Response VO") |
| | | @Data |
| | | public class MesWmMaterialStockBagRespVO { |
| | | private Long id; |
| | | private Long materialStockId; |
| | | private Long bagCodeId; |
| | | private String bagCode; |
| | | private Long itemId; |
| | | private Long batchId; |
| | | private String batchCode; |
| | | private Long warehouseId; |
| | | private Long locationId; |
| | | private Long areaId; |
| | | private Integer stockState; |
| | | private Integer status; |
| | | private BigDecimal quantity; |
| | | private Boolean frozen; |
| | | private LocalDateTime inboundTime; |
| | | private LocalDateTime outboundTime; |
| | | } |
| | |
| | | @Schema(description = "ä»åºç¼å·") |
| | | private Long warehouseId; |
| | | |
| | | @Schema(description = "ä»åºç±»åï¼10æååºï¼20åæ ¼åºï¼æç±»åè¿æ»¤ä»åºï¼ä¸ warehouseId äºéä¸ï¼", example = "20") |
| | | private Integer warehouseType; |
| | | |
| | | @Schema(description = "åºåºç¼å·") |
| | | private Long locationId; |
| | | |
| | |
| | | @Schema(description = "ä»åºç¼å·", example = "1") |
| | | private Long warehouseId; |
| | | |
| | | @Schema(description = "ä»åºç±»åï¼10æååºï¼20åæ ¼åºï¼æç±»åè¿æ»¤ä»åºï¼ä¸ warehouseId äºéä¸ï¼", example = "20") |
| | | private Integer warehouseType; |
| | | |
| | | @Schema(description = "åºåºç¼å·", example = "1") |
| | | private Long locationId; |
| | | |
| | |
| | | @ExcelProperty("æ¹æ¬¡å·") |
| | | private String batchCode; |
| | | |
| | | @Schema(description = "å½åè¢ç æ°é", example = "10") |
| | | private Long bagCount; |
| | | |
| | | @Schema(description = "æ¯å¦åå¨è¢ç æç»", example = "true") |
| | | private Boolean bagDetailSupported; |
| | | |
| | | @Schema(description = "ä»åºç¼å·", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") |
| | | private Long warehouseId; |
| | | |
| | |
| | | @ExcelProperty("åºåºæä½äºº") |
| | | private String outboundUserName; |
| | | |
| | | @Schema(description = "éå®è®¢åå·", example = "SO2026030001") |
| | | @ExcelProperty("éå®è®¢åå·") |
| | | private String salesOrderCode; |
| | | |
| | | @Schema(description = "åºåºæ¥æ") |
| | | @ExcelProperty("åºåºæ¥æ") |
| | | private LocalDateTime salesDate; |
| | |
| | | @NotNull(message = "客æ·ä¸è½ä¸ºç©º") |
| | | private Long clientId; |
| | | |
| | | @Schema(description = "éå®è®¢åå·", example = "SO2026030001") |
| | | private String salesOrderCode; |
| | | |
| | | @Schema(description = "åºåºæ¥æ", requiredMode = Schema.RequiredMode.REQUIRED) |
| | | @NotNull(message = "åºåºæ¥æä¸è½ä¸ºç©º") |
| | | private LocalDateTime salesDate; |
| | |
| | | @Schema(description = "éè´§ååç§°", example = "éå®éè´§") |
| | | private String name; |
| | | |
| | | @Schema(description = "éå®è®¢å ID", example = "1") |
| | | private Long saleOrderId; |
| | | |
| | | @Schema(description = "éå®è®¢åç¼å·", example = "SO202603010001") |
| | | private String salesOrderCode; |
| | | |
| | | @Schema(description = "å®¢æ· ID", example = "1") |
| | | private Long clientId; |
| | | |
| | |
| | | @Schema(description = "éè´§ååç§°", requiredMode = Schema.RequiredMode.REQUIRED, example = "éå®éè´§") |
| | | private String name; |
| | | |
| | | @Schema(description = "éå®è®¢å ID", example = "1") |
| | | private Long saleOrderId; |
| | | |
| | | @Schema(description = "éå®è®¢åç¼å·", example = "SO202603010001") |
| | | private String salesOrderCode; |
| | | |
| | | @Schema(description = "å®¢æ· ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") |
| | | private Long clientId; |
| | | |
| | |
| | | @NotBlank(message = "éè´§ååç§°ä¸è½ä¸ºç©º") |
| | | private String name; |
| | | |
| | | @Schema(description = "éå®è®¢å ID", example = "1") |
| | | private Long saleOrderId; |
| | | |
| | | @Schema(description = "éå®è®¢åç¼å·", example = "SO202603010001") |
| | | private String salesOrderCode; |
| | | |
| | | @Schema(description = "å®¢æ· ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") |
| | | @NotNull(message = "å®¢æ· ID ä¸è½ä¸ºç©º") |
| | | private Long clientId; |
| | |
| | | return success(true); |
| | | } |
| | | |
| | | @PostMapping("/generate-from-sale-order") |
| | | @Operation(summary = "ä»éå®è®¢åçæåè´§éç¥å") |
| | | @PreAuthorize("@ss.hasPermission('mes:wm-sales-notice:create')") |
| | | public CommonResult<Long> generateFromSaleOrder(@RequestBody Map<String, Long> params) { |
| | | Long saleOrderId = params.get("saleOrderId"); |
| | | return success(salesNoticeService.generateSalesNoticeFromSaleOrder(saleOrderId)); |
| | | } |
| | | |
| | | @PostMapping("/generate-product-sales") |
| | | @Operation(summary = "ä»åè´§éç¥åçæéå®åºåºå") |
| | | @Parameter(name = "id", description = "åè´§éç¥åç¼å·", required = true) |
| | |
| | | @Schema(description = "éç¥ååç§°", example = "æµè¯åè´§éç¥") |
| | | private String name; |
| | | |
| | | @Schema(description = "éå®è®¢åç¼å·", example = "SO202603010001") |
| | | private String saleOrderCode; |
| | | |
| | | @Schema(description = "客æ·ç¼å·", example = "1") |
| | | private Long clientId; |
| | | |
| | |
| | | @ExcelProperty("客æ·åç§°") |
| | | private String clientName; |
| | | |
| | | @Schema(description = "éå®è®¢åID", example = "1") |
| | | private Long saleOrderId; |
| | | |
| | | @Schema(description = "éå®è®¢åå·", example = "SO202603010001") |
| | | @ExcelProperty("éå®è®¢åå·") |
| | | private String saleOrderCode; |
| | | |
| | | @Schema(description = "åè´§æ¥æ", requiredMode = Schema.RequiredMode.REQUIRED) |
| | | @ExcelProperty("åè´§æ¥æ") |
| | | private LocalDateTime salesDate; |
| | |
| | | @NotNull(message = "客æ·ç¼å·ä¸è½ä¸ºç©º") |
| | | private Long clientId; |
| | | |
| | | @Schema(description = "éå®è®¢åID", example = "1") |
| | | private Long saleOrderId; |
| | | |
| | | @Schema(description = "éå®è®¢åå·", example = "SO202603010001") |
| | | private String saleOrderCode; |
| | | |
| | | @Schema(description = "åè´§æ¥æ", requiredMode = Schema.RequiredMode.REQUIRED) |
| | | @NotNull(message = "åè´§æ¥æä¸è½ä¸ºç©º") |
| | | private LocalDateTime salesDate; |
| | |
| | | @Schema(description = "åè´§éç¥åç¼å·", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") |
| | | private Long noticeId; |
| | | |
| | | @Schema(description = "éå®è®¢åæç»ID", example = "1") |
| | | private Long saleOrderItemId; |
| | | |
| | | @Schema(description = "ç©æç¼å·", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") |
| | | private Long itemId; |
| | | |
| | |
| | | @NotNull(message = "åè´§éç¥åç¼å·ä¸è½ä¸ºç©º") |
| | | private Long noticeId; |
| | | |
| | | @Schema(description = "éå®è®¢åæç»ID", example = "1") |
| | | private Long saleOrderItemId; |
| | | |
| | | @Schema(description = "ç©æç¼å·", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") |
| | | @NotNull(message = "ç©æç¼å·ä¸è½ä¸ºç©º") |
| | | private Long itemId; |
| | |
| | | return "æªç¥"; |
| | | } |
| | | switch (bizType) { |
| | | case MesBizTypeConstants.QC_SEED_QUALITY: |
| | | return "ç§åè´¨æ£"; |
| | | case MesBizTypeConstants.WM_ITEM_RECEIPT_CANCEL: |
| | | return "éè´å
¥åºåæ¶"; |
| | | case MesBizTypeConstants.WM_STOCK_TAKING: |
| | | return "çç¹è°æ´"; |
| | | case MesBizTypeConstants.WM_STOCK_ADJUST_IN: |
| | | return "èªå®ä¹å
¥åº"; |
| | | case MesBizTypeConstants.WM_STOCK_ADJUST_OUT: |
| | |
| | | @Schema(description = "æ¹æ¬¡å·", example = "BATCH001") |
| | | private String batchCode; |
| | | |
| | | @Schema(description = "è¢ç ", example = "BG202608180001") |
| | | private String bagCode; |
| | | |
| | | @Schema(description = "ä»åºID", example = "1") |
| | | private Long warehouseId; |
| | | |
| | |
| | | @Schema(description = "æ¹æ¬¡å·", example = "BATCH001") |
| | | private String batchCode; |
| | | |
| | | @Schema(description = "è¢ç ID", example = "1") |
| | | private Long bagCodeId; |
| | | |
| | | @Schema(description = "è¢ç ", example = "BG202608180001") |
| | | private String bagCode; |
| | | |
| | | // ========== åºåä½ç½® ========== |
| | | |
| | | @Schema(description = "ä»åºID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") |
| | |
| | | @Schema(description = "æ¯å¦å»ç»", example = "false") |
| | | private Boolean frozen; |
| | | |
| | | @Schema(description = "ä»åºç±»åï¼10æååº 20åæ ¼åº", example = "20") |
| | | private Integer type; |
| | | |
| | | } |
| | |
| | | @ExcelProperty("æ¯å¦å»ç»") |
| | | private Boolean frozen; |
| | | |
| | | @Schema(description = "ä»åºç±»åï¼10æååº 20åæ ¼åº", requiredMode = Schema.RequiredMode.REQUIRED, example = "20") |
| | | @ExcelProperty("ä»åºç±»å") |
| | | private Integer type; |
| | | |
| | | @Schema(description = "夿³¨", example = "夿³¨") |
| | | @ExcelProperty("夿³¨") |
| | | private String remark; |
| | |
| | | @NotNull(message = "æ¯å¦å»ç»ä¸è½ä¸ºç©º") |
| | | private Boolean frozen; |
| | | |
| | | @Schema(description = "ä»åºç±»åï¼10æååº 20åæ ¼åº", requiredMode = Schema.RequiredMode.REQUIRED, example = "20") |
| | | @NotNull(message = "ä»åºç±»åä¸è½ä¸ºç©º") |
| | | private Integer type; |
| | | |
| | | @Schema(description = "夿³¨", example = "夿³¨") |
| | | private String remark; |
| | | |
| | |
| | | package cn.iocoder.yudao.module.mes.controller.pub.trace.vo; |
| | | |
| | | import cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo.MesWmBatchFlowRespVO; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo.MesWmBatchProcessTraceRespVO; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo.MesWmBatchPurchaseSourceRespVO; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo.MesWmBatchSalesTargetRespVO; |
| | |
| | | * H5 æ«ç æº¯æº - å
¨ç¨æº¯æºä¿¡æ¯ Response VO |
| | | * <p> |
| | | * 以ãä¿¡æ¯åºåãæ¨¡ååç»ç»ï¼æ ¸å¿ä¿¡æ¯ï¼åç§/æ¹æ¬¡/人å/è´¨æ£/å
¥åºï¼å§ç»è¿åï¼ |
| | | * éè´æ¥æºãéå®å»åãå å·¥æµè½¬ä¸ºå¯éæ©å±åºåï¼ææ°æ®æé空ï¼ãåç»æ°å¢æ°æ®æºæå䏿¨¡å¼è¿½å åºååæ®µã |
| | | * éè´æ¥æºãéå®å»åãç§åæµåï¼æ¹æ¬¡åºå
¥åºæµæ°´ï¼ãå å·¥æµè½¬ä¸ºå¯éæ©å±åºåï¼ææ°æ®æé空ï¼ãåç»æ°å¢æ°æ®æºæå䏿¨¡å¼è¿½å åºååæ®µã |
| | | */ |
| | | @Schema(description = "H5 æ«ç æº¯æº - å
¨ç¨æº¯æºä¿¡æ¯ Response VO") |
| | | @Data |
| | |
| | | @Schema(description = "请æ±ç追溯ç ï¼åå§æ«ç å¼ï¼", example = "PC20260828twoITEM_001") |
| | | private String requestCode; |
| | | |
| | | @Schema(description = "æ¯å¦å·²å½å
¥çäº§æ¹æ¬¡ï¼false 表示è¢ç /æçå·²çæä½å°æªå½å
¥æ¹æ¬¡ï¼æ¤æ¶ä»
è¿ååç§ä¿¡æ¯ï¼", example = "true") |
| | | private Boolean batchBound; |
| | | |
| | | // ====== åç§ä¿¡æ¯åºå ====== |
| | | @Schema(description = "åç§ç¼ç ") |
| | | private String itemCode; |
| | |
| | | |
| | | @Schema(description = "åç§è§æ ¼") |
| | | private String itemSpecification; |
| | | |
| | | @Schema(description = "åç§è®¡éåä½åç§°", example = "48åå
") |
| | | private String itemUnitMeasureName; |
| | | |
| | | // ====== çäº§æ¹æ¬¡ä¿¡æ¯åºå ====== |
| | | @Schema(description = "æ¹æ¬¡å·") |
| | |
| | | @Schema(description = "éå®å»åï¼å¯éï¼") |
| | | private List<MesWmBatchSalesTargetRespVO> salesTargets; |
| | | |
| | | @Schema(description = "ç§åæµåä¿¡æ¯ï¼æ¹æ¬¡åºå
¥åºæµæ°´ï¼ç产å
¥åº â éå®åºåºçï¼å¯éï¼") |
| | | private List<MesWmBatchFlowRespVO> seedFlows; |
| | | |
| | | @Schema(description = "å å·¥æµè½¬ï¼å¯éï¼") |
| | | private List<MesWmBatchProcessTraceRespVO> processTraces; |
| | | |
| | | @Schema(description = "追溯æ¶é´çº¿") |
| | | private List<TimelineVO> timeline; |
| | | |
| | | @Schema(description = "追溯å³çæè¦") |
| | | private DecisionVO decision; |
| | | |
| | | @Schema(description = "追溯æ¶é´çº¿äºä»¶") |
| | | @Data |
| | | public static class TimelineVO { |
| | | @Schema(description = "é¶æ®µ") |
| | | private String stage; |
| | | @Schema(description = "äºä»¶ç±»å") |
| | | private String eventType; |
| | | @Schema(description = "äºä»¶åç§°") |
| | | private String eventName; |
| | | @Schema(description = "äºä»¶æ¶é´") |
| | | private LocalDateTime eventTime; |
| | | @Schema(description = "æ°é") |
| | | private BigDecimal quantity; |
| | | @Schema(description = "ç¶æ") |
| | | private String status; |
| | | } |
| | | |
| | | @Schema(description = "追溯å³çæè¦") |
| | | @Data |
| | | public static class DecisionVO { |
| | | @Schema(description = "è´¨éæ¯å¦åå¨é£é©") |
| | | private Boolean qualityRisk; |
| | | @Schema(description = "åºåå
¥åºæ°é") |
| | | private BigDecimal inboundQuantity; |
| | | @Schema(description = "éå®å»åæ°é") |
| | | private Integer salesTargetCount; |
| | | @Schema(description = "æ¶è´¹è
æ«ç 次æ°") |
| | | private Long consumerScanCount; |
| | | @Schema(description = "é£é©ç级") |
| | | private String riskLevel; |
| | | } |
| | | |
| | | @Schema(description = "ç产人å") |
| | | @Data |
| | | public static class WorkerVO { |
| | |
| | | private String batchCode; |
| | | private Long palletId; |
| | | private String palletCode; |
| | | /** |
| | | * åç§ï¼ç©æï¼ç¼å·ï¼çææ°æ®å
æ¶éå®ï¼å
³è mdm_itemï¼ |
| | | */ |
| | | private Long itemId; |
| | | /** |
| | | * åç§ç¼ç ï¼åä½ï¼ |
| | | */ |
| | | private String itemCode; |
| | | /** |
| | | * åç§åç§°ï¼åä½ï¼ |
| | | */ |
| | | private String itemName; |
| | | private Integer status; |
| | | private Integer qcStatus; |
| | | private LocalDateTime printTime; |
| | | private LocalDateTime cancelTime; |
| | | private String cancelReason; |
| | |
| | | /** |
| | | * MES çäº§æ¹æ¬¡ DO |
| | | * <p> |
| | | * æ¹æ¬¡ç产管çï¼ä¸è¢ä¸ç 模åï¼ï¼å
³èåç§ï¼MDM ç©æï¼ã产线ï¼äº§çº¿ç»´æ¤ï¼ä¸ç产人åï¼äººåé
ç½®è§ {@link MesProBatchWorkerDO}ï¼ï¼è´£ä»»è½å®å°äººã |
| | | * æ¹æ¬¡å·èªå¨çæï¼ç¼ç è§åå
嫿¥æã产线ç¼ç ãåç§ç¼ç ãæµæ°´å·çè¦ç´ ï¼å¹¶ä¸è¢ç ï¼ä¸è¢ä¸ç ï¼ãæçç èªå¨å
³èã |
| | | * æ¹æ¬¡ç产管çï¼ä¸è¢ä¸ç 模åï¼ï¼å
³è产线ï¼äº§çº¿ç»´æ¤ï¼ä¸ç产人åï¼äººåé
ç½®è§ {@link MesProBatchWorkerDO}ï¼ï¼è´£ä»»è½å®å°äººã |
| | | * åç§å·²ä¸æ²å°è¢ç æ°æ®å
ï¼èµç 管çï¼ï¼æ¹æ¬¡ä¸åç»å®åç§ã |
| | | * æ¹æ¬¡å·èªå¨çæï¼ç¼ç è§åå
嫿¥æã产线ç¼ç ãæµæ°´å·çè¦ç´ ï¼å¹¶ä¸è¢ç ï¼ä¸è¢ä¸ç ï¼ãæçç èªå¨å
³èã |
| | | * |
| | | * @author è¶
级管çå |
| | | */ |
| | |
| | | @TableId |
| | | private Long id; |
| | | /** |
| | | * æ¹æ¬¡å·ï¼èªå¨çæï¼åç¼ + æ¥æ + 产线ç¼ç + åç§ç¼ç + æµæ°´å·ï¼è¡¥å½ä¸å¡ä¿¡æ¯åçæï¼ |
| | | * æ¹æ¬¡å·ï¼èªå¨çæï¼åç¼ + æ¥æ + 产线ç¼ç + æµæ°´å·ï¼è¡¥å½ä¸å¡ä¿¡æ¯åçæï¼ |
| | | */ |
| | | private String code; |
| | | /** |
| | |
| | | */ |
| | | private String tempCode; |
| | | /** |
| | | * åç§ï¼äº§åç©æï¼ç¼å· |
| | | * åç§ï¼äº§åç©æï¼ç¼å·ï¼å·²åºå¼ï¼ |
| | | * <p> |
| | | * å
³è {@link cn.iocoder.yudao.module.mes.dal.dataobject.mdm.MesMdmItemDO#getId()} |
| | | * <p> |
| | | * åç§å·²ä¸æ²å°è¢ç æ°æ®å
ï¼{@code mes_pro_bag_code.item_id}ï¼ï¼æ°æ¹æ¬¡ä¸ååå
¥ï¼ä»
ä¿çä¾å岿¹æ¬¡è¿½æº¯åé |
| | | */ |
| | | private Long itemId; |
| | | /** |
| | |
| | | */ |
| | | private String lineCode; |
| | | /** |
| | | * 产线åç§°ï¼åä½åï¼ç± {@link #lineId} åå¡«ï¼ |
| | | * 产线åç§°ï¼åä½åï¼ç± {@link #lineId} åå¡«ï¼é¡µé¢å±ç¤ºä¸ºãå å·¥åä½ãï¼ |
| | | */ |
| | | private String lineName; |
| | | /** |
| | | * å å·¥çç»ï¼æå·¥å¡«åï¼ |
| | | */ |
| | | private String processingTeam; |
| | | /** |
| | | * çäº§æ¥æ |
| | | */ |
| | | private LocalDateTime produceDate; |
| | |
| | | */ |
| | | private Integer bagCount; |
| | | /** |
| | | * æè¿å
¥åºæ«ç äºä»¶ç¼å·ï¼æ´ææ«ç å
¥åºåååï¼ç¨äºé²éå¤å
¥åºï¼ |
| | | */ |
| | | private Long inboundEventId; |
| | | /** |
| | | * æè¿å
¥åºæ¶é´ |
| | | */ |
| | | private java.time.LocalDateTime inboundTime; |
| | | /** |
| | | * æ¯å¦èªå¨çæï¼æææè¢ç 累计éå¼çæï¼å®¹éåºå®ä¸ºéå¼ï¼ |
| | | */ |
| | | private Boolean autoGenerated; |
| | |
| | | public class MesProScanEventDO extends BaseDO { |
| | | @TableId private Long id; |
| | | private String eventId; |
| | | /** |
| | | * æ«ç å
容ï¼è¢ç / æçç / æ¹æ¬¡ç çç å¼ï¼å«ä¸´æ¶ç ï¼ |
| | | */ |
| | | private String bagCode; |
| | | /** |
| | | * æ«ç ç±»åï¼BAG è¢ç / PALLET æçç / BATCH æ¹æ¬¡ç |
| | | */ |
| | | private String scanType; |
| | | private Long bagCodeId; |
| | | private Long batchId; |
| | | private String batchCode; |
| | |
| | | @TableId private Long id; |
| | | private String code; |
| | | private Long itemId; |
| | | /** çäº§æ¹æ¬¡ ID */ |
| | | private Long batchId; |
| | | private String batchCode; |
| | | private Integer result; |
| | | private String reason; |
| | |
| | | import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.md.workstation.MesMdWorkstationDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.pro.batch.MesProBatchDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.pro.task.MesProTaskDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder.MesProWorkOrderDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.tm.tool.MesTmToolDO; |
| | |
| | | @TableId |
| | | private Long id; |
| | | /** |
| | | * 对åºçäº§æ¹æ¬¡ ID |
| | | * |
| | | * å
³è {@link MesProBatchDO#getId()} |
| | | */ |
| | | private Long proBatchId; |
| | | /** |
| | | * æ¹æ¬¡ç¼ç |
| | | */ |
| | | private String code; |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.mes.dal.dataobject.wm.materialstockbag; |
| | | |
| | | import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; |
| | | import com.baomidou.mybatisplus.annotation.KeySequence; |
| | | import com.baomidou.mybatisplus.annotation.TableId; |
| | | import com.baomidou.mybatisplus.annotation.TableName; |
| | | import lombok.*; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.time.LocalDateTime; |
| | | |
| | | /** |
| | | * MES åºåè¢ç æç» DO |
| | | */ |
| | | @TableName("mes_wm_material_stock_bag") |
| | | @KeySequence("mes_wm_material_stock_bag_seq") |
| | | @Data |
| | | @EqualsAndHashCode(callSuper = true) |
| | | @ToString(callSuper = true) |
| | | @Builder |
| | | @NoArgsConstructor |
| | | @AllArgsConstructor |
| | | public class MesWmMaterialStockBagDO extends BaseDO { |
| | | |
| | | @TableId |
| | | private Long id; |
| | | private Long materialStockId; |
| | | private Long bagCodeId; |
| | | private String bagCode; |
| | | private Long itemId; |
| | | private Long batchId; |
| | | private String batchCode; |
| | | private Long vendorId; |
| | | private Long warehouseId; |
| | | private Long locationId; |
| | | private Long areaId; |
| | | private Integer stockState; |
| | | private Integer status; |
| | | private BigDecimal quantity; |
| | | private Boolean frozen; |
| | | private Long lastTransactionId; |
| | | private LocalDateTime inboundTime; |
| | | private LocalDateTime outboundTime; |
| | | } |
| | |
| | | */ |
| | | private String clientName; |
| | | /** |
| | | * éå®è®¢åID |
| | | */ |
| | | private Long saleOrderId; |
| | | /** |
| | | * éå®è®¢åå· |
| | | */ |
| | | private String salesOrderCode; |
| | | /** |
| | | * åè´§éç¥å ID |
| | | * |
| | | * å
³è {@link MesWmSalesNoticeDO#getId()} |
| | |
| | | */ |
| | | private Long salesId; |
| | | /** |
| | | * éå®è®¢åæç»ID |
| | | */ |
| | | private Long saleOrderItemId; |
| | | /** |
| | | * åè´§éç¥åè¡ID |
| | | * |
| | | * å
³è {@link MesWmSalesNoticeLineDO#getId()} |
| | |
| | | */ |
| | | private String name; |
| | | /** |
| | | * éå®è®¢å ID |
| | | */ |
| | | private Long saleOrderId; |
| | | /** |
| | | * éå®è®¢åç¼å· |
| | | */ |
| | | private String salesOrderCode; |
| | | /** |
| | | * å®¢æ· ID |
| | | * |
| | | * å
³è CRM å®¢æ· {@link cn.iocoder.yudao.module.crm.api.customer.dto.CrmCustomerRespDTO#getId()} |
| | |
| | | */ |
| | | private Long clientId; |
| | | /** |
| | | * éå®è®¢åID |
| | | */ |
| | | private Long saleOrderId; |
| | | /** |
| | | * éå®è®¢åå· |
| | | */ |
| | | private String saleOrderCode; |
| | | /** |
| | | * åè´§æ¥æ |
| | | */ |
| | | private LocalDateTime salesDate; |
| | |
| | | */ |
| | | private Long noticeId; |
| | | /** |
| | | * éå®è®¢åæç»ID |
| | | */ |
| | | private Long saleOrderItemId; |
| | | /** |
| | | * ç©æç¼å· |
| | | * |
| | | * å
³è {@link MesMdItemDO#getId()} |
| | |
| | | |
| | | import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.pro.bagcode.MesProBagCodeDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.pro.batch.MesProBatchDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.pro.pallet.MesProPalletDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder.MesProWorkOrderDO; |
| | | import com.baomidou.mybatisplus.annotation.KeySequence; |
| | | import com.baomidou.mybatisplus.annotation.TableId; |
| | |
| | | @TableId |
| | | private Long id; |
| | | /** |
| | | * çäº§æ¹æ¬¡ ID |
| | | * |
| | | * å
³è {@link MesProBatchDO#getId()} |
| | | */ |
| | | private Long proBatchId; |
| | | /** |
| | | * è¢ç ID |
| | | * |
| | | * å
³è {@link MesProBagCodeDO#getId()} |
| | | */ |
| | | private Long bagCodeId; |
| | | /** |
| | | * æç ID |
| | | * |
| | | * å
³è {@link MesProPalletDO#getId()} |
| | | */ |
| | | private Long palletId; |
| | | /** |
| | | * éå®åºåºå ID |
| | | */ |
| | | private Long salesId; |
| | | /** |
| | | * æ¹æ¬¡ UUIDï¼ç¨äºæ è®°å䏿¹æ¬¡çæç SN ç ï¼ |
| | | */ |
| | | private String uuid; |
| | |
| | | * å
³è {@link MesWmBatchDO#getCode()} |
| | | */ |
| | | private String batchCode; |
| | | /** è¢ç ID */ |
| | | private Long bagCodeId; |
| | | /** è¢ç */ |
| | | private String bagCode; |
| | | |
| | | // ==================== åºåä½ç½® ==================== |
| | | |
| | |
| | | */ |
| | | private Boolean frozen; |
| | | /** |
| | | * ä»åºç±»å |
| | | * |
| | | * å
³è {@link cn.iocoder.yudao.module.mes.enums.wm.MesWmWarehouseTypeEnum}ï¼ |
| | | * 10 æååºï¼å¦èæçº¿è¾¹ä»åºï¼åæ¾æ«ç å
¥åºå¾
æ£/æååºåï¼ï¼20 åæ ¼åºï¼åæ¾è´¨æ£åæ ¼ã坿£è´§åºåï¼ |
| | | */ |
| | | private Integer type; |
| | | /** |
| | | * 夿³¨ |
| | | */ |
| | | private String remark; |
| | |
| | | /** ç»è®¡æçç æ»æ°ï¼mes_pro_palletï¼ */ |
| | | Long selectPalletCount(); |
| | | |
| | | // ========== åºåºæµé / ä»å¨ / è´¨é ========== |
| | | |
| | | /** ç»è®¡åè´§éç¥åæ°ï¼mes_wm_sales_noticeï¼ */ |
| | | Long selectSalesNoticeCount(); |
| | | |
| | | /** ç»è®¡éå®åºåºåæ°ï¼mes_wm_product_salesï¼ */ |
| | | Long selectProductSalesCount(); |
| | | |
| | | /** ç»è®¡éå®éè´§åæ°ï¼mes_wm_return_salesï¼ */ |
| | | Long selectReturnSalesCount(); |
| | | |
| | | /** ç»è®¡æªå¤çåºåé¢è¦æ°ï¼mes_wm_stock_warning.status=10ï¼ */ |
| | | Long selectStockWarningPendingCount(); |
| | | |
| | | /** ç»è®¡å¾
è¯å®¡ä¸åæ ¼ååæ°ï¼mes_qc_ncr.status=0ï¼ */ |
| | | Long selectNcrPendingCount(); |
| | | |
| | | // ========== ç¶æåå¸ ========== |
| | | |
| | | /** |
| | |
| | | int markInbound(@org.apache.ibatis.annotations.Param("id") Long id, @org.apache.ibatis.annotations.Param("eventId") Long eventId, |
| | | @org.apache.ibatis.annotations.Param("deviceCode") String deviceCode, @org.apache.ibatis.annotations.Param("lineCode") String lineCode); |
| | | |
| | | /** æ¹æ¬¡æ´æ¹å
¥åºæ¶æ¹éæ è®°å
¶ä¸æªå
¥åºè¢ç ï¼å¹çï¼ï¼ä¿æè¢ç ä¸åºåç¶æä¸è´ */ |
| | | @Update("UPDATE mes_pro_bag_code SET inbound_time = NOW(), inbound_event_id = #{eventId}, inbound_line_code = #{lineCode}, update_time = NOW() " |
| | | + "WHERE deleted = 0 AND inbound_event_id IS NULL AND batch_id = #{batchId}") |
| | | int markInboundByBatchId(@Param("batchId") Long batchId, @Param("eventId") Long eventId, |
| | | @Param("lineCode") String lineCode); |
| | | |
| | | /** æ´æå
¥åºæ¶æ¹éæ è®°æç䏿ªå
¥åºè¢ç ï¼å¹çï¼ */ |
| | | @Update("UPDATE mes_pro_bag_code SET inbound_time = NOW(), inbound_event_id = #{eventId}, inbound_line_code = #{lineCode}, update_time = NOW() " |
| | | + "WHERE deleted = 0 AND inbound_event_id IS NULL AND pallet_id = #{palletId}") |
| | | int markInboundByPalletId(@Param("palletId") Long palletId, @Param("eventId") Long eventId, |
| | | @Param("lineCode") String lineCode); |
| | | |
| | | /** |
| | | * æ´æ°è¢ç è´¨æ£ç¶æï¼ç§åè´¨æ£åæ ¼/ä¸åæ ¼æ¶è®°å½è¯¥è¢ç»æï¼ |
| | | * |
| | | * @param id è¢ç ç¼å· |
| | | * @param qcStatus è´¨æ£ç¶æï¼è§ MesProBagCodeQcStatusEnumï¼ |
| | | */ |
| | | default void updateQcStatus(Long id, Integer qcStatus) { |
| | | update(null, new LambdaUpdateWrapper<MesProBagCodeDO>() |
| | | .eq(MesProBagCodeDO::getId, id) |
| | | .set(MesProBagCodeDO::getQcStatus, qcStatus)); |
| | | } |
| | | |
| | | default List<MesProBagCodeDO> selectListByUuid(String uuid) { |
| | | return selectList(MesProBagCodeDO::getUuid, uuid); |
| | | } |
| | |
| | | .likeIfPresent(MesProBagCodeDO::getBatchCode, reqVO.getBatchCode()) |
| | | .eqIfPresent(MesProBagCodeDO::getUuid, reqVO.getUuid()) |
| | | .eqIfPresent(MesProBagCodeDO::getPalletId, reqVO.getPalletId()) |
| | | .eqIfPresent(MesProBagCodeDO::getItemId, reqVO.getItemId()) |
| | | .eqIfPresent(MesProBagCodeDO::getStatus, reqVO.getStatus()) |
| | | .betweenIfPresent(MesProBagCodeDO::getCreateTime, reqVO.getCreateTime()) |
| | | .orderByAsc(MesProBagCodeDO::getBagNo)); |
| | | .orderByDesc(MesProBagCodeDO::getCreateTime) |
| | | .orderByDesc(MesProBagCodeDO::getId)); |
| | | } |
| | | |
| | | /** |
| | |
| | | .set(MesProBagCodeDO::getPalletId, palletId) |
| | | .set(MesProBagCodeDO::getPalletCode, palletCode) |
| | | .in(MesProBagCodeDO::getId, ids)); |
| | | } |
| | | |
| | | /** |
| | | * æçæ£å¼ç çæåï¼ååå
¶ä¸ææè¢ç çå使çç |
| | | * |
| | | * @param palletId æçç¼å· |
| | | * @param palletCode æ£å¼æçç |
| | | */ |
| | | default void updatePalletCodeByPalletId(Long palletId, String palletCode) { |
| | | update(null, new LambdaUpdateWrapper<MesProBagCodeDO>() |
| | | .set(MesProBagCodeDO::getPalletCode, palletCode) |
| | | .eq(MesProBagCodeDO::getPalletId, palletId)); |
| | | } |
| | | |
| | | /** |
| | |
| | | Integer selectMaxBagNo(); |
| | | |
| | | @Update("<script>UPDATE mes_pro_bag_code SET batch_id = #{batchId}, batch_code = #{batchCode}, update_time = NOW() " + |
| | | "WHERE deleted = 0 AND batch_id IS NULL AND status = #{status} AND id IN " + |
| | | "WHERE deleted = 0 AND batch_id IS NULL AND status IN " + |
| | | "<foreach collection='statuses' item='st' open='(' separator=',' close=')'>#{st}</foreach> AND id IN " + |
| | | "<foreach collection='ids' item='id' open='(' separator=',' close=')'>#{id}</foreach></script>") |
| | | int bindBatchByIds(@Param("ids") Collection<Long> ids, @Param("batchId") Long batchId, |
| | | @Param("batchCode") String batchCode, @Param("status") Integer status); |
| | | @Param("batchCode") String batchCode, @Param("statuses") Collection<Integer> statuses); |
| | | |
| | | /** æ¥è¯¢æçä¸å°æªç»å®æ¹æ¬¡çè¢ç ï¼æçç»å®æ¹æ¬¡æ¶çº§èå½å
¥ç¨ï¼ */ |
| | | default List<MesProBagCodeDO> selectUnboundListByPalletIds(Collection<Long> palletIds) { |
| | | return selectList(new LambdaQueryWrapperX<MesProBagCodeDO>() |
| | | .in(MesProBagCodeDO::getPalletId, palletIds) |
| | | .isNull(MesProBagCodeDO::getBatchId) |
| | | .orderByAsc(MesProBagCodeDO::getId)); |
| | | } |
| | | |
| | | /** æ¹æ¬¡å
ææè¢ç çåç§ç¼å·éåï¼å¿½ç¥åå²ç©ºåç§è¢ç ï¼ï¼ç¨äºå½å
¥æ¹æ¬¡æ¶çåç§ä¸è´æ§æ ¡éª */ |
| | | @Select("SELECT DISTINCT item_id FROM mes_pro_bag_code " + |
| | | "WHERE deleted = 0 AND status <> 30 AND batch_id = #{batchId} AND item_id IS NOT NULL") |
| | | List<Long> selectDistinctItemIdsByBatchId(@Param("batchId") Long batchId); |
| | | |
| | | default List<MesProBagCodeDO> selectListByIdsForUpdate(Collection<Long> ids) { |
| | | return selectList(new LambdaQueryWrapperX<MesProBagCodeDO>() |
| | |
| | | int markInbound(@org.apache.ibatis.annotations.Param("id") Long id, @org.apache.ibatis.annotations.Param("eventId") Long eventId, |
| | | @org.apache.ibatis.annotations.Param("deviceCode") String deviceCode, @org.apache.ibatis.annotations.Param("lineCode") String lineCode); |
| | | |
| | | /** æ¹æ¬¡æ´æ¹æ«ç å
¥åºååï¼å
¥åºè¢æ°ç´æ¥ç½®ä¸ºæ¹æ¬¡è¢æ°ï¼å¹çï¼å·²æå
¥åºæ è®°çä¸åæ´æ°ï¼ */ |
| | | @org.apache.ibatis.annotations.Update("UPDATE mes_pro_batch SET inbound_time = NOW(), inbound_event_id = #{eventId}, inbound_line_code = #{lineCode}, inbound_bag_quantity = #{bagQuantity}, update_time = NOW() " |
| | | + "WHERE id = #{id} AND deleted = 0 AND inbound_event_id IS NULL") |
| | | int markBatchInbound(@org.apache.ibatis.annotations.Param("id") Long id, @org.apache.ibatis.annotations.Param("eventId") Long eventId, |
| | | @org.apache.ibatis.annotations.Param("lineCode") String lineCode, @org.apache.ibatis.annotations.Param("bagQuantity") Integer bagQuantity); |
| | | |
| | | default PageResult<MesProBatchDO> selectPage(MesProBatchPageReqVO reqVO) { |
| | | return selectPage(reqVO, new LambdaQueryWrapperX<MesProBatchDO>() |
| | | .likeIfPresent(MesProBatchDO::getCode, reqVO.getCode()) |
| | | .likeIfPresent(MesProBatchDO::getTempCode, reqVO.getTempCode()) |
| | | .eqIfPresent(MesProBatchDO::getItemId, reqVO.getItemId()) |
| | | .eqIfPresent(MesProBatchDO::getLineId, reqVO.getLineId()) |
| | | .likeIfPresent(MesProBatchDO::getLineCode, reqVO.getLineCode()) |
| | | .likeIfPresent(MesProBatchDO::getLineName, reqVO.getLineName()) |
| | | .likeIfPresent(MesProBatchDO::getProcessingTeam, reqVO.getProcessingTeam()) |
| | | .eqIfPresent(MesProBatchDO::getOwnerUserId, reqVO.getOwnerUserId()) |
| | | .eqIfPresent(MesProBatchDO::getStatus, reqVO.getStatus()) |
| | | .betweenIfPresent(MesProBatchDO::getProduceDate, reqVO.getProduceDate()) |
| | |
| | | import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.pro.pallet.vo.MesProPalletPageReqVO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.pro.pallet.MesProPalletDO; |
| | | import cn.iocoder.yudao.module.mes.enums.pro.MesProPalletStatusEnum; |
| | | import org.apache.ibatis.annotations.Mapper; |
| | | import org.apache.ibatis.annotations.Param; |
| | | import org.apache.ibatis.annotations.Select; |
| | |
| | | return selectList(MesProPalletDO::getBatchId, batchId); |
| | | } |
| | | |
| | | /** æ¥è¯¢æªç»å®çäº§æ¹æ¬¡çä¸´æ¶æçï¼æ æ£å¼æçç 䏿ªä½åºï¼ï¼ä¾æ¹æ¬¡æ°å¢/è¡¥å½ç»å®æçä¸æä½¿ç¨ */ |
| | | default List<MesProPalletDO> selectUnboundList() { |
| | | return selectList(new LambdaQueryWrapperX<MesProPalletDO>() |
| | | .isNull(MesProPalletDO::getBatchId) |
| | | .isNull(MesProPalletDO::getCode) |
| | | .eq(MesProPalletDO::getStatus, MesProPalletStatusEnum.IN_USE.getStatus()) |
| | | .orderByAsc(MesProPalletDO::getId)); |
| | | } |
| | | |
| | | default PageResult<MesProPalletDO> selectPage(MesProPalletPageReqVO reqVO) { |
| | | return selectPage(reqVO, new LambdaQueryWrapperX<MesProPalletDO>() |
| | | .likeIfPresent(MesProPalletDO::getCode, reqVO.getCode()) |
| | |
| | | void markOutbound(@Param("id") Long id, @Param("salesId") Long salesId, |
| | | @Param("outboundTime") java.time.LocalDateTime outboundTime); |
| | | |
| | | /** æ´ææ«ç å
¥åºååï¼å¹çï¼å·²æå
¥åºæ è®°çä¸åæ´æ°ï¼ï¼ç¨äºé²éå¤å
¥åº */ |
| | | @org.apache.ibatis.annotations.Update("UPDATE mes_pro_pallet SET inbound_event_id = #{eventId}, inbound_time = NOW(), update_time = NOW() " |
| | | + "WHERE id = #{id} AND deleted = 0 AND inbound_event_id IS NULL") |
| | | int markInbound(@Param("id") Long id, @Param("eventId") Long eventId); |
| | | |
| | | @org.apache.ibatis.annotations.Update("UPDATE mes_pro_pallet SET sales_id = NULL, outbound_time = NULL, update_time = NOW() " |
| | | + "WHERE id = #{id} AND deleted = 0") |
| | | void clearOutbound(@Param("id") Long id); |
| | |
| | | package cn.iocoder.yudao.module.mes.dal.mysql.qc.seedquality; |
| | | |
| | | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| | | import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.qc.seedquality.vo.MesQcSeedQualityPageReqVO; |
| | | import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.qc.seedquality.MesQcSeedQualityDO; |
| | | import org.apache.ibatis.annotations.Mapper; |
| | |
| | | |
| | | @Mapper |
| | | public interface MesQcSeedQualityMapper extends BaseMapperX<MesQcSeedQualityDO> { |
| | | |
| | | default PageResult<MesQcSeedQualityDO> selectPage(MesQcSeedQualityPageReqVO reqVO) { |
| | | return selectPage(reqVO, new LambdaQueryWrapperX<MesQcSeedQualityDO>() |
| | | .likeIfPresent(MesQcSeedQualityDO::getCode, reqVO.getCode()) |
| | | .likeIfPresent(MesQcSeedQualityDO::getBatchCode, reqVO.getBatchCode()) |
| | | .eqIfPresent(MesQcSeedQualityDO::getResult, reqVO.getResult()) |
| | | .orderByDesc(MesQcSeedQualityDO::getInspectedAt) |
| | | .orderByDesc(MesQcSeedQualityDO::getId)); |
| | | } |
| | | default MesQcSeedQualityDO selectByCode(String code) { |
| | | return selectOne(new LambdaQueryWrapperX<MesQcSeedQualityDO>().eq(MesQcSeedQualityDO::getCode, code)); |
| | | } |
| | |
| | | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| | | import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; |
| | | import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo.MesWmBatchFlowRespVO; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo.MesWmBatchPageReqVO; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo.MesWmBatchProcessTraceRespVO; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo.MesWmBatchPurchaseSourceRespVO; |
| | |
| | | List<MesWmBatchSalesTargetRespVO> selectSalesTargetList(String batchCode); |
| | | |
| | | /** |
| | | * æ¥è¯¢æ¹æ¬¡åºå
¥åºæµæ°´ï¼ç§åæµåï¼ |
| | | * |
| | | * @param batchCode æ¹æ¬¡å· |
| | | * @return åºå
¥åºæµæ°´å表 |
| | | */ |
| | | List<MesWmBatchFlowRespVO> selectBatchFlowList(String batchCode); |
| | | |
| | | /** |
| | | * æ¥è¯¢æ¹æ¬¡å·¥åºæµè½¬ï¼äº§åº/æå
¥äºä»¶ï¼ |
| | | * |
| | | * @param batchCode æ¹æ¬¡å· |
| | |
| | | import cn.iocoder.yudao.module.mes.controller.admin.wm.materialstock.vo.MesWmMaterialStockListReqVO; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.wm.materialstock.vo.MesWmMaterialStockPageReqVO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.materialstock.MesWmMaterialStockDO; |
| | | import cn.iocoder.yudao.module.mes.enums.wm.MesWmStockStateEnum; |
| | | import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; |
| | | import org.apache.ibatis.annotations.Mapper; |
| | | |
| | |
| | | default PageResult<MesWmMaterialStockDO> selectPage(MesWmMaterialStockPageReqVO reqVO, |
| | | Collection<Long> itemTypeIds, |
| | | Collection<Long> itemIds, |
| | | Long virtualWarehouseId) { |
| | | Long virtualWarehouseId, |
| | | Collection<Long> warehouseIds) { |
| | | LambdaQueryWrapperX<MesWmMaterialStockDO> wrapper = new LambdaQueryWrapperX<MesWmMaterialStockDO>() |
| | | .inIfPresent(MesWmMaterialStockDO::getItemTypeId, itemTypeIds) |
| | | .inIfPresent(MesWmMaterialStockDO::getItemId, itemIds) |
| | | .likeIfPresent(MesWmMaterialStockDO::getBatchCode, reqVO.getBatchCode()) |
| | | .eqIfPresent(MesWmMaterialStockDO::getBatchId, reqVO.getBatchId()) |
| | | .eqIfPresent(MesWmMaterialStockDO::getWarehouseId, reqVO.getWarehouseId()) |
| | | .inIfPresent(MesWmMaterialStockDO::getWarehouseId, warehouseIds) |
| | | .eqIfPresent(MesWmMaterialStockDO::getLocationId, reqVO.getLocationId()) |
| | | .eqIfPresent(MesWmMaterialStockDO::getAreaId, reqVO.getAreaId()) |
| | | .eqIfPresent(MesWmMaterialStockDO::getVendorId, reqVO.getVendorId()) |
| | |
| | | } |
| | | |
| | | /** |
| | | * æç»å鮿¥è¯¢åºåè®°å½ï¼å¿½ç¥ä¾åºåç»´åº¦ï¼ |
| | | * æç»å鮿¥è¯¢åºåè®°å½ï¼å¿½ç¥ä¾åºå维度ï¼ä»
åæ ¼åºï¼ |
| | | * |
| | | * ç¨äºç§»åºåºæ¯ï¼ç§»åºæ¶å°åºååå¹¶å°ç®æ åºä½å·²æåºåï¼ä¸åºåä¾åºå |
| | | * ç¨äºç§»åºåºæ¯ï¼ç§»åºæ¶å°åæ ¼åºååå¹¶å°ç®æ åºä½å·²æåæ ¼åºåï¼ä¸åºåä¾åºå |
| | | * åªå¹é
åæ ¼åº(20)ï¼é¿å
å°ç§»å
¥æ°éåå¹¶å°åæ¹æ¬¡çæååºè®°å½ |
| | | */ |
| | | default MesWmMaterialStockDO selectByCompositeKeyIgnoreVendor(Long itemId, Long warehouseId, Long locationId, |
| | | Long areaId, Long batchId) { |
| | |
| | | .eq(MesWmMaterialStockDO::getItemId, itemId) |
| | | .eq(MesWmMaterialStockDO::getWarehouseId, warehouseId) |
| | | .eq(MesWmMaterialStockDO::getLocationId, locationId) |
| | | .eq(MesWmMaterialStockDO::getAreaId, areaId); |
| | | .eq(MesWmMaterialStockDO::getAreaId, areaId) |
| | | .eq(MesWmMaterialStockDO::getStockState, MesWmStockStateEnum.QUALIFIED.getState()); |
| | | // batchId=null æ¶ç²¾ç¡®å¹é
is null |
| | | if (batchId != null) { |
| | | wrapper.eq(MesWmMaterialStockDO::getBatchId, batchId); |
| | |
| | | return selectOne(wrapper); |
| | | } |
| | | |
| | | /** |
| | | * æç»å鮿¥è¯¢åæ ¼åºåºåè®°å½ï¼ç¨äºåºåºäºå¡å¹é
ï¼ |
| | | * |
| | | * åæ¹æ¬¡å¯è½åæ¶å卿ååº(10)ä¸åæ ¼åº(20)两æ¡è®°å½ï¼ç§åè´¨æ£æè¢ææ°éï¼ï¼ |
| | | * åºåºå¿
é¡»åªä»åæ ¼åºå¹é
ï¼é¿å
æ£å°æªè´¨æ£çæååºåã |
| | | */ |
| | | default MesWmMaterialStockDO selectQualifiedByCompositeKey(Long itemId, Long warehouseId, Long locationId, |
| | | Long areaId, Long batchId, Long vendorId) { |
| | | LambdaQueryWrapperX<MesWmMaterialStockDO> wrapper = new LambdaQueryWrapperX<MesWmMaterialStockDO>() |
| | | .eq(MesWmMaterialStockDO::getItemId, itemId) |
| | | .eq(MesWmMaterialStockDO::getWarehouseId, warehouseId) |
| | | .eq(MesWmMaterialStockDO::getLocationId, locationId) |
| | | .eq(MesWmMaterialStockDO::getAreaId, areaId) |
| | | .eq(MesWmMaterialStockDO::getStockState, MesWmStockStateEnum.QUALIFIED.getState()); |
| | | // batchId=null æ¶ç²¾ç¡®å¹é
is null |
| | | if (batchId != null) { |
| | | wrapper.eq(MesWmMaterialStockDO::getBatchId, batchId); |
| | | } else { |
| | | wrapper.isNull(MesWmMaterialStockDO::getBatchId); |
| | | } |
| | | if (vendorId != null) { |
| | | wrapper.eq(MesWmMaterialStockDO::getVendorId, vendorId); |
| | | } |
| | | wrapper.last("ORDER BY quantity DESC LIMIT 1"); |
| | | return selectOne(wrapper); |
| | | } |
| | | |
| | | default List<MesWmMaterialStockDO> selectList(MesWmMaterialStockListReqVO reqVO) { |
| | | return selectList(reqVO, null); |
| | | } |
| | | |
| | | default List<MesWmMaterialStockDO> selectList(MesWmMaterialStockListReqVO reqVO, Collection<Long> warehouseIds) { |
| | | return selectList(new LambdaQueryWrapperX<MesWmMaterialStockDO>() |
| | | .eqIfPresent(MesWmMaterialStockDO::getWarehouseId, reqVO.getWarehouseId()) |
| | | .inIfPresent(MesWmMaterialStockDO::getWarehouseId, warehouseIds) |
| | | .eqIfPresent(MesWmMaterialStockDO::getLocationId, reqVO.getLocationId()) |
| | | .eqIfPresent(MesWmMaterialStockDO::getAreaId, reqVO.getAreaId()) |
| | | .eqIfPresent(MesWmMaterialStockDO::getItemId, reqVO.getItemId()) |
| | |
| | | .orderByAsc(MesWmMaterialStockDO::getReceiptTime)); |
| | | } |
| | | |
| | | /** |
| | | * æç©æ/æ¹æ¬¡æ¥è¯¢åæ ¼åºåºåè®°å½ï¼ä»
stock_state=20ï¼ä¸ä»
éåæ ¼ä»åºï¼ |
| | | * |
| | | * <p>åæ¹æ¬¡å¯è½åæ¶å卿ååº(10)ä¸åæ ¼åº(20)两æ¡è®°å½ï¼ç§åè´¨æ£æè¢ææ°éï¼ï¼ |
| | | * éå®åºåºéåºååªè½ä»åæ ¼åºè®°å½ä¸éï¼æç»é䏿ªè´¨æ£çæååºåï¼ |
| | | * åæ¶éå®åæ ¼ä»åºï¼type=20ï¼ï¼é¿å
仿åä»åºä¸è¯¯éåæ ¼æåºåã</p> |
| | | */ |
| | | default List<MesWmMaterialStockDO> selectQualifiedListByItemAndBatch(Long itemId, Long batchId, |
| | | Collection<Long> qualifiedWarehouseIds) { |
| | | return selectList(new LambdaQueryWrapperX<MesWmMaterialStockDO>() |
| | | .eq(MesWmMaterialStockDO::getItemId, itemId) |
| | | .eqIfPresent(MesWmMaterialStockDO::getBatchId, batchId) |
| | | .eq(MesWmMaterialStockDO::getStockState, MesWmStockStateEnum.QUALIFIED.getState()) |
| | | .in(MesWmMaterialStockDO::getWarehouseId, qualifiedWarehouseIds) |
| | | .gt(MesWmMaterialStockDO::getQuantity, BigDecimal.ZERO) |
| | | .orderByAsc(MesWmMaterialStockDO::getReceiptTime)); |
| | | } |
| | | |
| | | /** |
| | | * æä»åºæ¹æ¬¡æ¥è¯¢å
¨é¨åºåè®°å½ï¼å«æååºä¸åæ ¼åºï¼quantity>0ï¼ |
| | | * |
| | | * <p>ç¨äºç§åè´¨æ£æè¢ç æµè½¬ï¼å®ä½è¯¥æ¹æ¬¡æååºè®°å½æ£å 1 è¢ï¼ä»¥åå®ä½/æ°å»ºåæ ¼åºè®°å½ç´¯å 1 è¢ã</p> |
| | | */ |
| | | default List<MesWmMaterialStockDO> selectStockListByBatchId(Long batchId) { |
| | | return selectList(new LambdaQueryWrapperX<MesWmMaterialStockDO>() |
| | | .eq(MesWmMaterialStockDO::getBatchId, batchId) |
| | | .gt(MesWmMaterialStockDO::getQuantity, BigDecimal.ZERO) |
| | | .orderByAsc(MesWmMaterialStockDO::getReceiptTime)); |
| | | } |
| | | |
| | | default List<MesWmMaterialStockDO> selectListByItemIds(Collection<Long> itemIds) { |
| | | if (itemIds == null || itemIds.isEmpty()) { |
| | | return java.util.Collections.emptyList(); |
| | |
| | | } |
| | | |
| | | /** |
| | | * ææ¹æ¬¡å·æ´æ°åºåç¶æï¼ç¨äºç§åè´¨æ£åæ ¼åï¼å°æååºæ´æ¹è½¬ä¸ºåæ ¼åºï¼ |
| | | * ç»è®¡æ¹æ¬¡å¨æååºä¸çåºåè®°å½æ°ï¼ç¨äºç§åè´¨æ£åæ ¡éªè¢ç /æ¹æ¬¡æ¯å¦å¤äºå¾
è´¨æ£ç¶æï¼ |
| | | * |
| | | * @param batchId ä»åºæ¹æ¬¡ID |
| | | * @param toState ç®æ åºåç¶æ |
| | | * @param fromState ååºåç¶æï¼éå®åªæ´æ°è¯¥ç¶æçè®°å½ï¼ |
| | | * @return å½±åè¡æ° |
| | | * @param batchId ä»åºæ¹æ¬¡ID |
| | | * @return æååºåºåè®°å½æ° |
| | | */ |
| | | default int updateStockStateByBatchId(Long batchId, Integer toState, Integer fromState) { |
| | | return update(new MesWmMaterialStockDO().setStockState(toState), |
| | | new LambdaUpdateWrapper<MesWmMaterialStockDO>() |
| | | .eq(MesWmMaterialStockDO::getBatchId, batchId) |
| | | .eq(MesWmMaterialStockDO::getStockState, fromState)); |
| | | default Long selectTempStockCountByBatchId(Long batchId) { |
| | | return selectCount(new LambdaQueryWrapperX<MesWmMaterialStockDO>() |
| | | .eq(MesWmMaterialStockDO::getBatchId, batchId) |
| | | .eq(MesWmMaterialStockDO::getStockState, MesWmStockStateEnum.TEMP.getState()) |
| | | .gt(MesWmMaterialStockDO::getQuantity, BigDecimal.ZERO)); |
| | | } |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.mes.dal.mysql.wm.materialstockbag; |
| | | |
| | | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| | | import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.wm.materialstock.vo.MesWmMaterialStockBagPageReqVO; |
| | | import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.materialstockbag.MesWmMaterialStockBagDO; |
| | | import org.apache.ibatis.annotations.Mapper; |
| | | |
| | | import java.util.Collection; |
| | | import java.util.List; |
| | | |
| | | @Mapper |
| | | public interface MesWmMaterialStockBagMapper extends BaseMapperX<MesWmMaterialStockBagDO> { |
| | | |
| | | default PageResult<MesWmMaterialStockBagDO> selectPage(MesWmMaterialStockBagPageReqVO reqVO) { |
| | | return selectPage(reqVO, new LambdaQueryWrapperX<MesWmMaterialStockBagDO>() |
| | | .eq(MesWmMaterialStockBagDO::getMaterialStockId, reqVO.getMaterialStockId()) |
| | | .likeIfPresent(MesWmMaterialStockBagDO::getBagCode, reqVO.getBagCode()) |
| | | .eq(MesWmMaterialStockBagDO::getStatus, 1) |
| | | .orderByAsc(MesWmMaterialStockBagDO::getInboundTime)); |
| | | } |
| | | |
| | | default MesWmMaterialStockBagDO selectByBagCode(String bagCode) { |
| | | return selectOne(new LambdaQueryWrapperX<MesWmMaterialStockBagDO>() |
| | | .eq(MesWmMaterialStockBagDO::getBagCode, bagCode) |
| | | .orderByDesc(MesWmMaterialStockBagDO::getId) |
| | | .last("LIMIT 1")); |
| | | } |
| | | |
| | | default MesWmMaterialStockBagDO selectByBagCodeId(Long bagCodeId) { |
| | | return selectOne(new LambdaQueryWrapperX<MesWmMaterialStockBagDO>() |
| | | .eq(MesWmMaterialStockBagDO::getBagCodeId, bagCodeId) |
| | | .orderByDesc(MesWmMaterialStockBagDO::getId) |
| | | .last("LIMIT 1")); |
| | | } |
| | | |
| | | default MesWmMaterialStockBagDO selectOneActiveByMaterialStockId(Long materialStockId) { |
| | | return selectOne(new LambdaQueryWrapperX<MesWmMaterialStockBagDO>() |
| | | .eq(MesWmMaterialStockBagDO::getMaterialStockId, materialStockId) |
| | | .eq(MesWmMaterialStockBagDO::getStatus, 1) |
| | | .last("LIMIT 1")); |
| | | } |
| | | |
| | | default MesWmMaterialStockBagDO selectActiveByBagCode(String bagCode) { |
| | | return selectOne(new LambdaQueryWrapperX<MesWmMaterialStockBagDO>() |
| | | .eq(MesWmMaterialStockBagDO::getBagCode, bagCode) |
| | | .eq(MesWmMaterialStockBagDO::getStatus, 1) |
| | | .last("LIMIT 1")); |
| | | } |
| | | |
| | | default MesWmMaterialStockBagDO selectActiveByBagCodeId(Long bagCodeId) { |
| | | return selectOne(new LambdaQueryWrapperX<MesWmMaterialStockBagDO>() |
| | | .eq(MesWmMaterialStockBagDO::getBagCodeId, bagCodeId) |
| | | .eq(MesWmMaterialStockBagDO::getStatus, 1) |
| | | .last("LIMIT 1")); |
| | | } |
| | | |
| | | default List<MesWmMaterialStockBagDO> selectActiveListByItemAndBatch(Long itemId, Long batchId, Integer stockState) { |
| | | return selectList(new LambdaQueryWrapperX<MesWmMaterialStockBagDO>() |
| | | .eq(MesWmMaterialStockBagDO::getItemId, itemId) |
| | | .eqIfPresent(MesWmMaterialStockBagDO::getBatchId, batchId) |
| | | .eqIfPresent(MesWmMaterialStockBagDO::getStockState, stockState) |
| | | .eq(MesWmMaterialStockBagDO::getStatus, 1) |
| | | .eq(MesWmMaterialStockBagDO::getFrozen, false) |
| | | .orderByAsc(MesWmMaterialStockBagDO::getInboundTime)); |
| | | } |
| | | |
| | | default List<MesWmMaterialStockBagDO> selectListByMaterialStockIds(Collection<Long> materialStockIds) { |
| | | return selectList(new LambdaQueryWrapperX<MesWmMaterialStockBagDO>() |
| | | .in(MesWmMaterialStockBagDO::getMaterialStockId, materialStockIds) |
| | | .eq(MesWmMaterialStockBagDO::getStatus, 1) |
| | | .orderByAsc(MesWmMaterialStockBagDO::getInboundTime)); |
| | | } |
| | | |
| | | default List<MesWmMaterialStockBagDO> selectListByMaterialStockId(Long materialStockId) { |
| | | return selectList(new LambdaQueryWrapperX<MesWmMaterialStockBagDO>() |
| | | .eq(MesWmMaterialStockBagDO::getMaterialStockId, materialStockId) |
| | | .eq(MesWmMaterialStockBagDO::getStatus, 1) |
| | | .orderByAsc(MesWmMaterialStockBagDO::getInboundTime)); |
| | | } |
| | | } |
| | |
| | | import org.apache.ibatis.annotations.Mapper; |
| | | |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | |
| | | /** |
| | | * MES éå®åºåºåè¡ Mapper |
| | |
| | | .eqIfPresent(MesWmProductSalesLineDO::getSalesId, reqVO.getSalesId()) |
| | | .inIfPresent(MesWmProductSalesLineDO::getSalesId, reqVO.getSalesIds()) |
| | | .orderByDesc(MesWmProductSalesLineDO::getId)); |
| | | } |
| | | |
| | | /** |
| | | * æ ¹æ®éå®è®¢åæç» ID å表æ¥è¯¢åºåºè¡ï¼æ saleOrderItemId åç»è¿åæ¹å· |
| | | */ |
| | | default Map<Long, String> selectBatchCodesBySaleOrderItemIds(java.util.Collection<Long> saleOrderItemIds) { |
| | | if (saleOrderItemIds == null || saleOrderItemIds.isEmpty()) { |
| | | return java.util.Collections.emptyMap(); |
| | | } |
| | | List<MesWmProductSalesLineDO> lines = selectList(new LambdaQueryWrapperX<MesWmProductSalesLineDO>() |
| | | .in(MesWmProductSalesLineDO::getSaleOrderItemId, saleOrderItemIds)); |
| | | return lines.stream() |
| | | .filter(l -> l.getBatchCode() != null && !l.getBatchCode().isEmpty()) |
| | | .collect(java.util.stream.Collectors.groupingBy( |
| | | MesWmProductSalesLineDO::getSaleOrderItemId, |
| | | java.util.LinkedHashMap::new, |
| | | java.util.stream.Collectors.collectingAndThen( |
| | | java.util.stream.Collectors.mapping(MesWmProductSalesLineDO::getBatchCode, |
| | | java.util.stream.Collectors.toSet()), |
| | | codes -> String.join("ã", codes)))); |
| | | } |
| | | |
| | | default void updateQualityStatusByIds(List<Long> ids, Integer qualityStatus) { |
| | |
| | | return selectPage(reqVO, new LambdaQueryWrapperX<MesWmReturnSalesDO>() |
| | | .likeIfPresent(MesWmReturnSalesDO::getCode, reqVO.getCode()) |
| | | .likeIfPresent(MesWmReturnSalesDO::getName, reqVO.getName()) |
| | | .likeIfPresent(MesWmReturnSalesDO::getSalesOrderCode, reqVO.getSalesOrderCode()) |
| | | .eqIfPresent(MesWmReturnSalesDO::getClientId, reqVO.getClientId()) |
| | | .eqIfPresent(MesWmReturnSalesDO::getStatus, reqVO.getStatus()) |
| | | .betweenIfPresent(MesWmReturnSalesDO::getReturnDate, reqVO.getReturnDate()) |
| | |
| | | LambdaQueryWrapperX<MesWmReturnSalesDO> wrapper = new LambdaQueryWrapperX<MesWmReturnSalesDO>() |
| | | .likeIfPresent(MesWmReturnSalesDO::getCode, reqVO.getCode()) |
| | | .likeIfPresent(MesWmReturnSalesDO::getName, reqVO.getName()) |
| | | .likeIfPresent(MesWmReturnSalesDO::getSalesOrderCode, reqVO.getSalesOrderCode()) |
| | | .eqIfPresent(MesWmReturnSalesDO::getClientId, reqVO.getClientId()) |
| | | .eqIfPresent(MesWmReturnSalesDO::getStatus, reqVO.getStatus()) |
| | | .betweenIfPresent(MesWmReturnSalesDO::getReturnDate, reqVO.getReturnDate()) |
| | |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.salesnotice.MesWmSalesNoticeDO; |
| | | import org.apache.ibatis.annotations.Mapper; |
| | | |
| | | import java.util.Collection; |
| | | import java.util.List; |
| | | |
| | | /** |
| | |
| | | return selectPage(reqVO, new LambdaQueryWrapperX<MesWmSalesNoticeDO>() |
| | | .likeIfPresent(MesWmSalesNoticeDO::getCode, reqVO.getCode()) |
| | | .likeIfPresent(MesWmSalesNoticeDO::getName, reqVO.getName()) |
| | | .likeIfPresent(MesWmSalesNoticeDO::getSaleOrderCode, reqVO.getSaleOrderCode()) |
| | | .eqIfPresent(MesWmSalesNoticeDO::getClientId, reqVO.getClientId()) |
| | | .eqIfPresent(MesWmSalesNoticeDO::getStatus, reqVO.getStatus()) |
| | | .orderByDesc(MesWmSalesNoticeDO::getId)); |
| | |
| | | LambdaQueryWrapperX<MesWmSalesNoticeDO> wrapper = new LambdaQueryWrapperX<MesWmSalesNoticeDO>() |
| | | .likeIfPresent(MesWmSalesNoticeDO::getCode, reqVO.getCode()) |
| | | .likeIfPresent(MesWmSalesNoticeDO::getName, reqVO.getName()) |
| | | .likeIfPresent(MesWmSalesNoticeDO::getSaleOrderCode, reqVO.getSaleOrderCode()) |
| | | .eqIfPresent(MesWmSalesNoticeDO::getClientId, reqVO.getClientId()) |
| | | .eqIfPresent(MesWmSalesNoticeDO::getStatus, reqVO.getStatus()) |
| | | .orderByDesc(MesWmSalesNoticeDO::getId); |
| | |
| | | |
| | | default MesWmSalesNoticeDO selectByCode(String code) { |
| | | return selectOne(MesWmSalesNoticeDO::getCode, code); |
| | | } |
| | | |
| | | default MesWmSalesNoticeDO selectBySaleOrderId(Long saleOrderId) { |
| | | return selectOne(MesWmSalesNoticeDO::getSaleOrderId, saleOrderId); |
| | | } |
| | | |
| | | /** |
| | | * æ¥è¯¢å·²åå¨åè´§éç¥åçéå®è®¢å ID å表 |
| | | */ |
| | | default List<Long> selectExistingSaleOrderIds(Collection<Long> saleOrderIds) { |
| | | return selectObjs(new LambdaQueryWrapperX<MesWmSalesNoticeDO>() |
| | | .select(MesWmSalesNoticeDO::getSaleOrderId) |
| | | .in(MesWmSalesNoticeDO::getSaleOrderId, saleOrderIds)); |
| | | } |
| | | |
| | | } |
| | |
| | | return selectPage(reqVO, new LambdaQueryWrapperX<MesWmTransactionDO>() |
| | | .eqIfPresent(MesWmTransactionDO::getItemId, reqVO.getItemId()) |
| | | .likeIfPresent(MesWmTransactionDO::getBatchCode, reqVO.getBatchCode()) |
| | | .likeIfPresent(MesWmTransactionDO::getBagCode, reqVO.getBagCode()) |
| | | .eqIfPresent(MesWmTransactionDO::getWarehouseId, reqVO.getWarehouseId()) |
| | | .eqIfPresent(MesWmTransactionDO::getLocationId, reqVO.getLocationId()) |
| | | .eqIfPresent(MesWmTransactionDO::getAreaId, reqVO.getAreaId()) |
| | |
| | | .likeIfPresent(MesWmWarehouseDO::getCode, reqVO.getCode()) |
| | | .likeIfPresent(MesWmWarehouseDO::getName, reqVO.getName()) |
| | | .eqIfPresent(MesWmWarehouseDO::getFrozen, reqVO.getFrozen()) |
| | | .eqIfPresent(MesWmWarehouseDO::getType, reqVO.getType()) |
| | | .orderByDesc(MesWmWarehouseDO::getId)); |
| | | } |
| | | |
| | | default List<MesWmWarehouseDO> selectListByType(Integer type) { |
| | | return selectList(new LambdaQueryWrapperX<MesWmWarehouseDO>() |
| | | .eq(MesWmWarehouseDO::getType, type) |
| | | .orderByAsc(MesWmWarehouseDO::getId)); |
| | | } |
| | | |
| | | default MesWmWarehouseDO selectByCode(String code) { |
| | | return selectOne(MesWmWarehouseDO::getCode, code); |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.mes.dal.redis; |
| | | |
| | | import cn.iocoder.yudao.framework.common.util.number.BizNoUtils; |
| | | import jakarta.annotation.Resource; |
| | | import org.springframework.data.redis.core.StringRedisTemplate; |
| | | import org.springframework.stereotype.Repository; |
| | | |
| | | /** |
| | | * MES ä¸å¡ç¼ç çæç Redis DAOï¼å®ä¾ç ï¼è¢ç / æçç / 临æ¶ç çï¼ã |
| | | * |
| | | * <p>éæ±ï¼ææä¸å¡ç¼ç ç»ä¸ä¸ºã16 ä½çº¯æ°åãï¼ä¸å
¨ç³»ç»å¯ä¸ã |
| | | * è¿éå¤ç¨å
¨ç³»ç»ç»ä¸ç Redis èªå¢ KEYï¼ä¿è¯ä¸å
¶å®æ¨¡åçç¼ç ä¹ä¸éå¤ã |
| | | */ |
| | | @Repository |
| | | public class MesCodeRedisDAO { |
| | | |
| | | @Resource |
| | | private StringRedisTemplate stringRedisTemplate; |
| | | |
| | | /** |
| | | * çæä¸ä¸ª 16 ä½çº¯æ°åä¸å¡ç¼ç ï¼å
¨ç³»ç»å¯ä¸ï¼ |
| | | * |
| | | * @return 16 ä½çº¯æ°åç¼ç |
| | | */ |
| | | public String generate() { |
| | | // éæºçæ 16 ä½çº¯æ°åç¼ç ï¼å¹¶ç¨ Redis é忥éï¼ä¿è¯å
¨ç³»ç»å¯ä¸ï¼ä¸ä½¿ç¨èªå¢/顺åºï¼ |
| | | for (int i = 0; i < BizNoUtils.MAX_RETRY; i++) { |
| | | String code = BizNoUtils.randomCode(); |
| | | Long added = stringRedisTemplate.opsForSet().add(BizNoUtils.USED_SET_KEY, code); |
| | | if (added != null && added > 0) { |
| | | return code; |
| | | } |
| | | } |
| | | throw new IllegalStateException("çæå¯ä¸ä¸å¡ç¼ç 失败ï¼è¯·éè¯"); |
| | | } |
| | | |
| | | } |
| | |
| | | ErrorCode WM_WAREHOUSE_HAS_WORKSTATION = new ErrorCode(1_040_700_004, "ä»åºå·²è¢«å·¥ä½ç«å¼ç¨ï¼æ æ³å é¤"); |
| | | ErrorCode WM_WAREHOUSE_HAS_MATERIAL_STOCK = new ErrorCode(1_040_700_005, "ä»åºä¸æåºåè®°å½ï¼æ æ³å é¤"); |
| | | ErrorCode WM_WAREHOUSE_IS_VIRTUAL = new ErrorCode(1_040_700_006, "èæä»åºä¸å
许æä½"); |
| | | ErrorCode WM_WAREHOUSE_TYPE_NOT_QUALIFIED = new ErrorCode(1_040_700_007, "æéä»åºä¸æ¯åæ ¼åº"); |
| | | ErrorCode WM_QUALIFIED_WAREHOUSE_NOT_CONFIGURED = new ErrorCode(1_040_700_008, "æªé
ç½®åæ ¼åºï¼è¯·å
å¨ä»åºç®¡çä¸å建并设置ä»åºç±»åä¸ºåæ ¼åº"); |
| | | |
| | | // ========== MES ä»åºç®¡ç-åºåºï¼1-040-701-000ï¼ ========== |
| | | ErrorCode WM_WAREHOUSE_LOCATION_NOT_EXISTS = new ErrorCode(1_040_701_000, "åºåºä¸åå¨"); |
| | |
| | | ErrorCode WM_MATERIAL_STOCK_SELECTION_MISMATCH = new ErrorCode(1_040_703_014, "åºåè®°å½ä¸æäº¤çç©æãæ¹æ¬¡æåºä½ä¿¡æ¯ä¸ä¸è´"); |
| | | ErrorCode WM_MATERIAL_STOCK_QUANTITY_INVALID = new ErrorCode(1_040_703_015, "è°æ´æ°éä¸è½ä¸ºç©ºæé¶"); |
| | | ErrorCode WM_MATERIAL_STOCK_FROZEN = new ErrorCode(1_040_703_016, "åºåè®°å½å·²å»ç»ï¼æ æ³ç§»åº"); |
| | | ErrorCode WM_MATERIAL_STOCK_NOT_QUALIFIED = new ErrorCode(1_040_703_017, "éåæ ¼åºåä¸å¯åºåº"); |
| | | ErrorCode WM_MATERIAL_STOCK_BAG_NOT_EXISTS = new ErrorCode(1_040_703_018, "åºåè¢ç æç»ä¸åå¨"); |
| | | ErrorCode WM_MATERIAL_STOCK_BAG_DUPLICATE = new ErrorCode(1_040_703_019, "è¢ç ({})å·²å¨åºï¼ç¦æ¢éå¤å
¥åº"); |
| | | ErrorCode WM_MATERIAL_STOCK_BAG_NOT_ACTIVE = new ErrorCode(1_040_703_020, "è¢ç ({})ä¸å¨åºæå·²åºåº/æ¥åºï¼æ æ³æä½"); |
| | | ErrorCode WM_MATERIAL_STOCK_BAG_REQUIRED = new ErrorCode(1_040_703_021, "è¯¥ç©æå¯ç¨è¢ç 管çï¼å¿
é¡»æºå¸¦è¢ç "); |
| | | ErrorCode WM_MATERIAL_STOCK_BAG_INSUFFICIENT = new ErrorCode(1_040_703_022, "å¨åºè¢ç æç»æ°éä¸è¶³ï¼æ æ³åºåº"); |
| | | |
| | | // ========== MES ä»åºç®¡ç-å°è´§éç¥åï¼1-040-704-000ï¼ ========== |
| | | ErrorCode WM_ARRIVAL_NOTICE_NOT_EXISTS = new ErrorCode(1_040_704_000, "å°è´§éç¥åä¸åå¨"); |
| | |
| | | ErrorCode WM_PRODUCT_SALES_SCAN_STOCK_NOT_FOUND = new ErrorCode(1_040_714_105, "æ«ææ¹æ¬¡å¨åæ ¼åºä¸æªæ¾å°å¯¹åºåºåè®°å½"); |
| | | ErrorCode WM_PRODUCT_SALES_SCAN_NO_MATCH_LINE = new ErrorCode(1_040_714_106, "åºåºå䏿²¡æä¸è¯¥ç©æ/æ¹æ¬¡å¹é
çè¡"); |
| | | ErrorCode WM_PRODUCT_SALES_SCAN_BAG_ALREADY_SCANNED = new ErrorCode(1_040_714_107, "该è¢ç å·²æ«æåºåºï¼è¯·å¿é夿«æ"); |
| | | ErrorCode WM_PRODUCT_SALES_SCAN_BAG_NOT_QUALIFIED = new ErrorCode(1_040_714_108, "该è¢ç æªè´¨æ£åæ ¼ï¼ç¦æ¢åºåº"); |
| | | ErrorCode WM_PRODUCT_SALES_SCAN_PALLET_NOT_ALL_QUALIFIED = new ErrorCode(1_040_714_109, "æçä¸å卿ªè´¨æ£è¢ç ï¼ç¦æ¢æ´æåºåº"); |
| | | |
| | | // ========== MES ä»åºç®¡ç-æé¡¹åºåºåï¼1-040-715-000ï¼ ========== |
| | | ErrorCode WM_MISC_ISSUE_NOT_EXISTS = new ErrorCode(1_040_715_000, "æé¡¹åºåºåä¸åå¨"); |
| | |
| | | ErrorCode WM_SALES_NOTICE_LINE_NOT_EXISTS = new ErrorCode(1_040_720_010, "åè´§éç¥åè¡ä¸åå¨"); |
| | | ErrorCode WM_SALES_NOTICE_LINE_EMPTY = new ErrorCode(1_040_720_011, "åè´§éç¥åè¡ä¸ºç©ºï¼ä¸è½æäº¤"); |
| | | ErrorCode WM_SALES_NOTICE_LINE_NOT_MATCH = new ErrorCode(1_040_720_012, "åè´§éç¥åè¡ä¸å±äºæå®çåè´§éç¥å"); |
| | | ErrorCode WM_SALES_NOTICE_SALE_ORDER_NOT_EXISTS = new ErrorCode(1_040_720_013, "éå®è®¢åä¸åå¨"); |
| | | ErrorCode WM_SALES_NOTICE_SALE_ORDER_ITEM_EMPTY = new ErrorCode(1_040_720_014, "éå®è®¢åæç»ä¸ºç©º"); |
| | | ErrorCode WM_SALES_NOTICE_ALREADY_EXISTS = new ErrorCode(1_040_720_015, "该éå®è®¢åå·²çæåè´§éç¥åï¼ä¸è½éå¤çæ"); |
| | | |
| | | // ========== MES ä»åºç®¡ç-æ¡ç é
ç½®ï¼1-040-730-000ï¼ ========== |
| | | ErrorCode WM_BARCODE_CONFIG_NOT_EXISTS = new ErrorCode(1_040_730_000, "æ¡ç é
ç½®ä¸åå¨"); |
| | |
| | | ErrorCode PRO_BAG_CODE_BIND_PALLET_MISMATCH = new ErrorCode(1_040_752_003, "è¢ç 䏿çä¸å±äºåä¸çäº§æ¹æ¬¡ï¼ä¸å
许ç»å®"); |
| | | ErrorCode PRO_BAG_CODE_BIND_PALLET_BOUND = new ErrorCode(1_040_752_004, "åå¨å·²ç»å®æççè¢ç ï¼è¯·å
è§£ç»"); |
| | | ErrorCode PRO_BAG_CODE_UUID_NOT_EXISTS = new ErrorCode(1_040_752_005, "è¢ç çæç»ä¸åå¨"); |
| | | ErrorCode PRO_BAG_CODE_BIND_PALLET_OVER_CAPACITY = new ErrorCode(1_040_752_006, "ç»å®åè¢ç æ°éè¶
è¿æçå¯è£
è¢æ°"); |
| | | ErrorCode PRO_BAG_CODE_REPLACE_BATCH_STATUS_INVALID = new ErrorCode(1_040_752_007, "çäº§æ¹æ¬¡ç¶æä¸å
è®¸ç ´æè¢ç æ¿æ¢"); |
| | | ErrorCode PRO_BAG_CODE_REPLACE_BATCH_MISMATCH = new ErrorCode(1_040_752_008, "å¾
æ¿æ¢è¢ç ä¸å±äºæå®çäº§æ¹æ¬¡"); |
| | | ErrorCode PRO_BAG_CODE_REPLACE_ALREADY_REPLACED = new ErrorCode(1_040_752_009, "è¢ç å·²å®ææ¿æ¢ï¼ä¸å
许é夿¿æ¢"); |
| | | ErrorCode PRO_BAG_CODE_REPLACE_STATUS_INVALID = new ErrorCode(1_040_752_010, "è¢ç ç¶æä¸å
è®¸ç ´ææ¿æ¢"); |
| | | ErrorCode PRO_BAG_CODE_REPLACE_PALLET_INVALID = new ErrorCode(1_040_752_011, "è¢ç åæçä¸å卿已ä½åºï¼ä¸å
许继æ¿"); |
| | | ErrorCode PRO_BAG_CODE_ITEM_TYPE_NOT_CONFIGURED = new ErrorCode(1_040_752_012, "åç§ä¸»è®¡éå使ªé
置类åï¼ä»
æ¯æ 48åå
/100åå
/å¨"); |
| | | ErrorCode PRO_BAG_CODE_PALLET_COUNT_REQUIRED = new ErrorCode(1_040_752_013, "该åç§ææççæè¢ç ï¼æçæ°å¿
é¡»å¤§äº 0"); |
| | | ErrorCode PRO_BAG_CODE_BIND_BATCH_ITEM_MISMATCH = new ErrorCode(1_040_752_014, "å½å
¥æ¹æ¬¡çè¢ç å¿
é¡»å±äºåä¸åç§"); |
| | | |
| | | // ========== MES ç产管ç-æçç ï¼1-040-753-000ï¼ ========== |
| | | ErrorCode PRO_PALLET_NOT_EXISTS = new ErrorCode(1_040_753_000, "æçç ä¸åå¨"); |
| | |
| | | public static final int QC_IPQC = 2; // è¿ç¨æ£éªï¼MesQcIpqcDO |
| | | public static final int QC_OQC = 3; // åºè´§æ£éªï¼MesQcOqcDO |
| | | public static final int QC_RQC = 4; // éè´§æ£éªï¼MesQcRqcDO |
| | | public static final int QC_SEED_QUALITY = 5; // ç§åè´¨æ£ï¼MesQcSeedQualityDOï¼å«æååºåº/åæ ¼å
¥åº/æ¥åºï¼ |
| | | |
| | | // ========== WM ä»åºæ¨¡å [100, 200) ========== |
| | | |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.mes.enums.pro; |
| | | |
| | | import cn.iocoder.yudao.framework.common.core.ArrayValuable; |
| | | import lombok.AllArgsConstructor; |
| | | import lombok.Getter; |
| | | |
| | | import java.util.Arrays; |
| | | |
| | | /** |
| | | * MES è¢ç ï¼ä¸è¢ä¸ç ï¼è´¨æ£ç¶ææä¸¾ |
| | | * |
| | | * <p>è®°å½æ¯è¢çç§åè´¨æ£ç»æï¼éå®åºåºæ«è¢ç æ¶æ ¡éªè¯¥è¢å·²è´¨æ£åæ ¼ã</p> |
| | | * |
| | | * @author è¶
级管çå |
| | | */ |
| | | @Getter |
| | | @AllArgsConstructor |
| | | public enum MesProBagCodeQcStatusEnum implements ArrayValuable<Integer> { |
| | | |
| | | UNCHECKED(10, "æªè´¨æ£"), |
| | | QUALIFIED(20, "è´¨æ£åæ ¼"), |
| | | UNQUALIFIED(30, "è´¨æ£ä¸åæ ¼"); |
| | | |
| | | public static final Integer[] ARRAYS = Arrays.stream(values()).map(MesProBagCodeQcStatusEnum::getStatus).toArray(Integer[]::new); |
| | | |
| | | /** |
| | | * ç¶æ |
| | | */ |
| | | private final Integer status; |
| | | /** |
| | | * ç¶æåç§° |
| | | */ |
| | | private final String name; |
| | | |
| | | @Override |
| | | public Integer[] array() { |
| | | return ARRAYS; |
| | | } |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.mes.enums.wm; |
| | | |
| | | import lombok.AllArgsConstructor; |
| | | import lombok.Getter; |
| | | |
| | | @Getter |
| | | @AllArgsConstructor |
| | | public enum MesWmMaterialStockBagStatusEnum { |
| | | ACTIVE(1, "å¨åº"), |
| | | OUT(2, "å·²åºåº"), |
| | | SCRAPPED(3, "å·²æ¥åº"); |
| | | |
| | | private final Integer status; |
| | | private final String name; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.mes.enums.wm; |
| | | |
| | | import lombok.AllArgsConstructor; |
| | | import lombok.Getter; |
| | | |
| | | /** |
| | | * MES ä»åºç±»å |
| | | * |
| | | * ä¸ {@link MesWmStockStateEnum} è¯ä¹å¯¹é½ï¼æååºåæ¾å¾
æ£/æååºåï¼åæ ¼åºåæ¾è´¨æ£åæ ¼ã坿£è´§åºåã |
| | | */ |
| | | @Getter |
| | | @AllArgsConstructor |
| | | public enum MesWmWarehouseTypeEnum { |
| | | |
| | | TEMP(10, "æååº"), |
| | | QUALIFIED(20, "åæ ¼åº"); |
| | | |
| | | private final Integer type; |
| | | private final String name; |
| | | } |
| | |
| | | if (StrUtil.isNotEmpty(bagCode.getPalletCode())) { |
| | | keyValues.put("ç»å®æç", bagCode.getPalletCode()); |
| | | } |
| | | // åç§ä¼å
åè¢ç èªèº«ï¼æ°æ®å
çææ¶ç»å®ï¼æªå½æ¹æ¬¡ä¹å¯æå°ï¼ï¼åå²è¢ç åéæ¹æ¬¡åç§ |
| | | if (StrUtil.isNotEmpty(bagCode.getItemName())) { |
| | | keyValues.put("åç§", bagCode.getItemName()); |
| | | } |
| | | if (batch != null) { |
| | | fillBatchKeyValues(keyValues, batch, itemMap, userMap); |
| | | } |
| | |
| | | summary.setBagCodeCount(getCount(homeStatisticsMapper.selectBagCodeCount())); |
| | | summary.setPalletCount(getCount(homeStatisticsMapper.selectPalletCount())); |
| | | |
| | | // 3. ç¶æåå¸ |
| | | // 3. åºåºæµé |
| | | summary.setSalesNoticeCount(getCount(homeStatisticsMapper.selectSalesNoticeCount())); |
| | | summary.setProductSalesCount(getCount(homeStatisticsMapper.selectProductSalesCount())); |
| | | summary.setReturnSalesCount(getCount(homeStatisticsMapper.selectReturnSalesCount())); |
| | | |
| | | // 4. ä»å¨é¢è¦ / è´¨é |
| | | summary.setStockWarningPendingCount(getCount(homeStatisticsMapper.selectStockWarningPendingCount())); |
| | | summary.setNcrPendingCount(getCount(homeStatisticsMapper.selectNcrPendingCount())); |
| | | |
| | | // 5. ç¶æåå¸ |
| | | summary.setBatchStatusList(toStatusList(homeStatisticsMapper.selectBatchCountGroupByStatus())); |
| | | summary.setBagCodeStatusList(toStatusList(homeStatisticsMapper.selectBagCodeCountGroupByStatus())); |
| | | |
| | |
| | | import cn.hutool.core.lang.Assert; |
| | | import cn.hutool.core.util.StrUtil; |
| | | import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; |
| | | import cn.iocoder.yudao.framework.common.util.number.BizNoUtils; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.md.autocode.MesMdAutoCodePartDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.md.autocode.MesMdAutoCodeRecordDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.md.autocode.MesMdAutoCodeRuleDO; |
| | |
| | | import cn.iocoder.yudao.module.mes.service.md.autocode.strategy.MesMdAutoCodePartStrategy; |
| | | import jakarta.annotation.PostConstruct; |
| | | import jakarta.annotation.Resource; |
| | | import org.springframework.data.redis.core.StringRedisTemplate; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | import org.springframework.validation.annotation.Validated; |
| | |
| | | private MesMdAutoCodeRuleService ruleService; |
| | | @Resource |
| | | private MesMdAutoCodePartService partService; |
| | | |
| | | @Resource |
| | | private StringRedisTemplate stringRedisTemplate; |
| | | |
| | | @Resource |
| | | private List<MesMdAutoCodePartStrategy> strategyList; |
| | |
| | | */ |
| | | private String generateCode(MesMdAutoCodeRuleDO rule, List<MesMdAutoCodePartDO> parts, |
| | | MesMdAutoCodeContext context) { |
| | | StringBuilder codeBuilder = new StringBuilder(); |
| | | for (MesMdAutoCodePartDO part : parts) { |
| | | MesMdAutoCodePartStrategy strategy = strategyMap.get(part.getType()); |
| | | Assert.notNull(strategy, () -> exception(AUTO_CODE_GENERATE_FAILED)); |
| | | // çæå段ç¼ç |
| | | String partCode = strategy.generate(part, context); |
| | | // ç»ä¸æªåæå®é¿åº¦ |
| | | partCode = StrUtil.sub(partCode, 0, part.getLength()); |
| | | // æ¼æ¥å段ç¼ç |
| | | codeBuilder.append(partCode); |
| | | // éæ±ï¼ææä¸å¡ç¼ç ç»ä¸ä¸ºã16 ä½çº¯æ°åãï¼ä¸å
¨ç³»ç»å¯ä¸ã |
| | | // å æ¤ä¸åæè§ååæ®µæ¼è£
ï¼åºå®å符/æ¥ææ®µä¼å¸¦å
¥åæ¯ï¼ï¼æ¹ä¸ºåå
¨ç³»ç»ç»ä¸èªå¢åºåã |
| | | // éæºçæ 16 ä½çº¯æ°åç¼ç ï¼å¹¶ç¨ Redis é忥éï¼ä¿è¯å
¨ç³»ç»å¯ä¸ï¼ä¸ä½¿ç¨èªå¢/顺åºï¼ |
| | | for (int i = 0; i < BizNoUtils.MAX_RETRY; i++) { |
| | | String code = BizNoUtils.randomCode(); |
| | | Long added = stringRedisTemplate.opsForSet().add(BizNoUtils.USED_SET_KEY, code); |
| | | if (added != null && added > 0) { |
| | | return code; |
| | | } |
| | | } |
| | | // è¡¥é½å¤ç |
| | | String result = codeBuilder.toString(); |
| | | if (Boolean.TRUE.equals(rule.getPadded()) && rule.getMaxLength() != null) { |
| | | result = padCode(result, rule); |
| | | } |
| | | return result; |
| | | throw new IllegalStateException("çæå¯ä¸ä¸å¡ç¼ç 失败ï¼è¯·éè¯"); |
| | | } |
| | | |
| | | /** |
| | |
| | | validateItemCodeUnique(reqVO.getId(), reqVO.getCode()); |
| | | // æ ¡éªç©æåç§°çå¯ä¸æ§ |
| | | validateItemNameUnique(reqVO.getId(), reqVO.getName()); |
| | | // æ ¡éªç©æåç±»åå¨ |
| | | validateItemTypeExists(reqVO.getItemTypeId()); |
| | | // æ ¡éªç©æåç±»åå¨ï¼MDM åç§åæ¥ä¸ä¼ åç±»ï¼å
è®¸ä¸ºç©ºï¼ |
| | | if (reqVO.getItemTypeId() != null) { |
| | | validateItemTypeExists(reqVO.getItemTypeId()); |
| | | } |
| | | // æ ¡éªè®¡éåä½åå¨ |
| | | validateUnitMeasureExists(reqVO.getUnitMeasureId()); |
| | | } |
| | |
| | | import cn.iocoder.yudao.module.mes.controller.admin.pro.bagcode.vo.MesProBagCodeGenerateReqVO; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.pro.bagcode.vo.MesProBagCodeGenerateRespVO; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.pro.bagcode.vo.MesProBagCodePageReqVO; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.pro.bagcode.vo.MesProBagCodeRawGenerateReqVO; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.pro.bagcode.vo.MesProBagCodeReplaceReqVO; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.pro.bagcode.vo.MesProBagCodeReplaceRespVO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.pro.bagcode.MesProBagCodeDO; |
| | |
| | | */ |
| | | MesProBagCodeGenerateRespVO generateBagCodes(@Valid MesProBagCodeGenerateReqVO generateReqVO); |
| | | |
| | | /** |
| | | * çæåå§è¢ç ï¼ä»
éåç§+è¢ç æ°éï¼ä¸æ ¡éªè®¡éåä½ç±»åãä¸çææçï¼ |
| | | * è¢ç 带åç§åä½ï¼åç»å¯æ£å¸¸å½å
¥æ¹æ¬¡/ç»å®æç |
| | | * |
| | | * @param rawGenerateReqVO çæä¿¡æ¯ |
| | | * @return çæç» UUID 䏿°éï¼type/perPallet/palletIds ä¸ºç©ºï¼ |
| | | */ |
| | | MesProBagCodeGenerateRespVO generateRawBagCodes(@Valid MesProBagCodeRawGenerateReqVO rawGenerateReqVO); |
| | | |
| | | void bindBatch(@Valid MesProBagCodeBindBatchReqVO bindReqVO); |
| | | |
| | | /** |
| | |
| | | import cn.hutool.core.collection.CollUtil; |
| | | import cn.hutool.core.util.IdUtil; |
| | | import cn.hutool.core.util.StrUtil; |
| | | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| | | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| | | import cn.iocoder.yudao.module.mdm.api.unit.MdmUnitMeasureApi; |
| | | import cn.iocoder.yudao.module.mdm.api.unit.dto.MdmUnitMeasureRespDTO; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.pro.bagcode.vo.MesProBagCodeBindBatchReqVO; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.pro.bagcode.vo.MesProBagCodeBindReqVO; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.pro.bagcode.vo.MesProBagCodeGenerateReqVO; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.pro.bagcode.vo.MesProBagCodeGenerateRespVO; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.pro.bagcode.vo.MesProBagCodePageReqVO; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.pro.bagcode.vo.MesProBagCodeRawGenerateReqVO; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.pro.bagcode.vo.MesProBagCodeReplaceItemRespVO; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.pro.bagcode.vo.MesProBagCodeReplaceReqVO; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.pro.bagcode.vo.MesProBagCodeReplaceRespVO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.mdm.MesMdmItemDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.pro.bagcode.MesProBagCodeDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.pro.bagcode.MesProBagCodeReplaceDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.pro.batch.MesProBatchDO; |
| | |
| | | import cn.iocoder.yudao.module.mes.dal.mysql.pro.bagcode.MesProBagCodeReplaceMapper; |
| | | import cn.iocoder.yudao.module.mes.dal.mysql.pro.batch.MesProBatchMapper; |
| | | import cn.iocoder.yudao.module.mes.dal.mysql.pro.pallet.MesProPalletMapper; |
| | | import cn.iocoder.yudao.module.mes.dal.redis.MesCodeRedisDAO; |
| | | import cn.iocoder.yudao.module.mes.enums.pro.MesProBagCodeStatusEnum; |
| | | import cn.iocoder.yudao.module.mes.enums.pro.MesProBatchStatusEnum; |
| | | import cn.iocoder.yudao.module.mes.enums.pro.MesProPalletStatusEnum; |
| | | import cn.iocoder.yudao.module.mes.service.mdm.MesMdmItemService; |
| | | import cn.iocoder.yudao.module.mes.service.pro.pallet.MesProPalletService; |
| | | import jakarta.annotation.Resource; |
| | | import lombok.extern.slf4j.Slf4j; |
| | |
| | | import java.util.ArrayList; |
| | | import java.util.Collection; |
| | | 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.regex.Matcher; |
| | | import java.util.regex.Pattern; |
| | | |
| | | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| | | import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*; |
| | |
| | | |
| | | @Resource |
| | | private MesProPalletService palletService; |
| | | @Resource |
| | | private MesMdmItemService mdmItemService; |
| | | @Resource |
| | | private MdmUnitMeasureApi unitMeasureApi; |
| | | |
| | | /** |
| | | * 计éåä½ç±»åãå¨ãï¼æ æç模å¼ï¼ |
| | | */ |
| | | private static final String UNIT_TYPE_TON = "å¨"; |
| | | /** |
| | | * 计éåä½ç±»åãNåå
ãï¼æ¯æçè£
N 个è¢ç |
| | | */ |
| | | private static final Pattern KG_TYPE_PATTERN = Pattern.compile("^(\\d{1,5})åå
$"); |
| | | |
| | | @Resource |
| | | private MesCodeRedisDAO codeRedisDao; |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public MesProBagCodeGenerateRespVO generateBagCodes(MesProBagCodeGenerateReqVO generateReqVO) { |
| | | if (generateReqVO.getCount() == null || generateReqVO.getCount() <= 0) { |
| | | throw exception(PRO_BAG_CODE_GENERATE_COUNT_INVALID); |
| | | // 1. æ ¡éªåç§å¹¶è¯»å主计éåä½ç±»å |
| | | MesMdmItemDO item = mdmItemService.validateItemExists(generateReqVO.getItemId()); |
| | | String type = getUnitType(item); |
| | | |
| | | // 2. æç±»åæ¢ç®è¢ç æ°éï¼Nåå
= æ¯æ N è¢ Ã æçæ°ï¼å¨ = ç´æ¥è¾å
¥è¢ç æ°ï¼æ æçï¼ |
| | | boolean ton = UNIT_TYPE_TON.equals(type); |
| | | int perPallet = ton ? 0 : parseKgPerPallet(type); |
| | | int totalCount; |
| | | int palletCount = 0; |
| | | if (ton) { |
| | | if (generateReqVO.getBagCount() == null || generateReqVO.getBagCount() <= 0) { |
| | | throw exception(PRO_BAG_CODE_GENERATE_COUNT_INVALID); |
| | | } |
| | | totalCount = generateReqVO.getBagCount(); |
| | | } else { |
| | | if (generateReqVO.getPalletCount() == null || generateReqVO.getPalletCount() <= 0) { |
| | | throw exception(PRO_BAG_CODE_PALLET_COUNT_REQUIRED); |
| | | } |
| | | palletCount = generateReqVO.getPalletCount(); |
| | | totalCount = perPallet * palletCount; |
| | | } |
| | | |
| | | // çæé¶æ®µåªå建å
¨å±å¯ä¸è¢ç ï¼çäº§æ¹æ¬¡å¨åç»å½å
¥ |
| | | int startNo = bagCodeMapper.selectMaxBagNo() + 1; |
| | | // 3. çæé¶æ®µï¼è¢ç ç´æ¥ç»å®åç§ï¼çäº§æ¹æ¬¡å¨åç»å½å
¥ |
| | | String uuid = IdUtil.fastSimpleUUID(); |
| | | List<MesProPalletDO> pallets = new ArrayList<>(palletCount); |
| | | if (!ton) { |
| | | for (int i = 0; i < palletCount; i++) { |
| | | pallets.add(new MesProPalletDO() |
| | | .setTempCode(codeRedisDao.generate()) |
| | | .setBagCount(perPallet) |
| | | .setAutoGenerated(true) |
| | | .setStatus(MesProPalletStatusEnum.IN_USE.getStatus())); |
| | | } |
| | | palletMapper.insertBatch(pallets); |
| | | } |
| | | int startNo = bagCodeMapper.selectMaxBagNo() + 1; |
| | | List<MesProBagCodeDO> bagCodes = new ArrayList<>(totalCount); |
| | | for (int i = 0; i < totalCount; i++) { |
| | | int bagNo = startNo + i; |
| | | MesProPalletDO pallet = ton ? null : pallets.get(i / perPallet); |
| | | bagCodes.add(new MesProBagCodeDO() |
| | | .setUuid(uuid) |
| | | .setCode(codeRedisDao.generate()) |
| | | .setBagNo(bagNo) |
| | | .setItemId(item.getId()) |
| | | .setItemCode(item.getCode()) |
| | | .setItemName(item.getName()) |
| | | .setPalletId(pallet == null ? null : pallet.getId()) |
| | | .setPalletCode(pallet == null ? null : pallet.getTempCode()) |
| | | .setStatus(MesProBagCodeStatusEnum.GENERATED.getStatus()) |
| | | .setRemark(generateReqVO.getRemark())); |
| | | } |
| | | bagCodeMapper.insertBatch(bagCodes); |
| | | return new MesProBagCodeGenerateRespVO() |
| | | .setUuid(uuid) |
| | | .setType(type) |
| | | .setPerPallet(perPallet) |
| | | .setTotalCount(totalCount) |
| | | .setPalletIds(pallets.stream().map(MesProPalletDO::getId).toList()); |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public MesProBagCodeGenerateRespVO generateRawBagCodes(MesProBagCodeRawGenerateReqVO generateReqVO) { |
| | | // åå§è¢ç ä¸ä¾èµè®¡éåä½ç±»å䏿çï¼ä»
ææ°éçæï¼è¢ç 带åç§åä½ï¼åç»å¯æ£å¸¸å½å
¥æ¹æ¬¡/ç»å®æç |
| | | MesMdmItemDO item = mdmItemService.validateItemExists(generateReqVO.getItemId()); |
| | | String uuid = IdUtil.fastSimpleUUID(); |
| | | int startNo = bagCodeMapper.selectMaxBagNo() + 1; |
| | | List<MesProBagCodeDO> bagCodes = new ArrayList<>(generateReqVO.getCount()); |
| | | for (int i = 0; i < generateReqVO.getCount(); i++) { |
| | | int bagNo = startNo + i; |
| | | bagCodes.add(new MesProBagCodeDO() |
| | | .setUuid(uuid) |
| | | .setCode("BAG-" + StrUtil.padPre(String.valueOf(bagNo), 8, '0')) |
| | | .setCode(codeRedisDao.generate()) |
| | | .setBagNo(bagNo) |
| | | .setItemId(item.getId()) |
| | | .setItemCode(item.getCode()) |
| | | .setItemName(item.getName()) |
| | | .setStatus(MesProBagCodeStatusEnum.GENERATED.getStatus()) |
| | | .setRemark(generateReqVO.getRemark())); |
| | | } |
| | | bagCodeMapper.insertBatch(bagCodes); |
| | | return new MesProBagCodeGenerateRespVO().setUuid(uuid); |
| | | return new MesProBagCodeGenerateRespVO() |
| | | .setUuid(uuid) |
| | | .setTotalCount(bagCodes.size()) |
| | | .setPalletIds(List.of()); |
| | | } |
| | | |
| | | /** |
| | | * 读ååç§ä¸»è®¡éåä½çç±»åï¼48åå
/100åå
/å¨ï¼ï¼æªé
ç½®ææ æ³è¯å«æ¶æ¥é |
| | | */ |
| | | private String getUnitType(MesMdmItemDO item) { |
| | | String type = null; |
| | | if (item.getUnitMeasureId() != null) { |
| | | CommonResult<MdmUnitMeasureRespDTO> result = unitMeasureApi.getUnitMeasure(item.getUnitMeasureId()); |
| | | if (result != null && result.isSuccess() && result.getData() != null) { |
| | | type = StrUtil.trimToNull(result.getData().getType()); |
| | | } |
| | | } |
| | | if (type == null) { |
| | | throw exception(PRO_BAG_CODE_ITEM_TYPE_NOT_CONFIGURED); |
| | | } |
| | | if (!UNIT_TYPE_TON.equals(type) && !KG_TYPE_PATTERN.matcher(type).matches()) { |
| | | throw exception(PRO_BAG_CODE_ITEM_TYPE_NOT_CONFIGURED); |
| | | } |
| | | return type; |
| | | } |
| | | |
| | | /** |
| | | * è§£æãNåå
ãç±»åå¾åºæ¯æçè¢æ° |
| | | */ |
| | | private int parseKgPerPallet(String type) { |
| | | Matcher matcher = KG_TYPE_PATTERN.matcher(type); |
| | | if (!matcher.matches()) { |
| | | throw exception(PRO_BAG_CODE_ITEM_TYPE_NOT_CONFIGURED); |
| | | } |
| | | return Integer.parseInt(matcher.group(1)); |
| | | } |
| | | |
| | | @Override |
| | |
| | | List<Long> ids = bindReqVO.getIds().stream().distinct().toList(); |
| | | List<MesProBagCodeDO> bagCodes = bagCodeMapper.selectListByIdsForUpdate(ids); |
| | | if (bagCodes.size() != ids.size() || bagCodes.stream().anyMatch(code -> |
| | | code.getBatchId() != null || !MesProBagCodeStatusEnum.GENERATED.getStatus().equals(code.getStatus()))) { |
| | | code.getBatchId() != null |
| | | || (!MesProBagCodeStatusEnum.GENERATED.getStatus().equals(code.getStatus()) |
| | | && !MesProBagCodeStatusEnum.PRINTED.getStatus().equals(code.getStatus())))) { |
| | | throw exception(PRO_BAG_CODE_STATUS_NOT_GENERATED); |
| | | } |
| | | // å½å
¥çè¢ç å¿
é¡»å±äºåä¸åç§ï¼ä¸ä¸æ¹æ¬¡å·²æè¢ç åç§ä¸è´ï¼åå²ç©ºç½è¢ç item 为空ä¸å䏿 ¡éªï¼ |
| | | Set<Long> itemIds = new LinkedHashSet<>(); |
| | | bagCodes.stream().map(MesProBagCodeDO::getItemId).filter(Objects::nonNull).forEach(itemIds::add); |
| | | itemIds.addAll(bagCodeMapper.selectDistinctItemIdsByBatchId(batch.getId())); |
| | | if (itemIds.size() > 1) { |
| | | throw exception(PRO_BAG_CODE_BIND_BATCH_ITEM_MISMATCH); |
| | | } |
| | | if (bagCodeMapper.bindBatchByIds(ids, batch.getId(), batch.getCode(), |
| | | MesProBagCodeStatusEnum.GENERATED.getStatus()) != ids.size()) { |
| | | List.of(MesProBagCodeStatusEnum.GENERATED.getStatus(), |
| | | MesProBagCodeStatusEnum.PRINTED.getStatus())) != ids.size()) { |
| | | throw exception(PRO_BAG_CODE_STATUS_NOT_GENERATED); |
| | | } |
| | | batchMapper.updateById(new MesProBatchDO().setId(batch.getId()) |
| | | .setBagQuantity(bagCodeMapper.selectEffectiveCountByBatchId(batch.getId()))); |
| | | // 级èï¼æ¬ç»è¢ç ç»å®çæªå
¥æ¹æ¬¡æçï¼åé
æ£å¼æçç å¹¶ç»å®æ¹æ¬¡ |
| | | bindPalletsToBatch(bagCodes, batch); |
| | | } |
| | | |
| | | /** |
| | | * è¢ç å½å
¥æ¹æ¬¡æ¶ï¼å°å
¶ç»å®çä¸´æ¶æçï¼æªç»å®æ¹æ¬¡ï¼çº§èç»å®å°å䏿¹æ¬¡ï¼ |
| | | * åé
æ£å¼æçç ï¼16 ä½éæºæ°åï¼ä¸æçç çæè§åä¸è´ï¼ãååè¢ç ä¸çå使çç ãç´¯è®¡æ¹æ¬¡æçæ° |
| | | */ |
| | | private void bindPalletsToBatch(List<MesProBagCodeDO> bagCodes, MesProBatchDO batch) { |
| | | List<Long> palletIds = bagCodes.stream().map(MesProBagCodeDO::getPalletId) |
| | | .filter(Objects::nonNull).distinct().sorted().toList(); |
| | | if (palletIds.isEmpty()) { |
| | | return; |
| | | } |
| | | int nextPalletNo = palletMapper.selectMaxPalletNo(batch.getId()) + 1; |
| | | int boundCount = 0; |
| | | for (Long palletId : palletIds) { |
| | | MesProPalletDO pallet = palletMapper.selectByIdForUpdate(palletId); |
| | | if (pallet == null || pallet.getBatchId() != null || StrUtil.isNotEmpty(pallet.getCode())) { |
| | | continue; |
| | | } |
| | | String palletCode = codeRedisDao.generate(); |
| | | palletMapper.updateById(new MesProPalletDO().setId(palletId) |
| | | .setCode(palletCode) |
| | | .setBatchId(batch.getId()) |
| | | .setBatchCode(batch.getCode()) |
| | | .setPalletNo(nextPalletNo++)); |
| | | // è¢ç ä¸çå使çç ç±ä¸´æ¶ç æ´æ°ä¸ºæ£å¼ç |
| | | bagCodeMapper.updatePalletCodeByPalletId(palletId, palletCode); |
| | | boundCount++; |
| | | } |
| | | if (boundCount > 0) { |
| | | batchMapper.updateById(new MesProBatchDO().setId(batch.getId()) |
| | | .setPalletQuantity((batch.getPalletQuantity() == null ? 0 : batch.getPalletQuantity()) + boundCount)); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | |
| | | MesProPalletDO pallet = oldBagCode.getPalletId() == null ? null : palletMap.get(oldBagCode.getPalletId()); |
| | | MesProBagCodeDO newBagCode = new MesProBagCodeDO() |
| | | .setUuid(replaceUuid) |
| | | .setCode(batch.getCode() + "-" + StrUtil.padPre(String.valueOf(newBagNo), 4, '0')) |
| | | .setCode(codeRedisDao.generate()) |
| | | .setBagNo(newBagNo) |
| | | .setBatchId(batch.getId()) |
| | | .setBatchCode(batch.getCode()) |
| | | .setItemId(oldBagCode.getItemId()) |
| | | .setItemCode(oldBagCode.getItemCode()) |
| | | .setItemName(oldBagCode.getItemName()) |
| | | .setPalletId(pallet == null ? null : pallet.getId()) |
| | | .setPalletCode(pallet == null ? null : pallet.getCode()) |
| | | .setStatus(MesProBagCodeStatusEnum.GENERATED.getStatus()) |
| | |
| | | if (CollUtil.isEmpty(bagCodes)) { |
| | | throw exception(PRO_BAG_CODE_UUID_NOT_EXISTS); |
| | | } |
| | | // 2. æ ¡éªå为已çæç¶æä¸æªç»å®æç |
| | | // 2. æ ¡éªå为已çæç¶æ |
| | | if (bagCodes.stream().anyMatch(bagCode -> |
| | | !MesProBagCodeStatusEnum.GENERATED.getStatus().equals(bagCode.getStatus()))) { |
| | | throw exception(PRO_BAG_CODE_STATUS_NOT_GENERATED); |
| | | } |
| | | if (bagCodes.stream().anyMatch(bagCode -> bagCode.getPalletId() != null)) { |
| | | throw exception(PRO_BAG_CODE_BIND_PALLET_BOUND); |
| | | // 3. ç»å®çæçä»
é"èªå¨çæä¸æªç»å®æ¹æ¬¡"ï¼çææ°æ®å
æ¶èªå¨ç»å®ï¼ï¼çº§èå é¤ï¼å·²å
¥æ¹æ¬¡çæçä¸å
许éå
å é¤ |
| | | Set<Long> palletIds = new LinkedHashSet<>(); |
| | | bagCodes.stream().map(MesProBagCodeDO::getPalletId).filter(Objects::nonNull).forEach(palletIds::add); |
| | | for (Long palletId : palletIds) { |
| | | MesProPalletDO pallet = palletMapper.selectById(palletId); |
| | | if (pallet != null && (pallet.getBatchId() != null || StrUtil.isNotEmpty(pallet.getCode()))) { |
| | | throw exception(PRO_BAG_CODE_BIND_PALLET_BOUND); |
| | | } |
| | | } |
| | | // 3. å é¤çæç» |
| | | // 4. å é¤çæç»ä¸å
¶èªå¨çæçä¸´æ¶æç |
| | | bagCodeMapper.deleteByIds(bagCodes.stream().map(MesProBagCodeDO::getId).toList()); |
| | | // 4. ååæ¹æ¬¡è¢ç æ°é |
| | | if (!palletIds.isEmpty()) { |
| | | palletMapper.deleteByIds(palletIds); |
| | | } |
| | | // 5. ååæ¹æ¬¡è¢ç æ°é |
| | | MesProBatchDO batch = batchMapper.selectById(bagCodes.get(0).getBatchId()); |
| | | if (batch != null && batch.getBagQuantity() != null) { |
| | | batchMapper.updateById(new MesProBatchDO().setId(batch.getId()) |
| | |
| | | } |
| | | // 2. éå®å¹¶æ ¡éªè¢ç |
| | | List<MesProBagCodeDO> bagCodes = validateBagCodesForBind(bindReqVO.getIds(), pallet, true); |
| | | // 3. æ ¡éªä¸è¶
è¿æçå¯è£
è¢æ° |
| | | // 3. ç»å®è¢ç å¹¶ç´¯å æçå·²è£
è¢æ°ï¼æçæ 容éä¸éï¼ |
| | | int currentCount = pallet.getBagCount() == null ? 0 : pallet.getBagCount(); |
| | | if (pallet.getCapacity() != null && pallet.getCapacity() > 0 |
| | | && currentCount + bagCodes.size() > pallet.getCapacity()) { |
| | | throw exception(PRO_BAG_CODE_BIND_PALLET_OVER_CAPACITY); |
| | | } |
| | | // 4. ç»å®è¢ç å¹¶ç´¯å æçå·²è£
è¢æ° |
| | | bagCodeMapper.bindPalletByIds(bindReqVO.getIds(), pallet.getId(), pallet.getCode()); |
| | | palletService.updatePalletBagCount(pallet.getId(), currentCount + bagCodes.size()); |
| | | } |
| | |
| | | import cn.iocoder.yudao.module.mes.controller.admin.pro.batch.vo.MesProBatchPageReqVO; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.pro.batch.vo.MesProBatchPreGenerateReqVO; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.pro.batch.vo.MesProBatchSaveReqVO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.mdm.MesMdmItemDO; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.pro.pallet.vo.MesProPalletBindBatchReqVO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.pro.batch.MesProBatchDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.pro.batch.MesProBatchWorkerDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.pro.line.MesProLineDO; |
| | |
| | | import cn.iocoder.yudao.module.mes.dal.mysql.pro.batch.MesProBatchMapper; |
| | | import cn.iocoder.yudao.module.mes.dal.mysql.pro.batch.MesProBatchWorkerMapper; |
| | | import cn.iocoder.yudao.module.mes.dal.mysql.pro.pallet.MesProPalletMapper; |
| | | import cn.iocoder.yudao.module.mes.dal.redis.MesCodeRedisDAO; |
| | | import cn.iocoder.yudao.module.mes.enums.md.autocode.MesMdAutoCodeRuleCodeEnum; |
| | | import cn.iocoder.yudao.module.mes.enums.pro.MesProBatchStatusEnum; |
| | | import cn.iocoder.yudao.module.mes.service.md.autocode.MesMdAutoCodeRecordService; |
| | | import cn.iocoder.yudao.module.mes.service.mdm.MesMdmItemService; |
| | | import cn.iocoder.yudao.module.mes.service.pro.line.MesProLineService; |
| | | import cn.iocoder.yudao.module.mes.service.pro.pallet.MesProPalletService; |
| | | import cn.iocoder.yudao.module.mes.service.trace.integrity.MesTraceIntegrityService; |
| | | import cn.iocoder.yudao.module.system.api.user.AdminUserApi; |
| | | import jakarta.annotation.Resource; |
| | |
| | | private MesProPalletMapper palletMapper; |
| | | |
| | | @Resource |
| | | private MesProPalletService palletService; |
| | | |
| | | @Resource |
| | | private MesCodeRedisDAO codeRedisDao; |
| | | |
| | | @Resource |
| | | private MesMdAutoCodeRecordService autoCodeRecordService; |
| | | @Resource |
| | | private AdminUserApi adminUserApi; |
| | | @Resource |
| | | private MesMdmItemService mdmItemService; |
| | | @Resource |
| | | private MesProLineService lineService; |
| | | @Resource |
| | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public Long createBatch(MesProBatchSaveReqVO createReqVO) { |
| | | // 1. æ ¡éªå
³èæ°æ®ï¼åç§ã产线ãç产人åï¼ |
| | | MesMdmItemDO item = mdmItemService.validateItemExists(createReqVO.getItemId()); |
| | | // 1. æ ¡éªå
³èæ°æ®ï¼äº§çº¿ãç产人åï¼ |
| | | MesProLineDO line = lineService.validateLineExistsAndEnable(createReqVO.getLineId()); |
| | | validateRelations(createReqVO); |
| | | |
| | | // 2. çææ¹æ¬¡å·ï¼ç¼ç è§åï¼åç¼ + æ¥æ + 产线ç¼ç + åç§ç¼ç + æµæ°´å·ï¼ |
| | | String code = generateBatchCode(line.getCode(), item.getCode()); |
| | | // 2. çææ¹æ¬¡å·ï¼ç¼ç è§åï¼åç¼ + æ¥æ + 产线ç¼ç + æµæ°´å·ï¼ |
| | | String code = generateBatchCode(line.getCode()); |
| | | |
| | | // 3. æå
¥æ¹æ¬¡ï¼äº§çº¿ç¼ç /åç§°åä½åå¡«ï¼ |
| | | // 3. æå
¥æ¹æ¬¡ï¼äº§çº¿ç¼ç /åç§°åä½åå¡«ï¼å¾éç»å®æçæ¶æ¹æ¬¡ç´æ¥è¿å
¥ç产ä¸ï¼ |
| | | boolean bindPallets = CollUtil.isNotEmpty(createReqVO.getPalletIds()); |
| | | MesProBatchDO batch = BeanUtils.toBean(createReqVO, MesProBatchDO.class) |
| | | .setCode(code) |
| | | .setLineCode(line.getCode()) |
| | | .setLineName(line.getName()) |
| | | .setBagQuantity(0) |
| | | .setPalletQuantity(0) |
| | | .setStatus(MesProBatchStatusEnum.DRAFT.getStatus()); |
| | | .setStatus(bindPallets ? MesProBatchStatusEnum.PRODUCING.getStatus() |
| | | : MesProBatchStatusEnum.DRAFT.getStatus()); |
| | | batchMapper.insert(batch); |
| | | |
| | | // 4. æå
¥ç产人åé
ç½® |
| | | insertBatchWorkers(batch.getId(), createReqVO.getWorkers()); |
| | | // 5. çææ¹æ¬¡å®æ´æ§æè¦ |
| | | // 5. ç»å®æçï¼çº§èçææ£å¼æçç å¹¶å½å
¥æçä¸è¢ç ï¼å¤±è´¥æ´ä½åæ»ï¼ |
| | | bindPalletsToBatch(batch.getId(), createReqVO.getPalletIds()); |
| | | // 6. çææ¹æ¬¡å®æ´æ§æè¦ |
| | | integrityService.recordBatchIntegrity(batch.getId()); |
| | | return batch.getId(); |
| | | } |
| | |
| | | List<MesProBatchDO> list = new ArrayList<>(reqVO.getCount()); |
| | | for (int i = 0; i < reqVO.getCount(); i++) { |
| | | list.add(new MesProBatchDO() |
| | | .setTempCode("PB-" + StrUtil.padPre(String.valueOf(startSeq + i), 8, '0')) |
| | | .setTempCode(codeRedisDao.generate()) |
| | | .setBagQuantity(0) |
| | | .setPalletQuantity(0) |
| | | .setStatus(MesProBatchStatusEnum.DRAFT.getStatus()) |
| | |
| | | throw exception(PRO_BATCH_ALREADY_FILLED); |
| | | } |
| | | // 2. æ ¡éªå
³èæ°æ®å¹¶çææ£å¼æ¹æ¬¡å· |
| | | MesMdmItemDO item = mdmItemService.validateItemExists(fillReqVO.getItemId()); |
| | | MesProLineDO line = lineService.validateLineExistsAndEnable(fillReqVO.getLineId()); |
| | | validateRelations(fillReqVO); |
| | | String code = generateBatchCode(line.getCode(), item.getCode()); |
| | | // 3. è½åºä¸å¡ä¿¡æ¯ï¼ä¿çä¸´æ¶æ¹æ¬¡ç ç¨äºå岿«ç 追溯ï¼äº§çº¿ç¼ç /åç§°åä½åå¡«ï¼ |
| | | String code = generateBatchCode(line.getCode()); |
| | | // 3. è½åºä¸å¡ä¿¡æ¯ï¼ä¿çä¸´æ¶æ¹æ¬¡ç ç¨äºå岿«ç 追溯ï¼äº§çº¿ç¼ç /åç§°åä½åå¡«ï¼å¾éç»å®æçæ¶æ¹æ¬¡ç´æ¥è¿å
¥ç产ä¸ï¼ |
| | | boolean bindPallets = CollUtil.isNotEmpty(fillReqVO.getPalletIds()); |
| | | MesProBatchDO updateObj = BeanUtils.toBean(fillReqVO, MesProBatchDO.class) |
| | | .setCode(code) |
| | | .setLineCode(line.getCode()) |
| | | .setLineName(line.getName()) |
| | | .setStatus(MesProBatchStatusEnum.DRAFT.getStatus()); |
| | | .setStatus(bindPallets ? MesProBatchStatusEnum.PRODUCING.getStatus() |
| | | : MesProBatchStatusEnum.DRAFT.getStatus()); |
| | | batchMapper.updateById(updateObj); |
| | | // 4. é建ç产人åé
ç½® |
| | | batchWorkerMapper.deleteByBatchId(fillReqVO.getId()); |
| | | insertBatchWorkers(fillReqVO.getId(), fillReqVO.getWorkers()); |
| | | // 5. çææ¹æ¬¡å®æ´æ§æè¦ï¼è¡¥å½æ£å¼ä¿¡æ¯åè¦çï¼ |
| | | // 5. ç»å®æçï¼çº§èçææ£å¼æçç å¹¶å½å
¥æçä¸è¢ç ï¼å¤±è´¥æ´ä½åæ»ï¼ |
| | | bindPalletsToBatch(fillReqVO.getId(), fillReqVO.getPalletIds()); |
| | | // 6. çææ¹æ¬¡å®æ´æ§æè¦ï¼è¡¥å½æ£å¼ä¿¡æ¯åè¦çï¼ |
| | | integrityService.recordBatchIntegrity(fillReqVO.getId()); |
| | | } |
| | | |
| | |
| | | // 2. æ ¡éªå
³èæ°æ®ï¼ç产人åï¼ |
| | | validateRelations(updateReqVO); |
| | | |
| | | // 3. æªçææ£å¼æ¹æ¬¡å·æåç§/产线ååæ¶éæ°çææ¹æ¬¡å·ï¼æ¹æ¬¡å·å
å«äº§çº¿ç¼ç + åç§ç¼ç è¦ç´ ï¼ |
| | | // 3. æªçææ£å¼æ¹æ¬¡å·æäº§çº¿ååæ¶éæ°çææ¹æ¬¡å·ï¼æ¹æ¬¡å·å
å«äº§çº¿ç¼ç è¦ç´ ï¼ |
| | | boolean codeEmpty = StrUtil.isEmpty(oldBatch.getCode()); |
| | | boolean itemChanged = !Objects.equals(oldBatch.getItemId(), updateReqVO.getItemId()); |
| | | boolean lineChanged = !Objects.equals(oldBatch.getLineId(), updateReqVO.getLineId()); |
| | | String code = oldBatch.getCode(); |
| | | MesProBatchDO updateObj = BeanUtils.toBean(updateReqVO, MesProBatchDO.class); |
| | | if (codeEmpty || itemChanged || lineChanged) { |
| | | MesMdmItemDO item = mdmItemService.validateItemExists(updateReqVO.getItemId()); |
| | | if (codeEmpty || lineChanged) { |
| | | // åæ´äº§çº¿æ¶ï¼ç®æ 产线å¿
é¡»å¯ç¨ï¼æªåæ´åä»
æ ¡éªåå¨ï¼é¿å
åç¨äº§çº¿çå岿¹æ¬¡æ æ³ç¼è¾å
¶ä»åæ®µï¼ |
| | | MesProLineDO line = (lineChanged || codeEmpty) |
| | | ? lineService.validateLineExistsAndEnable(updateReqVO.getLineId()) |
| | | : lineService.validateLineExists(updateReqVO.getLineId()); |
| | | code = generateBatchCode(line.getCode(), item.getCode()); |
| | | code = generateBatchCode(line.getCode()); |
| | | updateObj.setLineCode(line.getCode()).setLineName(line.getName()); |
| | | } |
| | | // 4. æ´æ°æ¹æ¬¡ |
| | | // 4. æ´æ°æ¹æ¬¡ï¼å¾éç»å®æçæ¶æ¹æ¬¡ç´æ¥è¿å
¥ç产ä¸ï¼åæ¶å¾éä¸åéï¼å·²ç»å®æçä¸å¯è§£ç»ï¼ |
| | | boolean bindPallets = CollUtil.isNotEmpty(updateReqVO.getPalletIds()); |
| | | updateObj.setCode(code); |
| | | if (bindPallets) { |
| | | updateObj.setStatus(MesProBatchStatusEnum.PRODUCING.getStatus()); |
| | | } |
| | | batchMapper.updateById(updateObj); |
| | | |
| | | // 5. é建ç产人åé
ç½® |
| | | batchWorkerMapper.deleteByBatchId(updateReqVO.getId()); |
| | | insertBatchWorkers(updateReqVO.getId(), updateReqVO.getWorkers()); |
| | | // 6. æè¦è¦çèå´å«åç§/产线/çäº§æ¥æ/è®¡åæ°éï¼ç¼è¾åéæ°çæé¿å
误æ¥ç¯¡æ¹ |
| | | // 6. ç»å®æ°å¢å¾éçæçï¼çº§èçææ£å¼æçç å¹¶å½å
¥æçä¸è¢ç ï¼å¤±è´¥æ´ä½åæ»ï¼ |
| | | bindPalletsToBatch(updateReqVO.getId(), updateReqVO.getPalletIds()); |
| | | // 7. æè¦è¦çèå´å«åç§/产线/çäº§æ¥æ/è®¡åæ°éï¼ç¼è¾åéæ°çæé¿å
误æ¥ç¯¡æ¹ |
| | | integrityService.recordBatchIntegrity(updateReqVO.getId()); |
| | | } |
| | | |
| | |
| | | /** |
| | | * æ ¡éªå
³èæ°æ®ï¼ç产人åï¼è´£ä»»äºº + ç产人åé
ç½®ï¼ |
| | | * <p> |
| | | * åç§ãäº§çº¿çæ ¡éªå¨å建/æ´æ°æµç¨ä¸å
èæ§è¡ï¼éåç¼ç å䏿¹æ¬¡å·çæï¼ |
| | | * äº§çº¿çæ ¡éªå¨å建/æ´æ°æµç¨ä¸å
èæ§è¡ï¼éåç¼ç å䏿¹æ¬¡å·çæï¼ |
| | | */ |
| | | private void validateRelations(MesProBatchSaveReqVO reqVO) { |
| | | Set<Long> userIds = new HashSet<>(); |
| | |
| | | } |
| | | |
| | | /** |
| | | * æ¹æ¬¡ç»å®æçï¼å¯éï¼ï¼åäºå¡å
å¤ç¨æçç»å®æ¹æ¬¡é»è¾ï¼ |
| | | * çææ£å¼æçç 并级èå½å
¥æç䏿ªç»æ¹æ¬¡çè¢ç ï¼å¤±è´¥æ´ä½åæ» |
| | | */ |
| | | private void bindPalletsToBatch(Long batchId, List<Long> palletIds) { |
| | | if (CollUtil.isEmpty(palletIds)) { |
| | | return; |
| | | } |
| | | MesProPalletBindBatchReqVO bindReqVO = new MesProPalletBindBatchReqVO(); |
| | | bindReqVO.setBatchId(batchId); |
| | | bindReqVO.setIds(palletIds); |
| | | palletService.bindBatch(bindReqVO); |
| | | } |
| | | |
| | | /** |
| | | * çææ¹æ¬¡å· |
| | | * <p> |
| | | * ç¼ç è§åï¼åºå®åç¼(PC) + æ¥æ(yyyyMMdd) + è¾å
¥å符(产线ç¼ç + åç§ç¼ç ) + æµæ°´å·(ææ¥å¾ªç¯) |
| | | * ç¼ç è§åï¼åºå®åç¼(PC) + æ¥æ(yyyyMMdd) + è¾å
¥å符(产线ç¼ç ) + æµæ°´å·(ææ¥å¾ªç¯) |
| | | * |
| | | * @param lineCode 产线ç¼ç |
| | | * @param itemCode åç§ï¼ç©æï¼ç¼ç |
| | | * @return æ¹æ¬¡å· |
| | | */ |
| | | private String generateBatchCode(String lineCode, String itemCode) { |
| | | String inputChar = StrUtil.emptyToDefault(lineCode, "") + StrUtil.emptyToDefault(itemCode, ""); |
| | | private String generateBatchCode(String lineCode) { |
| | | String inputChar = StrUtil.emptyToDefault(lineCode, ""); |
| | | return autoCodeRecordService.generateAutoCode(MesMdAutoCodeRuleCodeEnum.PRO_BATCH_CODE.getCode(), inputChar); |
| | | } |
| | | |
| | |
| | | List<MesProPalletDO> getPalletListByBatchId(Long batchId); |
| | | |
| | | /** |
| | | * è·å¾æªç»å®çäº§æ¹æ¬¡çä¸´æ¶æçå表ï¼ä¾æ¹æ¬¡æ°å¢/è¡¥å½ç»å®æçä¸æä½¿ç¨ï¼ |
| | | * |
| | | * @return æçç å表 |
| | | */ |
| | | List<MesProPalletDO> getUnboundPalletList(); |
| | | |
| | | /** |
| | | * è·å¾æçç åè¡¨ï¼æç¼å·åè¡¨ï¼ |
| | | * |
| | | * @param ids ç¼å·å表 |
| | |
| | | import cn.iocoder.yudao.module.mes.controller.admin.pro.pallet.vo.MesProPalletBindBatchReqVO; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.pro.pallet.vo.MesProPalletPageReqVO; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.pro.pallet.vo.MesProPalletPreGenerateReqVO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.pro.bagcode.MesProBagCodeDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.pro.batch.MesProBatchDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.pro.pallet.MesProPalletDO; |
| | | import cn.iocoder.yudao.module.mes.dal.mysql.pro.bagcode.MesProBagCodeMapper; |
| | | import cn.iocoder.yudao.module.mes.dal.mysql.pro.batch.MesProBatchMapper; |
| | | import cn.iocoder.yudao.module.mes.dal.mysql.pro.pallet.MesProPalletMapper; |
| | | import cn.iocoder.yudao.module.mes.dal.redis.MesCodeRedisDAO; |
| | | import cn.iocoder.yudao.module.mes.enums.pro.MesProBagCodeStatusEnum; |
| | | import cn.iocoder.yudao.module.mes.enums.pro.MesProBatchStatusEnum; |
| | | import cn.iocoder.yudao.module.mes.enums.pro.MesProPalletStatusEnum; |
| | | import jakarta.annotation.Resource; |
| | |
| | | |
| | | import java.util.ArrayList; |
| | | import java.util.Collection; |
| | | import java.util.LinkedHashSet; |
| | | import java.util.List; |
| | | import java.util.Set; |
| | | |
| | | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| | | import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*; |
| | |
| | | private MesProBagCodeMapper bagCodeMapper; |
| | | @Resource |
| | | private MesProBatchMapper batchMapper; |
| | | |
| | | @Resource |
| | | private MesCodeRedisDAO codeRedisDao; |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | |
| | | for (int i = 0; i < createReqVO.getCount(); i++) { |
| | | int palletNo = startNo + i; |
| | | pallets.add(new MesProPalletDO() |
| | | .setCode(batch.getCode() + "-P" + StrUtil.padPre(String.valueOf(palletNo), 2, '0')) |
| | | .setCode(codeRedisDao.generate()) |
| | | .setBatchId(batch.getId()) |
| | | .setBatchCode(batch.getCode()) |
| | | .setPalletNo(palletNo) |
| | | .setCapacity(createReqVO.getCapacity()) |
| | | .setBagCount(0) |
| | | .setAutoGenerated(false) |
| | | .setStatus(MesProPalletStatusEnum.IN_USE.getStatus()) |
| | |
| | | List<MesProPalletDO> list = new ArrayList<>(reqVO.getCount()); |
| | | for (int i = 0; i < reqVO.getCount(); i++) { |
| | | list.add(new MesProPalletDO() |
| | | .setTempCode("PL-" + StrUtil.padPre(String.valueOf(startSeq + i), 8, '0')) |
| | | .setCapacity(reqVO.getCapacity()) |
| | | .setTempCode(codeRedisDao.generate()) |
| | | .setBagCount(0) |
| | | .setAutoGenerated(false) |
| | | .setStatus(MesProPalletStatusEnum.IN_USE.getStatus()) |
| | |
| | | } |
| | | pallets.add(pallet); |
| | | } |
| | | // 3. åé
æ£å¼æçç ï¼æ¹æ¬¡å· + -P + 2 使çåºå·ï¼å«é»è¾å é¤è®°å½åä¸åºå·ï¼ä¿è¯ä¸åéãç å¼å¯ä¸ï¼ |
| | | // 3. 级èåå¤ï¼æç䏿ªç»æ¹æ¬¡çè¢ç éæçä¸èµ·å½å
¥æ¹æ¬¡ï¼åç§é¡»ä¸æ¹æ¬¡å·²æè¢ç ä¸è´ |
| | | List<MesProBagCodeDO> bags = bagCodeMapper.selectUnboundListByPalletIds(ids); |
| | | List<Long> bindBagIds = new ArrayList<>(); |
| | | Set<Long> bagItemIds = new LinkedHashSet<>(); |
| | | for (MesProBagCodeDO bag : bags) { |
| | | if (!MesProBagCodeStatusEnum.GENERATED.getStatus().equals(bag.getStatus()) |
| | | && !MesProBagCodeStatusEnum.PRINTED.getStatus().equals(bag.getStatus())) { |
| | | continue; |
| | | } |
| | | bindBagIds.add(bag.getId()); |
| | | if (bag.getItemId() != null) { |
| | | bagItemIds.add(bag.getItemId()); |
| | | } |
| | | } |
| | | if (!bindBagIds.isEmpty()) { |
| | | bagItemIds.addAll(bagCodeMapper.selectDistinctItemIdsByBatchId(batch.getId())); |
| | | if (bagItemIds.size() > 1) { |
| | | throw exception(PRO_BAG_CODE_BIND_BATCH_ITEM_MISMATCH); |
| | | } |
| | | } |
| | | // 4. åé
æ£å¼æçç ï¼æ¹æ¬¡å· + -P + 2 使çåºå·ï¼å«é»è¾å é¤è®°å½åä¸åºå·ï¼ä¿è¯ä¸åéãç å¼å¯ä¸ï¼ |
| | | int startNo = palletMapper.selectMaxPalletNo(batch.getId()) + 1; |
| | | for (int i = 0; i < pallets.size(); i++) { |
| | | int palletNo = startNo + i; |
| | | palletMapper.updateById(new MesProPalletDO() |
| | | .setId(pallets.get(i).getId()) |
| | | .setCode(batch.getCode() + "-P" + StrUtil.padPre(String.valueOf(palletNo), 2, '0')) |
| | | .setCode(codeRedisDao.generate()) |
| | | .setBatchId(batch.getId()) |
| | | .setBatchCode(batch.getCode()) |
| | | .setPalletNo(palletNo)); |
| | | // æçä¸è¢ç çå使çç ç±ä¸´æ¶ç æ´æ°ä¸ºæ£å¼ç |
| | | bagCodeMapper.updatePalletCodeByPalletId(pallets.get(i).getId(), |
| | | batch.getCode() + "-P" + StrUtil.padPre(String.valueOf(palletNo), 2, '0')); |
| | | } |
| | | // 4. ååæ¹æ¬¡æçç æ°é |
| | | // 5. æçä¸è¢ç æ¹éç»å®æ¬æ¹æ¬¡ |
| | | if (!bindBagIds.isEmpty() && bagCodeMapper.bindBatchByIds(bindBagIds, batch.getId(), batch.getCode(), |
| | | List.of(MesProBagCodeStatusEnum.GENERATED.getStatus(), |
| | | MesProBagCodeStatusEnum.PRINTED.getStatus())) != bindBagIds.size()) { |
| | | throw exception(PRO_BAG_CODE_STATUS_NOT_GENERATED); |
| | | } |
| | | // 6. ååæ¹æ¬¡æçç æ°é䏿æè¢ç æ°é |
| | | batchMapper.updateById(new MesProBatchDO().setId(batch.getId()) |
| | | .setPalletQuantity((batch.getPalletQuantity() == null ? 0 : batch.getPalletQuantity()) + pallets.size())); |
| | | .setPalletQuantity((batch.getPalletQuantity() == null ? 0 : batch.getPalletQuantity()) + pallets.size()) |
| | | .setBagQuantity(bagCodeMapper.selectEffectiveCountByBatchId(batch.getId()))); |
| | | return pallets.size(); |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | @Override |
| | | public List<MesProPalletDO> getUnboundPalletList() { |
| | | return palletMapper.selectUnboundList(); |
| | | } |
| | | |
| | | @Override |
| | | public List<MesProPalletDO> getPalletListByIds(Collection<Long> ids) { |
| | | if (CollUtil.isEmpty(ids)) { |
| | | return List.of(); |
| | |
| | | import cn.iocoder.yudao.module.mes.controller.admin.pro.scan.vo.MesProScanEventPageReqVO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.pro.bagcode.MesProBagCodeDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.pro.batch.MesProBatchDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.pro.pallet.MesProPalletDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.pro.scan.MesProScanEventDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.batch.MesWmBatchDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseDO; |
| | | import cn.iocoder.yudao.module.mes.dal.mysql.pro.bagcode.MesProBagCodeMapper; |
| | | import cn.iocoder.yudao.module.mes.dal.mysql.pro.batch.MesProBatchMapper; |
| | | import cn.iocoder.yudao.module.mes.dal.mysql.pro.pallet.MesProPalletMapper; |
| | | import cn.iocoder.yudao.module.mes.dal.mysql.pro.scan.MesProScanEventMapper; |
| | | import cn.iocoder.yudao.module.mes.enums.MesBizTypeConstants; |
| | | import cn.iocoder.yudao.module.mes.enums.MesProScanEventStatusEnum; |
| | |
| | | import cn.iocoder.yudao.module.mes.service.wm.transaction.dto.MesWmTransactionSaveReqDTO; |
| | | import cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseService; |
| | | import jakarta.annotation.Resource; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | import org.springframework.validation.annotation.Validated; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.time.LocalDateTime; |
| | | import java.util.HashMap; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | |
| | | @Slf4j |
| | | @Service |
| | | @Validated |
| | | public class MesProScanEventServiceImpl implements MesProScanEventService { |
| | | @Resource private MesProScanEventMapper eventMapper; |
| | | @Resource private MesProBagCodeMapper bagCodeMapper; |
| | | @Resource private MesProBatchMapper batchMapper; |
| | | @Resource private MesProPalletMapper palletMapper; |
| | | @Resource private MesWmTransactionService transactionService; |
| | | @Resource private MesWmWarehouseService warehouseService; |
| | | @Resource private MesWmBatchService mesWmBatchService; |
| | | |
| | | /** æ«ç ç±»åï¼è¢ç ï¼é»è®¤ï¼ */ |
| | | private static final String SCAN_TYPE_BAG = "BAG"; |
| | | /** æ«ç ç±»åï¼æçç ï¼ææçå·²è£
è¢æ°æ´æå
¥åºï¼ */ |
| | | private static final String SCAN_TYPE_PALLET = "PALLET"; |
| | | /** æ«ç ç±»åï¼æ¹æ¬¡ç ï¼ææ¹æ¬¡è¢æ°æ´æ¹å
¥åºï¼ */ |
| | | private static final String SCAN_TYPE_BATCH = "BATCH"; |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public MesProScanEventDO createInbound(MesProScanEventCreateReqVO req) { |
| | | MesProScanEventDO existing = eventMapper.selectByEventIdForUpdate(req.getEventId()); |
| | | if (existing != null) { |
| | | if (!req.getBagCode().equals(existing.getBagCode()) || !req.getDeviceCode().equals(existing.getDeviceCode())) { |
| | | boolean contentMatch = req.getBagCode().equals(existing.getBagCode()) |
| | | && (req.getDeviceCode() == null || req.getDeviceCode().equals(existing.getDeviceCode())); |
| | | if (!contentMatch) { |
| | | return failed(existing, "MES_SCAN_EVENT_ID_CONFLICT", "äºä»¶å·å·²åå¨ä½å
容ä¸ä¸è´"); |
| | | } |
| | | return existing; |
| | | } |
| | | String scanType = (req.getScanType() == null || req.getScanType().isBlank()) ? SCAN_TYPE_BAG : req.getScanType(); |
| | | MesProScanEventDO event = new MesProScanEventDO(); |
| | | event.setEventId(req.getEventId()).setBagCode(req.getBagCode()).setQuantity(req.getQuantity()) |
| | | .setDeviceCode(req.getDeviceCode()).setLineCode(req.getLineCode()).setRemark(req.getRemark()) |
| | | .setStatus(MesProScanEventStatusEnum.FAILED).setReceivedTime(LocalDateTime.now()); |
| | | event.setEventId(req.getEventId()).setBagCode(req.getBagCode()).setScanType(scanType) |
| | | .setQuantity(req.getQuantity()).setDeviceCode(req.getDeviceCode()).setLineCode(req.getLineCode()) |
| | | .setRemark(req.getRemark()).setStatus(MesProScanEventStatusEnum.FAILED).setReceivedTime(LocalDateTime.now()); |
| | | eventMapper.insert(event); |
| | | MesProBagCodeDO bag = bagCodeMapper.selectByCodeForUpdate(req.getBagCode()); |
| | | if (bag == null) return failed(event, "MES_SCAN_BAG_NOT_EXISTS", "è¢ç ä¸åå¨"); |
| | | event.setBagCodeId(bag.getId()); |
| | | if (bag.getInboundEventId() != null) return failed(event, "MES_SCAN_BAG_ALREADY_INBOUND", "è¢ç å·²å
¥åº"); |
| | | MesProBatchDO batch = batchMapper.selectByIdForUpdate(bag.getBatchId()); |
| | | if (batch == null) return failed(event, "MES_SCAN_BATCH_NOT_EXISTS", "çäº§æ¹æ¬¡ä¸åå¨"); |
| | | event.setBatchId(batch.getId()).setBatchCode(batch.getCode()).setItemId(batch.getItemId()); |
| | | // 1. ææ«ç ç±»åè§£ææ«ç ç®æ ä¸å
¥åºæ°éï¼æçæå·²è£
è¢æ°ãæ¹æ¬¡ææ¹æ¬¡è¢æ°æ´æ¹/æ´æå
¥åºï¼ |
| | | Long targetId; |
| | | Long batchId; |
| | | BigDecimal quantity; |
| | | MesProBatchDO batch; |
| | | // åè¢æ«ç å
¥åºæ¶ä¼ éè¢ç ï¼ä¾åºåè¢ç æç»å¨å
¥åºç¬¬ä¸æ¶é´å»ºç«ï¼æç/æ¹æ¬¡æ´æ¹å
¥åºä¸ºæ¹éï¼ä¸éè¢å»ºæç» |
| | | Long bagCodeId = null; |
| | | String bagCode = null; |
| | | if (SCAN_TYPE_PALLET.equals(scanType)) { |
| | | MesProPalletDO pallet = palletMapper.selectByCode(req.getBagCode()); |
| | | if (pallet == null) { |
| | | pallet = palletMapper.selectByTempCode(req.getBagCode()); |
| | | } |
| | | if (pallet == null) return failed(event, "MES_SCAN_PALLET_NOT_EXISTS", "æçç ä¸åå¨"); |
| | | if (pallet.getInboundEventId() != null) return failed(event, "MES_SCAN_PALLET_ALREADY_INBOUND", "æçå·²å
¥åº"); |
| | | batch = batchMapper.selectByIdForUpdate(pallet.getBatchId()); |
| | | if (batch == null) return failed(event, "MES_SCAN_BATCH_NOT_EXISTS", "çäº§æ¹æ¬¡ä¸åå¨"); |
| | | batchId = batch.getId(); |
| | | targetId = pallet.getId(); |
| | | quantity = pallet.getBagCount() != null && pallet.getBagCount() > 0 |
| | | ? BigDecimal.valueOf(pallet.getBagCount()) |
| | | : BigDecimal.valueOf(bagCodeMapper.selectCountByPalletId(pallet.getId())); |
| | | } else if (SCAN_TYPE_BATCH.equals(scanType)) { |
| | | batch = batchMapper.selectByCode(req.getBagCode()); |
| | | if (batch == null) { |
| | | batch = batchMapper.selectByTempCode(req.getBagCode()); |
| | | } |
| | | if (batch == null) return failed(event, "MES_SCAN_BATCH_NOT_EXISTS", "çäº§æ¹æ¬¡ä¸åå¨"); |
| | | if (batch.getInboundEventId() != null) return failed(event, "MES_SCAN_BATCH_ALREADY_INBOUND", "æ¹æ¬¡å·²æ´æ¹å
¥åº"); |
| | | batchId = batch.getId(); |
| | | targetId = batch.getId(); |
| | | quantity = batch.getBagQuantity() != null && batch.getBagQuantity() > 0 |
| | | ? BigDecimal.valueOf(batch.getBagQuantity()) |
| | | : BigDecimal.valueOf(bagCodeMapper.selectCountByBatchId(batch.getId())); |
| | | } else { |
| | | MesProBagCodeDO bag = bagCodeMapper.selectByCodeForUpdate(req.getBagCode()); |
| | | if (bag == null) return failed(event, "MES_SCAN_BAG_NOT_EXISTS", "è¢ç ä¸åå¨"); |
| | | event.setBagCodeId(bag.getId()); |
| | | bagCodeId = bag.getId(); |
| | | bagCode = req.getBagCode(); |
| | | if (bag.getInboundEventId() != null) return failed(event, "MES_SCAN_BAG_ALREADY_INBOUND", "è¢ç å·²å
¥åº"); |
| | | batch = batchMapper.selectByIdForUpdate(bag.getBatchId()); |
| | | if (batch == null) return failed(event, "MES_SCAN_BATCH_NOT_EXISTS", "çäº§æ¹æ¬¡ä¸åå¨"); |
| | | batchId = batch.getId(); |
| | | targetId = bag.getId(); |
| | | quantity = req.getQuantity(); |
| | | } |
| | | event.setBatchId(batchId).setBatchCode(batch.getCode()).setItemId(batch.getItemId()); |
| | | MesWmWarehouseDO warehouse = warehouseService.getWarehouseByCode(MesWmWarehouseDO.WIP_VIRTUAL_WAREHOUSE); |
| | | if (warehouse == null) return failed(event, "MES_SCAN_WIP_WAREHOUSE_NOT_EXISTS", "WIPèæä»ä¸åå¨"); |
| | | event.setWarehouseId(warehouse.getId()).setLocationId(req.getLocationId()).setAreaId(req.getAreaId()); |
| | |
| | | } |
| | | Long txId = transactionService.createTransaction(new MesWmTransactionSaveReqDTO() |
| | | .setType(MesWmTransactionTypeEnum.IN.getType()).setBizType(MesBizTypeConstants.WM_PRODUCT_PRODUCE) |
| | | .setBizId(batch.getId()).setBizCode(batch.getCode()).setBizLineId(bag.getId()) |
| | | .setItemId(batch.getItemId()).setQuantity(req.getQuantity()) |
| | | .setBizId(batchId).setBizCode(batch.getCode()).setBizLineId(targetId) |
| | | .setItemId(batch.getItemId()).setQuantity(quantity) |
| | | .setBatchId(wmBatch.getId()).setBatchCode(batch.getCode()) |
| | | .setBagCodeId(bagCodeId).setBagCode(bagCode) |
| | | .setWarehouseId(warehouse.getId()).setLocationId(req.getLocationId()).setAreaId(req.getAreaId()) |
| | | .setReceiptTime(LocalDateTime.now()).setCheckFlag(true) |
| | | .setStockState(MesWmStockStateEnum.TEMP.getState())); |
| | | event.setTransactionId(txId).setStatus(MesProScanEventStatusEnum.SUCCESS).setEventTime(LocalDateTime.now()); |
| | | eventMapper.updateById(event); |
| | | bagCodeMapper.markInbound(bag.getId(), event.getId(), req.getDeviceCode(), req.getLineCode()); |
| | | batchMapper.markInbound(batch.getId(), event.getId(), req.getDeviceCode(), req.getLineCode()); |
| | | // 2. ååå
¥åºæ è®°ï¼æç/æ¹æ¬¡æ´æ/æ´æ¹å
¥åºæ¶åæ¥æ è®°å
¶ä¸æªå
¥åºè¢ç ï¼ä¿æç¶æä¸è´ï¼ |
| | | if (SCAN_TYPE_PALLET.equals(scanType)) { |
| | | palletMapper.markInbound(targetId, event.getId()); |
| | | bagCodeMapper.markInboundByPalletId(targetId, event.getId(), req.getLineCode()); |
| | | } else if (SCAN_TYPE_BATCH.equals(scanType)) { |
| | | batchMapper.markBatchInbound(targetId, event.getId(), req.getLineCode(), batch.getBagQuantity()); |
| | | bagCodeMapper.markInboundByBatchId(targetId, event.getId(), req.getLineCode()); |
| | | } else { |
| | | bagCodeMapper.markInbound(targetId, event.getId(), req.getDeviceCode(), req.getLineCode()); |
| | | batchMapper.markInbound(batchId, event.getId(), req.getDeviceCode(), req.getLineCode()); |
| | | } |
| | | return event; |
| | | } catch (Exception ex) { |
| | | return failed(event, "MES_SCAN_TRANSACTION_FAILED", "åºåäºå¡å¤ç失败"); |
| | | log.error("[createInbound] åºåäºå¡å¤ç失败ï¼eventId={}, bagCode={}, batchId={}, itemId={}", |
| | | req.getEventId(), req.getBagCode(), batchId, batch.getItemId(), ex); |
| | | throw ex; |
| | | } |
| | | } |
| | | |
| | |
| | | package cn.iocoder.yudao.module.mes.service.qc.seedquality; |
| | | |
| | | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.qc.seedquality.vo.MesQcSeedQualityPageReqVO; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.qc.seedquality.vo.MesQcSeedQualitySubmitReqVO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.qc.seedquality.MesQcSeedQualityDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.qc.seedquality.MesQcSeedQualityIndicatorDO; |
| | |
| | | |
| | | Long submit(MesQcSeedQualitySubmitReqVO reqVO); |
| | | |
| | | PageResult<MesQcSeedQualityDO> getQualityPage(MesQcSeedQualityPageReqVO reqVO); |
| | | |
| | | /** |
| | | * æ ¹æ®æ¹æ¬¡å·æ¥è¯¢è´¨æ£è®°å½ï¼ææ£éªæ¶é´ååºï¼åææ°ï¼ï¼ç¨äºå
¬å¼æº¯æºã |
| | | * ç§åè´¨æ£è¡¨æªåå§åæ¶è¿å空å表ï¼å®¹éï¼ä¸å½±å追溯ï¼ã |
| | |
| | | package cn.iocoder.yudao.module.mes.service.qc.seedquality; |
| | | |
| | | import cn.hutool.core.collection.CollUtil; |
| | | import cn.hutool.core.util.StrUtil; |
| | | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| | | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.qc.seedquality.vo.MesQcSeedQualityPageReqVO; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.qc.seedquality.vo.MesQcSeedQualitySubmitReqVO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.pro.bagcode.MesProBagCodeDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.pro.batch.MesProBatchDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.qc.seedquality.*; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.batch.MesWmBatchDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.materialstock.MesWmMaterialStockDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseAreaDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseLocationDO; |
| | | import cn.iocoder.yudao.module.mes.dal.mysql.pro.bagcode.MesProBagCodeMapper; |
| | | import cn.iocoder.yudao.module.mes.dal.mysql.qc.seedquality.*; |
| | | import cn.iocoder.yudao.module.mes.dal.mysql.wm.batch.MesWmBatchMapper; |
| | | import cn.iocoder.yudao.module.mes.dal.mysql.wm.materialstock.MesWmMaterialStockMapper; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.materialstockbag.MesWmMaterialStockBagDO; |
| | | import cn.iocoder.yudao.module.mes.dal.mysql.wm.materialstockbag.MesWmMaterialStockBagMapper; |
| | | import cn.iocoder.yudao.module.mes.enums.pro.MesProBagCodeQcStatusEnum; |
| | | import cn.iocoder.yudao.module.mes.enums.wm.MesWmStockStateEnum; |
| | | import cn.iocoder.yudao.module.mes.enums.wm.MesWmTransactionTypeEnum; |
| | | import cn.iocoder.yudao.module.mes.enums.MesBizTypeConstants; |
| | | import cn.iocoder.yudao.module.mes.enums.wm.MesWmWarehouseTypeEnum; |
| | | import cn.iocoder.yudao.module.mes.service.pro.batch.MesProBatchService; |
| | | import cn.iocoder.yudao.module.mes.service.wm.batch.MesWmBatchService; |
| | | import cn.iocoder.yudao.module.mes.service.wm.materialstock.MesWmMaterialStockService; |
| | | import cn.iocoder.yudao.module.mes.service.wm.materialstockbag.MesWmMaterialStockBagService; |
| | | import cn.iocoder.yudao.module.mes.service.wm.transaction.MesWmTransactionService; |
| | | import cn.iocoder.yudao.module.mes.service.wm.transaction.dto.MesWmTransactionSaveReqDTO; |
| | | import cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseAreaService; |
| | | import cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseLocationService; |
| | | import cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseService; |
| | | import jakarta.annotation.Resource; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.jdbc.BadSqlGrammarException; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | import org.springframework.validation.annotation.Validated; |
| | | import java.math.BigDecimal; |
| | | import java.time.LocalDateTime; |
| | | import java.util.*; |
| | | |
| | | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| | | import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.WM_QUALIFIED_WAREHOUSE_NOT_CONFIGURED; |
| | | import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.WM_WAREHOUSE_NOT_EXISTS; |
| | | import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.WM_WAREHOUSE_TYPE_NOT_QUALIFIED; |
| | | |
| | | @Service @Validated @Slf4j |
| | | public class MesQcSeedQualityServiceImpl implements MesQcSeedQualityService { |
| | | private static final Set<String> REQUIRED = Set.of("purity", "cleanliness", "germination_rate", "moisture"); |
| | | @Resource private MesQcSeedQualityMapper qualityMapper; |
| | | @Resource private MesQcSeedQualityIndicatorMapper indicatorMapper; |
| | | @Resource private MesProBagCodeMapper bagCodeMapper; |
| | | @Resource private MesProBatchService proBatchService; |
| | | @Resource private MesWmBatchService mesWmBatchService; |
| | | @Resource private MesWmMaterialStockService materialStockService; |
| | | @Resource private MesWmBatchMapper mesWmBatchMapper; |
| | | @Resource private MesWmMaterialStockMapper materialStockMapper; |
| | | @Resource private MesWmMaterialStockBagMapper materialStockBagMapper; |
| | | @Resource private MesWmMaterialStockBagService materialStockBagService; |
| | | @Resource private MesWmTransactionService wmTransactionService; |
| | | @Resource private MesWmWarehouseService warehouseService; |
| | | @Resource private MesWmWarehouseLocationService warehouseLocationService; |
| | | @Resource private MesWmWarehouseAreaService warehouseAreaService; |
| | | |
| | | @Override |
| | | public PageResult<MesQcSeedQualityDO> getQualityPage(MesQcSeedQualityPageReqVO reqVO) { |
| | | return qualityMapper.selectPage(reqVO); |
| | | } |
| | | |
| | | @Override @Transactional(rollbackFor = Exception.class) |
| | | public Long submit(MesQcSeedQualitySubmitReqVO reqVO) { |
| | | if (reqVO.getIndicators().size() != 4) throw new IllegalArgumentException("å¿
é¡»æäº¤åé¡¹ææ "); |
| | | if (qualityMapper.selectByCode(reqVO.getCode()) != null) throw new IllegalArgumentException("该è¢ç 已质æ£ï¼ç¦æ¢éå¤æäº¤"); |
| | | // ç§åè´¨æ£å¿
须以è¢ç ï¼åè¢ï¼æäº¤ï¼ç©æä¿¡æ¯ç±è¢ç èªå¨è§£æï¼å端ä¸ååç¬éæ©ç©æ |
| | | MesProBagCodeDO bag = bagCodeMapper.selectByCode(reqVO.getCode()); |
| | | if (bag == null) { |
| | | throw new IllegalArgumentException("æªè§£æå°ææè¢ç ï¼ç§åè´¨æ£å¿
须以è¢ç æäº¤"); |
| | | } |
| | | MesProBatchDO batch = resolveBatch(reqVO.getCode(), reqVO.getBatchCode()); |
| | | if (batch == null || batch.getItemId() == null) { |
| | | throw new IllegalArgumentException("æªæ ¹æ®è¢ç è§£æå°ç©æä¿¡æ¯ï¼è¯·ç¡®è®¤æ«ç å
å®¹ææ¹æ¬¡å·æ£ç¡®"); |
| | | } |
| | | // è¢ç å¯¹åºæ¹æ¬¡çåºåå¿
é¡»å¤äºæååºï¼å¾
è´¨æ£ï¼ä¸ï¼æè½è¿è¡ç§åè´¨æ£ |
| | | MesWmBatchDO wmBatch = mesWmBatchMapper.selectByCode(batch.getCode()); |
| | | if (wmBatch == null || materialStockMapper.selectTempStockCountByBatchId(wmBatch.getId()) == 0) { |
| | | throw new IllegalArgumentException("该è¢ç /æ¹æ¬¡å¯¹åºçåºåä¸å¨æååºä¸ï¼æ æ³è¿è¡è´¨æ£"); |
| | | } |
| | | // æ ¡éªç®æ åæ ¼åºï¼å¿
é¡»åå¨ä¸ä»åºç±»åä¸ºåæ ¼åº(20) |
| | | if (warehouseService.getFirstQualifiedWarehouse() == null) { |
| | | throw exception(WM_QUALIFIED_WAREHOUSE_NOT_CONFIGURED); |
| | | } |
| | | MesWmWarehouseDO qualifiedWarehouse = warehouseService.getWarehouse(reqVO.getQualifiedWarehouseId()); |
| | | if (qualifiedWarehouse == null) { |
| | | throw exception(WM_WAREHOUSE_NOT_EXISTS); |
| | | } |
| | | if (!MesWmWarehouseTypeEnum.QUALIFIED.getType().equals(qualifiedWarehouse.getType())) { |
| | | throw exception(WM_WAREHOUSE_TYPE_NOT_QUALIFIED); |
| | | } |
| | | // è§£æåæ ¼åºé»è®¤åºåº/åºä½ï¼å该ä»åºä¸ç¬¬ä¸ä¸ªåºåºãå
¶ä¸ç¬¬ä¸ä¸ªåºä½ï¼æªé
ç½®å为 nullï¼ |
| | | Long qualifiedLocationId = null; |
| | | Long qualifiedAreaId = null; |
| | | List<MesWmWarehouseLocationDO> locations = warehouseLocationService.getWarehouseLocationList(qualifiedWarehouse.getId()); |
| | | if (CollUtil.isNotEmpty(locations)) { |
| | | qualifiedLocationId = locations.get(0).getId(); |
| | | List<MesWmWarehouseAreaDO> areas = warehouseAreaService.getWarehouseAreaList(qualifiedLocationId); |
| | | if (CollUtil.isNotEmpty(areas)) { |
| | | qualifiedAreaId = areas.get(0).getId(); |
| | | } |
| | | } |
| | | Set<String> codes = new HashSet<>(); |
| | | boolean passed = true; |
| | | MesQcSeedQualityDO quality = MesQcSeedQualityDO.builder().code(reqVO.getCode()).itemId(reqVO.getItemId()) |
| | | .batchCode(reqVO.getBatchCode()).reason(reqVO.getReason()).result(0) |
| | | MesQcSeedQualityDO quality = MesQcSeedQualityDO.builder().code(reqVO.getCode()).itemId(batch.getItemId()) |
| | | .batchCode(batch.getCode()).reason(reqVO.getReason()).result(0) |
| | | .inspectedAt(LocalDateTime.now()).build(); |
| | | qualityMapper.insert(quality); |
| | | for (MesQcSeedQualitySubmitReqVO.Indicator item : reqVO.getIndicators()) { |
| | |
| | | if (!codes.equals(REQUIRED)) throw new IllegalArgumentException("åé¡¹ææ ä¸å®æ´"); |
| | | quality.setResult(passed ? 1 : 2); |
| | | qualityMapper.updateById(quality); |
| | | // è´¨æ£åæ ¼ â åºåæ´æ¹ç±æååºï¼å¾
è´¨æ£ï¼è½¬ä¸ºåæ ¼åºï¼æ£å¼åºåï¼ |
| | | // æè¢ç ç²åº¦æµè½¬åºåï¼éå®è¯¥è¢å¨æååºä¸çæ´»å¨æç»ï¼ç¦æ¢ææ¹æ¬¡ä»»ææ£å |
| | | MesWmMaterialStockBagDO stockBag = materialStockBagMapper.selectActiveByBagCode(bag.getCode()); |
| | | MesWmMaterialStockDO tempStock = resolveTempStock(bag, wmBatch, stockBag); |
| | | // A. æååºåºï¼-1ï¼ï¼è¯¥è¢ç¦»å¼æååºï¼åå
¥è´¨æ£æååºåºäºå¡ï¼è·³è¿è¢ç èªå¨ç»´æ¤ï¼ç±è´¨æ£ç»ä¸æ§å¶è¢ç æç»è½ç¹ï¼ |
| | | MesWmTransactionSaveReqDTO tempOutReq = new MesWmTransactionSaveReqDTO() |
| | | .setType(MesWmTransactionTypeEnum.OUT.getType()) |
| | | .setBizType(MesBizTypeConstants.QC_SEED_QUALITY) |
| | | .setBizId(quality.getId()) |
| | | .setBizCode(reqVO.getCode()) |
| | | .setBizLineId(quality.getId()) |
| | | .setItemId(batch.getItemId()) |
| | | .setQuantity(BigDecimal.ONE.negate()) |
| | | .setBatchId(tempStock.getBatchId()) |
| | | .setBatchCode(tempStock.getBatchCode()) |
| | | .setBagCodeId(bag.getId()) |
| | | .setBagCode(bag.getCode()) |
| | | .setWarehouseId(tempStock.getWarehouseId()) |
| | | .setLocationId(tempStock.getLocationId()) |
| | | .setAreaId(tempStock.getAreaId()) |
| | | .setVendorId(tempStock.getVendorId()) |
| | | .setMaterialStockId(tempStock.getId()) |
| | | .setCheckFlag(true) |
| | | .setSkipBagManage(true); |
| | | Long tempOutTxId = wmTransactionService.createTransaction(tempOutReq); |
| | | if (passed) { |
| | | MesProBatchDO proBatch = proBatchService.getBatchByCode(reqVO.getBatchCode()); |
| | | if (proBatch != null) { |
| | | MesWmBatchDO wmBatch = mesWmBatchService.getOrCreateByProBatch(proBatch); |
| | | if (wmBatch != null) { |
| | | int updated = materialStockService.updateStockStateByBatchId(wmBatch.getId(), |
| | | MesWmStockStateEnum.QUALIFIED.getState(), MesWmStockStateEnum.TEMP.getState()); |
| | | log.info("[submit][è´¨æ£åæ ¼ï¼æ¹æ¬¡ {} åºåç±æååºè½¬åæ ¼åºï¼å½±å {} æ¡]", reqVO.getBatchCode(), updated); |
| | | // B1. è´¨æ£åæ ¼ â 该è¢è½¬å
¥æä½åéæ©çåæ ¼åºï¼åå
¥åæ ¼å
¥åºäºå¡ï¼è·³è¿è¢ç èªå¨ç»´æ¤ï¼ |
| | | MesWmMaterialStockDO qualifiedStock = getOrCreateQualifiedStock(tempStock, qualifiedWarehouse.getId(), qualifiedLocationId, qualifiedAreaId); |
| | | MesWmTransactionSaveReqDTO qualInReq = new MesWmTransactionSaveReqDTO() |
| | | .setType(MesWmTransactionTypeEnum.IN.getType()) |
| | | .setBizType(MesBizTypeConstants.QC_SEED_QUALITY) |
| | | .setBizId(quality.getId()) |
| | | .setBizCode(reqVO.getCode()) |
| | | .setBizLineId(quality.getId()) |
| | | .setItemId(batch.getItemId()) |
| | | .setQuantity(BigDecimal.ONE) |
| | | .setBatchId(qualifiedStock.getBatchId()) |
| | | .setBatchCode(qualifiedStock.getBatchCode()) |
| | | .setBagCodeId(bag.getId()) |
| | | .setBagCode(bag.getCode()) |
| | | .setWarehouseId(qualifiedStock.getWarehouseId()) |
| | | .setLocationId(qualifiedStock.getLocationId()) |
| | | .setAreaId(qualifiedStock.getAreaId()) |
| | | .setVendorId(qualifiedStock.getVendorId()) |
| | | .setMaterialStockId(qualifiedStock.getId()) |
| | | .setCheckFlag(false) |
| | | .setStockState(MesWmStockStateEnum.QUALIFIED.getState()) |
| | | .setSkipBagManage(true); |
| | | Long qualInTxId = wmTransactionService.createTransaction(qualInReq); |
| | | // B2. 忥è¿ç§»è¢ç æç»å°åæ ¼åºåè½ç¹ |
| | | materialStockBagService.moveIn(qualInReq, qualifiedStock, qualInTxId); |
| | | bagCodeMapper.updateQcStatus(bag.getId(), MesProBagCodeQcStatusEnum.QUALIFIED.getStatus()); |
| | | log.info("[submit][è´¨æ£åæ ¼ï¼è¢ç {} ç±æååºè½¬åæ ¼åº {}]", bag.getCode(), qualifiedWarehouse.getName()); |
| | | } else { |
| | | // C. è´¨æ£ä¸åæ ¼ â è¯¥è¢æ¥åºï¼æååºåºäºå¡å·²æ£åæååºåï¼æ è®°è¢ç æ¥åº |
| | | materialStockBagService.scrap(tempOutReq, tempOutTxId); |
| | | bagCodeMapper.updateQcStatus(bag.getId(), MesProBagCodeQcStatusEnum.UNQUALIFIED.getStatus()); |
| | | log.info("[submit][è´¨æ£ä¸åæ ¼ï¼è¢ç {} æ¥åº]", bag.getCode()); |
| | | } |
| | | return quality.getId(); |
| | | } |
| | | |
| | | /** |
| | | * å®ä½è¯¥è¢çæååºåæ±æ»è®°å½ï¼åªå®ä½ï¼ä¸æ£åï¼æ£åç±è´¨æ£æååºåºäºå¡å®æï¼ã |
| | | * <p> |
| | | * ä¼å
ä¸¥æ ¼æè¢ç éå®å
¶æ´»å¨æç»å¯¹åºçæåè®°å½ï¼å岿 æç»æ¶åéææ¹æ¬¡å®ä½å¹¶è¡¥å»ºæç»ã |
| | | */ |
| | | private MesWmMaterialStockDO resolveTempStock(MesProBagCodeDO bag, MesWmBatchDO wmBatch, MesWmMaterialStockBagDO stockBag) { |
| | | if (stockBag != null && stockBag.getMaterialStockId() != null) { |
| | | MesWmMaterialStockDO stock = materialStockMapper.selectById(stockBag.getMaterialStockId()); |
| | | if (stock != null && MesWmStockStateEnum.TEMP.getState().equals(stock.getStockState())) { |
| | | return stock; |
| | | } |
| | | } |
| | | MesWmMaterialStockDO tempStock = materialStockMapper.selectStockListByBatchId(wmBatch.getId()).stream() |
| | | .filter(s -> MesWmStockStateEnum.TEMP.getState().equals(s.getStockState())) |
| | | .max(Comparator.comparing(MesWmMaterialStockDO::getQuantity)) |
| | | .orElse(null); |
| | | if (tempStock == null) { |
| | | throw new IllegalArgumentException("è¯¥æ¹æ¬¡æååºåä¸è¶³ï¼æ æ³è´¨æ£"); |
| | | } |
| | | getOrCreateStockBag(bag, tempStock); |
| | | return tempStock; |
| | | } |
| | | |
| | | /** |
| | | * è´¨æ£åæ ¼ï¼å°è´¨æ£éè¿çé£è¢è½¬å
¥æä½åéæ©çåæ ¼åºï¼åç»åé®åæ ¼åºè®°å½ +1ï¼ä¸åå¨åæ°å»ºï¼ã |
| | | * |
| | | * @param tempStock 仿ååºæ£ååè¿åçæåè®°å½ï¼æºå¸¦ item/batch/vendor ç»´åº¦ï¼ |
| | | * @param qualifiedWarehouseId ç®æ åæ ¼åºä»åºç¼å· |
| | | * @param qualifiedLocationId ç®æ åæ ¼åºåºåºç¼å·ï¼æªé
ç½®å为 nullï¼ |
| | | * @param qualifiedAreaId ç®æ åæ ¼åºåºä½ç¼å·ï¼æªé
ç½®å为 nullï¼ |
| | | */ |
| | | private MesWmMaterialStockBagDO getOrCreateStockBag(MesProBagCodeDO bag, MesWmMaterialStockDO tempStock) { |
| | | MesWmMaterialStockBagDO stockBag = materialStockBagMapper.selectByBagCode(bag.getCode()); |
| | | if (stockBag != null) { |
| | | return stockBag; |
| | | } |
| | | stockBag = MesWmMaterialStockBagDO.builder().materialStockId(tempStock.getId()) |
| | | .bagCodeId(bag.getId()).bagCode(bag.getCode()).itemId(tempStock.getItemId()) |
| | | .batchId(tempStock.getBatchId()).batchCode(tempStock.getBatchCode()).vendorId(tempStock.getVendorId()) |
| | | .warehouseId(tempStock.getWarehouseId()).locationId(tempStock.getLocationId()).areaId(tempStock.getAreaId()) |
| | | .stockState(MesWmStockStateEnum.TEMP.getState()).status(1).quantity(BigDecimal.ONE) |
| | | .frozen(false).inboundTime(tempStock.getReceiptTime()).build(); |
| | | materialStockBagMapper.insert(stockBag); |
| | | return stockBag; |
| | | } |
| | | |
| | | private MesWmMaterialStockDO getOrCreateQualifiedStock(MesWmMaterialStockDO tempStock, Long qualifiedWarehouseId, |
| | | Long qualifiedLocationId, Long qualifiedAreaId) { |
| | | MesWmMaterialStockDO qualified = materialStockMapper.selectQualifiedByCompositeKey( |
| | | tempStock.getItemId(), qualifiedWarehouseId, qualifiedLocationId, |
| | | qualifiedAreaId, tempStock.getBatchId(), tempStock.getVendorId()); |
| | | if (qualified != null) { |
| | | return qualified; |
| | | } |
| | | // ä¸åå¨åæ°å»ºåæ ¼åºè®°å½ï¼ä»åº/åºåº/åºä½éç¨æéåæ ¼åºçç»´åº¦ï¼æ°éç±è´¨æ£å
¥åºäºå¡ +1ï¼ |
| | | MesWmMaterialStockDO newStock = MesWmMaterialStockDO.builder() |
| | | .itemId(tempStock.getItemId()).itemTypeId(tempStock.getItemTypeId()) |
| | | .warehouseId(qualifiedWarehouseId).locationId(qualifiedLocationId).areaId(qualifiedAreaId) |
| | | .batchId(tempStock.getBatchId()).batchCode(tempStock.getBatchCode()).vendorId(tempStock.getVendorId()) |
| | | .quantity(BigDecimal.ZERO).receiptTime(LocalDateTime.now()) |
| | | .stockState(MesWmStockStateEnum.QUALIFIED.getState()) |
| | | .frozen(false) |
| | | .build(); |
| | | materialStockMapper.insert(newStock); |
| | | return newStock; |
| | | } |
| | | |
| | | /** |
| | | * ç±è¢ç æçäº§æ¹æ¬¡è§£ææå±çäº§æ¹æ¬¡ï¼è¢ç ä¼å
ï¼æ¹æ¬¡ç å
¼å®¹ä¸´æ¶ç ï¼ |
| | | */ |
| | | private MesProBatchDO resolveBatch(String code, String batchCode) { |
| | | if (StrUtil.isNotBlank(code)) { |
| | | MesProBagCodeDO bag = bagCodeMapper.selectByCode(code); |
| | | if (bag != null && bag.getBatchId() != null) { |
| | | MesProBatchDO batch = proBatchService.getBatch(bag.getBatchId()); |
| | | if (batch != null) { |
| | | return batch; |
| | | } |
| | | } |
| | | } |
| | | // åºä½ç±åå°é
ç½®æå¡æ¥ç®¡ï¼å½åçæ¬ä¿ç审计éç¯ï¼ç¦æ¢åç«¯ä¼ å
¥åºä½ã |
| | | return quality.getId(); |
| | | if (StrUtil.isNotBlank(batchCode)) { |
| | | return proBatchService.getBatchByCode(batchCode); |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | @Override |
| | |
| | | |
| | | import cn.hutool.core.collection.CollUtil; |
| | | import cn.hutool.core.util.StrUtil; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo.MesWmBatchFlowRespVO; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo.MesWmBatchProcessTraceRespVO; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo.MesWmBatchPurchaseSourceRespVO; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo.MesWmBatchSalesTargetRespVO; |
| | |
| | | import cn.iocoder.yudao.module.mes.service.trace.crossregion.MesTraceCrossRegionService; |
| | | import cn.iocoder.yudao.module.mes.service.trace.integrity.MesTraceIntegrityService; |
| | | import cn.iocoder.yudao.module.mes.service.wm.batch.MesWmBatchService; |
| | | import cn.iocoder.yudao.module.mdm.api.unit.MdmUnitMeasureApi; |
| | | import cn.iocoder.yudao.module.mdm.api.unit.dto.MdmUnitMeasureRespDTO; |
| | | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| | | import cn.iocoder.yudao.module.system.api.user.AdminUserApi; |
| | | import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; |
| | | import jakarta.annotation.Resource; |
| | |
| | | |
| | | import java.net.URLDecoder; |
| | | import java.nio.charset.StandardCharsets; |
| | | import java.math.BigDecimal; |
| | | import java.util.ArrayList; |
| | | import java.util.Comparator; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.Objects; |
| | | import java.util.Set; |
| | | |
| | | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| | |
| | | @Resource |
| | | private MesMdmItemService mdmItemService; |
| | | @Resource |
| | | private MdmUnitMeasureApi unitMeasureApi; |
| | | @Resource |
| | | private AdminUserApi adminUserApi; |
| | | @Resource |
| | | private MesWmBatchService mesWmBatchService; |
| | |
| | | } |
| | | TraceEntry entry = null; |
| | | try { |
| | | // 1. è§£æè¿½æº¯å
¥å£ï¼å®ä½æ¹æ¬¡ |
| | | // 1. è§£æè¿½æº¯å
¥å£ï¼å®ä½æ¹æ¬¡ï¼è¢ç /æçå·²çæä½æªå½å
¥æ¹æ¬¡æ¶ï¼é级为ä»
è¿ååç§ä¿¡æ¯ï¼ |
| | | entry = resolveEntry(traceCode); |
| | | if (entry.batchId == null) { |
| | | if (entry.batchId == null && entry.bagItemId == null) { |
| | | throw exception(MES_TRACE_CODE_NOT_FOUND); |
| | | } |
| | | // 2. èåå
¨ç¨ä¿¡æ¯ |
| | | MesProTracePublicRespVO result = buildRespVO(rawCode, traceCode, entry.sourceType, entry.batchId); |
| | | MesProTracePublicRespVO result = buildRespVO(rawCode, traceCode, entry.sourceType, entry.batchId, entry.bagItemId); |
| | | recordConsumerScan(rawCode, traceCode, entry.sourceType, entry.batchId, true); |
| | | return result; |
| | | } catch (RuntimeException ex) { |
| | |
| | | // â è¢ç |
| | | MesProBagCodeDO bag = bagCodeService.getBagCodeByCode(traceCode); |
| | | if (bag != null) { |
| | | return new TraceEntry("BAG", bag.getBatchId()); |
| | | return new TraceEntry("BAG", bag.getBatchId(), bag.getItemId()); |
| | | } |
| | | // â¡ æçç |
| | | MesProPalletDO pallet = palletService.getPalletByCode(traceCode); |
| | | if (pallet != null) { |
| | | return new TraceEntry("PALLET", pallet.getBatchId()); |
| | | // æªå½å
¥æ¹æ¬¡çæçåæçå
ä»»ä¸è¢ç åç§ï¼ä¿è¯ä»è½å±ç¤ºåç§ä¿¡æ¯ |
| | | Long itemId = pallet.getBatchId() == null |
| | | ? firstItemId(bagCodeService.getBagCodeListByPalletId(pallet.getId())) : null; |
| | | return new TraceEntry("PALLET", pallet.getBatchId(), itemId); |
| | | } |
| | | // â¢ æ¹æ¬¡ç ï¼å«ä¸´æ¶æ¹æ¬¡ç ï¼getBatchByCode å
é¨å
¼å®¹ï¼ |
| | | MesProBatchDO batch = batchService.getBatchByCode(traceCode); |
| | | if (batch != null) { |
| | | return new TraceEntry("BATCH", batch.getId()); |
| | | return new TraceEntry("BATCH", batch.getId(), null); |
| | | } |
| | | return new TraceEntry("", null); |
| | | return new TraceEntry("", null, null); |
| | | } |
| | | |
| | | // ==================== èåæå»º ==================== |
| | | |
| | | private MesProTracePublicRespVO buildRespVO(String requestCode, String traceCode, String sourceType, Long batchId) { |
| | | MesProBatchDO batch = batchService.getBatch(batchId); |
| | | if (batch == null) { |
| | | private MesProTracePublicRespVO buildRespVO(String requestCode, String traceCode, String sourceType, Long batchId, Long bagItemId) { |
| | | MesProBatchDO batch = batchId == null ? null : batchService.getBatch(batchId); |
| | | if (batchId != null && batch == null) { |
| | | throw exception(MES_TRACE_CODE_NOT_FOUND); |
| | | } |
| | | MesProTracePublicRespVO resp = new MesProTracePublicRespVO(); |
| | | resp.setSourceType(sourceType); |
| | | resp.setRequestCode(requestCode); |
| | | // åç§åºå |
| | | fillItem(resp, batch); |
| | | fillItem(resp, batch, bagItemId); |
| | | if (batch == null) { |
| | | // è¢ç /æçå·²çæä½å°æªå½å
¥çäº§æ¹æ¬¡ï¼åªè¿ååç§ä¿¡æ¯ï¼ç±å端æç¤ºæªç»å®æ¹æ¬¡ |
| | | resp.setBatchBound(false); |
| | | fillAntiFake(resp, traceCode); |
| | | fillTimelineAndDecision(resp); |
| | | return resp; |
| | | } |
| | | resp.setBatchBound(true); |
| | | // æ¹æ¬¡åºå |
| | | resp.setBatchCode(batch.getCode()).setTempCode(batch.getTempCode()) |
| | | .setBatchStatus(batch.getStatus()).setBatchStatusName(batchStatusName(batch.getStatus())) |
| | |
| | | fillAntiFake(resp, traceCode); |
| | | // å¯éæ©å±åºåï¼ææ°æ®æè¿åï¼ |
| | | fillOptionalModules(resp, batch); |
| | | fillTimelineAndDecision(resp); |
| | | return resp; |
| | | } |
| | | |
| | | private void fillItem(MesProTracePublicRespVO resp, MesProBatchDO batch) { |
| | | if (batch.getItemId() == null) { |
| | | /** |
| | | * åç§å·²ä¸æ²å°è¢ç æ°æ®å
ï¼ä¼å
åæ«ç è¢ç åç§ï¼å岿¹æ¬¡åéæ¹æ¬¡åç§ï¼æ¹æ¬¡/æçå
¥å£åæ¹å
ä»»ä¸è¢ç åç§ |
| | | */ |
| | | private void fillItem(MesProTracePublicRespVO resp, MesProBatchDO batch, Long bagItemId) { |
| | | Long itemId = bagItemId != null ? bagItemId : (batch == null ? null : batch.getItemId()); |
| | | if (itemId == null && batch != null) { |
| | | itemId = firstItemId(bagCodeService.getBagCodeListByBatchId(batch.getId())); |
| | | } |
| | | if (itemId == null) { |
| | | return; |
| | | } |
| | | MesMdmItemDO item = mdmItemService.getItem(batch.getItemId()); |
| | | MesMdmItemDO item = mdmItemService.getItem(itemId); |
| | | if (item == null) { |
| | | return; |
| | | } |
| | | resp.setItemCode(item.getCode()).setItemName(item.getName()).setItemSpecification(item.getSpecification()); |
| | | resp.setItemCode(item.getCode()).setItemName(item.getName()).setItemSpecification(item.getSpecification()) |
| | | .setItemUnitMeasureName(unitMeasureName(item.getUnitMeasureId())); |
| | | } |
| | | |
| | | /** |
| | | * 读åè¢ç å表ä¸ç¬¬ä¸ä¸ªé空åç§ç¼å· |
| | | */ |
| | | private Long firstItemId(List<MesProBagCodeDO> bags) { |
| | | return CollUtil.isEmpty(bags) ? null : bags.stream().map(MesProBagCodeDO::getItemId) |
| | | .filter(Objects::nonNull).findFirst().orElse(null); |
| | | } |
| | | |
| | | /** |
| | | * 读ååç§ä¸»è®¡éåä½åç§°ï¼æªé
ç½®å使åä½ä¸å卿¶è¿å null |
| | | */ |
| | | private String unitMeasureName(Long unitMeasureId) { |
| | | if (unitMeasureId == null) { |
| | | return null; |
| | | } |
| | | CommonResult<MdmUnitMeasureRespDTO> result = unitMeasureApi.getUnitMeasure(unitMeasureId); |
| | | if (result == null || !result.isSuccess() || result.getData() == null) { |
| | | return null; |
| | | } |
| | | return StrUtil.trimToNull(result.getData().getName()); |
| | | } |
| | | |
| | | private List<MesProTracePublicRespVO.WorkerVO> buildWorkers(Long batchId) { |
| | |
| | | resp.setPurchaseSources(CollUtil.isNotEmpty(purchaseSources) ? purchaseSources : List.of()); |
| | | resp.setSalesTargets(CollUtil.isNotEmpty(salesTargets) ? salesTargets : List.of()); |
| | | resp.setProcessTraces(CollUtil.isNotEmpty(processTraces) ? processTraces : List.of()); |
| | | List<MesWmBatchFlowRespVO> seedFlows = mesWmBatchService.getBatchFlowList(batch.getCode()); |
| | | resp.setSeedFlows(CollUtil.isNotEmpty(seedFlows) ? seedFlows : List.of()); |
| | | } catch (Exception ex) { |
| | | // ä»åºæ¹æ¬¡ä½ç³»ï¼éè´/éå®/æµè½¬ï¼æªå¯ç¨æ¶å®¹éï¼ä¸å½±åæ ¸å¿è¿½æº¯ |
| | | log.warn("[fillOptionalModules][æ¹æ¬¡ {} æ©å±æ¨¡åæ¥è¯¢å¤±è´¥: {}]", batch.getCode(), ex.getMessage()); |
| | | resp.setPurchaseSources(List.of()); |
| | | resp.setSalesTargets(List.of()); |
| | | resp.setProcessTraces(List.of()); |
| | | resp.setSeedFlows(List.of()); |
| | | } |
| | | } |
| | | |
| | | private void fillTimelineAndDecision(MesProTracePublicRespVO resp) { |
| | | List<MesProTracePublicRespVO.TimelineVO> timeline = new ArrayList<>(); |
| | | if (resp.getProduceDate() != null) { |
| | | timeline.add(timeline("ç产", "BATCH_CREATED", "çäº§æ¹æ¬¡å»ºç«", resp.getProduceDate(), null, |
| | | resp.getBatchStatusName())); |
| | | } |
| | | if (resp.getProcessTraces() != null) { |
| | | resp.getProcessTraces().forEach(item -> timeline.add(timeline("å å·¥", item.getEventType(), |
| | | item.getEventType() == null ? "å·¥åºæµè½¬" : ("IN".equals(item.getEventType()) ? "å·¥åºæå
¥" : "å·¥åºäº§åº"), |
| | | item.getEventTime(), item.getQuantity(), item.getQualityStatus() == null ? null : String.valueOf(item.getQualityStatus())))); |
| | | } |
| | | if (resp.getInbound() != null) { |
| | | timeline.add(timeline("ä»å¨", "INBOUND", "ä»å¨å
¥åº", resp.getInbound().getEventTime(), |
| | | resp.getInbound().getQuantity(), resp.getInbound().getStatus())); |
| | | } |
| | | if (resp.getSalesTargets() != null) { |
| | | resp.getSalesTargets().forEach(item -> timeline.add(timeline("éå®", "OUTBOUND", "éå®åºåº", |
| | | item.getSalesDate(), item.getQuantity(), item.getQualityStatus() == null ? null : String.valueOf(item.getQualityStatus())))); |
| | | } |
| | | timeline.sort(Comparator.comparing(MesProTracePublicRespVO.TimelineVO::getEventTime, |
| | | Comparator.nullsLast(Comparator.naturalOrder()))); |
| | | resp.setTimeline(timeline); |
| | | |
| | | MesProTracePublicRespVO.DecisionVO decision = new MesProTracePublicRespVO.DecisionVO(); |
| | | decision.setQualityRisk(resp.getQuality() != null && Integer.valueOf(2).equals(resp.getQuality().getResult())); |
| | | decision.setInboundQuantity(resp.getInbound() == null ? null : resp.getInbound().getQuantity()); |
| | | decision.setSalesTargetCount(resp.getSalesTargets() == null ? 0 : resp.getSalesTargets().size()); |
| | | decision.setConsumerScanCount(resp.getAntiFake() == null ? 0L : resp.getAntiFake().getScanCount()); |
| | | decision.setRiskLevel(Boolean.TRUE.equals(decision.getQualityRisk()) ? "HIGH" : "NORMAL"); |
| | | resp.setDecision(decision); |
| | | } |
| | | |
| | | private MesProTracePublicRespVO.TimelineVO timeline(String stage, String eventType, String eventName, |
| | | java.time.LocalDateTime eventTime, BigDecimal quantity, |
| | | String status) { |
| | | MesProTracePublicRespVO.TimelineVO vo = new MesProTracePublicRespVO.TimelineVO(); |
| | | vo.setStage(stage).setEventType(eventType).setEventName(eventName).setEventTime(eventTime) |
| | | .setQuantity(quantity).setStatus(status); |
| | | return vo; |
| | | } |
| | | |
| | | // ==================== åç§°æ å° ==================== |
| | |
| | | }; |
| | | } |
| | | |
| | | private record TraceEntry(String sourceType, Long batchId) { |
| | | private record TraceEntry(String sourceType, Long batchId, Long bagItemId) { |
| | | } |
| | | |
| | | } |
| | |
| | | package cn.iocoder.yudao.module.mes.service.wm.batch; |
| | | |
| | | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo.MesWmBatchFlowRespVO; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo.MesWmBatchGenerateReqVO; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo.MesWmBatchPageReqVO; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo.MesWmBatchProcessTraceRespVO; |
| | |
| | | List<MesWmBatchProcessTraceRespVO> getProcessTraceList(String code); |
| | | |
| | | /** |
| | | * è·å¾æ¹æ¬¡åºå
¥åºæµæ°´ï¼ç§åæµåï¼å
¥åº + éå®åºåºçå
¨é¨åºåäºå¡ï¼ |
| | | * |
| | | * @param code æ¹æ¬¡å· |
| | | * @return åºå
¥åºæµæ°´å表 |
| | | */ |
| | | List<MesWmBatchFlowRespVO> getBatchFlowList(String code); |
| | | |
| | | /** |
| | | * æ ¹æ® SN ç è·å¾æ¹æ¬¡ |
| | | * |
| | | * @param sn SN ç |
| | |
| | | import cn.hutool.core.util.ObjUtil; |
| | | import cn.hutool.core.util.StrUtil; |
| | | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo.MesWmBatchFlowRespVO; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo.MesWmBatchGenerateReqVO; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo.MesWmBatchPageReqVO; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo.MesWmBatchProcessTraceRespVO; |
| | |
| | | } |
| | | |
| | | @Override |
| | | public List<MesWmBatchFlowRespVO> getBatchFlowList(String code) { |
| | | return batchMapper.selectBatchFlowList(code); |
| | | } |
| | | |
| | | @Override |
| | | public MesWmBatchDO getBatchBySn(String sn) { |
| | | MesWmSnDO snDO = snMapper.selectOne(MesWmSnDO::getCode, sn); |
| | | if (snDO == null || StrUtil.isBlank(snDO.getBatchCode())) { |
| | |
| | | if (proBatch == null || StrUtil.isBlank(proBatch.getCode())) { |
| | | return null; |
| | | } |
| | | // 1. å¤ç¨å·²æä»åºæ¹æ¬¡ï¼åä¸çäº§æ¹æ¬¡å·ï¼ |
| | | MesWmBatchDO existing = batchMapper.selectByCode(proBatch.getCode()); |
| | | // 1. ä¼å
æçäº§æ¹æ¬¡ ID å¤ç¨ï¼å
¼å®¹å岿°æ®åææ¹æ¬¡å·å¹é
|
| | | MesWmBatchDO existing = batchMapper.selectOne(MesWmBatchDO::getProBatchId, proBatch.getId()); |
| | | if (existing == null) { |
| | | existing = batchMapper.selectByCode(proBatch.getCode()); |
| | | } |
| | | if (existing != null) { |
| | | if (existing.getProBatchId() == null && proBatch.getId() != null) { |
| | | existing.setProBatchId(proBatch.getId()); |
| | | batchMapper.updateById(existing); |
| | | } |
| | | return existing; |
| | | } |
| | | // 2. æ°å»ºä»åºæ¹æ¬¡ï¼ä»¥çäº§æ¹æ¬¡å·ä½ä¸ºä»åºæ¹æ¬¡å·ï¼è´¨éç¶æç½®ä¸ºå¾
æ£éª |
| | | MesWmBatchDO batch = MesWmBatchDO.builder() |
| | | .proBatchId(proBatch.getId()) |
| | | .code(proBatch.getCode()) |
| | | .itemId(proBatch.getItemId()) |
| | | .produceDate(proBatch.getProduceDate()) |
| | |
| | | List<MesWmMaterialStockDO> getMaterialStockListByItemAndBatch(Long itemId, Long batchId); |
| | | |
| | | /** |
| | | * æ¥è¯¢ç©æ/æ¹æ¬¡çåæ ¼åºåºåè®°å½ï¼ä»
stock_state=20ï¼ |
| | | * |
| | | * <p>åæ¹æ¬¡å¯è½åæ¶å卿ååºä¸åæ ¼åºä¸¤æ¡è®°å½ï¼ç§åè´¨æ£æè¢ææ°éï¼ï¼ |
| | | * éå®åºåºéåºåå¿
é¡»ä»åæ ¼åºè®°å½ä¸éï¼é¿å
é䏿ªè´¨æ£çæååºåã</p> |
| | | * |
| | | * @param itemId ç©æç¼å· |
| | | * @param batchId æ¹æ¬¡ç¼å· |
| | | * @return åæ ¼åºåºåè®°å½å表 |
| | | */ |
| | | List<MesWmMaterialStockDO> getQualifiedMaterialStockListByItemAndBatch(Long itemId, Long batchId); |
| | | |
| | | /** |
| | | * æ´æ°åºåæ°é |
| | | * |
| | | * @param id åºåè®°å½ç¼å· |
| | |
| | | * @return ä»åºæ±æ»å表 |
| | | */ |
| | | List<MesWmStockSummaryRespVO> getStockSummaryByWarehouse(MesWmMaterialStockListReqVO reqVO); |
| | | |
| | | /** |
| | | * æä»åºæ¹æ¬¡æ´æ°åºåç¶æï¼ç¨äºç§åè´¨æ£åæ ¼åï¼å°æååºæ´æ¹è½¬ä¸ºåæ ¼åºï¼ |
| | | * |
| | | * @param batchId ä»åºæ¹æ¬¡ID |
| | | * @param toState ç®æ åºåç¶æ |
| | | * @param fromState ååºåç¶æï¼éå®åªæ´æ°è¯¥ç¶æçè®°å½ï¼ |
| | | * @return å½±åè¡æ° |
| | | */ |
| | | int updateStockStateByBatchId(Long batchId, Integer toState, Integer fromState); |
| | | |
| | | /** |
| | | * åºä½æ··æ¾è§åæ ¡éª |
| | |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.batch.MesWmBatchDO; |
| | | import cn.iocoder.yudao.module.mes.service.wm.transaction.MesWmTransactionService; |
| | | import cn.iocoder.yudao.module.mes.service.wm.transaction.dto.MesWmTransactionSaveReqDTO; |
| | | import cn.iocoder.yudao.module.mes.service.wm.materialstockbag.MesWmMaterialStockBagService; |
| | | import cn.iocoder.yudao.module.mes.dal.mysql.wm.materialstockbag.MesWmMaterialStockBagMapper; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.materialstockbag.MesWmMaterialStockBagDO; |
| | | import cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseAreaService; |
| | | import cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseService; |
| | | import jakarta.annotation.Resource; |
| | |
| | | import java.util.function.Function; |
| | | |
| | | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| | | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; |
| | | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; |
| | | import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*; |
| | | |
| | |
| | | @Resource |
| | | @Lazy |
| | | private MesWmBatchService batchService; |
| | | |
| | | @Resource |
| | | private MesWmMaterialStockBagMapper materialStockBagMapper; |
| | | @Resource |
| | | private MesWmMaterialStockBagService materialStockBagService; |
| | | |
| | | @Override |
| | | public MesWmMaterialStockDO getMaterialStock(Long id) { |
| | |
| | | Assert.notNull(virtualWarehouse, "èæä»åºï¼WIP_VIRTUAL_WAREHOUSEï¼ä¸åå¨"); |
| | | virtualWarehouseId = virtualWarehouse.getId(); |
| | | } |
| | | // 1.4 è§£æ warehouseTypeï¼è½¬æ¢ä¸ºè¯¥ç±»åä»åº warehouseIdsï¼ä¸ warehouseId / virtualFilter å¹¶åï¼ä¿çå
¼å®¹ï¼ |
| | | List<Long> warehouseIds = resolveWarehouseIdsByType(pageReqVO.getWarehouseType()); |
| | | if (warehouseIds != null && warehouseIds.isEmpty()) { |
| | | return PageResult.empty(); |
| | | } |
| | | |
| | | // 2. å页æ¥è¯¢ |
| | | return materialStockMapper.selectPage(pageReqVO, itemTypeIds, itemIds, virtualWarehouseId); |
| | | return materialStockMapper.selectPage(pageReqVO, itemTypeIds, itemIds, virtualWarehouseId, warehouseIds); |
| | | } |
| | | |
| | | /** |
| | | * å°ä»åºç±»åè§£æä¸ºä»åº id éåï¼warehouseType 为 null æ¶ä¸å è¿æ»¤ï¼è¿å nullï¼ |
| | | * |
| | | * @param warehouseType ä»åºç±»åï¼è§ {@link cn.iocoder.yudao.module.mes.enums.wm.MesWmWarehouseTypeEnum} |
| | | * @return 该类åä»åº id éåï¼warehouseType 为 null è¿å nullï¼è¯¥ç±»åæ ä»åºè¿å空éå |
| | | */ |
| | | private List<Long> resolveWarehouseIdsByType(Integer warehouseType) { |
| | | if (warehouseType == null) { |
| | | return null; |
| | | } |
| | | return convertList(warehouseService.getWarehouseListByType(warehouseType), MesWmWarehouseDO::getId); |
| | | } |
| | | |
| | | @Override |
| | |
| | | |
| | | @Override |
| | | public List<MesWmMaterialStockDO> getMaterialStockList(MesWmMaterialStockListReqVO reqVO) { |
| | | return materialStockMapper.selectList(reqVO); |
| | | List<Long> warehouseIds = resolveWarehouseIdsByType(reqVO.getWarehouseType()); |
| | | if (warehouseIds != null && warehouseIds.isEmpty()) { |
| | | return Collections.emptyList(); |
| | | } |
| | | return materialStockMapper.selectList(reqVO, warehouseIds); |
| | | } |
| | | |
| | | @Override |
| | |
| | | @Override |
| | | public MesWmMaterialStockDO getMaterialStockByCompositeKey(Long itemId, Long warehouseId, Long locationId, Long areaId, |
| | | Long batchId, Long vendorId) { |
| | | return materialStockMapper.selectByCompositeKey(itemId, warehouseId, locationId, areaId, batchId, vendorId); |
| | | // åºåº/å ç¨åªä»åæ ¼åºå¹é
ï¼é¿å
æ£å°åæ¹æ¬¡çæååºï¼ç§åè´¨æ£æè¢ææ°éååæ¹æ¬¡åç¶æå¹¶åï¼ |
| | | return materialStockMapper.selectQualifiedByCompositeKey(itemId, warehouseId, locationId, areaId, batchId, vendorId); |
| | | } |
| | | |
| | | @Override |
| | | public List<MesWmMaterialStockDO> getQualifiedMaterialStockListByItemAndBatch(Long itemId, Long batchId) { |
| | | List<Long> qualifiedWarehouseIds = warehouseService.getQualifiedWarehouseIds(); |
| | | if (CollUtil.isEmpty(qualifiedWarehouseIds)) { |
| | | return Collections.emptyList(); |
| | | } |
| | | return materialStockMapper.selectQualifiedListByItemAndBatch(itemId, batchId, qualifiedWarehouseIds); |
| | | } |
| | | |
| | | @Override |
| | |
| | | @Override |
| | | public void updateMaterialStockState(Long id, Integer stockState) { |
| | | materialStockMapper.updateById(new MesWmMaterialStockDO().setId(id).setStockState(stockState)); |
| | | } |
| | | |
| | | @Override |
| | | public int updateStockStateByBatchId(Long batchId, Integer toState, Integer fromState) { |
| | | return materialStockMapper.updateStockStateByBatchId(batchId, toState, fromState); |
| | | } |
| | | |
| | | @Override |
| | |
| | | || ObjUtil.notEqual(stock.getAreaId(), areaId)) { |
| | | throw exception(WM_MATERIAL_STOCK_SELECTION_MISMATCH); |
| | | } |
| | | // 3. æ ¡éªåºåæ°éå
è¶³ï¼å¦æåç«¯ä¼ äº quantityï¼åå¿
é¡»ä¿è¯åºåæ°é >= quantityï¼ |
| | | // 3. æ ¡éªåºåè®°å½å¿
é¡»æ¯åæ ¼åºï¼æååºåæªè´¨æ£ï¼ä¸å¯ç¨äºåºåº/å ç¨ï¼ |
| | | if (!MesWmStockStateEnum.QUALIFIED.getState().equals(stock.getStockState())) { |
| | | throw exception(WM_MATERIAL_STOCK_NOT_QUALIFIED); |
| | | } |
| | | // 4. æ ¡éªåºåæ°éå
è¶³ï¼å¦æåç«¯ä¼ äº quantityï¼åå¿
é¡»ä¿è¯åºåæ°é >= quantityï¼ |
| | | if (quantity != null && stock.getQuantity() != null && stock.getQuantity().compareTo(quantity) < 0) { |
| | | throw exception(WM_MATERIAL_STOCK_INSUFFICIENT); |
| | | } |
| | |
| | | .setRelatedTransactionId(outTransactionId) |
| | | .setCheckFlag(false); |
| | | wmTransactionService.createTransaction(inTransaction); |
| | | |
| | | // 9. æ´ä½ç½®ç§»åºæ¶ï¼éè¢è¿ç§»è¢ç æç»ä½ç½®ï¼æ°éçäºæºåºä½æ´»å¨è¢æ°ä¸ä¸ºæ´æ°æè§ä¸ºæ´ä½ç§»åºï¼ |
| | | MesWmMaterialStockDO finalTargetStock = materialStockMapper.selectByCompositeKeyIgnoreVendor( |
| | | sourceStock.getItemId(), reqVO.getToWarehouseId(), reqVO.getToLocationId(), |
| | | reqVO.getToAreaId(), sourceStock.getBatchId()); |
| | | relocateBagsForMove(sourceStock, reqVO.getQuantity(), inTransaction, finalTargetStock); |
| | | } |
| | | |
| | | /** |
| | | * æ´ä½ç§»åºï¼å°æºåºä½çæ´»å¨è¢ç æç»è¿ç§»å°ç®æ åºä½ã |
| | | * <p> |
| | | * ä»
å½ç§»åºæ°éçäºæºåºä½æ´»å¨è¢æ°ä¸ä¸ºæ´æ°æ¶æ§è¡ï¼æ´ä½ç½®æ¬ç§»ï¼ï¼å°æ¯è¢æç»çåºåæ±æ»ãä»åºãåºåºãåºä½ |
| | | * æ´æ°ä¸ºç®æ ä½ç½®ï¼é¨åç§»åº/æ è¢ç æç»çæ§åºåä¸åè¢ç è¿ç§»ï¼ä¿ææ±æ»åºååå¨å³å¯ã |
| | | */ |
| | | private void relocateBagsForMove(MesWmMaterialStockDO sourceStock, BigDecimal quantity, |
| | | MesWmTransactionSaveReqDTO moveInReq, MesWmMaterialStockDO targetStock) { |
| | | List<MesWmMaterialStockBagDO> bags = materialStockBagMapper.selectActiveListByItemAndBatch( |
| | | sourceStock.getItemId(), sourceStock.getBatchId(), sourceStock.getStockState()); |
| | | if (CollUtil.isEmpty(bags) || targetStock == null || quantity == null |
| | | || quantity.compareTo(BigDecimal.valueOf(bags.size())) != 0) { |
| | | return; |
| | | } |
| | | for (MesWmMaterialStockBagDO bag : bags) { |
| | | moveInReq.setBagCodeId(bag.getBagCodeId()).setBagCode(bag.getBagCode()); |
| | | materialStockBagService.moveIn(moveInReq, targetStock, null); |
| | | } |
| | | } |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.mes.service.wm.materialstockbag; |
| | | |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.materialstock.MesWmMaterialStockDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.materialstockbag.MesWmMaterialStockBagDO; |
| | | import cn.iocoder.yudao.module.mes.service.wm.transaction.dto.MesWmTransactionSaveReqDTO; |
| | | |
| | | /** |
| | | * MES åºåè¢ç æç» Service æ¥å£ |
| | | * |
| | | * ç»ä¸å°è£
è¢ç åºåæç»ç建ç«ãè¿ç§»ãåºåºãæ¥åºé»è¾ï¼ä¾ææå¸¦è¢ç çåºååå¨å
¥å£å¤ç¨ã |
| | | * æ¯ä¸ªè¢ç å¨å䏿¶é´åªæä¸æ¡å¨åºæç»ï¼å¯ä¸çº¦æ bag_codeï¼ï¼æµè½¬éè¿æ´æ°æç»ä½ç½®/ç¶æå®ç°ã |
| | | */ |
| | | public interface MesWmMaterialStockBagService { |
| | | |
| | | /** |
| | | * å
¥åºï¼å»ºç«ææ¿æ´»æ´»å¨è¢ç æç»ã |
| | | * <p> |
| | | * è¢ç 馿¬¡å
¥åºæ¶æ°å»ºæç»ï¼å·²åºåº/å·²æ¥åºçè¢ç 忬¡å
¥åºæ¶æ¿æ´»ä¸ºå¨åºå¹¶æ´æ°ä½ç½®ï¼å·²å¨åºåè§ä¸ºéå¤å
¥åºæåºå¼å¸¸ã |
| | | * |
| | | * @param reqDTO äºå¡è¯·æ± |
| | | * @param stock ç®æ åºåæ±æ»è®°å½ |
| | | * @param transactionId æ¬ç¬äºå¡ ID |
| | | * @return è¢ç æç» |
| | | */ |
| | | MesWmMaterialStockBagDO inbound(MesWmTransactionSaveReqDTO reqDTO, MesWmMaterialStockDO stock, Long transactionId); |
| | | |
| | | /** |
| | | * åºåºï¼å°æå®è¢ç æç»ç½®ä¸ºå·²åºåºã |
| | | * |
| | | * @param reqDTO äºå¡è¯·æ±ï¼éæºå¸¦ bagCode/bagCodeIdï¼ |
| | | * @param transactionId æ¬ç¬äºå¡ ID |
| | | */ |
| | | void outbound(MesWmTransactionSaveReqDTO reqDTO, Long transactionId); |
| | | |
| | | /** |
| | | * ç§»å
¥/è¿ç§»ï¼æ´æ°æ´»å¨è¢ç æç»çä½ç½®ä¸åºåç¶æï¼ç§»åºãè°æ¨ãè´¨æ£åæ ¼è¿ç§»ï¼ã |
| | | * |
| | | * @param reqDTO äºå¡è¯·æ±ï¼éæºå¸¦ bagCodeï¼ |
| | | * @param targetStock ç®æ åºåæ±æ»è®°å½ |
| | | * @param transactionId æ¬ç¬äºå¡ ID |
| | | */ |
| | | void moveIn(MesWmTransactionSaveReqDTO reqDTO, MesWmMaterialStockDO targetStock, Long transactionId); |
| | | |
| | | /** |
| | | * æ¥åºï¼å°æå®è¢ç æç»ç½®ä¸ºæ¥åºã |
| | | * |
| | | * @param reqDTO äºå¡è¯·æ±ï¼éæºå¸¦ bagCodeï¼ |
| | | * @param transactionId æ¬ç¬äºå¡ ID |
| | | */ |
| | | void scrap(MesWmTransactionSaveReqDTO reqDTO, Long transactionId); |
| | | |
| | | /** |
| | | * æ ¹æ®åºåæ±æ» ID æ¥è¯¢å¨åºè¢ç æç»ã |
| | | * |
| | | * @param materialStockId åºåæ±æ» ID |
| | | * @return è¢ç æç»ï¼æ å nullï¼ |
| | | */ |
| | | MesWmMaterialStockBagDO getActiveByMaterialStockId(Long materialStockId); |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.mes.service.wm.materialstockbag; |
| | | |
| | | import cn.hutool.core.util.ObjUtil; |
| | | import cn.hutool.core.util.StrUtil; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.materialstock.MesWmMaterialStockDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.materialstockbag.MesWmMaterialStockBagDO; |
| | | import cn.iocoder.yudao.module.mes.dal.mysql.wm.materialstockbag.MesWmMaterialStockBagMapper; |
| | | import cn.iocoder.yudao.module.mes.enums.wm.MesWmMaterialStockBagStatusEnum; |
| | | import cn.iocoder.yudao.module.mes.enums.wm.MesWmStockStateEnum; |
| | | import cn.iocoder.yudao.module.mes.service.wm.transaction.dto.MesWmTransactionSaveReqDTO; |
| | | import jakarta.annotation.Resource; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | import org.springframework.validation.annotation.Validated; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.time.LocalDateTime; |
| | | |
| | | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| | | import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*; |
| | | |
| | | /** |
| | | * MES åºåè¢ç æç» Service å®ç°ç±» |
| | | * |
| | | * è¢ç æç»çå½å¨æï¼é¦æ¬¡å
¥åºå»ºç«ï¼ACTIVEï¼â ç§»åº/è´¨æ£è¿ç§»ä½ç½®ç¶æ â åºåº/æ¥åºç»æï¼OUT/SCRAPPEDï¼ã |
| | | * å¯ä¸çº¦æ bag_code ä¿è¯æ¯ä¸ªè¢ç ä»
䏿¡æç»ï¼å¤ç¨åä¸è¡å®æå
¨çå½å¨ææµè½¬ã |
| | | */ |
| | | @Service |
| | | @Validated |
| | | public class MesWmMaterialStockBagServiceImpl implements MesWmMaterialStockBagService { |
| | | |
| | | @Resource |
| | | private MesWmMaterialStockBagMapper materialStockBagMapper; |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public MesWmMaterialStockBagDO inbound(MesWmTransactionSaveReqDTO reqDTO, MesWmMaterialStockDO stock, Long transactionId) { |
| | | String bagCode = reqDTO.getBagCode(); |
| | | if (StrUtil.isBlank(bagCode)) { |
| | | throw exception(WM_MATERIAL_STOCK_BAG_REQUIRED); |
| | | } |
| | | // 1. æ¥è¯¢è¯¥è¢ç æ¢ææç»ï¼ä¼å
æ bagCodeIdï¼å
¶æ¬¡æ bagCode |
| | | MesWmMaterialStockBagDO existing = materialStockBagMapper.selectByBagCode(bagCode); |
| | | if (existing == null && reqDTO.getBagCodeId() != null) { |
| | | existing = materialStockBagMapper.selectByBagCodeId(reqDTO.getBagCodeId()); |
| | | } |
| | | if (existing != null) { |
| | | // 2. å·²å¨åº â éå¤å
¥åºï¼ç¦æ¢ |
| | | if (MesWmMaterialStockBagStatusEnum.ACTIVE.getStatus().equals(existing.getStatus())) { |
| | | throw exception(WM_MATERIAL_STOCK_BAG_DUPLICATE, bagCode); |
| | | } |
| | | // 3. å·²åºåº/æ¥åº â éæ°æ¿æ´»å¹¶æ´æ°ä½ç½® |
| | | return reactivate(existing, reqDTO, stock, transactionId); |
| | | } |
| | | // 4. 馿¬¡å
¥åº â æ°å»ºæç» |
| | | MesWmMaterialStockBagDO bag = MesWmMaterialStockBagDO.builder() |
| | | .materialStockId(stock.getId()) |
| | | .bagCodeId(reqDTO.getBagCodeId()) |
| | | .bagCode(bagCode) |
| | | .itemId(stock.getItemId()) |
| | | .batchId(stock.getBatchId()) |
| | | .batchCode(stock.getBatchCode()) |
| | | .vendorId(stock.getVendorId()) |
| | | .warehouseId(stock.getWarehouseId()) |
| | | .locationId(stock.getLocationId()) |
| | | .areaId(stock.getAreaId()) |
| | | .stockState(ObjUtil.defaultIfNull(reqDTO.getStockState(), stock.getStockState())) |
| | | .status(MesWmMaterialStockBagStatusEnum.ACTIVE.getStatus()) |
| | | .quantity(BigDecimal.ONE) |
| | | .frozen(false) |
| | | .lastTransactionId(transactionId) |
| | | .inboundTime(LocalDateTime.now()) |
| | | .build(); |
| | | materialStockBagMapper.insert(bag); |
| | | return bag; |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void outbound(MesWmTransactionSaveReqDTO reqDTO, Long transactionId) { |
| | | MesWmMaterialStockBagDO bag = requireActiveBag(reqDTO); |
| | | MesWmMaterialStockBagDO update = new MesWmMaterialStockBagDO(); |
| | | update.setId(bag.getId()); |
| | | update.setStatus(MesWmMaterialStockBagStatusEnum.OUT.getStatus()); |
| | | update.setStockState(MesWmStockStateEnum.OUT.getState()); |
| | | update.setLastTransactionId(transactionId); |
| | | update.setOutboundTime(LocalDateTime.now()); |
| | | materialStockBagMapper.updateById(update); |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void moveIn(MesWmTransactionSaveReqDTO reqDTO, MesWmMaterialStockDO targetStock, Long transactionId) { |
| | | MesWmMaterialStockBagDO bag = requireActiveBag(reqDTO); |
| | | MesWmMaterialStockBagDO update = new MesWmMaterialStockBagDO(); |
| | | update.setId(bag.getId()); |
| | | update.setMaterialStockId(targetStock.getId()); |
| | | update.setWarehouseId(targetStock.getWarehouseId()); |
| | | update.setLocationId(targetStock.getLocationId()); |
| | | update.setAreaId(targetStock.getAreaId()); |
| | | update.setStockState(ObjUtil.defaultIfNull(reqDTO.getStockState(), targetStock.getStockState())); |
| | | update.setLastTransactionId(transactionId); |
| | | materialStockBagMapper.updateById(update); |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void scrap(MesWmTransactionSaveReqDTO reqDTO, Long transactionId) { |
| | | MesWmMaterialStockBagDO bag = requireActiveBag(reqDTO); |
| | | MesWmMaterialStockBagDO update = new MesWmMaterialStockBagDO(); |
| | | update.setId(bag.getId()); |
| | | update.setStatus(MesWmMaterialStockBagStatusEnum.SCRAPPED.getStatus()); |
| | | update.setStockState(MesWmStockStateEnum.OUT.getState()); |
| | | update.setQuantity(BigDecimal.ZERO); |
| | | update.setLastTransactionId(transactionId); |
| | | update.setOutboundTime(LocalDateTime.now()); |
| | | materialStockBagMapper.updateById(update); |
| | | } |
| | | |
| | | @Override |
| | | public MesWmMaterialStockBagDO getActiveByMaterialStockId(Long materialStockId) { |
| | | return materialStockBagMapper.selectOneActiveByMaterialStockId(materialStockId); |
| | | } |
| | | |
| | | /** |
| | | * æ¥è¯¢æå®è¢ç çæ´»å¨æç»ï¼ä¸å卿已åºåº/æ¥åºåæå¼å¸¸ã |
| | | */ |
| | | private MesWmMaterialStockBagDO requireActiveBag(MesWmTransactionSaveReqDTO reqDTO) { |
| | | MesWmMaterialStockBagDO bag = null; |
| | | if (reqDTO.getBagCodeId() != null) { |
| | | bag = materialStockBagMapper.selectActiveByBagCodeId(reqDTO.getBagCodeId()); |
| | | } |
| | | if (bag == null && StrUtil.isNotBlank(reqDTO.getBagCode())) { |
| | | bag = materialStockBagMapper.selectActiveByBagCode(reqDTO.getBagCode()); |
| | | } |
| | | if (bag == null) { |
| | | String code = StrUtil.blankToDefault(reqDTO.getBagCode(), String.valueOf(reqDTO.getBagCodeId())); |
| | | throw exception(WM_MATERIAL_STOCK_BAG_NOT_ACTIVE, code); |
| | | } |
| | | return bag; |
| | | } |
| | | |
| | | private MesWmMaterialStockBagDO reactivate(MesWmMaterialStockBagDO existing, MesWmTransactionSaveReqDTO reqDTO, |
| | | MesWmMaterialStockDO stock, Long transactionId) { |
| | | MesWmMaterialStockBagDO update = new MesWmMaterialStockBagDO(); |
| | | update.setId(existing.getId()); |
| | | update.setMaterialStockId(stock.getId()); |
| | | update.setItemId(stock.getItemId()); |
| | | update.setBatchId(stock.getBatchId()); |
| | | update.setBatchCode(stock.getBatchCode()); |
| | | update.setVendorId(stock.getVendorId()); |
| | | update.setWarehouseId(stock.getWarehouseId()); |
| | | update.setLocationId(stock.getLocationId()); |
| | | update.setAreaId(stock.getAreaId()); |
| | | update.setStockState(ObjUtil.defaultIfNull(reqDTO.getStockState(), stock.getStockState())); |
| | | update.setStatus(MesWmMaterialStockBagStatusEnum.ACTIVE.getStatus()); |
| | | update.setQuantity(BigDecimal.ONE); |
| | | update.setFrozen(false); |
| | | update.setLastTransactionId(transactionId); |
| | | update.setInboundTime(LocalDateTime.now()); |
| | | update.setOutboundTime(null); |
| | | materialStockBagMapper.updateById(update); |
| | | return existing; |
| | | } |
| | | } |
| | |
| | | import cn.iocoder.yudao.module.mes.dal.mysql.wm.productsales.MesWmProductSalesMapper; |
| | | import cn.iocoder.yudao.module.mes.dal.mysql.wm.productsales.MesWmProductSalesLineMapper; |
| | | import cn.iocoder.yudao.module.mes.enums.MesBizTypeConstants; |
| | | import cn.iocoder.yudao.module.mes.enums.pro.MesProBagCodeQcStatusEnum; |
| | | import cn.iocoder.yudao.module.mes.enums.wm.MesWmProductSalesStatusEnum; |
| | | import cn.iocoder.yudao.module.mes.enums.wm.MesWmQualityStatusEnum; |
| | | import cn.iocoder.yudao.module.mes.enums.wm.MesWmSalesNoticeStatusEnum; |
| | |
| | | import cn.iocoder.yudao.module.mes.service.wm.transaction.MesWmTransactionService; |
| | | import cn.iocoder.yudao.module.mes.service.wm.transaction.dto.MesWmTransactionSaveReqDTO; |
| | | import cn.iocoder.yudao.module.mes.service.qc.oqc.MesQcOqcService; |
| | | import cn.iocoder.yudao.module.erp.api.sale.ErpSaleOrderApi; |
| | | import cn.iocoder.yudao.module.erp.api.sale.enums.ErpSaleOrderOutStatusEnum; |
| | | import jakarta.annotation.Resource; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.context.annotation.Lazy; |
| | |
| | | |
| | | @Resource |
| | | private MesTraceIntegrityService integrityService; |
| | | |
| | | @Resource |
| | | private ErpSaleOrderApi saleOrderApi; |
| | | |
| | | @Override |
| | | public Long createProductSales(MesWmProductSalesSaveReqVO createReqVO) { |
| | |
| | | if (pallet != null && pallet.getBatchId() == null) { |
| | | throw exception(PRO_PALLET_NOT_BIND_BATCH); |
| | | } |
| | | // ç§åè´¨æ£æè¢ç ç²åº¦æµè½¬åï¼åºåºåªå
许已质æ£åæ ¼çè¢ç /æç |
| | | if (pallet != null) { |
| | | List<MesProBagCodeDO> palletBags = bagCodeService.getBagCodeListByPalletId(pallet.getId()); |
| | | if (palletBags.stream().anyMatch(b -> !MesProBagCodeQcStatusEnum.QUALIFIED.getStatus().equals(b.getQcStatus()))) { |
| | | throw exception(WM_PRODUCT_SALES_SCAN_PALLET_NOT_ALL_QUALIFIED); |
| | | } |
| | | } else if (!MesProBagCodeQcStatusEnum.QUALIFIED.getStatus().equals(bag.getQcStatus())) { |
| | | throw exception(WM_PRODUCT_SALES_SCAN_BAG_NOT_QUALIFIED); |
| | | } |
| | | Long codeId = pallet != null ? pallet.getId() : bag.getId(); |
| | | MesWmProductSalesDetailDO existed = pallet != null |
| | | ? productSalesDetailMapper.selectBySalesIdAndPalletCodeId(reqVO.getSalesId(), codeId) |
| | |
| | | if (quantity == null) { |
| | | quantity = line.getQuantity(); |
| | | } |
| | | List<MesWmMaterialStockDO> stocks = materialStockService.getMaterialStockListByItemAndBatch(batch.getItemId(), wmBatch.getId()); |
| | | // åªä»åæ ¼åºè®°å½ä¸éåºåï¼åæ¹æ¬¡æååºè®°å½ä¸å¯åºåºï¼ |
| | | List<MesWmMaterialStockDO> stocks = materialStockService.getQualifiedMaterialStockListByItemAndBatch(batch.getItemId(), wmBatch.getId()); |
| | | BigDecimal outboundQuantity = quantity; |
| | | MesWmMaterialStockDO stock = stocks.stream().filter(item -> item.getQuantity().compareTo(outboundQuantity) >= 0).findFirst().orElse(null); |
| | | if (stock == null) { |
| | |
| | | // æ§è¡æ£è´§ï¼å¾
æ£è´§ â å¾
å¡«åè¿åï¼ |
| | | productSalesMapper.updateById(new MesWmProductSalesDO() |
| | | .setId(id).setStatus(MesWmProductSalesStatusEnum.SHIPPING.getStatus())); |
| | | |
| | | // åå ERP éå®è®¢ååºåºç¶æä¸º"é¨ååºåº"ï¼è¡¨ç¤ºå·²æ£è´§/å ç¨ï¼ |
| | | if (sales.getSaleOrderId() != null) { |
| | | saleOrderApi.updateOrderOutStatusTo(sales.getSaleOrderId(), |
| | | ErpSaleOrderOutStatusEnum.PART_OUT.getStatus()); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | |
| | | updateSalesNoticeOutCount(sales); |
| | | } |
| | | |
| | | // 6. åå ERP éå®è®¢åçåºåºæ°éåç¶æ |
| | | updateErpSaleOrderOutCount(sales); |
| | | |
| | | // 7. ååè¢ç /æçåºåºå»åï¼ä¾çªè´§ç¨½æ¥å®ä½ç»éåå°åºï¼ï¼å¹¶çæåºåºå®æ´æ§æè¦ |
| | | // 6. ååè¢ç /æçåºåºå»åï¼ä¾çªè´§ç¨½æ¥å®ä½ç»éåå°åºï¼ï¼å¹¶çæåºåºå®æ´æ§æè¦ |
| | | List<MesWmProductSalesDetailDO> outDetails = productSalesDetailService.getProductSalesDetailListBySalesId(id); |
| | | for (MesWmProductSalesDetailDO detail : outDetails) { |
| | | if (detail.getBagCodeId() != null) { |
| | |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * åå ERP éå®è®¢åçåºåºæ°éåç¶æ |
| | | */ |
| | | private void updateErpSaleOrderOutCount(MesWmProductSalesDO sales) { |
| | | // è·ååºåºåè¡ |
| | | List<MesWmProductSalesLineDO> lines = productSalesLineService.getProductSalesLineListBySalesId(sales.getId()); |
| | | if (CollUtil.isEmpty(lines)) { |
| | | return; |
| | | } |
| | | // ç¨äºåå¨éå®è®¢å IDï¼é¿å
é夿´æ° |
| | | Long saleOrderId = null; |
| | | // éåè¡ï¼æ saleOrderItemId æ´æ°åºåºæ°é |
| | | for (MesWmProductSalesLineDO line : lines) { |
| | | if (line.getSaleOrderItemId() != null && line.getQuantity() != null) { |
| | | saleOrderApi.updateOrderItemOutCount(line.getSaleOrderItemId(), line.getQuantity()); |
| | | // è·åéå®è®¢å IDï¼ä»ç¬¬ä¸ä¸ªææçæç»é¡¹è·åï¼ |
| | | if (saleOrderId == null) { |
| | | cn.iocoder.yudao.module.erp.api.sale.dto.ErpSaleOrderItemRespDTO itemDTO = |
| | | saleOrderApi.getSaleOrderItem(line.getSaleOrderItemId()).getCheckedData(); |
| | | if (itemDTO != null && itemDTO.getOrderId() != null) { |
| | | saleOrderId = itemDTO.getOrderId(); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | // æ´æ°éå®è®¢åçåºåºç¶æ |
| | | if (saleOrderId != null) { |
| | | saleOrderApi.updateOrderOutStatus(saleOrderId); |
| | | } |
| | | } |
| | | |
| | | private void createTransactionList(MesWmProductSalesDO sales) { |
| | | List<MesWmProductSalesDetailDO> details = productSalesDetailService.getProductSalesDetailListBySalesId(sales.getId()); |
| | | wmTransactionService.createTransactionList(convertList(details, detail -> new MesWmTransactionSaveReqDTO() |
| | | .setType(MesWmTransactionTypeEnum.OUT.getType()).setItemId(detail.getItemId()) |
| | | .setQuantity(detail.getQuantity().negate()) // åºåºæ°éä¸ºè´æ° |
| | | .setBatchId(detail.getBatchId()).setBatchCode(detail.getBatchCode()) |
| | | .setBagCodeId(detail.getBagCodeId()) // è¢ç åæç»åºåºæ¶ç½®è¢ç å·²åºåºï¼æçåæç»ä¸éè¢å¤ç |
| | | .setWarehouseId(detail.getWarehouseId()).setLocationId(detail.getLocationId()).setAreaId(detail.getAreaId()) |
| | | .setBizType(MesBizTypeConstants.WM_PRODUCT_SALES).setBizId(sales.getId()) |
| | | .setBizCode(sales.getCode()).setBizLineId(detail.getLineId()) |
| | |
| | | import cn.iocoder.yudao.module.mes.controller.admin.wm.salesnotice.vo.line.MesWmSalesNoticeLinePageReqVO; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.wm.salesnotice.vo.line.MesWmSalesNoticeLineSaveReqVO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.batch.MesWmBatchDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.materialstock.MesWmMaterialStockDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.salesnotice.MesWmSalesNoticeDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.salesnotice.MesWmSalesNoticeLineDO; |
| | | import cn.iocoder.yudao.module.mes.dal.mysql.wm.salesnotice.MesWmSalesNoticeLineMapper; |
| | | import cn.iocoder.yudao.module.mes.service.mdm.MesMdmItemService; |
| | | import cn.iocoder.yudao.module.mes.service.wm.batch.MesWmBatchService; |
| | | import cn.iocoder.yudao.module.mes.service.wm.materialstock.MesWmMaterialStockService; |
| | | import jakarta.annotation.Resource; |
| | | import org.springframework.context.annotation.Lazy; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.validation.annotation.Validated; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.util.List; |
| | | |
| | | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| | |
| | | private MesWmSalesNoticeService salesNoticeService; |
| | | @Resource |
| | | private MesWmBatchService batchService; |
| | | @Resource |
| | | private MesWmMaterialStockService materialStockService; |
| | | @Resource |
| | | private MesMdmItemService mdmItemService; |
| | | |
| | |
| | | } |
| | | |
| | | private void validateLineSaveData(MesWmSalesNoticeLineSaveReqVO reqVO) { |
| | | // æ ¡éªç¶åæ®åå¨ä¸ä¸ºèç¨¿ç¶æ |
| | | validateNoticeStatusDraft(reqVO.getNoticeId()); |
| | | // æ ¡éªç©æåå¨ |
| | | if (reqVO.getItemId() != null) { |
| | | mdmItemService.validateItemExistsAndEnable(reqVO.getItemId()); |
| | | mdmItemService.validateItemExistsAndEnable(reqVO.getItemId()); |
| | | |
| | | MesWmBatchDO batch = resolveBatch(reqVO); |
| | | if (batch == null) { |
| | | throw exception(WM_MATERIAL_STOCK_NOT_EXISTS); |
| | | } |
| | | if (ObjUtil.notEqual(batch.getItemId(), reqVO.getItemId())) { |
| | | throw exception(WM_MATERIAL_STOCK_NOT_EXISTS); |
| | | } |
| | | BigDecimal qualifiedQuantity = materialStockService |
| | | .getQualifiedMaterialStockListByItemAndBatch(reqVO.getItemId(), batch.getId()).stream() |
| | | .map(MesWmMaterialStockDO::getQuantity) |
| | | .filter(quantity -> quantity != null) |
| | | .reduce(BigDecimal.ZERO, BigDecimal::add); |
| | | if (qualifiedQuantity.compareTo(reqVO.getQuantity()) < 0) { |
| | | throw exception(WM_MATERIAL_STOCK_INSUFFICIENT); |
| | | } |
| | | reqVO.setBatchId(batch.getId()); |
| | | reqVO.setBatchCode(batch.getCode()); |
| | | } |
| | | |
| | | private MesWmBatchDO resolveBatch(MesWmSalesNoticeLineSaveReqVO reqVO) { |
| | | if (reqVO.getBatchId() != null) { |
| | | return batchService.getBatch(reqVO.getBatchId()); |
| | | } |
| | | if (StrUtil.isNotBlank(reqVO.getBatchCode())) { |
| | | return batchService.getBatchByCode(reqVO.getBatchCode()); |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | /** |
| | |
| | | } |
| | | |
| | | /** |
| | | * ä»éå®è®¢åçæåè´§éç¥å |
| | | * |
| | | * @param saleOrderId éå®è®¢åID |
| | | * @return åè´§éç¥åID |
| | | */ |
| | | Long generateSalesNoticeFromSaleOrder(Long saleOrderId); |
| | | |
| | | /** |
| | | * 宿åè´§éç¥åï¼åºåºå®æåè°ç¨ï¼ |
| | | * ç´¯å åºåºæ°é并计ç®åºåºç¶æ |
| | | * |
| | |
| | | import cn.iocoder.yudao.module.mes.enums.wm.MesWmProductSalesStatusEnum; |
| | | import cn.iocoder.yudao.module.mes.service.md.autocode.MesMdAutoCodeRecordService; |
| | | import cn.iocoder.yudao.module.crm.api.customer.CrmCustomerApi; |
| | | import cn.iocoder.yudao.module.erp.api.sale.ErpSaleOrderApi; |
| | | import cn.iocoder.yudao.module.erp.api.sale.dto.ErpSaleOrderItemRespDTO; |
| | | import cn.iocoder.yudao.module.erp.api.sale.dto.ErpSaleOrderRespDTO; |
| | | import cn.iocoder.yudao.module.erp.api.sale.enums.ErpSaleOrderOutStatusEnum; |
| | | import jakarta.annotation.Resource; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.stereotype.Service; |
| | |
| | | @Resource |
| | | private CrmCustomerApi customerApi; |
| | | |
| | | @Resource |
| | | private ErpSaleOrderApi saleOrderApi; |
| | | @Resource |
| | | private MesMdAutoCodeRecordService autoCodeRecordService; |
| | | |
| | |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void submitSalesNotice(Long id) { |
| | | // 1.1 æ ¡éªåå¨ + èç¨¿ç¶æ |
| | | MesWmSalesNoticeDO notice = validateSalesNoticeExistsAndDraft(id); |
| | | validateSalesNoticeExistsAndDraft(id); |
| | | // 1.2 æ£æ¥æ¯å¦æè¡é¡¹ç® |
| | | List<MesWmSalesNoticeLineDO> lines = salesNoticeLineService.getSalesNoticeLineListByNoticeId(id); |
| | | if (CollUtil.isEmpty(lines)) { |
| | |
| | | // 2. æ´æ°ç¶æï¼è稿 â å¾
åºåº |
| | | salesNoticeMapper.updateById(new MesWmSalesNoticeDO() |
| | | .setId(id).setStatus(APPROVED.getStatus())); |
| | | |
| | | // 3. åå ERP éå®è®¢ååºåºç¶æä¸º"å·²é¢ç" |
| | | if (notice.getSaleOrderId() != null) { |
| | | saleOrderApi.updateOrderOutStatusTo(notice.getSaleOrderId(), |
| | | ErpSaleOrderOutStatusEnum.RESERVED.getStatus()); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | |
| | | if (ObjUtil.notEqual(id, notice.getId())) { |
| | | throw exception(WM_SALES_NOTICE_CODE_DUPLICATE); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public Long generateSalesNoticeFromSaleOrder(Long saleOrderId) { |
| | | // 1. æ ¡éªæ¯å¦å·²çæè¿åè´§éç¥åï¼é²æ¢éå¤çæï¼ |
| | | MesWmSalesNoticeDO existNotice = salesNoticeMapper.selectBySaleOrderId(saleOrderId); |
| | | if (existNotice != null) { |
| | | throw exception(WM_SALES_NOTICE_ALREADY_EXISTS); |
| | | } |
| | | |
| | | // 2. è·åéå®è®¢åä¿¡æ¯ |
| | | ErpSaleOrderRespDTO saleOrder = saleOrderApi.getSaleOrder(saleOrderId).getCheckedData(); |
| | | if (saleOrder == null) { |
| | | throw exception(WM_SALES_NOTICE_SALE_ORDER_NOT_EXISTS); |
| | | } |
| | | |
| | | // 3. è·åéå®è®¢åæç» |
| | | List<ErpSaleOrderItemRespDTO> saleOrderItems = saleOrderApi.getSaleOrderItemList(saleOrderId).getCheckedData(); |
| | | if (CollUtil.isEmpty(saleOrderItems)) { |
| | | throw exception(WM_SALES_NOTICE_SALE_ORDER_ITEM_EMPTY); |
| | | } |
| | | |
| | | // 4. çæåè´§éç¥åç¼ç |
| | | String code = autoCodeRecordService.generateAutoCode("SALESNOTICE_CODE", null); |
| | | |
| | | // 5. å建åè´§éç¥å主表 |
| | | MesWmSalesNoticeDO notice = new MesWmSalesNoticeDO(); |
| | | notice.setCode(code); |
| | | notice.setName("éå®è®¢å[" + saleOrder.getNo() + "]åè´§éç¥"); |
| | | notice.setClientId(saleOrder.getCustomerId()); |
| | | notice.setSaleOrderId(saleOrderId); |
| | | notice.setSaleOrderCode(saleOrder.getNo()); |
| | | notice.setSalesDate(java.time.LocalDateTime.now()); |
| | | notice.setStatus(PREPARE.getStatus()); |
| | | salesNoticeMapper.insert(notice); |
| | | |
| | | // 6. éåæç»å建åè´§éç¥åè¡ |
| | | for (ErpSaleOrderItemRespDTO saleOrderItem : saleOrderItems) { |
| | | MesWmSalesNoticeLineDO line = new MesWmSalesNoticeLineDO(); |
| | | line.setNoticeId(notice.getId()); |
| | | line.setSaleOrderItemId(saleOrderItem.getId()); |
| | | line.setItemId(saleOrderItem.getProductId()); |
| | | line.setQuantity(saleOrderItem.getCount()); |
| | | salesNoticeLineService.createSalesNoticeLine(line); |
| | | } |
| | | |
| | | return notice.getId(); |
| | | } |
| | | |
| | | @Override |
| | |
| | | productSales.setCode(code); |
| | | productSales.setName("åè´§éç¥å[" + notice.getCode() + "]åºåº"); |
| | | productSales.setClientId(notice.getClientId()); |
| | | productSales.setSaleOrderId(notice.getSaleOrderId()); |
| | | productSales.setSalesOrderCode(notice.getSaleOrderCode()); |
| | | productSales.setNoticeId(noticeId); |
| | | productSales.setSalesDate(notice.getSalesDate()); |
| | | // æ¶è´§ä¿¡æ¯ä»åè´§éç¥å带å
¥ |
| | |
| | | for (MesWmSalesNoticeLineDO noticeLine : noticeLines) { |
| | | MesWmProductSalesLineDO salesLine = new MesWmProductSalesLineDO(); |
| | | salesLine.setSalesId(productSales.getId()); |
| | | salesLine.setSaleOrderItemId(noticeLine.getSaleOrderItemId()); |
| | | salesLine.setNoticeLineId(noticeLine.getId()); |
| | | salesLine.setItemId(noticeLine.getItemId()); |
| | | salesLine.setQuantity(noticeLine.getQuantity()); |
| | |
| | | import cn.iocoder.yudao.module.mes.dal.mysql.wm.transaction.MesWmTransactionMapper; |
| | | import cn.iocoder.yudao.module.mes.enums.wm.MesWmStockStateEnum; |
| | | import cn.iocoder.yudao.module.mes.enums.wm.MesWmTransactionTypeEnum; |
| | | import cn.iocoder.yudao.module.mes.enums.wm.MesWmWarehouseTypeEnum; |
| | | import cn.iocoder.yudao.module.mes.service.mdm.MesMdmItemService; |
| | | import cn.iocoder.yudao.module.mes.service.wm.batch.MesWmBatchService; |
| | | import cn.iocoder.yudao.module.mes.service.wm.materialstock.MesWmMaterialStockService; |
| | |
| | | import cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseAreaService; |
| | | import cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseLocationService; |
| | | import cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseService; |
| | | import cn.iocoder.yudao.module.mes.service.wm.materialstockbag.MesWmMaterialStockBagService; |
| | | import jakarta.annotation.Resource; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | |
| | | private MesWmWarehouseLocationService locationService; |
| | | @Resource |
| | | private MesWmWarehouseAreaService areaService; |
| | | |
| | | @Resource |
| | | private MesWmMaterialStockBagService materialStockBagService; |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | |
| | | materialStockService.updateMaterialStockQuantity(materialStock.getId(), reqDTO.getQuantity(), checkFlag); |
| | | MesWmMaterialStockDO updatedStock = materialStockService.getMaterialStock(materialStock.getId()); |
| | | BigDecimal newQuantity = updatedStock.getQuantity(); |
| | | // åºåç¶æï¼æ¾å¼æå®ä¼å
ï¼å¦æ«ç å
¥æååºï¼ï¼å¦åææ°éèªå¨å¤å®ï¼â¤0 å·²åºåºï¼>0 åæ ¼åºï¼ |
| | | // åºåç¶æï¼æ¾å¼æå®ä¼å
ï¼å¦æ«ç å
¥æååºï¼ï¼å¦åèªå¨å¤å®âââ¤0 å·²åºåºï¼ |
| | | // >0 æ¶ä»
ç®æ ä»åºä¸ºåæ ¼åº(20)æç½®åæ ¼æï¼å¦åä¿ææåæ(10)ï¼ |
| | | // é¿å
çç¹/è°æ´/è°æ¨çæä½ææåä»åºåºåç¿»æåæ ¼æ |
| | | Integer stockState = reqDTO.getStockState(); |
| | | if (stockState == null) { |
| | | stockState = newQuantity.signum() <= 0 |
| | | ? MesWmStockStateEnum.OUT.getState() : MesWmStockStateEnum.QUALIFIED.getState(); |
| | | if (newQuantity.signum() <= 0) { |
| | | stockState = MesWmStockStateEnum.OUT.getState(); |
| | | } else { |
| | | MesWmWarehouseDO warehouse = warehouseService.getWarehouse(reqDTO.getWarehouseId()); |
| | | boolean qualifiedWarehouse = warehouse != null |
| | | && MesWmWarehouseTypeEnum.QUALIFIED.getType().equals(warehouse.getType()); |
| | | stockState = qualifiedWarehouse |
| | | ? MesWmStockStateEnum.QUALIFIED.getState() : MesWmStockStateEnum.TEMP.getState(); |
| | | } |
| | | } |
| | | materialStockService.updateMaterialStockState(updatedStock.getId(), stockState); |
| | | |
| | |
| | | MesWmTransactionDO transaction = MesWmTransactionDO.builder() |
| | | .type(reqDTO.getType()).quantity(reqDTO.getQuantity()).transactionTime(LocalDateTime.now()) |
| | | .itemId(reqDTO.getItemId()).batchId(reqDTO.getBatchId()).batchCode(reqDTO.getBatchCode()) |
| | | .bagCodeId(reqDTO.getBagCodeId()).bagCode(reqDTO.getBagCode()) |
| | | .warehouseId(reqDTO.getWarehouseId()).locationId(reqDTO.getLocationId()).areaId(reqDTO.getAreaId()) |
| | | .bizType(reqDTO.getBizType()).bizId(reqDTO.getBizId()).bizCode(reqDTO.getBizCode()).bizLineId(reqDTO.getBizLineId()) |
| | | .materialStockId(materialStock.getId()).relatedTransactionId(reqDTO.getRelatedTransactionId()) |
| | | .build(); |
| | | transactionMapper.insert(transaction); |
| | | // 4. 带è¢ç æ¶ï¼åæ¥ç»´æ¤åºåè¢ç æç»ï¼å
¥åºå»ºç«/æ¿æ´»ãåºåºç½®å·²åºåºãç§»å
¥è¿ç§»ãæ¥åºï¼ |
| | | boolean skipBagManage = ObjUtil.defaultIfNull(reqDTO.getSkipBagManage(), false); |
| | | if (!skipBagManage && (StrUtil.isNotBlank(reqDTO.getBagCode()) || reqDTO.getBagCodeId() != null)) { |
| | | handleStockBag(reqDTO, materialStock, transaction.getId(), transactionType); |
| | | } |
| | | return transaction.getId(); |
| | | } |
| | | |
| | | /** |
| | | * æäºå¡ç±»åç»´æ¤è¢ç æç»ï¼ä¿è¯æ±æ»åºåãè¢ç æç»ãäºå¡æµæ°´ä¸è
ä¸è´ã |
| | | */ |
| | | private void handleStockBag(MesWmTransactionSaveReqDTO reqDTO, MesWmMaterialStockDO materialStock, |
| | | Long transactionId, MesWmTransactionTypeEnum transactionType) { |
| | | switch (transactionType) { |
| | | case MOVE_IN: |
| | | // ç§»å
¥/è°æ¨/è´¨æ£è¿ç§»ï¼æ´æ°æç»ä½ç½®ä¸ç¶æ |
| | | materialStockBagService.moveIn(reqDTO, materialStock, transactionId); |
| | | break; |
| | | case IN: |
| | | case ADJUST_IN: |
| | | // å
¥åº/ççï¼å»ºç«ææ¿æ´»æç» |
| | | materialStockBagService.inbound(reqDTO, materialStock, transactionId); |
| | | break; |
| | | case MOVE_OUT: |
| | | case OUT: |
| | | case ADJUST_OUT: |
| | | // ç§»åº/åºåº/çäºï¼ç½®ä¸ºå·²åºåº |
| | | materialStockBagService.outbound(reqDTO, transactionId); |
| | | break; |
| | | default: |
| | | break; |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void createTransactionList(List<MesWmTransactionSaveReqDTO> reqDTOs) { |
| | |
| | | * æ¹æ¬¡å· |
| | | */ |
| | | private String batchCode; |
| | | /** è¢ç ID */ |
| | | private Long bagCodeId; |
| | | /** è¢ç */ |
| | | private String bagCode; |
| | | |
| | | // ===== åºåä½ç½® ===== |
| | | |
| | |
| | | */ |
| | | private Integer stockState; |
| | | |
| | | /** |
| | | * æ¯å¦è·³è¿è¢ç æç»èªå¨ç»´æ¤ï¼é»è®¤ falseï¼ã |
| | | * <p> |
| | | * è´¨æ£çéè¦èªè¡æ§å¶è¢ç çå½å¨æï¼å¦æååºåºä¸åæ ¼å
¥åºæå¯¹åçãè¢ç ä»
卿ç»è½ç¹è¿ç§»ï¼çåºæ¯ï¼ |
| | | * å¨åäºå¡æ¶ç½® trueï¼é¿å
createTransaction æåç¬äºå¡ç±»åèªå¨ç½®å·²åºåº/è¿ç§»ï¼å¯¼è´è¢ç ç¶æéä¹±ã |
| | | */ |
| | | private Boolean skipBagManage; |
| | | |
| | | } |
| | |
| | | */ |
| | | MesWmWarehouseDO getWarehouseByCode(String code); |
| | | |
| | | /** |
| | | * æä»åºç±»åè·å¾ä»åºåè¡¨ï¼æ id ååºï¼ |
| | | * |
| | | * @param type ä»åºç±»åï¼è§ {@link cn.iocoder.yudao.module.mes.enums.wm.MesWmWarehouseTypeEnum} |
| | | * @return ä»åºå表 |
| | | */ |
| | | List<MesWmWarehouseDO> getWarehouseListByType(Integer type); |
| | | |
| | | /** |
| | | * è·å¾åæ ¼åºï¼type=QUALIFIEDï¼çç¼å·éåï¼ç¨äºæä»åºç±»åè¿æ»¤åæ ¼åºå |
| | | * |
| | | * @return åæ ¼ä»åº id éå |
| | | */ |
| | | List<Long> getQualifiedWarehouseIds(); |
| | | |
| | | /** |
| | | * è·å¾ç¬¬ä¸ä¸ªåæ ¼åºï¼type=QUALIFIEDï¼æ id ååºï¼ |
| | | * |
| | | * @return åæ ¼ä»åºï¼æªé
ç½®è¿å null |
| | | */ |
| | | MesWmWarehouseDO getFirstQualifiedWarehouse(); |
| | | |
| | | } |
| | |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseDO; |
| | | import cn.iocoder.yudao.module.mes.dal.mysql.wm.warehouse.MesWmWarehouseMapper; |
| | | import cn.iocoder.yudao.module.mes.enums.wm.BarcodeBizTypeEnum; |
| | | import cn.iocoder.yudao.module.mes.enums.wm.MesWmWarehouseTypeEnum; |
| | | import cn.iocoder.yudao.module.mes.service.md.workstation.MesMdWorkstationService; |
| | | import cn.iocoder.yudao.module.mes.service.wm.barcode.MesWmBarcodeService; |
| | | import cn.iocoder.yudao.module.mes.service.wm.materialstock.MesWmMaterialStockService; |
| | |
| | | import java.util.List; |
| | | |
| | | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| | | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; |
| | | import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*; |
| | | |
| | | /** |
| | |
| | | if (MesWmWarehouseDO.WIP_VIRTUAL_WAREHOUSE.equals(code)) { |
| | | MesWmWarehouseDO newWarehouse = MesWmWarehouseDO.builder() |
| | | .code(code).name("èæçº¿è¾¹ä»åº").frozen(false) |
| | | .type(MesWmWarehouseTypeEnum.TEMP.getType()) |
| | | .remark("ç³»ç»èªå¨åå§åçèæçº¿è¾¹ä»åºï¼ç¨äºç产æ¥å·¥ä¸å¨å¶å管çè§£è¦ï¼") |
| | | .build(); |
| | | warehouseMapper.insert(newWarehouse); |
| | |
| | | return null; |
| | | } |
| | | |
| | | @Override |
| | | public List<MesWmWarehouseDO> getWarehouseListByType(Integer type) { |
| | | return warehouseMapper.selectListByType(type); |
| | | } |
| | | |
| | | @Override |
| | | public List<Long> getQualifiedWarehouseIds() { |
| | | return convertList(getWarehouseListByType(MesWmWarehouseTypeEnum.QUALIFIED.getType()), |
| | | MesWmWarehouseDO::getId); |
| | | } |
| | | |
| | | @Override |
| | | public MesWmWarehouseDO getFirstQualifiedWarehouse() { |
| | | List<MesWmWarehouseDO> list = getWarehouseListByType(MesWmWarehouseTypeEnum.QUALIFIED.getType()); |
| | | return CollUtil.isNotEmpty(list) ? list.get(0) : null; |
| | | } |
| | | |
| | | } |
| | |
| | | WHERE deleted = 0 |
| | | </select> |
| | | |
| | | <!-- ========== åºåºæµé / ä»å¨ / è´¨é ========== --> |
| | | |
| | | <!-- ç»è®¡åè´§éç¥åæ°ï¼mes_wm_sales_noticeï¼ --> |
| | | <select id="selectSalesNoticeCount" resultType="java.lang.Long"> |
| | | SELECT COUNT(*) |
| | | FROM mes_wm_sales_notice |
| | | WHERE deleted = 0 |
| | | </select> |
| | | |
| | | <!-- ç»è®¡éå®åºåºåæ°ï¼mes_wm_product_salesï¼ --> |
| | | <select id="selectProductSalesCount" resultType="java.lang.Long"> |
| | | SELECT COUNT(*) |
| | | FROM mes_wm_product_sales |
| | | WHERE deleted = 0 |
| | | </select> |
| | | |
| | | <!-- ç»è®¡éå®éè´§åæ°ï¼mes_wm_return_salesï¼ --> |
| | | <select id="selectReturnSalesCount" resultType="java.lang.Long"> |
| | | SELECT COUNT(*) |
| | | FROM mes_wm_return_sales |
| | | WHERE deleted = 0 |
| | | </select> |
| | | |
| | | <!-- ç»è®¡æªå¤çåºåé¢è¦æ°ï¼mes_wm_stock_warning.status=10ï¼ --> |
| | | <select id="selectStockWarningPendingCount" resultType="java.lang.Long"> |
| | | SELECT COUNT(*) |
| | | FROM mes_wm_stock_warning |
| | | WHERE deleted = 0 |
| | | AND status = 10 |
| | | </select> |
| | | |
| | | <!-- ç»è®¡å¾
è¯å®¡ä¸åæ ¼ååæ°ï¼mes_qc_ncr.status=0ï¼ --> |
| | | <select id="selectNcrPendingCount" resultType="java.lang.Long"> |
| | | SELECT COUNT(*) |
| | | FROM mes_qc_ncr |
| | | WHERE deleted = 0 |
| | | AND status = 0 |
| | | </select> |
| | | |
| | | <!-- ========== ç¶æåå¸ ========== --> |
| | | |
| | | <!-- æç¶æç»è®¡æ¹æ¬¡æ°é --> |
| | |
| | | WHERE rl.batch_code = #{batchCode} AND rl.deleted = 0 |
| | | </select> |
| | | |
| | | <!-- æ¹æ¬¡éå®å»åï¼æ¹æ¬¡ â éå®åºåºè¡ â éå®åºåºå â OQC --> |
| | | <!-- |
| | | æ¹æ¬¡éå®å»åï¼ç§åæµåï¼ï¼ |
| | | â è¡çº§å¹é
ï¼æ¹æ¬¡ â éå®åºåºè¡ â éå®åºåºå â OQCï¼è¡ä¸ç´æ¥è®°å½æ¹æ¬¡çæµç¨ï¼ï¼ |
| | | â¡ æç»çº§å¹é
ï¼æ¹æ¬¡ â æ«ç åºåºæç» â éå®åºåºå â OQCï¼ç§åè¢ç /æçæ«ç åºåºæ¶æ¹æ¬¡åªåå
¥æç»è¡¨ï¼æåæ®èåæ°éï¼ã |
| | | åä¸åºåºè¡è¥å·²ææç»çº§å¹é
åä¸åéå¤åºè¡çº§è®°å½ï¼æé¤å·²åæ¶ï¼ç¶æ 5ï¼åæ®ã |
| | | --> |
| | | <select id="selectSalesTargetList" parameterType="String" |
| | | resultType="cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo.MesWmBatchSalesTargetRespVO"> |
| | | SELECT s.code AS sales_code, s.sales_date, s.sales_order_code, s.client_id, |
| | | SELECT s.code AS sales_code, s.sales_date, s.sales_order_code, s.client_id, s.client_name, |
| | | oqc.code AS oqc_code, oqc.check_result AS check_result, |
| | | sl.batch_code, sl.item_id, sl.quantity, sl.quality_status |
| | | FROM mes_wm_product_sales_line sl |
| | | JOIN mes_wm_product_sales s ON s.id = sl.sales_id AND s.deleted = 0 |
| | | LEFT JOIN mes_qc_oqc oqc ON oqc.id = sl.oqc_id AND oqc.deleted = 0 |
| | | WHERE sl.batch_code = #{batchCode} AND sl.deleted = 0 |
| | | WHERE sl.batch_code = #{batchCode} AND sl.deleted = 0 AND s.status != 5 |
| | | AND NOT EXISTS (SELECT 1 FROM mes_wm_product_sales_detail d |
| | | WHERE d.line_id = sl.id AND d.batch_code = #{batchCode} AND d.deleted = 0) |
| | | UNION ALL |
| | | SELECT s.code AS sales_code, s.sales_date, s.sales_order_code, s.client_id, s.client_name, |
| | | oqc.code AS oqc_code, oqc.check_result AS check_result, |
| | | d.batch_code, d.item_id, SUM(d.quantity) AS quantity, MAX(sl.quality_status) AS quality_status |
| | | FROM mes_wm_product_sales_detail d |
| | | JOIN mes_wm_product_sales s ON s.id = d.sales_id AND s.deleted = 0 |
| | | JOIN mes_wm_product_sales_line sl ON sl.id = d.line_id AND sl.deleted = 0 |
| | | LEFT JOIN mes_qc_oqc oqc ON oqc.id = sl.oqc_id AND oqc.deleted = 0 |
| | | WHERE d.batch_code = #{batchCode} AND d.deleted = 0 AND s.status != 5 |
| | | GROUP BY s.id, s.code, s.sales_date, s.sales_order_code, s.client_id, s.client_name, |
| | | oqc.code, oqc.check_result, d.batch_code, d.item_id |
| | | ORDER BY sales_date |
| | | </select> |
| | | |
| | | <!-- æ¹æ¬¡åºå
¥åºæµæ°´ï¼ç§åæµåï¼ï¼åºåäºå¡ â ä»åº/åºåº/åºä½ â éå®åºåºåï¼biz_type 119 带åºå®¢æ·åç§°ï¼ --> |
| | | <select id="selectBatchFlowList" parameterType="String" |
| | | resultType="cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo.MesWmBatchFlowRespVO"> |
| | | SELECT tx.type, tx.biz_type, tx.biz_code, tx.quantity, tx.transaction_time, |
| | | w.name AS warehouse_name, loc.name AS location_name, area.name AS area_name, |
| | | sales.client_name |
| | | FROM mes_wm_transaction tx |
| | | LEFT JOIN mes_wm_warehouse w ON w.id = tx.warehouse_id AND w.deleted = 0 |
| | | LEFT JOIN mes_wm_warehouse_location loc ON loc.id = tx.location_id AND loc.deleted = 0 |
| | | LEFT JOIN mes_wm_warehouse_area area ON area.id = tx.area_id AND area.deleted = 0 |
| | | LEFT JOIN mes_wm_product_sales sales ON tx.biz_type = 119 AND sales.id = tx.biz_id AND sales.deleted = 0 |
| | | WHERE tx.batch_code = #{batchCode} AND tx.deleted = 0 |
| | | ORDER BY tx.transaction_time |
| | | </select> |
| | | |
| | | <!-- æ¹æ¬¡å·¥åºæµè½¬ï¼äº§åº(OUT)/æå
¥(IN) äºä»¶èåï¼æ é建表 --> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.server.framework.bizno; |
| | | |
| | | import cn.iocoder.yudao.framework.common.util.number.BizNoUtils; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.boot.ApplicationArguments; |
| | | import org.springframework.boot.ApplicationRunner; |
| | | import org.springframework.data.redis.core.StringRedisTemplate; |
| | | import org.springframework.jdbc.core.JdbcTemplate; |
| | | import org.springframework.stereotype.Component; |
| | | |
| | | import javax.sql.DataSource; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | |
| | | /** |
| | | * å·²ç¨ä¸å¡ç¼ç éåå
åºåå§åã |
| | | * |
| | | * <p>ä¸å¡ç¼ç 为ãéæº 16 ä½çº¯æ°åãï¼å¯ä¸æ§é Redis éåï¼{@link BizNoUtils#USED_SET_KEY}ï¼æ¥éã |
| | | * è¥ Redis 丢失该éåï¼å·²çæçåå²ç¼ç ä¼è¢«"å¿è®°"ï¼ä¹åå¯è½è¢«éæ°éæºå½ä¸èéå·ã |
| | | * |
| | | * <p>å æ¤ï¼å¯å¨æ¶è¥åç°è¯¥éå **ä¸åå¨**ï¼å仿°æ®åºä¸æ«æææä¸å¡ç¼ç åéç |
| | | * ã16 ä½çº¯æ°åãç¼ç ï¼éæ°è½½å
¥éåï¼æ¢å¤é²éè½åã |
| | | * |
| | | * <p>说æï¼ |
| | | * <ul> |
| | | * <li>ä»
å¨éåç¼ºå¤±æ¶æ«æï¼æ£å¸¸å¯å¨æ é¢å¤å¼éï¼ï¼</li> |
| | | * <li>best-effortï¼å¤±è´¥åªåè¦ãä¸å½±åå¯å¨ï¼</li> |
| | | * <li>æ§ç另忝ç¼ç ä¼è¢«å¿½ç¥ã</li> |
| | | * </ul> |
| | | */ |
| | | @Component |
| | | @Slf4j |
| | | public class BizCodeSetInitializer implements ApplicationRunner { |
| | | |
| | | /** éååå§åæ è®°ï¼é 16 ä½ï¼ä¸ä¼ä¸çå®ç¼ç å²çªï¼ï¼ç¨äºå¨åºå
æ ç¼ç æ¶ä¹æ 记为已åå§å */ |
| | | private static final String INIT_MARKER = "__initialized__"; |
| | | |
| | | private final StringRedisTemplate stringRedisTemplate; |
| | | private final JdbcTemplate jdbcTemplate; |
| | | |
| | | public BizCodeSetInitializer(StringRedisTemplate stringRedisTemplate, DataSource dataSource) { |
| | | this.stringRedisTemplate = stringRedisTemplate; |
| | | this.jdbcTemplate = new JdbcTemplate(dataSource); |
| | | } |
| | | |
| | | @Override |
| | | public void run(ApplicationArguments args) { |
| | | if (Boolean.TRUE.equals(stringRedisTemplate.hasKey(BizNoUtils.USED_SET_KEY))) { |
| | | log.info("[run][å·²ç¨ç¼ç éåå
åº] éåå·²åå¨ï¼è·³è¿åºå
æ«æ"); |
| | | return; |
| | | } |
| | | long start = System.currentTimeMillis(); |
| | | long total = 0L; |
| | | try { |
| | | String schema = jdbcTemplate.queryForObject("SELECT DATABASE()", String.class); |
| | | List<Map<String, Object>> columns = jdbcTemplate.queryForList( |
| | | "SELECT table_name, column_name FROM information_schema.columns " + |
| | | "WHERE table_schema = ? AND data_type IN ('varchar', 'char') " + |
| | | "AND (column_name = 'no' OR column_name = 'code' OR column_name = 'temp_code' " + |
| | | " OR column_name LIKE '%\\_no' OR column_name LIKE '%\\_code')", |
| | | schema); |
| | | for (Map<String, Object> column : columns) { |
| | | String table = String.valueOf(column.get("table_name")); |
| | | String col = String.valueOf(column.get("column_name")); |
| | | if (table.toLowerCase().startsWith("qrtz_") || table.toLowerCase().startsWith("act_")) { |
| | | continue; |
| | | } |
| | | List<String> codes = jdbcTemplate.queryForList( |
| | | "SELECT `" + col + "` FROM `" + table + "` WHERE `" + col + "` REGEXP '^[0-9]{" |
| | | + BizNoUtils.CODE_LENGTH + "}$'", |
| | | String.class); |
| | | if (!codes.isEmpty()) { |
| | | stringRedisTemplate.opsForSet().add(BizNoUtils.USED_SET_KEY, codes.toArray(new String[0])); |
| | | total += codes.size(); |
| | | } |
| | | } |
| | | // æ 记为已åå§åï¼é¿å
䏿¬¡å¯å¨é夿«æ |
| | | stringRedisTemplate.opsForSet().add(BizNoUtils.USED_SET_KEY, INIT_MARKER); |
| | | log.info("[run][å·²ç¨ç¼ç éåå
åº] éå缺失ï¼å·²è½½å
¥åºå
{} 个ç¼ç ", total); |
| | | } catch (Exception e) { |
| | | log.warn("[run][å·²ç¨ç¼ç éåå
åº] åå§å失败ï¼ä¸å½±åå¯å¨ï¼ï¼è¯·ææ¥", e); |
| | | } finally { |
| | | log.info("[run][å·²ç¨ç¼ç éåå
åº] åºå
æ«æèæ¶ {} ms", System.currentTimeMillis() - start); |
| | | } |
| | | } |
| | | |
| | | } |
| | |
| | | |
| | | # H5 溯æºé¡µé¢åºç¡å°åï¼äºç»´ç å
容åç¼ï¼ï¼é为å
¬ä¼æ«ç å¯è®¿é®çå°å |
| | | mes: |
| | | trace-base-url: http://192.168.0.10:48080/trace.html |
| | | trace-base-url: http://192.168.1.7:48080/trace.html |
| | | |
| | | --- #################### æ°æ®åºç¸å
³é
ç½® #################### |
| | | spring: |
| | |
| | | - org.springframework.ai.vectorstore.milvus.autoconfigure.MilvusVectorStoreAutoConfiguration # ç¦ç¨ AI 模åç Milvusï¼æå¨å建 |
| | | - org.dromara.trans.config.TransServiceConfig # TODO èè¿ï¼easy-trans å
¼å®¹ Spring Boot 4 åç§»é¤ï¼TransServiceConfig å¼ç¨äºå·²ç§»é¤ç RestTemplateBuilderï¼ |
| | | # ç¦ç¨æªé
ç½® API Key çæ¨¡åèªå¨é
ç½®ï¼åªä¿çéä¹åé® Embedding çæå¨é
ç½®ï¼ |
| | | - org.springframework.ai.model.openai.autoconfigure.OpenAiChatAutoConfiguration |
| | | - org.springframework.ai.model.openai.autoconfigure.OpenAiChatAutoConfiguration |
| | | - org.springframework.ai.model.openai.autoconfigure.OpenAiEmbeddingAutoConfiguration |
| | | - org.springframework.ai.model.openai.autoconfigure.OpenAiImageAutoConfiguration |
| | | - org.springframework.ai.model.openai.autoconfigure.OpenAiAudioSpeechAutoConfiguration |
| | |
| | | |
| | | # H5 溯æºé¡µé¢åºç¡å°åï¼äºç»´ç å
容åç¼ï¼ï¼é为å
¬ä¼æ«ç å¯è®¿é®çå°å |
| | | mes: |
| | | trace-base-url: http://47.97.181.254:9001/trace.html |
| | | trace-base-url: http://1.95.78.124:9008/prod/trace.html |
| | | |
| | | --- #################### æ°æ®åºç¸å
³é
ç½® #################### |
| | | spring: |
| | |
| | | min-idle: 1 # æå°è¿æ¥æ± æ°é |
| | | max-active: 20 # æå¤§è¿æ¥æ± æ°é |
| | | max-wait: 60000 # é
ç½®è·åè¿æ¥çå¾
è¶
æ¶çæ¶é´ï¼åä½ï¼æ¯«ç§ï¼1 åéï¼ |
| | | time-between-eviction-runs-millis: 60000 # é
ç½®é´éå¤ä¹
æè¿è¡ä¸æ¬¡æ£æµï¼æ£æµéè¦å
³éç空é²è¿æ¥ï¼åä½ï¼æ¯«ç§ï¼1 åéï¼ |
| | | time-between-eviction-runs-millis: 30000 # é
ç½®é´éå¤ä¹
æè¿è¡ä¸æ¬¡æ£æµï¼æ£æµéè¦å
³éç空é²è¿æ¥ï¼åä½ï¼æ¯«ç§ï¼30 ç§ï¼å缩空é²è¿æ¥æªè¢«æ£æµçç¼éï¼ |
| | | min-evictable-idle-time-millis: 600000 # é
ç½®ä¸ä¸ªè¿æ¥å¨æ± 䏿å°çåçæ¶é´ï¼åä½ï¼æ¯«ç§ï¼10 åéï¼ |
| | | max-evictable-idle-time-millis: 1800000 # é
ç½®ä¸ä¸ªè¿æ¥å¨æ± 䏿大çåçæ¶é´ï¼åä½ï¼æ¯«ç§ï¼30 åéï¼ |
| | | validation-query: SELECT 1 FROM DUAL # é
ç½®æ£æµè¿æ¥æ¯å¦ææ |
| | | test-while-idle: true |
| | | keepAlive: true # 空é²è¿æ¥å®æå鿣æµå
ä¿æ´»ï¼é¿å
被æå¡ç«¯ wait_timeout åæ¶ |
| | | test-on-borrow: false |
| | | test-on-return: false |
| | | pool-prepared-statements: true # æ¯å¦å¼å¯ PreparedStatement ç¼å |
| | |
| | | primary: master |
| | | datasource: |
| | | master: |
| | | url: jdbc:mysql://172.17.0.1:9000/mom-thzy?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X è¿æ¥çç¤ºä¾ |
| | | url: jdbc:mysql://172.17.0.1:9000/mom-thzynew?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X è¿æ¥çç¤ºä¾ |
| | | username: root |
| | | password: thzy@123456.. |
| | | password: xinjiang@123456.. |
| | | |
| | | # Redis é
ç½®ãRedisson é»è®¤çé
置足å¤ä½¿ç¨ï¼ä¸è¬ä¸éè¦è¿è¡è°ä¼ |
| | | data: |
| | | redis: |
| | | host: 172.17.0.1 # å°å |
| | | port: 6379 # ç«¯å£ |
| | | database: 1 # æ°æ®åºç´¢å¼ |
| | | database: 3 # æ°æ®åºç´¢å¼ |
| | | # password: dev # å¯ç ï¼å»ºè®®ç产ç¯å¢å¼å¯ |
| | | |
| | | --- #################### 宿¶ä»»å¡ç¸å
³é
ç½® #################### |
| | |
| | | storage: # æä»¶ä¸ä¼ é
ç½® |
| | | path: /home/mom/javaWork/file # æä»¶å卿 ¹ç®å½ |
| | | url-prefix: /admin-api/system/storage-blob # URLè·¯å¾åç¼ |
| | | domain: http://47.97.181.254:9001 # åååç¼ï¼æå®é
ååé
ç½®ï¼ï¼å端é
置好åä¸å¤ªå¯¹ç°å¨æ¯ç´è¿åç«¯ï¼ææè¦åç«¯ç«¯å£ |
| | | domain: http://1.95.78.124:9008 # åååç¼ï¼æå®é
ååé
ç½®ï¼ï¼å端é
置好åä¸å¤ªå¯¹ç°å¨æ¯ç´è¿åç«¯ï¼ææè¦åç«¯ç«¯å£ |
| | | expired: 120 # tokenè¿ææ¶é´ï¼åéï¼ |
| | | use-limit: 10 # tokenä½¿ç¨æ¬¡æ°ä¸é |
| | | jwt-secret: abcdefghijklmnopqrstuvwxyz0123456789ABCDEFG # JWTå¯é¥ |
| | |
| | | |
| | | aj: |
| | | captcha: |
| | | jigsaw: classpath:images/jigsaw # æ»å¨éªè¯ï¼åºå¾è·¯å¾ï¼ä¸é
ç½®å°ä½¿ç¨é»è®¤å¾çï¼ä»¥ classpath: å¼å¤´ï¼å resource ç®å½ä¸è·¯å¾ |
| | | pic-click: classpath:images/pic-click # æ»å¨éªè¯ï¼åºå¾è·¯å¾ï¼ä¸é
ç½®å°ä½¿ç¨é»è®¤å¾çï¼ä»¥ classpath: å¼å¤´ï¼å resource ç®å½ä¸è·¯å¾ |
| | | # 注æï¼å¿
é¡»ç¨ classpath*: åç¼ãclasspath: éé
æ«æä¸äº jar å
ç®å½ï¼ |
| | | # fat jar é¨ç½²æ¶åºå¾å¨ BOOT-INF/lib/yudao-module-system-*.jar å
伿«æä¸ºç©ºï¼å¯¼è´ /captcha/get æ¥ 6113 |
| | | jigsaw: classpath*:images/jigsaw # æ»å¨éªè¯ï¼åºå¾è·¯å¾ï¼ä¸é
ç½®å°ä½¿ç¨é»è®¤å¾çï¼ä»¥ classpath å¼å¤´ï¼å resource ç®å½ä¸è·¯å¾ |
| | | pic-click: classpath*:images/pic-click # æåç¹éï¼åºå¾è·¯å¾ï¼ä¸é
ç½®å°ä½¿ç¨é»è®¤å¾çï¼ä»¥ classpath å¼å¤´ï¼å resource ç®å½ä¸è·¯å¾ |
| | | cache-type: redis # ç¼å local/redis... |
| | | cache-number: 1000 # local ç¼åçéå¼,è¾¾å°è¿ä¸ªå¼ï¼æ¸
é¤ç¼å |
| | | timing-clear: 180 # local宿¶æ¸
é¤è¿æç¼å(åä½ç§),设置为0ä»£è¡¨ä¸æ§è¡ |
| | |
| | | <meta charset="UTF-8"> |
| | | <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"> |
| | | <meta name="format-detection" content="telephone=no"> |
| | | <title>äº§åæº¯æº</title> |
| | | <title>æ°çå¡éæ¨æ²³ç§ä¸è¡ä»½æéå
¬å¸ · äº§åæº¯æº</title> |
| | | <style> |
| | | :root { |
| | | --primary: #2e7d32; |
| | | --primary-light: #43a047; |
| | | --primary-bg: #e8f5e9; |
| | | --primary: #1f7a38; |
| | | --primary-light: #35a055; |
| | | --primary-bg: #eef7ef; |
| | | --brand-blue: #0d5faa; |
| | | --text: #1f2933; |
| | | --text-strong: #111827; |
| | | --text-sub: #6b7280; |
| | | --border: #e5e7eb; |
| | | --bg: #f5f7f4; |
| | | --card-shadow: 0 1px 4px rgba(0,0,0,.06); |
| | | --green: #2e7d32; |
| | | --red: #d32f2f; |
| | | --text-mute: #9aa1ab; |
| | | --line: #e9ecef; |
| | | --line-soft: #f1f3f5; |
| | | --bg: #f6f7f6; |
| | | --green: #1f7a38; |
| | | --red: #c62828; |
| | | --blue: #1565c0; |
| | | --amber: #b06f00; |
| | | --gray: #6b7280; |
| | | --radius: 12px; |
| | | --radius-sm: 8px; |
| | | --shadow: 0 1px 2px rgba(16, 24, 40, .05); |
| | | --mono: ui-monospace, SFMono-Regular, Menlo, Consolas, "Courier New", monospace; |
| | | } |
| | | * { box-sizing: border-box; margin: 0; padding: 0; -webkit-tap-highlight-color: transparent; } |
| | | html, body { height: 100%; } |
| | | body { |
| | | font-family: -apple-system, BlinkMacSystemFont, "PingFang SC", "Helvetica Neue", "Microsoft YaHei", sans-serif; |
| | | background: var(--bg); |
| | | color: var(--text); |
| | | line-height: 1.5; |
| | | font-size: 16px; |
| | | line-height: 1.7; |
| | | -webkit-font-smoothing: antialiased; |
| | | text-size-adjust: 100%; |
| | | } |
| | | .wrap { max-width: 480px; margin: 0 auto; padding: 0 12px 32px; } |
| | | |
| | | /* é¡¶é¨åçåº */ |
| | | .brand { |
| | | /* ========== é¡¶é¨åçåº ========== */ |
| | | .hero { background: #fff; box-shadow: var(--shadow); } |
| | | .hero-top { |
| | | max-width: 480px; margin: 0 auto; |
| | | padding: 20px 16px 14px; |
| | | text-align: center; |
| | | display: flex; align-items: center; gap: 12px; |
| | | padding: 12px 16px; |
| | | } |
| | | .brand .logo { |
| | | display: inline-flex; align-items: center; gap: 8px; |
| | | font-size: 20px; font-weight: 700; color: var(--primary); |
| | | .hero-logo { flex: 0 0 auto; height: 44px; width: auto; } |
| | | .hero-name { |
| | | flex: 1; min-width: 0; |
| | | font-size: clamp(16px, 4.6vw, 20px); |
| | | font-weight: 800; line-height: 1.35; |
| | | color: var(--brand-blue); |
| | | letter-spacing: .3px; |
| | | } |
| | | .brand .logo .mark { |
| | | width: 26px; height: 26px; border-radius: 50%; |
| | | background: linear-gradient(135deg, var(--primary-light), var(--primary)); |
| | | position: relative; |
| | | /* 宿¯å¤§å¾ä»¥ base64 å
èå¨ background-imageï¼å端å®å
¨è¿æ»¤ä»
æ¾è¡ htmlãcssãjs éæèµæºï¼ |
| | | ç¬ç«å¾çæä»¶ä¼è¢«æ¦æ 401 JSONï¼å
èåæ¶çæ /prod/ ç夿件é¨ç½² */ |
| | | .hero-banner { |
| | | position: relative; width: 100%; padding-top: 40%; overflow: hidden; |
| | | background-image: url("data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD/2wBDAAUEBAQEAwUEBAQGBQUGCA0ICAcHCBALDAkNExAUExIQEhIUFx0ZFBYcFhISGiMaHB4fISEhFBkkJyQgJh0gISD/2wBDAQUGBggHCA8ICA8gFRIVICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICD/wAARCAGwBDgDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDKPWkz9PypzCm4r9vPw+w7NJn2FOCE9BmkKkdRSHYMmk59P0oooFYO3ak/z0p4BI6VNb2kt1IEjQsaTdtWNRu7Iq49h+VPCt6fpXWW3hwQQia6A/Gq39lzX94I7eLCg4yBWH1mGtnodLwk9NNWZ+n6cJpl81gAT0xXd2Oj20EYfK8DuKfp3hprILIY+g5LVkeIb37LlIbjae+DXm1KzxE+SDPUp4dYWHNNEPiCazghZYirSHjOK5Oz025vpv3cfyk8nFNSK61K5xHukJPWvR/Dnh+8ijQyoFGK6Z1Fhae+pzUqTxdW9tCDRPC6LEHaLJ9SK3JNFjEXlpCMdziugRo7aEJI4AHesfUfElrbqVQgkV4Pt61aeh9B7ChRhZlH7DBAgRYwSO+KhdGztQKo9SKwb/xRK7nYwjWsC51qeUn987fjxXpU8LVlrI8yrjKUdInaXGoWtlGRuV5Pwrlr/WvNYhpFz6AVhSTzzNjLHPYVIdNvAm+SFkU9zxXfTw0KesnqebUxU6itFaDpL9m6fyqm8hc81eh0uWRdzYUepOKq3EKwybFkD+4rqi43sjkkpbyK5/D8qT8KkWNnbABJq01skce6Xg+matysRy3RRH0H5UY+n5U84z8tFO5A0Zp4JpMGkpEjs/T8qTn2/KilpBYb/npSj8KUUHii4WD8P0pPyozS0gG04fQUYpRigVhc+w/KjPfA/KijmkMXdjsKTPPT9KDRQFhRz2H5UH6CijNIBPy/KjPsKDSUAH5U7OfT8qbj2ooEOzj/APVRn6flRmjvQA4f54pwP0/KmjrTqQxcjPQUflSYpwJHUZ+tINBuxmPyrn8KeLK6YZW3Yj1C0C5mQ/I20e1Tx6hdqeJ2/Ok3LoNKHUiTTLtzxD+Yp50q9UZMBI9hWtb6zOijeiyfWtW18R2m4JPCBmuadWqtonXCjQlvKxz1hZPuLSJhR146VLdRqpLIAPeujv7yyeHMRVVPpXLXCozEpIW+tTCcpvmegVqUaa5Yu5SkkZsgnNRA4PQflVudIlhXb9/vVVVya6k9DicbMmD8AbQKQlc8/wAqRgB3ppxQBMhgIwwwfYUwxliSikr64poYocgAVb+2O0W3g+xpO62KVupClpLIRkbR6kVowQW9qN7kMfpVAXUv3S2FHYVMssB/1jZzUy5mOPKW7i9kmG23Un2ArNkuLlWIdiD6EVqxXUdqm6IBs1Ru71bg5aNRUw3sloVPa7epTaeY9XqMkseacSv92m5rYxJ45njTClQPpULvuJP9KbSc0DvcD9B+VAPsPyoApaYxPfH6UZ+n5UvelxSuFhufb9KPy/KlIoAphZDfy/KgevH5U4igCi4rB+H6UY9h+VLilouOw3/PSlB4/wDrUYoHtQA4H2H5U4fh+VNFLSGh+fp+VOH+eKYKcDSKHj8Pypcew/Kmg07NTqOwYHoPyoxnsPypc0oouOwzZz2/Kl2n0H5VIMdaeAKXMVykO0jsPyo59B+VTbaNtLmHykPQ9B+VOz9PyqTZR5YouLlGZPt+VLn6flTvLo8sii4+UM8UD8Pyp20gdKKVx2D8vypw/D8qSnLSuUPB46D8qPwH5UtAqR2Afh+VPHTt+VNpwpXHYXPsPyo/AflSgUoFK47DR9B+VSL+H5UgFOFK5VhR16D8qd+A/KkFPFTcaQD8PypwHsPypVFShahs0SGgH2/Kngew/KnBaeEqOYtRGY9h+VJgg9P0qcJQ0fFLmK5SEDnoPypcYHQflTgvNLtOaLhykZ+g/KjaSeg/KpCtOVOM0cwcpFtycAD8qlWI4yQPyqeGAtzip3j2rjFZufQ0VPS5nuO2B+VR7MHoPyq20eOtMKe1UpEOJWI9h+VNI56D8qsFfSm7KtSIcSLHHQflSEH0H5VNso207k8pW289vypCv0/KrBWoyPSqUiXEh28ngdPSipMc/nRVXIsclb20lzMI4x17+ldPbeE4RCJ7i8GP7oFd3pXhDTreJSgHmYGcnNS33h+JULed+Gawq5nGUuWDserSyuUI801c85udMgt0doPmwK5uQEucgivQb9I7SJggDEd2rk47KXUL4KI2KseSi134erdNyPNxNHlkox3MmKB5ZAkalmPYDNaVzoN7aWouJomVSM8jFeoaB4RtLa3WXyD5g53N1qn4ntr5oHWK0aVQMZHNcv8AaUZ1VCGx2f2XKFJznv5HlEY3ShOeTXdaHaLbxArEAx7msePw7qnliaK33H+6Ooq9awa8rLbwwMjdywrfEVI1I2jJHPhqcqUrzi/uOqTT3vZFSXpXTafoUFtHlEAOOpqDw5pk8MSvet8/fNdYUt2j2+YM/WvlMViWpckXofX4bDrl52tTitZW5ihZElGK84n0C91G8LtvYE+lev3mmW8k+Tlz2HarEGn+UnzIAPpXRRx3sI+7uc9fAqvL39jk9B8N2llCjSQjeo7itDUtShs4iqEDHatS8lEMbLGmT7VyU+i3upXBYAgHsaIS9tLnqvQKkXSjyUlqc3q2uX05KwnAPAxXPix1i+kIBdh3wDxXpUPg9IHE13Oq47U+fUdB0uMoJ1Z167ea9SGLhFctCNzyamDnJ81eVkeWT6Hd2x/fOuT2J5po0iUgMs0RP90nBNdFrniWyuji1tdxH8bDGa5m51C4ufvkDHTFerSlWnFOSseLWjRhJqLuXEj1CxXcsMaAfxDB/WoJNWuJBtcAn1rPZ5GGGdiPQmmc1sqaesjndR7RLUt5NKm0t8o7Cq6rk5JpMUAE1oklsQ5N7knm7RhBio3ZmPJzTwjHtSFNvFJWE22iLFOxS7TSgVVyRhFJtqQikIpXAaBS4pQtGPSkMKQ9aXFGKBXG4pcUuKUCgVxMUlPxSYpBcSlzRigA9qYXEoxS4paQXG0U7FGMUBcbijFOxRikA00CnEUAUBcQCnYzS0UgEApRRmlyKQXHKcGpM+ZwSB71DRzRYRK0QUZ3qfxpol2rhUXPrjNRGii3cPQNxBzmnbiec803bQBQBZinUDbKCwprSgPmPIHvUJopWQXHu29smk6DjimiloAWjmkpM0hjvrTsD1qOnA0wHbR60w8UvWgigQokcLt3HHpTevWkNJQG46iijFACGgUp9qBQMMUmKdiigBMUGlxRigBtAp2KMc0ANpaUikwaACil20oFAxMUoApccUAUAGBSgc9aAKXFIYUoFJSigEOApcGig0ihRS0gpRSKQ4GnBqZg0oFIokDYp4aou1HNKw7lgOKeChqrzTgTUtFKRbCqe+Kd5QPQ1VDkVKsnvUNMtNE/kH600wN/dpyS471Os471F2ikospmH2xQIj2q+JYm6qKeEgYdcUudlezTM7Yw7UmMHpWn9mQ/damm0bsM0e0QezZn9qB1q21qw/hIqNrdhT5kLlaIx9aeKPKcdqUKw7UMEO2g9KTaRVq3t3l5PC+taC2USrhlJrF1EjVU3LUxRUi1oSaehP7s4+tV3tJo+qEj1FNTTE6bRGDUyEHrUQB79akUGkxxLKpmpUTsajiOMZrQijD9BmsJOx0xVyuIiD0qTyMjGK0o7QtxjmpxZHbnbXO6qOpUWzBMBDYxS+TitmSzIbOKabXOOKftUL2DMgwn0q1FYO4ACmtay0xp7hVC5FdRDorDB28Cueriow0Oqjg5T1scrHYCOLLDmqU0QUk11moRLAh3DpXKzszuTjipo1HPUK9NU/dKLpznFQMuKuOH6BcmmrayMcsMD0rtUktzglFt6FQRlugpfKx1rR+z7RyKhZR0FPnuLktuUWSoyKsyYFV2YDpWqMXoRkVExpzN3qNmrVIybEzg0VGW5P0orSxiehatqNrYSMfNCqBxzXIXXjFAzJEjP6Hsa7xfAjXkgubyR5AwBEZONtSr8PNJhRibYKT3znFeDSxWEpq0ndn1lXC4yprC0UcHpt7JqJzPah1NdXYWllEyuq4PoOgqK60u20lhskBTpjGCKijuIz904FbVZqqrw0RnSh7J2qas6uO9jUBcAgdsVFcMlzjfCCOwPSs20uYMda1orqzwORn615UocjukepGpzqzZkXck+PJhtxGv94DFVoUWD5nfc3qal1zWre1jYBgprzbU/EV1IxWB9qHuK9PDYapWjtZHmYnFU6Du3dnos+twW4/eXCrjsDWefEdrLIFW7CfU15ojX9++2JJJmPXHNSvZ3GmSLLdqpPUIGya9BZfTWjep5kszqPVR0PZrC9haIPHLu9zV9tQhYbDKufTNeIzeLNQMXk2+IU9utZx1rUSc/aXH0Nc/9jyk7t2Nv7bhHRK576sdqw3tIPzol1TT7OIs88YCj1FeEf8ACRasYvL+1sq+x5qpPfXNx/rJWI9M045NJv356ClnkUvchqemav4y024ZreOYbe79j+NcbqGqaSEcWVr5kzdZGPA+grnCxNAr1qOCp0VaNzx6+Pq1tZWByWYsepphHFPxRiu+55zI9tG2pdtJtpXER4pRmn4pQtFxjcsRSbTUoWl20XFYh2mjbU2wntS+We9K4FfbS7an8pj2NN24OD1ouKzIttJtNW1t5HPyoTT3spkGWTFLmQ+WXYobeaXbVpYGJ+6anFmpH8RP0pc6BQbM3HtS4q40SI2D2qFiDwq073FYiVGY4A5pzRsvDCp4UbdmnyRvJJhQWNK+ocuhDFbCU/NIqD3pJIkVtqSB8dxWlBpBI33VysCe55qZpNJslKwIZ3/vtWftNdNTZU7L3tDE8tvQ03aR2rRmv94wsYAqkXJPQCtU29zBpLZke00beadnPeimIbikxTzSEUhiYoxS0UCG4opaKADBpBS5o70AGaQ0vFFIBMUtLRSGJRS4oNAhMUlLRigA70oFFLQAlJTj1pMUDExS0UopAN5paXHFGKAExmjbTsYooAbik5p1KBTAbzQKfgUYx2oENwaXmnYoxSGN5owafikxQA3mkwc06lxTAZg0YNPxS4oGMxS4p2KT8aQCUoBo/CloGJg0uDTgKXFIBnNOApcUAUDClxS4o5pFIAKUCgDNPAoGJijBp4FGKkYntSgUoFOAouUIBS7acBTgtSNDMU4CnYpQKQxKUE0oWnbaQxAzZp4c0gXilC1JSZMsxHep0uWHeqmKcBUOKZopNGkl2P4gDVlZLd/vLWMAR61IHYd6ydNdDVVX1NjyLZ+jYpDp6t91gazFmcdDUqXbr3NQ4SWzNFUg90XQJbY7cZFTLdRMcONpqot8xHPNSJIsw/1YrNxfVGimujNCNI5OUYGrAtpMfdyKz4bVmbdHlfcGtyxjuUIDsGX3Nc1R8uzOunHm3RSbTYpuGj2n1FVpNCuFG6Ebx6d67KKBJMblArSt9NQ8qwrjeNcDsWA5zzL7NJE+10Kkeoq7bhlIOK9NOgQ3K4liDe+KoXHg0j5rUn/dNT/aNOWktCv7Mqx1jqc9ZgOQDxW9DYiRQQKqro91aviSFhjviuh0yJuFYVyV6ytzRZ3Yeg78skY02lnH3agXTScDbXfjTlkTkClg0mNJAzgYB6VwrH2R6P1C7MjRtCEUYkdME1rXcEdvbnHpWqAAMKMCq1xbGfgnivNlXlUnzSZ6UaEYQ5Yo861K2nu5cIv0FQW/h6UHfcRZHpXpMWnW0K52An1NU76WGJCAor0YY+VuSCPNngIp882eez6SsZOI9tUZYEirodSvc5CiuWupWcmvWoynP4jxMQoRfulO4kVc1myTZJxVmZWY1WNux7GvVppLc8epd7FV2JqBs1eMDD+Go3hP0roUkcziygQe9NIq20Q7kVGY0/vCtVIyaKu0Z/CirG2IZ57GiquRY9ym1B4YchhnHas5dQvZWLb/AJR7cUxURiC7b+BxTpJVCEAAEdAK+MjCK0sfoDnJ63MvV5opV3PECw7+tcXePmUlE8sD0NdtPJEyMZQPxrAm021utzCUgHtXrYaSgrM8rFJzehy8upXEZwjFqtaXd6reXAQAeXnlumKW+s7SwDOvzEf3jWZbavdCTbEoVexAr11FTheCPFdR05rnkdNrsFsbBi0D3EwXhVrg7PS7vULsKIGjQH+NcD6V0t14pazt9qqkkxHcZrnJPEeoM7Mjqhb0FaYanWjFpL5mOLq0JzUm/kjtYrWy0bTmZ5IomI5x615vqNwLm9kkViVJ4yaLm9ubli0szuT6mqfNdmHw7ptyk7tnDicSqqUYqyQnNJmlP1oFdhwhThSAc0oFAC4oFLRipAOtKBQBT1FACAUbealC56CnLGx7VNykiDZmnrHzVpYCeoqxHbZqHMtQbKQiPSpFtnPJU49a2rSwG4FgPxpL/ehEUYx9Kx9rd2Rv7G0eZmOyRoMA80ioT9xC34VsWmjPOPMZSW9K0E0e7KgIgHsODUOvGOly44actbHNfZLmX+EgVds9GZzvkBwK6200Xy8NOfwrRNvCE2KAo9a5Z43pE7qeX/akcqLNY1wBkCmJpE9y+4qQnqa6T7JbRtksGP1pLiXZHsiXJ9BWPt5X903eGj9o5i7tYrNCMrn2rIB8wnBIrpJNKu72XdKCq+9K2j2tvH+8mC47Z5rqjWjFWbuzinh5Sd0rI52HTvPcjPHcmraaEXb92C30q3Ld2dopWIhj71mXGt3LqViYovtxWqdWfwmMlRpr3tWXZdMt7VM3E8ceP4Qcmsy4vYk+S2HH97GKpPPJISWOSe55qLqea3hTa+J3OWdZP4FYc8zvyxyfeojnPNPC9qXbW+iObciNJiptlG2i4rEO00uKl200igBtFLinY9qAGY4puOakxSYpAxm2jFPxS0XAjxSYqXHFNIoAjpcZp2KUCgBoFLinY9qXAJpAMGM0U7bSEc0ANxmjHvTsUuBQA2l4pcCkwKAEwKTtTsUYoAaBTgKBTqQCUmKdS4oAYBSmnUYoCwzFLinYp2BQMYBTsUoHtS0DsNIpMc0/FGO9A7DcUmKdil20CsMxS4p4Sgr6UirDMCjFO20uKYWGEUgAp+KAKB2GgUAU8LTsUgsMxSjmnYpQKQ7DcUuMU8CgigdhtLgUuCaXbSHYbingUoUU4CkOwmKMU/FLtpDsNAp4WnBacFqblJDAKdt5p2BSjFIY0ClxTsUoFIdhoApwAp22nBaTZVhuPelA5p2KNtK47CgelOAFAWn4FSxpDcUuKXFKF96kqw3bxShamWLcOtPFsfWpukUosgx9at27Y4NOS0J71ZisCSPmxWcpxsaRhK+hYhk2gVdjuSMYDUltpkrMOc1vWekEsPNIC151WpCO56dGlUkZsd7NFjO4Vft9YkQjLGt+TSNOniWPIAA61EvhTTzg/bSvtXnPEUWveR6kcNXi/cdwtNflUja/510ljrxkAWWMHNZ1p4X0tOWu8/jWzbaRpUJH77f9WrysROhLZfgevhoYiPxNfeakU1vcKMqPxFOFrbhtyxgH2pIktEGI9v51Y47GvJbt8J7KV1qAGB0paKKgsKSlxSE4Gc0ANdS64BxWbc6UZ8kyjHvT7rU1twcLmudvfELnIGRXbQo1XrE4a9alFWmSXeg2oz5t0PoKwrvSdOhTd5m78aq3etuxPU1iz6qWJzmvdoYet1kfPV8TQ6RLM6WiZ2R1lzyhc7FAqKXUN1UnuQa9enSa3PEq1k9hs9xJzzj6VQZ5W/iNTvICc1CTmu6Kt0PPk2+pCVc9TSeW3rUhzTNxrVGOg3yj69qKcGOfwoqrsk75fEUFvF+8kQkgYA61TTxNbNOTIvynvXESA5yWqMyhRiuJYCmes8xq6HX3HiVWLCOLcOxasafWn+YIQhPpWG8ztwOKhbOOa64YWEehxVMbUl1LM900pJllZ/Y1QlunUEIcCkcGoSjE12xgkcEpyZDIzOck5qMirgtpG/hNL9kk/umteZIx5WyjtNIVNX/sjHoDT10+Z/up+dHOh8kuxl7Tmjaa05LJ4hlsVAYD6UKaZLi1uU9vtTgOelW1tmJ4FWU02UjJAA96HNLcFCT2M3ZmnCJj2rT+yxR53SDI9KAUBGxcn3qfadivZ23KP2ZwNxHFIAF61ekEjA5GBVfyJGOFUmhSvuDjbYRGXPIq3EUPYVC1nNGu5lNNAdecEVLs9hpuO6NWMR8FhTZJURs7vwFZ4mkWr+nWovXOdzH0xWMoqOrOiMnP3Y7kQ1N0f5Rx703+0XaTcQDV+90OWBd8iHafQdKy2RIRhEyfU0R9nJXiE/awdpGxZ397Iw8pcKK211WaOP8Aebc+lctZS3hPlQoWz6Cuu03w/LKgluuCa4sQqcNZHo4V1KitC5ny6zdO21Bj2pq3V5MduHz6AV1Uem6VAcPgkd2NSy3um2q4ijBI9BXH7eO0IHesPPecznI7LUpACsBUernFMnN1aKWd4+PQU7VddujkQggViRah5pIu13+9dUKc5LmkkcdStTi+WLYt34gusFFXHvWHNd3MxJeVufetu4gSVc29rkn8aof2Rfuci3Kj3OK7qTpxW1jzK/tpu12zJIJ5JJpNtbLaHdquTsz6Zqs2nzof3ibfc1uqsXszkdGa3Rn7eKAnoKuNHGnG7JqM47VXNcjltuQhOad5fGakyOmKTJ6ZouxWRERTcVNhfrRhfSncViHFBWpSB24pNtFwsQlaMelSkUYzTuIix7UYqXFJg0rgRbaXbUmKTFFwI8UhFSY9qTFO4Ee2jBp+2jbSuAmKXFOC0YoAaV4pu32qSkxQAzHPSjHtT8UbTQMYBRipNtG2i4Ee3mjFPxQFouAzFOC+1PC04ClcZFtox7VLto20XAj2mjbT9po2mgLDMClFOxShaLjsNpce1SbcUbaVyrDAPajb7VIBS4ouOxFt9qNtTbDRsouOxHto21Jtpdp9KLjsRbaTaKn2UbaLhYg20bKm20m2i47EYXFLtqXbxRtpBYi204LUmylCUrjsR7aXb2qTbQEpXHYj204JUm00oQ0rjsRhadtqUKadtpXHYiC07bUgWnBaVyrEYXmlxxUm2l20rhYi25owc1LtpNvNK47DQvFO2804LT8UrjsRgU4D2p+2lC1LGhuKUCnbaXFK4xAKUClAoxzSAPwpR9KXFOC0hiqSOasxzAdRVfBpwFS0mWpNbF5bpB/DUy6gidEJrNGacATxWTpx6miqyRsJrciH5IgBV2HXLiQbVIU1zu0jqKcjlGDA4IrKVCD6G0cRUXU6yG9uCeZDWvFJ5tszNIVZR69a4yLU2AG5B+FTi/uJzsiBxXDPDN+R3U8Ul1udFHdzo5AlJH1rSt72RmAVmY+grB0/TriZg08hUegrtdMt7a1UbUBPqa8/EOEF3Z6mFU5u70RpabaXcyh3JjX3rfRBEmC3Tuawptchs48lhn0rEm1+4vHIViqV4roVazvayPeWIpUVa92dqbmIHAYE+1SoyuuRXF2964xlq3rK9zEcmsqmGcFobUsSpvU1TIm7aWGaSVN8ZUHB7Gub1C+YSZDYxUdp4kMTCOc7l9fShYWbXNEHi6alyyItYF1bsd6kr6iuUubqMkg8Gu9u7yG6h7MpFcRq1jEzlovlPpXrYOSfuyVmePjYv4oO6MSZQ5O0g1mzwuM1ZlSeFjkHHrVdpz0Ne/BNbHzdRp7lJoiO1V2j5q80g7ioWZTXVFs4pRRTKYpu2rJxUbCtUzJogIqMrU5FMIq0yGiEdfzoqTFFXczI5o242jtUH2V26itc7DxjFNKxg4LCpVRo6XSTMlrcqcEYpVtRIcZrT2QMeZasRW0K4fdxTdWwlQuzNj0xCepJqwukhv4QK2ovsxHbirUclv2HNcssRLodkMNAwl0hwOBxSjTQPvdK6HKuMAVE1s79Tge1ZfWJdTX6tHojENnHGMhBj6VUmWUnEURNdMLMDAJB9qsC1iVcMBTWIS8w+rOWmxw7adcStufP0FKmkuW5DfjXaPFEnIQGoiob7kRP4Vf1qTM/qUepzP8AZrhfljJNV30+9dsbcL9a7FLSRvvKQKmW1iUYK1P1tor6kpHFxaKzt84OavR6NCnfP0rpWhtxxSCKEjCjFS8VJlLBwic8dKgbgqani0lVGEQBfWt5LeHrgsamHlhcFKzliZdDWOFjuzmZNMRASBuNZ8mhXd04WKPaK7UiEDAjyfahfOHCoEHrTji5x2FLBwlozmIPCEaKrXb8dwDWxFNpmlRiO3gTI74pb6WOFSTMXf0zxXPSwXN7MBuwPQVa5qyvUloQ1ChpSjqbcmoR6ixjMZY9MCok8LxsTNPhAexNSabZvYrubr6tReX8j5/egD61neSfLSdkaWi489ZXZZt7LT7A5UqT6CpZZrqcbYsxx1jwThfnY5+op8+qBFy3C+uaTpycr7spVYqNtkXVso1ffczFj9eKSaNWyLeHJ9TWR/bBd8Rxb/c1aTUrjGWVUH1q3TmtWZqrTeiGHQLi5k3TS4B7CryaHZW6cxhyKpPqzA8SH8Kj/tC5m+VFc57mqarPd2RClQjsrsmnHk527EUelZsuolCQsZY+prTj08zENLkHvuNWfsGnwjL/ADUKcI6PUUqc5arRHOtd3siny4iM+gql/Zmp3b8qwz611E99ZQDbCgzWdLqNy5wjgL7GuiFSX2Y2OWpSh9uV/Qzf+EZnGDNKq0j6JCgwJQT65qeaeZ/vTH8DWdOrMMhj+ddEXUe8jmmqMfhiI+mwR533CfnVaSO1QYSTeahYHPPNNxXSk+rOCU4vaIhC9qZ+FSYFJtFWZEZzS4qTaDRtFO4iMikxUhFNxzRcVhuKMU/FGKAsREc0hFSYpMUXAjxS4p4Wl20XCxHijaBUm32oxRcBm33pCKlIpuKLgR4o2+1SbaMCi4DNtLipMUbaVx2I8UbakAo20XHYjC04LT9tOC0XCxFijFS7aNvtRcLEeKMVLtpdtK47EJFG2pdtKF9qLjsQhaeEqTbTttFy0iLbRj2qbbRtpXKsRhaULUm2nbaLj5SLbRtqXbS7aVx2IdtKFqXbS7cUXHykO2jbU22k20XDlIdtAXmpwtPAAouUokIjPoaPKbstWBT8VPMXyIq+WR2o2VcxTSoPajmDkKm2nBamKc9KXbRcXKRBRS7alC0u2puFiIClA9qk2+1KFouFhu2jbUoWjbU3HYjxRtzUm2gL7UXHYaFFLtp+2lApXCwzbRipMUYFK4DMU8AUu2nBKVwGUAVbtrQzHLHCirwtLZRjy8n3NZyqJMtQbVzGxVmKzd+T8o960Rb26tuEQBqURg/dPNZyq9g5LFEWKgf639KUWDH7rg1fltZYohKyjafepLZ40bLoT+NZOo7XTLSV7NWM2XTrmJNxTK+o5quke6QKWCjPU9q6qTVPItGCBQcdcc1y7MXdmbqTmnSnOafMi6kIxtyu5rXGn6XBY+Yt80k5HCqOKyM4o570AVcYuO7uKUlLZWAsTQAWNPCZNWI4uenFU5JCSbHQ2wYjPet6zt1jAO0Cs+EqgFWDfBF4NcNVyloj0KSjDVnRQypCu5mxTZ9c2KVirN03S9X1tg0MZjt+80nC/h6/hWpqXg67tIVurSRryFR+8AXDKfXHcV5knQjU5KktT1orESp89OLt3M1Zp7uXfIxIrSj/AHajoRWZCyoODxVhZsnrxW049EZQlpc0klI6GtS1uysXJrAEgwBmrkTkKBXHUpprU66dVpk+oXBbPNYskpOa0LnlaypRgmtqMUlYxryd7lq01SS3baxJQ1NeTLNCXjbNYzUgmZOM8Vt7FN8yOdV5JcsthwugSY5lyPWq1xZxyKXhI+lJNhm3CoPOZTwa6oxa1icspp6SKUsbISDUBFab7ZBz1qpJCQeldUZdzjnDsVCDTCKsFKYRWyZg0QEUwirBWmFaq5LIwoop4HP50U7k2L32S0kI2zHOORTv7Osg4Z5Tj0NU2ilX7jAfjSATbvmbPvWdn/MdakusTR+z2Ea/u8KfUjNU5pFjPyqT9OlSKseMu+afiLHynPtUrTfUu91poUftT54UClF3JnOale2VmyvGe1M+xv121peJk1MtQ6gQAG61ZF9LjGePUVnLZuedpq5DbyLxsLD6VjOMDeEp7MtR3POWJq2Jg3IYH61WEW4YKY+tTJaKxzuwK5pcp1xch4nj3YYZNXYXVhlAKgWyyPlOfrUqW08ZyVOPasJOL2OiPMt0WsFhjH5CnfY3bpnmpIGKnnrV+OXA+YVySm1sdcYp7lBdMP8AGOfXFP8A7OjFaPnqKikmIHyqB9az9pNmns4IqizVeQuKabVP4iAPSoprickkMAKos80pI3fnW0YyerZjKcVsi3NNb24wpXNZc00t58sJKD1xira2dpnfO+T9anFxYwDAXIHrW0Wo7K7MJJy3dkZcejQsd0zM59+lSyWgtk3IEUCp5dYt+kYWqpu/NJ3qCp9K1TqPWRk/ZLSJzmoXtx5zBpsJ2qqkby4ZZGZu3FdUbKxkG7yBu96y7yeSzlCKiBPYV3U6qfuxWp59Sk1703oUBbam7bUYhfXFObSwp3Xdwc+ma0LdrqdSRcLt/lVa50+ZyS8ob3BqlN3s3YlwXLdJsSKKxhHygk+tEjwOThPzNZz2EyH5Zcj60o86FfnKY9605E9b3MfaNaONi4htt20ct7Cr9uUX7qkn6VkRThucBfenO+DlZ2z7VMoX0KjUtqjWuZpEGeB+PNY897jIMppnnDdhjk++aZI/HMSVUKajuRUquWzKklyGz8pNVWk9ARVpju/5ZqBUJUegFdcUkcE231IvNkzwTUgllxjNB2jtmmkjtxV6GV2uox1BOTTGCY4BBqb5CO+aiYc8U0QyPApMU8im4qrkjaKd2oAouIZjijFPxRii4rDMUYqTFJii4WI9tGKkxS7aLhYi20u32p4Wl20XCxEVo21Lto20XHYix7Um2pitJtouFiPbSbeal20oWi4WI9tLtqXbRt9qVx2IdtOC1Lso20rjsR7aMVJtpwUelFw5SHbTttShaNtFyrEW2jbU4TNKEpXK5SHbQE5qfYKcEpcxSiQhOOlLsqXZS7KVyuUh20YGamK0m2ncdiMLml2VKFp22lcdiHbzRtqbbRtouOxFto21NtFGylcfKQ7aUJ7VYWL16VIFA7UuYtQKew0ojJq2UB7Uwx+lHMVykG3BpRUmMdabjmncVgpcUoBpwFK4DNuaNtSBfWpNgNK5XLcrhfanbakKYpdlK5PKRbaXZUoSnbaVx8pBtpdtT7KTZSuPlIQKXFWFgZue1SfZwOvWpckLlZUxS7Ce1XFg57VMIV6ECk5ofIzN2kdqUCtE2wYfKMUxbY+YAR35pe0QcjHQWQZA8uee1T/Y4O6frV/y9oHIphUZ5rl9o2zq9korYsQadH5KiMkGq91aTW5+dSPTIq/a6j9nj2+UMjo1Q3l4bkl5JcnGOe1c6lU5tdjdxpuGm5Lpuo6daWUsV1pKXUz/AHZGP3azS+ZCVQKCeAO1RebCOsgNMa6jX7oJraNOzbXUwlNyiovZFiWQmMl2yBVT7VGB8qkmopZXl68D0FR7a2jBLcwb10HSyvKeeg7VHin7acFrS6WxNhgSpFXFOVKeFqWy1EQLxTt5AwKmtrS5vZxb2kLzyt0VBn/9Vdxo3gONNs+tSCRuot4z8o/3m7/QVxYjF0sOr1H8up34XBVsS7Ul8+hx+m6bqWrz+VYQM4H3pDwi/U13+keC9Psds9+RfXA5wwxGp9h3/Gulhght4Vgt4liiXhUQYAqSvlsVmlWt7sPdX4/efXYTKKVC0qnvS/D7gAAAAAAHAA7VbtG5dR9aqVNanFwvvxXkHtnEeM7AWutRzwxBEuI8naMDcDz/AErnDPBb7RcTxw7zhd7Bcn2zXV/FoXsXw/uNQsZTFNZyo5dQMhCdrfTqD+FfM4u5Z7oyXMzyyN1Z2LH9a9P+1vZU40+W7R8Tmn+z13Zb6nvIX5sHjmr6jaBXM+DLkX/hy3ZnLyQsYmJOTx0/QiusKDivWjWVWEZrqOi+eKn3GuhZKy50Iat4IDHWddQ9aqnPU0qwurmM4wKrNV+SOqzpiu+LPOnEpkkcVEwzVl1qIoa6EzmaIMFTS5B61N5ZxSeVVXI5WV3izyKgaP2q6VIppUEVakS4lApTSh9KuGOo2StFIycSqEP6Gip9vPPoaKvmM+UgaxuQwxkcUotLocAk10sdzC2N0Y6VaQ2x5MYx9K5ZYiS3R6EcLF7SOTTTrlyODVyLR5sgls/Wurils+gUflVoeQwyqfpXNPGT7HVDBQ3uczFpL5zsNXksHVcbRj3rdSPI+VMU/wCzyN/CK5ZYmT3OyGFitjnvsBHKIM+lKsUqnBjzXRpZk/eqdbCPqwrN4q25qsL2MOHTlmX5xjNWxpESjgE1qC3jj6VJx2NYSryb0OiNCK3RjHTXQ7kfp2qVCifLIK02Td0FZ9zaSMcqT+FCqc2kmJ0+TWKJlSAjKqM1XldY8mqpS7j4zxVO4a8YECIk+taRp3e5lOrZbFiS7j5w2DWfPfso5bI9qiS1uJWy6Fj3GelWE0VpHBMe3/gVdijThuzicqk9kVI7u3kb94zZq6GRl+SEketX49PEKYZU474zTZBFGOW/IYqHUi37poqcor3jIubZnGScfSqE9qEX55uPc1rzXFsgOVLVj3eoRKD5cKfiK6qXOzkq8i1bKRlEXyhgfTjNMfU5VG0R8+oqnNdTSk7RH+AxVGZ5up4+lelGknueRUxDj8JqrqlzuwWyPQioruWOUCRnZD+dY5aQ/wARpEWR2xu59619ik7o5/rMpLlepu21+Y02xqG+vFSi8ZjkgLWS1qyqCJFOfekMC95z9BWbpwbubKrNKxfnm3/xDHtVXYjnO8VAyIvG4/iaiY/3TitIwtsYyqXepeyijk5FMa5C8KBiqOWPU0mDVKHch1X0LD3APTH5VC07n+Km7TTSKtJGTk2Bcnqab170YoxVEMTFNNPwaNtO4hmKbzUuKTbTuTYjxRipNtBWi4WIttAWpNtGKLisM2+1GPapNuaNtFwsREUYqXZRtouOxHto21Lto2ilcLEWKMVNto2UXHYhx7UuKk2UoSi47EW2jbU+yjYaVw5SDaKNtT7KNlFx8pFtpdtS7OaXZSuPlItvtRt9qmCc0uz2pXHykO2lCVMEpQlFyuUhCU7bUuw0oX2pXGokW2l21JtNOC+3NK5SRFtpwU1Nto2Url8pDso28VPso2UXHYg2UuzFT7KNlHMHKQbaXbUwT2p2z2ouPlK+0U7ZU22k20rjsRbfanonOTT8cU5AdtFzRLUMAdqTA7U/GaAKVy7CLA8n3QTTXgkT7y4q3FdSRIUQ4BphnY9eam8rlNRsUWXJ6Umw+lWv4s7RS9eoq7mXKVgmKcF54FT7M9qsW9lPcMRFGSB1J4AqXNLVlKF3ZFIJTguKuy2oiO0yBmHYVF5LHpUqaZTi0QFcik24q4lrK3RKHgZWwRzS5lsDg7XKgWnYFSmMjtSYp3ItYix7VLFDvbpwKMVdt1GwVEpWQ0rsQRYHSkePA4q0FxSsN64I/Kufm1NuTQoR53YIqwEHc0108sbs00Seoq99UZ2toyyjKo5XNV55Tv8AkOM9RSGQ9hURBJyaIx6sHJ2sizDdlQFlGR6irIlhfkSCs3bRtocExqcloaLPEB98fnVOeRXG1enrUeKXbQopA5NkWygIfSpwKNtXzEcpCEp2ypse1LtqblcpAF9qcFGalC1t6R4X1HVsSBfs9sf+W0g6/Qd6yqVoUo803ZG1KhOrLkpq7MNUJYIqlmY4AAyTXW6R4JuroLPqjm1iPPlj/WN/8TXX6ToGm6OgNvF5k+OZ5OWP09PwrWr5vFZvKXu0NF3PqcHkkY+9iNX26fMq2GnWWmQeRY2ywp3I6t7k9TVvvRRXgSk5O8ndn0kYxguWKsg/GloFLipKG05G2yKfQ0lJQAnibTV1nwtqmlMuRdW0kY/3tpx+uK+LlYrIu7gg4I9D3r7mRgY1c+lfGHjLTv7I8da3pwXasN3JsH+yTuX9CK5q62Z8rn9PSFT1X9fidR4J8TQaNO9ndRk29y64kB/1bdMkdx0r27S54zIkjIrKGG4HuO9fLsLkpwecV9A+Fr/7dpVrcg8SxAkeh6H9a3o1puHs29EYcPVoz5qUt1qvTqdnqtjFZTIYRiKQEgeh9KyZ4lZeldHcqb7w4ko5kh5/Lg/pXOPkrya9vDTco3b1PUxVNQm0lozKngGTVF4ea1pUqk6dQRXrwkePUgjNkhxSLbr1c4FXGSmFa6FM5XBFRo1XgCoWFXGHbrULJWkWZSRVYVEVqyyGmlTWqZi4lYrTCvtVkpik2+1WpEOJU2c/gaKtFB+lFVzGfKaX2AKwGecDpU4sW2cA5rQFsinPJOBUykIeteXKs3se5GjFblC3sWU7mU1eMgiGNual86MDk1A00W7gg1i5OT1N1GMFoSJcyFvuYq2s/HJArOM/oQKjM2M72FS6dy1V5TaW4UdxSm6UD1rnzeovQ006ko70vq7YnikuptyXRP3VpiSuT852iufk1cqPlFUZdXuWOFbGa2jhZMxljIx1O4FzAi8uOPeqVzrNtETiTPsK5YSu4zLJn6nFTxLbOct/OhYWMdZC+uSkrRVjVGtrK2BDn3NTC73feQKKyiYUX92FGPeq7XTA8uF/Gr9jF/CiPbyXxM3TNFjg/lUbXtvAMvKo+pxXNT3k6AmKRSayJ7x5VP2lQx9q3hhObdnNUxyjstTsZ9ZUofJ+fHpWDNqGpTybY7UAHuxxXPG5kU/uiVFSDUbzbjzTXbDCKGyPPqY91PibXodC1rdGEM7IhPvWdLbSFiJJowPXNZTXdwx+adz+NRNJI3VzW0aMl1OeeJg9kaTWligybhs98CoPLtWOFJx/tHrVMM31o3HNbKLXU53UT6F57e2VRgpj1AzUR2r90q2PUVAHOODT1mkHQg/UU7NB7RPoOd3blVQD0WoGD91xUxEsjZCjPsKkEMzHBAX6mi6QneRS2n0pfKY9BWkttCvMsy59BzQ6s3yRMgX1zRz9hez7maIjnng00x89K1RZFRvlYEe1RFIXOEO0+jUKohuk1uZpTApm2tb+zZXUsNv0zUf9nS55XFNVI9yXSl2MzbRt9q0GtDH981H5BPQVSmiXBrcp7aNvtVswEDnimeXinzE8pBtoKVPspNlHMLlINtGyp9lIVp3E0QbO9Gyp9lG2i4rEGw+lKF9qn2UuylzD5SHZRtqfZRsouPlINlLsqfZS7PalzD5SDZSbasbKNlFx8pX2UoSp9lL5dHMHKQ7KXZU4jpdgpcxXKV/LpQntU+yl280rj5Svs9qUJVjbRsFHMPlIAlKEFTbKcE9qXMNRIduO1Ls4qfaaNppXK5SvspfLqcLTtntRzDUSt5dLsNWNlLszS5h8pAENOEftUwSl20uYvlIfL46UeXU2KXbRzBykOyjZU22jbSuOxDso21MFpdmaOYLFfb7Uban2UbBTuFiDbSqMcVLspClHMNaDcelG32qQLnjvVhLO5cfJbyMPULScktzRRvsUttARicAVrLo1+y7jbMo/2uKZ9lmtmBO3I9Dmp9rF7Mp0pLdC2ehX92oYII0P8UhxV2Xw0YFDSXae/aoftl65H7xuOgqOU3MpBldifeuZyqt/EkjpSopfC2y/DptvGAFZG9+tWHsJjFthYKD2BrKSaSIYYke5pw1RkJG9j71k4VG7p3NVUppWasWxo+DmRgfWlMVvD/qrcu3qRVVNWIOcFvqadJqruMbAB7U+Wq3qLno9AnM33iFjHpWa5LOec+9PkleU9SM9qckPy5NbxXKtTnnLnehCEYnnpT/KHpmptgp6hF56mm5EKJTeEDlaRGKH2q6xDNnbiq7phqalfRkONtUOEqnvj60pkAHL1Ds9qNlKyC7Edy59qaFNSBKXbVXsTa5Hilwak20u2lcdiPbRtqXbxQFzSuOwwLxS7eelSBKXbSuOxHijFS7Kkht5Z5ligiaSRuAqjJNJyS1Go30RXxxV3T9MvdTm8qzgMhH3m6Kv1NdVpPgottm1d9o6+RGef+BH+grsoIILWBYLaJIol6IgwK8XFZtCn7tLV/h/wT3sJk1Sp71b3V26/wDAOe0jwhY2JWa9xd3A5wR8in2Hf8a6Wl/Clwa+ZrV6laXNUdz6uhh6dCPJTVkVNQ1Gy0qwe+1C4WC3TALN3JOAB6kntVvoea8H+NWq3TeJrLRpGZLS3t1uFUHAeRiRu/ADA/Gq0Pxr8SxafHbPZWE8qKFNxIjZbHcgHGa86WKjGbjLoeFUz+hRxFSjVTSjs7Xu+v8AwD6BpccZyMDkk9K+e7Xxr8VvEchGhpJKPW0sl2j/AIEwI/WrOp6z8V9F0yePxbZ3c+kXcbW87xJGXjDDGQyfdPPfg9KaxMWrpMqOfUpx54U5uPe2n3nS678WLh9VbSPBelf2rcBignKs4cjrsReSPc8VFa6n8bbqXa2k21qp53zwxoqj3+bNZUXjTwz8JlTw9YaW2qa75atqNwXEYViAfLBwTwCOBwO/NdP4y8cwXnwZXXNJEkLax/oyK5+ePORIOPQKRn3rnjVU2056rojtxeTZnhsCs0zGcoQkrpRaS2ul1evdk3w61fxN4hvdVvdX1eG7sLR/ssP2eJUjlk6swOASAMY+teh1y3w901dK+HejQKgR5IBcSY7s/wA38iB+FdTXdSTUFc2y+E4YaHtG22ru7vvrb5bF+D5rYD04r5n+Omm/YviJHfKuEv7RHz/tKSh/QLX0rZsNjL6GvHf2gNMM3h7R9YVcta3LQMf9l1yP1X9aVVXic2cU+fCSfazPA7dyU+hr1v4Z6nv0+exZvmtpNy/7rf8A1wfzryCA4Yj1Fdj4Dvfsni2GNmwl0hhP16j9R+tY0XZo+Hyyv9Xx8H0lp9//AAT6b0CdZFmtWOVYbgP0NYt5AYLqSA/wMR+Hal0e58i9t5Cflztb6HitPxFb7LmO4UcSLtP1H/1q9nCStPl7n6DjYXhzdjnJABVR+tXZEOM1UdOa92DPn5plcjniomAqwwNRFc1umczRAy1Ey1aYVGVrRMxaKrJ6VEy810+j+G7nVVE7OILXJG88lseg/rXTx+DNEWIq6Syt13NIQf0rmq4+lSfK3d+R1UcurVo80VZeZ5eUNN2Gu51HwO0fmz2N4PLGWEUikkD0yOtUdE8MX1zfRyXlsYbeNgzCVSN49BWix1Fwc1LYyll9dTVNx1Zn6J4dvdUmSQQlLXnMrDj8PWivWFCRqEVVVQMAAYAFFeDWzGtUleOiPo6GV0acbS1Z5dMxU9ccVTe9hTIaQZrVktYW4cZ4HU1Vl062fjYK9qEodTw5xn0MWfUkJ+VifpVdNSbeABmtWTRYzysdV20pkU7IcV2RnStY4ZQrXuxySySDJwPrUhQY5YNWZKL2IkBDgVV+2XIOGBFWqV9mQ6yj8SNOXYD94ZqhMz9F5+lReeX++nNPWRB95TWqhymLqKRCY5SMk4FV3lKH196vN5TcsxFQtbI/3Mn61tFrqYST6FFrh34yfzpxkmKgLNj2zUrWLg0w2zjoK0vHoYWmtys73APMjD6GmCacf8tW/OrZt5B95TUqWKMfmJH4VXPFbkck29DPMkjH5nJpCGPU5rcj063A+aN296Q2tiCRllPpU+2j0RfsJ9WYPlUeXXQro8cyhonY+1H9gy59RR9Yh3D6rU6I5wx+1Hl+1dMdEGOc5qF9EYcqx/KmsRB9RPC1F0MDyz6UmythtKnXtmoTp1yOsdUqsX1MnRkuhm7akWLjJIFTvbyRnDLimbcdqvmI5bbiqsQ+8WP0qVZLdesWfrUaxlj1A+tIUwcZzU7lJtD2cOcpCMUiyFf+Wa0gLKMDpSYNAr9R/nluG6e1R/IGyKXbRtphdvcV5ZOiuQKZluu45+tO20u2loDbY3zD3GTSGUnqP0pxSk8v2p6BqNyp7GkIjP8ADTtlLsouGpCUHpSbKn2Uuw5p8wuUr7KTZVny6Ty/ajmFykHl0eVVgJS+XRzBylYR07ZU+ylCUuYrlINlHl57VZ2UbKXMHKVvLpdntVjYPSl2H0o5ilErbBS+X7VZ2e1GylzD5Sv5fHSl2VY2GnCOjmDlK2yk2Vb8sUnl0uYrkKxSjZ7VZ2YpQlHMHKVtlAjqz5dHl0uYfIV9ntTgh9KsCPFPC+1LmKUSv5ZNJ5eKtY9qTYD70cw+Qr7Pal2e1WNh9KNh70uYfKVtlKE4qfZ7UbTRzAokW2k21NsNOWPJ54pcxXKV9lG2r6xJ3GaX7OD04pc5fIyhsOKcIWIyF4q8LRieMVft9NJGZWz6DNRKqolRouT0MQRMTgKT9BTvIbuprqbfRY5T+8kKD0Wn/wDCPlpMRudtYPFwTtc6VgqjV0jl4rCeY4RCferw0R0TdM+32Aya6uDSJYQBGB9atrpUjkGUg1yzx2uj0OyGX6arU4VNKeSQLGrYPrW5Z+FYXUGckn0rq4dLjQZIGati2RR1rkq5hJ6RdjtpZbCOslc5+Hw5psBDeWMitKNbW3TCxjI9quMsCj5mH41WaW0Y4VlY+3NcbqzqfE2ztVKFP4UkZV6JLvKqpVfYVnrpMEXzPDvPqTmunUK/3QMU7bGvULWsa7iuVGUqCk+aRy7WkrjEFoqj1xiqkuh303JKKPrzXVTSc/IBn1qhK143CofzrohXn00Oaph4dbs5xtCMY/ebpDVV9FJPDKo9OtdDJBfv/CPzqlNYXrH5mCj2NdkK8usjgnh49IsxX0wRDJI+lVGhwcVunTZOjzcfWonsEQcKT+NdMay6u5yyodlYxhHg1MAastbvnCpT1tpQPmiNaOaMlBoqBcmpBDnk1aFu3ZKikDR8HGfSp5r7F8ttWR+UM1BKF38c1ISx61HtyapaGUnfREZFJj2qbZkUm30qrk2IwtLsqQD0pwB9KLhYh20bam20m3FK47DNtKFp+KUKaVx2G7aTbg1KBgZr0PQNEtLSxt7qW3DXjqHLPztz0A9OMVyYrFxw0OaWtztwmDlip8sdLbnNaV4Tvb4LNdE2kB5+YfOw9h2/Gu3sNLsdLi8uzhCE/ec8s31NXKK+VxONq4jSTsux9hhcBRw2sVd93/WgUtJS1wnoB0rGvvE2k6f4l07w/dTql5fqzICcBQBxn3Y5AHfFbIOOa+cPidZ6s/xE1K4uLO5MUpT7NIsTMrRhQBtIHrn8awr1HTjdI8fNsdUwVFVKcbu6Xy6/5fM9w8UeHPCmt2Ky+KI4UjtwdlxLL5LRjuA2Rx7V5BqWv/DbwxIy+FfDia7eJ0ub5maFD6gN978h9a53T/APjfxOUdbW7Fuoz9o1CRkjQevzc/kKtvceFfAjmOyWPxZr6cfaJF/0K2b/AGF6yMPU8Vxzqc/vctvNnzGKxs8RasqUaa/mkrv5aa/c/VF5bn4qeL7L7XcXn9jaKBgSSSixtVHt0LfrVHT9I1Gw1+0l0LxtYavdCZfMt7O9cO67huADgB+M8D8q6DTfBHjHx7OmreMb+aztW+ZFmXMhH+xFwEH1x9K7eP4QeCIbZVjhvRcqQy3X2kh1YcggAbevtQqU5+9b72Ojl+JxLVXlfrKTTfole3zuZvin4L6N4k8Z3HiBNZmtI7txJcQLEGJbABKMTxnHcHFUfi3pdno/gDQdM0u28mxtLgxIgOcZjPJPck5OfevXVTAGTk45J7+9ee/GMoPh8CwG4XkWz64bP6V0ToU4RlKK1Z9zxDmOLxuVyw9eo3GEdF2t+fbU6fwffR6h4G0S5h+61pGp9io2kfmDW7Xn3wemeX4dKj5xFdzIvsOD/MmvQK6KbvBM5sBVdXC06j6pfkWrRv3pHqK5b4q6cNT+F+tQhN0kEQuU+qMGP6A10tu224TnrxVm9tEvrG4tJB+7niaJvowI/rVNXVjor0/aU5U+6aPhpTh1NaFpcPaXsF3GcPDIsg/A5qjcQSWlzLayjbJA7RMPQqcH+VWEOVBz1FcEdD8gr3jJSW6PpPTLlLi1jmjOUkUOp9iM13M+NQ8PrOOXVQ34jg/1rx34e6h9r8NwRM2XtmMJ+g5H6GvXPD8oe3ltX6D5gPY8GvThKzUkfrOHqrFYeNT+ZHPyJmqskZ71sXEHk3Dwn+A4rOnA3HFe/TnfY8WpC25QZOOlQslWXzniptO0241K5MUQCqv33PRRXTzqK5pPQ5eRykoxWpmFa6HwzosF6JLy8TzI0bYiHoT3Jrdg8L6XHGBMrzvjlmbH6CrlrYQaXZtDbltjOX+Y5rzq+OjODjTbuelQy+UZqdVJos/urSBUjjVEUYVVGAKpSXmW75qKWR26nNJDEzN8ynB74rgjBJXkem5t6RNG3nDrgnLVY69KgzDbRgnvRHdwSkhW5Fc7V9UjoTto2CvGJSpfn3orH1C6RXYiXDjsPpRXVHDOaucssSoOxyCx6jLEZVsp3jA5YIcDiqn2pieletE15z43ijt9XgkijEZljy5HG4g9frXqYTFKvU5HGx4+Mwjw9L2ilexRW6buaf8Aa17/ADVhiVvellE8b7JEaNsZwwwa9T2KPHWIZt/aIW6qKiZLSTnaufpWODKT1p4Vz1al7FLqV7dy3RpGxtWHAX8KYdNhPBjBA9KqIpB+/wDrU67x0kP50NSWzGnF7xBtIiP/ACzAFVJdKYH92D+FaSTsn8WamF2GG0gH60lUqRG6dORl2+mHP7x6s/Y7WLksrN9KneRc4k4B9KQTWUfOCx9qHObEoQWhTYRlvkhLH2FSLaXMmCtpx7iri6rBFjyIFJ9WGKsx6pLL1jCj2qZTqLZFxhTbs5EcVpiPEkAH0qCTSLV23FOfataOfzO2asLCH+9gVy+2lF3Oz2MZq25gyQNbxgRKoI9agGpGP5ZowTXTPawMMHmqc2mWbnLLnFVGvB/EiZ0Jr4GZSXtrKuQMH3oaWP8AhAq8beyh+7GMiq8xhwSIxWilFvRMxlGSWrRSeVTxgVUlJP3f5VaZ0B/1YxTDPj7qAV0x02OSbvuzLe1Vm3OrMagmtwB+7gx71sGVifu/pRliPufnW6qNHM6UXsc01tIWxjn0qRdOlOCK3CCDnYM+wpD5h6LWvt30MVho9TENjKvUcioTAwOCprfMUx7DNNNpI33sCmq3cl4fsYBi56Unl1vGwHU81A9nt6LVKsmQ8PJGT5Z9KPLrQMGOoIqMxVfOZunYp+XRsq15dJsp8wcpW2UmyrXl0eXRzC5Ct5dLsqz5Zo2Yo5g5Ct5eaXy/arWyl2HtS5x8hU8v2o8urWxj0FPET4+6KXOPkKXl0eWfSrhibPIo8puuKOYOQq+UfSl8o1bER9DR5LGjnHyFUR807yx61bFrIecU0wMDyDS50VyNdCv5Y70eWOwqcRtnG0n8KlFtORkRGk5JAot9CmEPpTtgq2tpKf4CKlFm/dDSdRFKm+xn7B6UeX6VeNuM4Gc+gpwtG25OFHuaXtEV7Nmf5Z9KBHzV1oUX+MH2pmwk8Cmp3JcLFYpSbKt+S5GQh/KlW2cn7po50HIyoEpwj46Vc+zP3U00x7evWlzlcjRWMeKQJ7VYKmhUyeaOYOUiCcUFfQfjVxI4zjORUptUfG2QfjUOdtzRQvsZojJPFTpYSuudpx9K17awxhsg1fWNl4yBWM8RbRHRDDX1kc4lhubByMe1TLaQhtoRpD9a3ZIGdDtqmqMmV2gGoVZyNPYKJnmOJDgxfkaUpEeiEfjWtBYFm3lOvrVowW8R+ZQT9Kh10nYqOHk1cxoreLqWP8qvxRwj+LP41ZM1sg5iBPuKga9t8keUv5Vm5Sl0NVGMOpciIwArAD61djfaMl/1rBe8hP8ADt+lV3vIwDtZjWboORssRGJ1n2pUGSwx9aZ/asecLz71xpmLtl2YjsM08vJIuPO8tf1o+px6h9el0R0lzr8cIIDgt6DmsS48RX0pIj+QdqoeTb7sKGc/3jVhIwuMKBW8aFKHS5zTxNappew6Ke7uj/pEzlT74rXtYrWMcOSfc1kmQqMAZqF5bk/dyBTlBz0WgRqqGr1Z0E98YBlGBH0zVFry5ujgXBA9hisXdKT87E/jUgLNx0+lCoRiKWKlL0NhBcRjJugT7mle7kQZa5H4Cs6IJ1dM/U1ZWa2UfNGo/DNS4a9yo1NN7CnUWB5nOPYU06iX/wCWmfqKgney5ZVLE9scVAkXmc4Cg1oqcbXsZurO9kyaS4nk+6vHrT0tbiQZaRQPrTEWCE587n060PeHGEGKdntFE3W82T+UsPG5S351C/mLlgyn61CsshfIODVhU3fPLJRbl3Dm5timVnlJABx/simmyn6iM1qC6hj77h6ClOoqRgRYFHtJ9EJ04fakZYsJT2zTv7MnxnZirzX4H3FP8qry3s0g25wKpSqMThSXUoyW7xnDD9aiKe1WDk+9MKmtk+5ztLoQheaeFp+2lA5p3FyjNtAT2qYLRtpXHykOylCEVMFpwSlzD5SbSrI3uq29tjKs2W/3Rya9P/DA9K5PwlZ/NPfMOn7tP5n+ldZXy+Z1ueryLZH1+UUeSjzveX5B3oo+lFeSeyFFFHSgDkPGHjyx8JX+l2c673uZQ8+BuMUAOC2O5J4H0NZep/GnwnaRMumxXmozdgqeSmfdm5/IVifE3wJ4g13xHHrGj263sbwpE8XmBWjK55GeoOa5/RPgvrt5Msmt3cWmW/UojCWU/THyj8TXDOdfncYo+PxOLzb61OjQp+7fR26eu2vmZes+LvGfj/UF0mzZxHMcJYWeQpHq7dSPUk4r0/wL8MrHw15Wpax5eoasBleMxW5/2Qerf7R/Cur8PeGdG8MWBtNHtFhDf6yVvmklPqzd/p0rZrWnQt71R3Z3YLKOWf1jGS56nnsvT+vQGO45PekI5opRycDmuk+iAZ7V4V8XfE8WqarDoFlIHt9PYvO6nIaYjGB/ujj6k12vxA8YnR9MNtp+q6fYGfdE19c3Kr5Z7rGoyzPgjtxkVzHw48EaJqccHiZ9Zt9bt0kPlpAreWJFPO/cASQexArmrKc/cij5rNvrGM/2LDx0fxSeit2Xfzt6HefD3R5tD8B6faXKFLiXdcSKeqlzkA/hiuqo/HNFdEY8qSR71CjGhSjSjtFJfcOU7XVvQ5rVYnbkVkVqxnfCh9RTNz5E+J2mjSvibrduq7Ulm+0IPaQBv5k1y8DZjx6HFesfH7TfJ8VaXqqLhbu1MTH1ZG/wYflXkVucOV9RXBLSbR+VZrR9niKkPO/36/qej/DO/wDK1q6sCeJ0Eij/AGl6/of0r3PSbkQX8LE/K3yN9DXzF4evTp3iXT7zdhUmAb/dPB/nX0TC+RgNyOhrspu8T6vhqv7TCum94v8AB6/5nXapaBpROpAJGD9RXMzL8xGK6xyb/RFkj5kZQ2PcdRWFc6dexoHa3JB/u84+tevhaitZs9TF03e6RlxWs13cLBAm526V1+l6UNLikxKZXkwTxgZHpWFpTT2+poyxO/VWVRziutkfYvXFLF1JXUFsGCpQs6j3RDLKd4A4AokcOAo5qFTuk5PWrSRqh3Nye3tXC7I9BNsYlvEnzsm5v5U1LxZJhCqc1TvNTWMvEg9s1l/2k8IKqwHWt4UZTV2YyrRg7Il1nUAtwY/vKvGM4rOs9RWFmb+LHrVC6kaWQsT1qlht3Ga9WnQiocrPKqYiTnzIv3d0biYsnGQaKrIMDkc4PNFbqKSsjmcm3dno0Upd8dsVzXi/Rje2yXttDJJcx4QqgzuX1xXUqiKOODiq08AMolSSYMOiq3yn6ivAo1XTqKceh7+IoqrSdOXU43w/4etTaGfU7VvNZvkDEggfTsa6SXStFukRbm1WUr0Zic/nRIt0rZaFiD6c0keQ/JI+tdVWtOpLn5vuZyUaFOlH2fLf1RTHgzSvtazK8phHJhLZB/HrVi+8KaRdQbYofssgGFeL+o71swthPmNSh1YZHNczxNa6fM9DqWFocrXItTxu8iexvprSXh4mKn396h849q9mMFu0jSmCMyMACxUZOPeuO8XaVawxR39tD5UjPtcIvyt7n0Ne1h8wjVkoSjqzwMTlkqUHUjK6XTyOJzK38WKZmUHG41ZMbd+KAig5bJ+letzI8Vplb983ALGpo7G6YZ2EVOkyxdAcU77c44G4VLlL7KLUYfaYyPS5S37xgo+taVvZpGuC2ay2u5m71GJJc53H86iUZy3ZpGpThsjok2w9GH51J9rAH3h9M1zRkkI5YmgO4/iNY/V77s3WLtsjojeeh5pPtpPWsETMDknNPFyTxS9gkP602az3SMOVFVJJEY/dxVYSbu9Lhj0xVqCiQ6rkKRF6Un7qkKOe1IsTe1X8zO/kSgJjil2LSCNv7y1MiHuwqG7FrUiESZzTwq9lqcMg4J/SpVKn0/KocmaKKKvkr1xTWhHbFXiAaaUGe1Tzl8iKBhP92mGNgOENX2Dj7gzUBE/90itFMylCxQaDJ5X86ha3jByQK0jDI33jgVG9svZ81qqnmYSp+RlPBGM4FQmJfStRrY9iKja3IGTWyqGDpeRm+UPSk8ur5ipphPWr5yPZlLyzR5Zq55eKPL9qOcXIVQlKI6s+X7UoSjmBQK4jIqRUJ9qm2jHSlAI7VLkWoiJADyTmp1gQdcUisegqTypX+7is3JmqS6IZsTOAQKVrQMM+aopPssueRip4tPkc/M2B9alyS6lKLf2SBFWFsFgfxzVpJIGHIH5VN/ZUYTJdifamR2KnhWJ/Ss3OMtbmqpzjpYZvtxwQMfSgvB6iri6O7L0NOXQZSeWwKz9pT6s19lV6RM9p41Hy1UknLZwa3/7AA+8+aYdHt1+9IM041qSJlh6z3Rzu5yeBilO9hhs1vG0tIurAiml7RPuRgn3rX2yeyMXQa3ZhiEk/6sn8KnRJBwluR+FaYndjtjiH4U55ZlX5go/Gh1ZPoCpRXUzmiutuDGwHpUHlT54Bq811P2eozdTnvmmnITUe7K/lXBHIJFRNC+fuHP0q4JZSe/4Cms8jDljVKTIcUUTH6ilEdWCntSbcdqvmM+UjVM/w5qVY2B9PrSgsOhoEjL0pNspWRajcqO5+gxVtLlFUFwSfSssyue9J5knrisXC+5vGrbY1ZNSXbtCY+lMivIQ2RGWb3rMLMaZg0KlEbryudB9vdlwERfxqlLdPnmRBWbzjvRtHcUKlFDliJSJ3l3cmQH8KhZkHTmm7KNvtWqSRg5NkZ57UbM9ql204IarmIsQbPSnCPJFS7MHmnhaTkNRHRxqoqVF3HGOKjAqZHIHArJtm6sBgXPNNZUA5PFPZieSKjbDdTUq/Ubt0RXkVG+4tR7GHNXERO9NcqTgDpWil0M3HqVcH3NNKmrJU9hTdtVzEcpW2GnYbGMnFT7BRsp8wuUrbKUJU/l+1OAAH3aOYOUg2AfWhueKm2k0hjpXHykGKQA1PspdmTT5hcpBtpdtWBCT0FOMOB1pcxXIyqV44pu32q55YxSGMGnzC5Cpsz2oCVb8v2pNmKOYfKQCOnbBUoWnheelLmHykAj54FSCJuynmpxlelaGkW7XWqRqwyifO34dP1rKpV5IuT6GlOl7SSgt2dTp1qLLTobf+JVy3uTyat0nWl/Gvj5ScpOT6n3UIKEVGOyCiiioLCiigdaYCUDrxXEXXi/xG/j618IWHhmG1luEkuFvNQuhseCNwruqRgnJzwGI9686h+K2ratr3iTT5biR9K1O1v7fRWtbV42tpoQ4QeYB87SKpYEE4IHSkYOtFaHu91eWdjE8t9eQ2qIjSM00gTaqjLMc9gOp7Vn6L4k0bxEJ5NEunvIINuZ1hdYnzn7jMAH6fw5rxCDwN488SWGg3t/cx3guPCd1YBpI/JNo8ka7ElLMWd2PJbHGDxXpHw28La94R0lrfWXsXdooYwtvPPO2UGMs8pxj0VAAPemKNSUpbaHGt8bbzUJdXt7KzstJeGxvZbSK8WZrppYUYruUoIxnaWK7icYrjrvX9d8ZfDPVS+uXuq6zNHZXAtILxJWVfNG/bBbqBGp3AYZi5HUDFe32Pw98OQam+p6gb7W70rLGsuq3TXIiSTIdUU/KoIODxnHFdPY2Fjplutvpllb2UK9I7eJY1H4KBQT7KcviZ4rp/hTxIsfhe/wDD/hFIJdF1Ka6MeowQ6bHMskIXcI0LsACB97LGvSPAfhWfwnod5Be3MNxfajfTajcmBSsSSSHOxAedoAAyetdXRQaRpKLuH40tIKWkbBWlaHNsPbIrNq9ZH5HX3zQB5b8edO8/wNZ6gFy1leLn/dcFT+u2vm+M4lFfYHxH05tV+HGvWarucWrTJ/vJ84/9Br49B4DD61xV1aVz4DiGly4lS/mX5af5F3HHXFfQHhjUP7S0Cxuy2WeIBv8AeHB/UV8/BsgH1r1T4Y6gZNNurBzzBJvUf7Lf/XBrai9bHJw1X9ni3Sf2l+K1/K57j4duA1tNbnqh3D6H/wCvW5nK8cVx+jTiHUYmJwsnyH8f/r1124IPmrotqfpJCYnSRpY0Xe33iByabMHMe5hj2q0GDd6Cqt1GRVc2upHJpoUbUDJZuB71cLowIVhkVQumaFiAuFPSs6S98skqxrdU3PVGDqKGjI9WTbIZNw5rnpZCzcmtO5uDPnJrLkXBr1qCsrM8mvLmd0Nz0yanSEuhK496pPndkULLKo4JrpcW9jlUktydwEPzN2NFVSJGJ4PQ0VSj3ZDbPVMA9aZJJHCm52wKry3saR5BBOKwrrUHkbGeK+cp0ZTPpqlaMTaj1ASS44A9KklltmcCQZIrlhPj5t1Xba7hYgOCT7muiWHtqjnjiL6M1LwxJAJomIxwQKSyuw3y1JKtvcW3yIAQOoFU7O2PnffBFZJJwaZo21NNGjPO6kbRx7UsYW5heOVQ6MMFSOCKkdI2jxwDTIFK9DwaxuraG9nfU5a48FttZre9DNkkK64GPTNc02m3oeVfskzGIkPtUkLXqrEKpNUor+EyMgXa2eR616FHH1kndXPLrZbQk1yvlPLDGT2ppirvr/Q7G/vi8dz5Er8suAR9RXLXtg9ldvby4LL0K9CPWvWpYqNXRbni18HOlq9u5k+V7U7yjVzy+elKI/UV0c5yezKXlUeVW3Z6Rd3xzBCdmcF24ArZPg98jF6mO/yGueeLpwdpM6aeBq1FeMdDivK9qPLrvh4OtPLGbubfjqAMflWRqXhu4sI2nSQT269TjDL9RUwx1Kb5UzSpl1anHma0OZCGpFQ9zVrywcYFIYsHHQiunnOPksNXywPmNSBrYdajKYpCoqdy07dCwLi2TopNKbqFuPKAqr5dGylyxHzyJS8Dc4INL5kWOCRUGyjbT5ULmZN5sY/if86YZh/CW/E0zbSbKdkJykP+0SrypI/GmG5n/vE04RUeX+VP3Re93IjLKf4jTfMfqTU3lijy6d0TZkGXJ60m1j1NWPL9qBGKOYOVlfZRsNWdntS+X7UcwchT8ul8qrnlH0pfKPpRzhyFLyqPKPpV8QknpUq25/u1LqWKVK5nCHPapBbE9jWmtv8A7IqdIOeUFZusbRw9zJSyZj0wKtR6e+Rj9DW3FbjHKirKW47cVzSxLOyGDRipZSg8nI96m/s9D0Q59uK3EtxUywqB0ArmliWdccKrGEumvjAz+dSRaRsk8w5zW6FRe9DOqisniJvY1WFgtWVI4ioxinlD2FOe4QVWe9APAqEpM0bjHqOaJyMYqlNpzydwv0qVtT29v1qNtUQ+ua3jGotkc85Unuyp/ZAGckmo20hO7H6CrDX5b7uPxpnnyNzvrdSq9WczVF7IpNpeDxJtFNOnRg/NLmrpdT1warSojc+Zj6Vspye7MJQgtkRPBZIvcn61VYW4+6pNPeMf3sio/Lx3raPqc0n5DD/sDbTCv94ZqYqBSba0uZWIdvtTSvtU+zNIUp8wuUrlKTZVjZ7UuynzC5Stso2VZ8ul8qjmDlKvl0vl1a8ul8v2pc4chU8uk2Vb8v2pRF7Uc4+QrCM0vle1XFipTF7Uucr2ZS8v2pfLq15VKIj6UucOQqbDRsq55XtTfKPpRzj5CsFpRxU5j9qTy6OYXKRbm6Um0HqKm8ulEdHMFmRqiVahsopusgWoth9KkVT2OKmTb2ZcUk9USPpLj/Vyo/6VTlt2jba4watguvR6lWJH+Z+TUKcluzRwjL4VYyvLo2Vr/YzIcRrinppUjH5vlFP20VuxfV5PZGN5dHl1uNpaoPvE/hVdrQDhRmhVk9geHlHczBFml8k+taP2cgfdxTDDjrT9oL2Zn+V7Uoj9queVg9KUAjonP0p85PIVBG3YUohc9qt7G70eU57GlzjUCsIR/EcUpSMcgZPvUxiYckU0qQOaOa4ctuhXZM803y/arWz171cttKvbqMyW9uzoO/8Ah60Oooq7YRpOTtFXMoIfSl8s10+m+HpLli94HhjHQYwWrSm8KWD4MM0sR9zuFc0sbSjLlbOuGX1px5kjh/Lx1rpPD9v5drJcEcynAPsP/r1rDw3psUTb/MkIHUtinRxxwxLFGu1FGAK4cVjI1IckD0cHgZ0qnPPoOpaTFGa8k9sWiiimAUhoxR9KAMybQdNuPEtv4hmjke+t7SSyjO8hPKcgsCvc8DmrdlY2Onafbadp9pFa2lquyCGJcLEPRR2qx9KxvFHibT/CHhe+8R6skpsrJQ0ghUM5ywUYBI7kd6CbJalyfUNMt76Gyn1SzivLhtkVu86iSRvQLnJNcr49+JXh74dWME+tedczXDlI7Wz2vJkDOWBI2j3NfH6+KJrj43N428OWL3d3NqrXlnZSgs8hYnah28k89BXpXjX4daSfBbfE34g6je+H/EWq3TzXWlxorGRuQsMKtypICsWYkKM8VVu5j7RtPlO1uf2n/BK6LHJaaZqk2sTxsVslhDeS/IUM2QG7H5c8V5t4O+M3xn8WeLZbLQ5bTVtQltn22UkSR28ABGZcZHI4HJPXvVj4Zaf8VPEXhuVvh1omh6DpkBeI6lcwI1xOx5ZfOdSznnGQAB0rF8M+K/iF8MvGTaDH4e03Ur9sxnT4reKSRu+EkgG4dM4yenSqsiHN6Nn2XYG8Ol2h1HYL3yU+0CP7vmbRvx7bs1YxWboN5dal4d03Ur2yawubq2jmltWzmBmGShyAeDxzWlWZ1IXFFHNH1pDCrVmcTEeoqrU1s2LhPc4pgXpoo54ZIZRlJFKMPUEYr4e1GzfTtVvNPkGHtZ3hIP8AssR/SvuRhkYr5J+Lem/2Z8U9WVVxHdFLpeOu9Rn/AMeBrlrrRM+V4jpXpQqdnb7/APhjkIGzEPbiut8C6h9h8VRRlsJdIYj9eq/qP1rjLdvmZfXmrsE721zFcRnDxOHH1BzWdN2sz4ShVeGxMay6NP8AzPpm1dmjBB5HINd5C/2vT4ph1dQfx715vplws9rDPG2UlQOPoRmu38PXG+2lt26xncPof/r16D0dz9iTUloakcXljduyahkv0icq4xWfI88d5KryttU/L9KoTszyFi1dUKPM7yZyTrcq0Rq3F1DcLjPNZctuzfd5FEbADGQa0bVo8fPya2t7NaGV/abmI1rIO1MFi0jY2k10F2YfK4IBqhFfCJSpHI71rGrKSukZSpQi7NlJ9IA55q5Z6baIpMoDMfXtRLqKuny8NVM3ZzndVfvJKzZP7qLukaP9m2ZztXJwaKrR38fl/exwaKz5avcfNSMk30jNyx6CpopEY5lbj2rNx8w+gqUROeleg4ROGM5dTXf7EY8RhicdSarwg+ZzwKob5EOCasxTk9az5Gl3NVUTexvJcSGIRrwPar1l8hyTk1iwTtj7taEM+O2K4KkNLI76c9bm2ZECgt37U4bcZUcVlfalYepFSreFO1cbpM7FVReYeYCpOAfSs7+yo1d2E7/N2HHFPfUlA5GM+tJFdh345zTipxWhMnCT1Ej0e0Rt6NIHI4JfOK468jkjvpklfzHViC3rXfSxvLblUk8ssMbgM4rAn0NI5Rvu12dyR81dWGr2bc2cOMw7kkoROciiaaZYo0LOxwAK6XT7K20wtNJMkkzLjbtyB9Kr+RaWcZkRWkk6CTOAPwqo0zO+c4rqqSdVWWiOWjTVF80tWdOnmOBKqk+w6VaV2KjehWsSxecYCyZJ7VuIwKhXIJry6seV2PYpS5lccrhiQO1OIHQ8ikARBxhRTWkjUZLCsPQ39SNLW1jmaaO3jWRurBeTUN7plpfRMs0KhuzgYINSNOcfKMimx3DMSrrxWq50+ZMyag1ytaHAXFsbe5kgcgshwSO9Q7BXWXnhsyS+bayg7iSyyHp9DWVcaReW7bWgyPVTkV7lPEwklrqfOVcJUg37uhj7PajZVtrd1OGUr9aTy66Oc5eRlXZ7UeXVry6Ty/ajnDkK/l+1J5ftVny/al8ujnDkK4Sjy81a2DuKPLzS5x8hV8v2pPL5rShsbm4z5EDSY64FI9pLHKIniZXPRccmp9qr2uX7KVr2M/y+OaTYPSutsPD8AAlvW3kj/VDgD61pDRtKIP8AoSc+5rlnjoRdtzshl9Sau7I4ERn0pwi9q7Sfw5YuB5DNCR77gfzrNk8OXiviN43Xs2cVUcZTl1sTPAVYdL+hgCMelOWIVpy6Xf267pYDt9V+YfpVUg47flWyqKWzMHRcdJKxEqqOozU6GIfw1GVPqKaQR3zSeoL3S6HiHagzRf3gKoc03BPal7NFe1fY0hclRkEEUf2iAeeKzcH1pNpNL2Ueo/bz6Gn/AGpjoaP7Xx1yay9lG00/Yw7C+sVe5pnVvr+VB1SM/eLVl7TSbfan7GAvrFQ0m1GI9EY1Xe9jP/LI/nVYJntTxATTUIIl1KkhrTq3SP8AWmGV88KBUpix2o8qtLoz94iMrHsBTfnPerIi9qUQn0pcyQcrZVw3c0bM96t+T6igw46Yo50HIyrs9qbsNXRHnjFTpaKy8kUnUS3KVJvYyvLo2VrtYDGQ1QNbFe1Cqpg6LRQ8v0pfKq9Hb72x3rTi01VXJ+aplWUdyoYeU9jA8n2o8gntXRm1AGNgA+lKkGD8q/pWf1g2+qHO/Zz6GjyD6V1At3I+WLn6VBJYOG3SoR9RUrErqU8I0tDnxCe4pwgrdFlEvLc0q2sUpwkJb6U/rCEsKzD+zcU6O13OBnj6V0sOnvyPs+3Hr3qBhbwyEcAjrWf1m+iNfqnLrIqx6ZBgHJJ96c1jAWClCake7iQ4ByfagXyYztb8qzvUepty0loL9jggXKxqT9M1WeKEAuYR+Aqc3xbhIXb6CrlvAJRuZcH0zU80o6yHyRnpA52SMM3yDFL9ilC7nUqPcV1iWdpCN/kqXHOTUU9yWQps3L7mqWJb0iiXg0leTOTaDHVcUwxD6Vus0zkr9n8wewzSQ6esxO4FD2GK39tZXZzPD3domCYqPKrcuNOe3XcwUj2NUvKBPbFaRrJq6M5UHF2ZR8o+lKISeorTVbdfv8n2qZZrRekY/Kk6r6IFQXVmdDaBjyCwrVt7FQMqoH1ppuoh9xcVG11M4xEuD7VjKU5HRCNOHmaAt4l+8Rmo5poYgQDk+lZ4W5cjeWx9avRJbbcsAT781i423dzojPm0irFRpRKcEYpyrEBlYyT71f8AMtEGML+VQve2w4VRVKTeiRLglrKSKTLK5wEVR9KUWO77xNWDfwgfKv6VXkv2bhVq059FYyaprd3BrKFRkkD61EViXopNNMzMeRTSz9jWiT6syco9EBI6hAPc1C7MeA3HtSneTyamtwonQyx+YgPKjvV7amXxOxVWF5G2oC59AM1taXpkAH2i8Ul1PEbDA/Gtu3kgggBitxCG5wBVW6kDneSc1xyxEqnupWPSp4SNO0m7svs1rJD+9ijZR0BANQrMS2IxtUdAo4FZ0MU07YXO0VpxItuhYk8dcmuOUVHTc7Yyc9diRTk7mbHuadvEjbUPHrWXNfCV9qthR61Ot4EULEufeh02UqiuWroiOEJnlj+lUc5pzyvKQznJxTa5mdK2ClzSUYpDFopKKADNFFFABUVzbWt5bvbXttFcQP8AeilQOrd+QeDzUtR3E9va20lxd3EVvDGMvLK4RVHqSeBTEz4t1yK3sP2tmWCMRLH4jgKog2qoLJwAOnWuk/aN8N+I4fGsWs6pr9vLpd2HFnHcOVFqq4zEiDLMT94kDuMmuJ+IWvWEH7Q9/wCKLC6jv9Pg1SC6WW2YMJQgQsFPQ8qR9a1vjf41vvGem+FfE1/oc2iRTm8ht4JydzxK0ZV8kDOcnpxxxWnVHJpZoxzrmnTaRaWWu/E3XdQiSFUj0nQ7R0SIY4TLsiD3wp/GqFlq+jeDfGGnazYeDtShFrIl3Cur3TpM4B5YBFQc4OOo+teteBfipDYeE9L0vwJ8IbnU9VhtkjuLxIAqyygfMxZFLHJ55YUzxD8M/i38XvFNtrXizS9P8MwRwi2XdJlo4txY4QFmZuT1IouHLfY+mNPvk1PS7TUolZYryFLhA3UB1DAH35qzVbTrGHTNJstMt2ZobOBLdC/UqihQT78VZrM60LmlpKWkMKVDtdW9DmkooA2Oxr56/aB00rq2h6uB/roZLdj7qQw/RjX0HE26FG9RXl/xz04Xnw5F4q5ewuo5c+itlD/6EKyqq8GeTm9L2mDmu2v3anzFH8soNXMcYqkauqcqD6iuKDPyustme0/D3URd+F7eJ2y9sTCfoOR+hr0vRpxDqURz8r/Ifx/+vXhPw0vfJ1e6sSeJoxIo91PP6H9K9jhkxhhwRyK9KDvFH6hkuI+sYKEnulZ/LT8jsdQVI2Wdlzn5TWBMQzkoMCuilxf6QHTlmQOPrWHHbySfw4HrXoYeS5bs3xKfNZdSqAc9aniZhwGp0tuEbGc1PDp0soBBwT/KumU42uzljGV7JAqRtzK+T6Uya3t2U7SBU7adLuAAY9tx4FV7m0mtyA4yD0I6VnGSb0kayUktYme1qck54qBoCDxV7Y1TwQZbBj3Megro9pZXZy8nM9DLW1dugPeiulFlIq5ZVXAPy0Vn9Z7Gv1Xuc41iuflfHAph0+62lozuA96tIzPIMITwK2bS2dgN6FV9xVzrOC1FCiqmiOUFrdEk+WSR2rQtLC6bkxbR71o6hEtpdBomyDyR6Vaszc3CllUAD+9SnXbhzIcKCU+V7mYwEB2yNgihrxVTgFvTArQnsme4/wBLkUp229asW8NjBh4lG4fxE5NYurG12rmypzva9jMhmuTH5hsZtv8AeC04XV/KpNtasy9MkdK3PtkeCQcn2qs9/Au5mADEdutZKo39g0dOy+MzUs9YkISXZsJ5JIOK0IkgsmKzTbvQAYqr9tkKFwxwOnNZrzPI5LsST61ryyno9F5GalGGqu35m0upEvtU4GatiFLlcnJJ61jR/ZlUEZLd6n+2NEP3TVlKn/JobRq/zjrnTSJtu8CM85NUbq1hi/1TMcdc06fUJpcAnkelNQySISw3EVtFTik5Mxk4SbUUMiuHhHytg1Kl9NnIY1TdSDyDTkOCK1cU9TJTktDoLdbi5QGSTYO3fNWxZRheZGJ9c1jW1wy4Ctz71fN0wHzNk1wThJPQ9CnOLWpcSBEG1wCOxp7RrgMoxis9r48A8inpdE/xYrJwluzVTjsaGTt9KrXS7rdmz0p8T71ByDUrKrIVPQ1mvdZbXMjkLkBmOe1Qx2ss7YiiZj7Diulk063CFlQ46n1oinhgXZGhXJ5FeisR7vuo8t4W8rzZjf2JfdfLXH+8Kpy2ckTlJFKsOxrrEuXLfNTbmJLlcNFlh0aojiZp+8XLBwavDc5MW0hBKoSB6CmeS/8AdrrEMcaeXt247VItnBJhnQH2rT61bdGSwV9mcf5NSJayORsjYg98cV1ktrYHl7dN3sKdDbqsZVG47DHSpeL0ukUsDrqyDT4xbW4j6HqfrVmQhju8sZHAbHIpjW7p8ynOKRJMttbgVxv3nzHoRXKlENjHkVZjBC80i7O1OzzxWbdzSKsOo7UUZqDQWs670i0vJfNO6Nz1Kd60KCQBmqjKUXeLInCM1aSuc3ceHpkANvL5uTyG+UiqVxpN7bqXeEso7rzXYBs0uRXVHF1FvqcUsDSltocB5foKTyzXYXOk2tw5kGYmPUr0NRDQ7QpjzJN397I/lXWsZCxxPAzvZHKeWfSjZXQy6DIMmKdX9AwxVNNOnecwhNrDqT0FaqvCSumYyw04uzRleXRsrom0B9mUuFLdwRgVnTWMsD7ZVwaca8JbMUsNOGskZ3l89KXyTn7pq4IueKdsfvzV85n7MpiFhS7PWrXlk0vk56ilzlKBVC08RjGSKupYyMMqhx61J9kkjGWUEVDqLuaKjLexRCqo+6KduH92rexem3FL9nj/AL1TzrqUqb6FAqG7UnkseQpP4VpGKE9qRQyHCvx6Ue07C9l3Msgg9KUZ9a2PJEvLr+NNNjGDkMv0NHtl1H7CW6M5FkJ+QE0945iMMuPrVl4nj+4w/CoCrmhSvqhcttGLbo0T7jsq6LlSQoHPpVJYZW5VGP0Gas2Z8i5zKoHue1ROz1Naba02RdS3mfl2WMejdanjvbeKXykUY7ms+8uBI+UJqmCwbIPNYqlzr3jd1uR2ibsl+POCocLVgXSMBnBB9a5ss5bcTk1YiE7nIO0D1OKmVCKRccRJs2p4LeQGRowTjoDjNV7O9gec20cJjI9utUpbuQDydw44yDmrVmjW0RYsDvOSahwtH3vkaKpefu/MuudjZ+Y+2eBUS2tlLndAhY9cnNQl5ZSxSTr04p8EXkAvJIWb37VnZpb6ml1J7aE3lWcK+WIUx3+WoTLbH5DEFXpwOlMnnj3ZJwaikNqUJVirfWqjF7u5MpJaKxZ32qxbdo2qOARWXJcuZiYl2D2phMzkogLD2FJ5LKf3oI9u9dEYKO5zTm5bF+HMybZZiT3AqaOwskcn5pPYt0rOEnlkMucdKl892H7tce9Q4y6M0Uo9Vc0mkg8oxqAAOOO1UpUuGG2A8HuetJDGc7nPPfFXA8agkcfjWfwPTU1+Na6Gd/Zs0rfvZtv05NRXWjSRRtJDI0oH8OOa1FnBFPilcNnnFX7WotTP2FNqxyux8ZK4+tMKe9dozxOnzKrD0IrKvrSKXElvFh+4Axn8K3hibuzVjlqYTlV07nP7cds0/c4HynbV42cy8tEwH0qWOySQjcdvsorZ1Y7nOqMr2Rll5T1Ymm7pPU1vLpCk5Z/l+nNMk0rDfu3yPcVKrw2KeGq7mHgnuacEb0rbTTgvUAmrSWiKPu0niIrYqOFk9znltpG6KacLSX+4fyrphCgHQUuwVk8S+xusGurOZFrKW2hDu9Kvroz+VuLjf6VsAKDkgUjOo9qiWIm9i44WC+IpWGmxxHzJ1V26BSMgVbdLSNxKIUR16ECo2k54ao2jD/fNZtuTvJm0VGEbRRXuLrc/BzUSHzHG7pVh7aED5Qc/WoSnlcoRmtouNrIxlzXuzQ3qkO2IhDWXcyTtnfJkfWh3nYYBqAwSufmY1UIKOrJnUurJDoJYonzIoarkV1G77YRtJ9KzzakDk5qzZweWWc9TwKKvKouQUeZyUbF6kozSV5Z6wvFFFHagA7UUfjR2oAKTNFLQAdaxPFvhqx8Y+E77w1qU0sNpehVkeHG8AMG4yCO1bVVNVTU30S/XRpI4tSNu4tXlAKrLtOwkHjGcUxM5Pw38JvAHhMpLpXh+CW6TpdXv+kSg+oLcL+AFdJq8Hh4tBf8AiKLSmNsD5M2oCP8AdZxnaX6dB09K+XfDPx+8X+FPG+pWvxSku72GONoJLKKKNHtp1ORtUYGDyDz0INVvirJ8OX+Is+ralB4i1m71i3t9Qhs4JY7eGNJY12JuIZieOQAOtVYx54paHvGs/Gz4ZaCjQv4lguSnHk6dG02Pb5Rt/WuA1D9qPQVDDQfDF9enor3UyQqfwG4149J4ji8IatZGT4O6TZRviZY9aW4uJZos4yDIQB0PIXrWp+0JZ2Nh8WVNjZw2Vu+m2syRQIEReG6AADtTSRDnK10fWXgzWtU8Q+DNO1nWdKOlX90jPJaEMPK+Ygfe55AB59a36gspfP060nBz5kEb5PuoNWKg6VsL0opKKQxe9HeiigDStG3WwHoSKxPG+mHWPAeu6eBlpbOTYPVgNy/qBWvYt8rr6HNWXAI2sMq3BB7ihq+hnUgpwcHs9D4ODZUH1FXLdsx49DU2t6e2l+ItS011wbW6kix7BiB+mKq25w5X1FeZHR2Px6tBpOL3Rv8Ah++/s3xHY3hOEWUK/wDung/zr6CtnynXNfM/UV7/AOFL/wDtHw7Y3RPzPEA/+8OD+oruovRo+r4Xr/xKD9V+T/Q9K8PXG+xeA9Ym4+h/yaW4/dTtGBwDkCsvQ5/J1JUJ+WUbT9e1dHcQxtIsrLk9K6qcrPU+0qxcloZ5DSEZi69MitK3iaNfmIJ9qAwXABoO9z3xVSk5aEwgou5KzIBkkZrLukuJR84xHn0q0QsTZVTnvmkBDtmRuOwNOHu6oU/e0ZFbWltHHvfLMR3qOR0juA1vGTjrirxkhPBwPeqqY8w7AT9KpSbbbIcUklEPOml6IQOc0VIZVVsE4GDRR6ITXdlO2EsJ3GIDpzitJXUgHPNUd7k7G4OBwakRDnOcU5q+rHB2VkSNbWzy+bIu5vepC6gYXp7Vn3sk0fP8PrmqqXbg1SpSkr3JdSMXaxdu4JJ4SY1JYdCDVWHTJnAMs6p6r1NTLelxt4AoDTBt4+Ye1WnOKsQ1CT5iwumgAKJSV78YqO40eIrujdlYep61Ml8gUbjzTzcRTEEyYrJSqJ3NXGk1YrJpSC0YSYZ+o2msFlZXIK4wa6xJYSuzdkVn3EdssgKxitaVWSbUjKrRjZcpkCKQRh2QhT0NKkZkbaOSa1ZZEaHbgYrNjcRTZNbxm5JnPKCi0Wxo7FN5kO7GcAU2HEB2tgn2q/8AbkWDcCCcVjzTmWYvnrWcHOd1I1nyQs4k1w0TnOBmqj4IwvFSYUr2qSONNpJ5rVe6jJ3kyqCynOamSZh15pwh3nirkVnCuGfn8aJTitwjCXQrozycKpP0oDMK11kgQYSNV+lQ/YlclixAPPFYe0XVHR7N9GR21xtPJq219xhQST0qKO0hDfNlvxxVjy7eCRSvX0PNYycW9jaCkluSQu5HzqefWq80OHJVSc1YcSOR5ZwPrSqjqn7wj6isk7O5o1dWZUhQhxvBB9K0VK4rOkB83KsTViKEgbm705q+rFB20RJOFwGKgkd6r+dwcCrnlqVwRmomhTP3KmLWzLlF7orKwzk8mrMZ44pkkC7dyr+VSKNicLTk00TFNPUcrMxwwxUUsaDkcGlh+d2LHn0qWRd0ZGMntU7Mr4kU/MIOAatRHIrP2ytJsCkmpVS8RsKv5nitJRVtzOMn2NCjIxkmqnk3TjLyhfpUbWkx4a5+X0FZ8q7mvO+xbe4iUZ3g1Va6JPFC2SqMvIWHtS4t04IH0q0orbUhuT30FS4BIBq0rqRmqTeT0UYqWI/3eaUorcIyexO5AGaYr5bFJIcLyKh34OMVKjdFN6lzODjtTHGTkdaUKGUZpjRlWyHP0qUUxwYL1qGfyn++ivj1p/l5OSwNPMKlcEVSaTuS02rEKJbyJtaJMdOmKrTaaq/NECwJ6dxUzRlH56VPFJk4zV8zjrFkcsZaSRleVEhwV5HqKcHVB8qD8q1Xjik+8oJ9RVaW1K8pyv61aqJ7mbpOOxTW4cH5hkU5pI26g0/C+lMOOwFXoZ69WNMUco4GKjNvt96mDNnCip/Im2ZKZz2zRzNdQ5FLZFHyVPtR5QXpUzbg2GQg+4phzV8zM+VDdh9aTyvxp2KOexouKyE8oHqMUnkx59acA1TRW8svIHHqaHK27KUbvREkdz5MYREUAVHNKk2N8SkjocVcSyhVRvUsfc0k1ijr+6wjD8qwU4XOhwny2MeSIE5UfhSIsaD5o9xqw6PG5RuoqMoTXUpaHG42dwWXb0jUe+KaWDN3b9KCtKY2252N7HFGgtSeKGzIG+Ln1zmrMqrIgVZNorMG9W7j61NvbH3iazcXe9zWM1a1hvmtbuVznHpTvtPmfeYrUL4JzTCK15UzPma2Bzh+W3Gnwp5hycn3qLFWbd9nTP405aLQUbN6lxGEKbRyKZjzDkqDSq24j5RTpJAqHBA+lc/U6enkJ5SbcED6GmmJVHyDFVftB3c8ipfPDDjiq5ZIlSiyYFgMHmkKZPeoRIQ24kVMtwppNNFJrqOWHbyTUw9FGaiVnc/JGTUgE4P+rP41D8y15EyqM/MOalCoOQADVVmkUdOaYTI3es+VvqacyRbcgrg81CkQjO5RSxhvQmsDXvHPhfw4jjVNYgWZRn7PEfMlPttXp+OKuFOc3yU1d+RFSrThHnqNJeZ0W/nHSmkEZJyB6mvmTxT8YfEutXMkWjTPo2n5wqxY85x6s/b6D9a4N9V1a5kIlv7yd5DyDKzFj+fNfRUeH60o81SSj+J8tiOJaMJctKDl57f5n1z4i8W+H/CtiLvWdSjhDDMcSfPJL/uqOv16VX07xel7oEetT6NfWdrInmLlRI2M4AKryCeuMV4no/wl8TSWMevXgihuYFSe2tJwZGfBztcfwjHOOa7rw78SrmKLUtP8aJFY3li2HnRgm4E4C7B1IGenb3rCrl9KMLUH7Rp62dvuX66nVQzKrOoniY+yTWl1+b6elkd5oniKHxClxNptuWt4WCh3kAckjunVfx61p+dNtIMDK4xlcj9D3riNP0nUNVsIv+EbuW0XTGkLtPJa7JZ4yc7UwflX/aPzfSt3VfEFj4URm17V7a2tWUCAsS0rsPvDH8X8682pSjz8tLV9tbnsU6j5Oaq7LvpYs3V5rbCSKysY4H25Sa6JZM/7q8/rTLae+km3S3EckZx8phKY47HPr603S/Fmj63bJc2kyyQPzvEi5QdiwzlavzJFcoWALJjJIPJHqMdR9Kl3h7ko2LiozXPGV0Yt/rrxRMNNtTd3PIRWyisR16jNcnceI/E+m6i11q+t2VvagjbapCGBz0BPXOeOCTXU50uxRojNJbsTtWWVGcyE9w3OR/Kuf1eDwrpInv8AWpA+4nIkYuxx2Rfr1Ir0MP7O/Ly3v5XbPPxKnbmUrW87JepRsvjBpk18ltf6bcQxu/lpcxDKFgcHKnkYNd5Hq2myusf2qOOVuiSnY3614WmpeHbjUbkpkWFxGQkSjYVJ4Ibg56A568CrnhLxlZIbbw94mud9tvMdtesvIUHCpJnnafXt3rur5fFrmpRatv8A1+a+48rDZk1LkrSTvs/8/Xo/vPeEhLqGXBU9wcipPIArlpNIld2OlX01lLG22TO5Awx1XsfasbWIH0Kw/tHUfE93aCFvlc3LEyHsCv8AF9B19q8iNFTdlLX0PcnUcE5OOi63O6upbKzVWvLqG2DnC+a4XcfQZ60/AUYAxXiXhf7f42+INrqlxLK1jZM0zvcMC82Pujb0RdxHA/Wvbjz71jjqH1eUabd3a78jTL8QsTGVSMbK9l5hS0lFeaeoL1o6UlLQAUUUlABRRS0wEqlq8epz6FqEOjXCW+pPbyLayuAVSXadhOeMZxV2lAJOFGTQI+PvCfxW1fwv4+v4vib4ah1nUC/l3MsljF9ugkUbVCnADLwOPTkGqvxX1K2v/jr4f8R29tLaxX1tpl3HFMuySNdwwGHYjFdX8evGeu3XxJ0zwV4Ou3t7xVSO4ltMLLJPIwCRlx83yrg4zxurC+N/hTXoPiZ4bs9G0vUNZnstGtE3xQvM0jROwJYgHqRnn1q0czvZrc0f2r9//Ca6BcD+LTplz/uyk/1rB/aJXzfFvh69x/x9eHrd8+v3v8a2fHPhz4v/ABNiPiTxV4Vt9DsdJtZXWJWCyeX959qliztgcA4Fc74sfxT8ZdX0NPCXgbU4bPTLBNOilnBIdR0eSTARR9Ce9CFLW/mfXXheX7R4L0KfOfM0+3bP/bJa2KyvDely6J4T0jRp5hPLYWkVs8ijhyiAEj2yK1cVmdS2CloooGFFFFAFqybEzL6ir55rMtm23CH1OK0z0NAHyd8YNOGn/FPUyq4S7WO5HvuXB/VTXBIdsgb3r239oHTgmo6FqwX/AFsUlsx/3SGH/oRrxLbXnVFyzZ+X5pS9ni6kfO/36/qXRXqfww1DfYXenM3MEgkUf7Ldf1H615WpJQH2rqPAl/8AYfF1ujHCXSmE/U8j9RW9J2kc2T1/q+Ng3s3Z/PT87HvcTsjK6nDKQQa7lWW5tEkXkOoYVwMDhkBrrtAuPN08wk5aFsfgeR/Wux6H6xujRG1AMClLjjBwfSqs7SRysB06iqUksjHk8ito0+bU55VOXQ0JNpbc7AYqrPNEeEwPeqxZm65P1ppQmtYwtuYSqX2QxpWz1zUyXpSPYq496b5Q9KUQ5rV8r3M1zLVCG5LdV7GipUhUH8D/ACopXiFpPcry3W5g2ewqaG7U8E81nFOfwFJtIPFaOnFqxmqsk7mu3kTDMhyaz7i3VMmOQMPSogWpSAwwQaIxceo5TUlsV9xU9anivni7ZpDATyDTfs7CtXyvcxXMtUSTXwkXGzDetQC4YHipBbnPSrMelyyruBQD3NK8Ioq1Sb0K63jg9cUrXbMMZqx/ZTBtruFP507+x3Ayrhvao56RfJVKPnuON3FQO+45J5rUXSZicbfzNDaTKv8AAT9DmqVWmupPsqj6GVvbGNxpNx9avPZ+XjejL9RTfs8fqa054mbhLqVRIakEpqwtop+7mnfYTnAzn6VLnEahIjjnxU/2gleDTPshU4JwfenC1ftg/jUNxZolNCLMd2c1pRPK0Y3MFFURbMvUD86sC2fbwB/31WU+Vm0HJDp5ZEwAR+FTW+XwzdagFsw5OD/wKjzSnyBwlZtXVkaJ2d2aLzHeFBApWZimV5NZQO58+d+NW43Cj/W7qzdOxoqlydIyTuc4qysibcDpWe9yo6c/WmrK7nAbFS4N7lKaWxc8/wCcqDxUjSgL1qvHCgG5zuNBkgDYJqXFX0LUn1JFk46U9mCp1GaqyyRBcq3NVGmbBAOatU+bUh1OUsCfE3JrQjcOue9YiBmbirsXm9ATTqQRNObLrfISVGWPrVecyDB381IsbdS2T9aHhkccEYrJWTNXdoqNO4Xr+NM+0uOtSvazDoMj2qEwTjjyzW65WYvmQ83RPGaaJocZcVEba4b/AJZGo2tLjvE1Uow7mfNLsWftFvjpU0N7CvGMCs77HcdfLak+zzD+Aim4QfUFUmtbGnNfx4wnJqotwS2ScVXFvMf4DUqWkmfm4oUIRQOc5M0Yp8jGTUsmNvGcmoYY4415BJqcBWOcCuaVr6HTG9rMjRXByTU4fnBpCQBio1yGzUvUpaFhsEYI4quQqHI5NK5ZuQaFBIIwM+9CVht3GhnJznipVbIx1oVRjGKCp7cCh2YK414I5F4wp9RVR4JEGSuR6irgDYwDxUgBA5pqbiTKCkZablbI4xV6GYMPnNEsWW3BRUGBnpg1TakiEnBk88fnqpUgEetV/syJ9+QE+mKmCs4xnC1A6ANwTiiN9rhJJ62LMa264wgB96kaKJxygP0qkW2rwOalimzjc2KTi90VGS2aFW0jEhJO5ewqxhVXCjAFN8xSODSgqVNQ23uXFJbDs5HFQzeftymMCgyBDjdmnefGByaEmnsDafUzJBLNJgKSw6ikWCQtt2kH0PFXGljEm9Uyx702acOQR1FdCk9rHM4R3bIoVCSfOnPuOlWvOUNyPxqo8jEZIqNXbPPShx5tWCly6I0HMbDJUN9az5YsuSoxUjSkjHamblJ64oinEU2pEDRHHSmmPFWcKxyOnvUoUbPuZrTnsZclzOKYpNprQESk5ZePQUxhCOApz71XOJ0yspcA80h3GpgQOwoYluwp3FbzKpUmjac9anwe9G0VVybEQUnrU8SgHkim7aJClvA1xM6RQoMtJIwVVHuTwKlu+g1pqXkl2jrVLWfEujeH7D7brV/FZw/w7z8zn0VRyx+leX+K/jRo+lI9l4cCapfHK/aCD5ER9fVz9OPevGrltd8V6p9rupJ7+8mbaHc/jgDoAPbgV62EyaVb36/ux/F/5fM8fG57Ch+7w655fgv8/kep678drhroR+HNIiW3VuZb3JaQeyqfl/MmqJ+K/jKe1F5PPpmm20g/diGHzJXOSOFZj0xyTiuQufB93pOjz3ssbzTxYz8h2r3JAI5HX5ulc9ZapLppnkjgRrh1xHKyhjEehIyPTP489q+hpYDBuH7mCdu+v5/5HzNXMsdGp+/m1fWy0/L/AD+Z2HifxrrNwosZ/FN/dztlZkVlhhjOePufeBFcXcwTxXXlMVdmAYFc/OD3qgdjDLHHua9S8E6Pd+Hoj4l1rU4NIhEYaCK5VTJOvbII3bMdhy1dcuTB0/dS9Nrv5L9Diip5hVtO/rvZed3+pHoXw+GoeDTqMuo2CXt5IogV5DmGNT85OP4jwNvpVrwjbTeH/GmjW2rWVrC8rvLDceXvZs/Ko4+7yM98Z7ZqnqXjjw/HdTSadpDzTkMyXMn7kNIf+Wh5J45wABXHT+MteeJoILtrOFmLKkBIKZGCAxywBHXnmuNQxNdSjPRPvpa+mn/BR6LngsM4Sp6yj21vZ31v+j0PpLxH4g07wXohl1SdN+SYbZTmWdjz8o7DJ+8eK8G0jxJpFz4mu/EniiCWaUS+bDaQRqUJzkbieuOBjqe9cfc3U903n3dxLcSgBd8jliABwOearqJZXCpkk1WFy6NCEk5Xb3exljc2niakWopRjsnrr3Z9Eaf8TPFHiSWOPR9Oi0myZvLF1OPOJY8KMcAc9a8v8Wa/4l1HVprLWoo5NQgLq4W1CsVx94+vA4OOB3r0f4e2CQ+G5bltbtIdLhtgJbjcreVICGYEsONvPGO/GasatY2niTQ73xX8P7SC8vyWgmmePMpUDB8sNwpxzjHIOa8mlOhhq7UYJJaX7Pzb7nu1qVfFYaLnUbk9Wu68kux4amqTaWj20lm0V2u5dxJQpuAyCO/GevrXSeFPHeoeH7mFV1K6msd5P2eIHKH2U8HPpXM6ppeo2U/maqP9JkY+YHlDuGH97nI/Gr+iXOi21wDqdt5pUcdSA54XIHBXpnvXvVYU6lNuSvf5nzFGpWpVVGL5bd9PvPe9K8baX4nuoBpeqRQOY3E9jJmK5L9mjB4zx0yetc74qsrjVbOSeQXc06KZJLeVQk0a4ysbKM4JwSD0IzXmOueC9d0Oyh1a6FrFA53wyx3AJzwRgjoeRgda6Lwv8Tj5nk+Lo/tZeMW7Xmwb3i7LJj7+MnBOf61431JU37XCvmS+/wDr8T6NZh7Rexxq5W/u/r8DmLq7ng1WNdNkltjbKJBABu2bsZyT1yCM8AVL4kktr7WI7q3vUuNyBCEJKxEcYyMfXjjmu88Y6H4N1Gymu/Dd3btqj5lEFpIHWVOBtPOAe/r1GOK82uUk0KIW+r22xZ8MphkVyoyN3TPQdsjnFeph6tOqlPZ7We54mKo1qLlDeL1utv8AgHfeAfHWoLcQ+EtYU6zY3DeVHvYF4vxPDL9enY12fiHwtB4tt/7bubnztLtYX+zJbsQxI4z9eAMfhXkB8VeENOkjk0DQ7wzKAvn3DBHXghmDAk5OfoPStjwp4jvNcvLfQmnvoo5rneFsVVB8w2kMMgYOcnHua4K2HfM8RRXJ3/VnqYXFLkWFxD9p2/RX6ntXgvRbfSNHzFbLGz/uw5++6r0LHuck11FQ29tHZ2sVpCT5UKCNcnJwOOp61LXxFeq6tRzfU+9o0lSpqEVawUUtJWBsLSUuKMUAH40UUlABRRRTAKxfFuj3XiDwXrGh2N99gur62aCK5BYeUx/i+Xn8q2qgvrk2OlXl8IWnNtA83lJ96TapO0e5xigTPJfh18B9G8D6/D4j1LWZ9d1aDLQlovLiicjBfBJLNgnBJ4zXs3mMwIVjjuBXzJ4o/aC+Iel6VFqUPw3/ALDsLh/KiutTWR9z4zgDCgnAJpvgZPiR43vdE8c+JfiTbaXos12ssdkbvyvtASTBjWFdoAJUjknOe9U11ZlGUVpFH0tIqJG8srIkagszOQAo7kk8YrM03xN4f1m8uNO0jXrLUbi1QPLFbTCTy1JwCccDmvn3xJ8f9S8U2useGPCfgWe48+CeCZ5ZTLIkeCrvsQYAA9TivHPh9ceOrAa9d+BtSNk1pprXN9IrIrfZ0IJ27gecntzRy9xOqr2R99d6K8O/Z08Z+IfFmha/D4h1afU5LG4iMMlwQXVXViRnuMrxnpXuPPepasaxlzK4d6dSUUigo7UCigByna6t6HNbHWsWteM7oUb1AoA8x+OGnfbvh2btUy+n3UcufRTlD/6EPyr5jIxX2f4w03+1/BGtadjLT2kgUf7QGV/UCvi/OVBPeuKuveufB8Q0uXERqd1+X9IsRHMePQ1Yt5ntrmK5jOHicOv1BzVOE/OR6irAqYs+OneM7o+j9Mu0urSKeM5SVA6/QjNdNoE/l6n5Z+7KuPxHIry/4d3/ANq8NRQs2XtXMJ+nUfof0rvoJTDNHMp5Rg1ehe6ufsWErrEUIVV9pJnZX0ZISQfQ1S2Yq7fSStpNxNaRLNMIjJEhOA7YyBn3r5/1D4savdvbSWEUum3Sr+8iEokiLdwQR0x716mCwlXEpqn0OHMMZRwjTqddj3QJTtteQ2HxS1eSC3llm0eXzG2uku6FwfQEZBrqbP4gTtJFa6l4Q1e2u5DhREiyRMP73mEgAfWt6uX4inuvxOejmOHq/C/w/wAjtdtG2uci8feE2uTbXGoPZTL95LmFkCnvlsEfrit+HU9HuIllg1WzljYZDJOpB/WuOdKpD4otfI74VKc/hkn8yYLz07Gip4ZIJiRDNHIQDnYwOPyorByszdQuZphdjv2EjjnFIU4wU/StAzHOF44FKGboUFa+0fYy9mu5lGMjjYfyo8k4zjitgSLjDilzGeqij2r7B7BdzMjiTHzGlaEZ+WtAwwEk4/WmCGNTwSfxpe0K9l0Ka2z9W4FW4isS4GTQ8fy/LkH61FtcDqPzpN824Jcj0LX7qT5mwDShVXlX5qkrsp6Uu7f0YqanlL50WjKVPzHBpVuVJx1quI1fhnJPrQLc9S3HtRyx6hzS6FrzUPDEfjWfdxp5oZBgnqKtqluOuSfc0EKpJUqwP50RfK9AkuZWZBbFIx8xxVsiOQZjfDVEGjI2iPP4U1Nsb52ECh66gtFYr3VtcL+8ch19R2qKJHY4AJrQdy42g4BqNUZW2gDHrVqbtZmcoK90QGGTONhqMbweKvPDKwA3DFLHbMvzFhn0o9orah7N30M9nfGKjIJ/hrVMSswJ25+lMe3yeF/I01UQnTZl+UeopVSQHgkVoeQR2oEY7jmq9oR7IpFXPXmlCSj7tXvLFIVPQYpc5XsymTNjBY03Yxq8Is9acYQBuxx60udB7Nmf5LnvThEwqe6uLWxtnubyeO2gQZaSVgqj8TTrWWC/tUu7OVLiCQZWRDkGnzO3NbQSir8t9RsbFP4asLPjquKQwyDoh/KsaXxDpUepf2atz590Mb44B5nlAnALkcLyalRdT4VctzVO3M7G+tyvepFuUPesG61WwsVaXUpPsEAbb585Cxk5xgHPX2qzdXNvZWsl1cSiKCJdzytwoHrmpdLbTctVt9djYEqt3qK5vrSyjWS8uYrdHYIrSsFDMegGepryPW/iheC1kfQbWOOLcUS4uVJZsfxKvQj8/fFcNcaxeavcm41q6m1C825QAnZDxk5xwuOuBXq0cmqzXNUdl+J49fPKUHy01zP8D6bEgYfKQfpSZZh8pGK878Ha7D4z025d7Sexa1URPcxyFVnJHJx9PfPNbmjeHp/D0l1Lp95JcwXD72tpZNyqe5Q9ifevOqYZUnKE3aS6f8E9WlifbRjUpq8X1/4B0xRj1aomIzgknFOSdZEU4KsR91uo9qY+d3IIrmV+p0SAbfQ08BMc5qLJFLgnvTsTcczKDgcj3pN4FARSec1IIYz0zRoh6saHHoKXzF9cU4woO9RnavAUUtHsPVbjw654p4Peq+89gBRuc8Zo5Q5i2G4oYjb6VXVnHFO39jio5S+YergVIMk+1RBk9RSh1H8VDQJkuKgaMlySBigXKmQxg8jtUm7dQk0F1IAQRgUxoi3oKdwOlBc0a9A06kDWzHuKYbZgODVncTRVKTIcYsq+XKOMUu2QDmrJBrI1TxLomjzC3v71FuCu/wAhPmfb/eIHQe5xWkVKbtFXZEnCmrydkXSh70ojY1yP/C0vBhjmdb2VjEuWXysE84wM9T9K1NC8XaXr8cj2zeWqNtyZFcdM5OPu/jW88NXhHmlBpHPDE4epLlhNN+TNsRAfe5pGjTsMVnaj4h0nTZ0tpbtZLqTlLeL5nb+gHuTXAePfHuu6WsWnaPbxW99OQNrEPKgI4OOgP51VDDVa8lGK37ixGKpYeDnPp2PS3hx1JGelR7FH8VeL+CP+Eq0nX4H1DULm5lvIzLdWs82VRWOI5CCc5z6djXrtlqlneyPAr7bmIDzIj1UkZ49R7j0rbE4Z0JWUuZd0YYXErEQ5nHlfZlwBR70hVOwqUKp6UuAK47nZYg2nGQDTlLjpmpwQO1KZfRRS5n2DlXcrjez9TUhiGdz5aguTTec8Hk0ahoiVGt15MeT6YpfMiPCwjPQYFcXqnxD8G6PNNBda2ktxCSGht0Mrbh2yOM/jXlXir4wanq8L2GhQPpNm4KvMWzO49MjhR9OfevRw+WYiu9ItLu9F/wAH5HlYrOMLhovmkm+y1f8AwPmen638TfBuiX8lhcXslzcx5Dpax+YEP90tkDNZ8/xc8Gpp5uoPt9w4O0wrb7SD7sTj9a+bnOOgoXkEsTt9AetfTxyLDpK7bZ8hPiPFSb5UkvTb8T07WfjR4juJmXRrO106HoC6+dIffJ4H5VxF9rPizxXOPt95eaiM4w7YiU/ThRWIH2nO7nNdjpHiTSU8MXUXiCF9QuIHX+z4FkKjdyS0gHBQHHUZOcDjNd31elhop0Kav+P9fM4Y4qri5OOJqu33L+vkytptjpllculzLDNqLRkwMwDWycHJZj1PHBHGfWut0C+tJIVsdK1BLzVGi2xsV2GFccqpIzIVJJycD615pLb6pqsNxqdy7GGM5aWT5ULE8KvbPsPepdM1KXRfKvNO8yPVY3fFwSCqIVxhVI+9yeT7Yp1aDqRet3+F/wDIuhilQkrK0fxt5eZ7LqjyaN4ZuzM88jzH5nvrjyzcHgNjPzFDzwO1eafbPCsSQW120lyB+8uGso8GQ54iVn+6PVsc8cVz91fX1/L5t/dTXUnPzTSFyM/XpUcJMEqzxsUmQhkYfwn1ooYR04u8tX20JxOYxrTVo6LvqaF3qgTWDe6XYQ6S0ZPlxoC5j7cl88++PyrJup7u7u2uru5luJ26ySuWY/iaUglixJZickk5JpwUAZf8q7VGMeh5sqsnfXR/1tsLZWN5qExit1BCjc7uwVI17szHgCti5h8PwWsGmWVwst2WZrnUpEby+nCRDrt9yMk+grFJYqVyQvpTCOck8VEouTvcqFVRVuXViyReXKyFkcD+JTkGtu11PwzZeG7i0fSJr/VrjgXEknlx2vP8AHLEjqTisQnPAoaNMcdfWpnHmSTf6ChV5G2lv8/zNK+8Sa1q2mx6GbkJpwdTFZQoEjVugwB9e55PWo1uvE/hW8udMF3faVMSvnQq5jJI5BP+NZQURyq6YLKQwyMjNdzrHiO38X6SlxrqMmqW4VEvIRkY7q6+ncY6ZOPSsJxUbJRXK9/X9TupT9onJ1Gprb06q/Ty6GXBZ33iu7+2ahrqSSJGfNlu5RujA6dSNw57ZI9Kw5lazmcRlJQjEb1GVOO4NU/MkWTpgqcgj+dac+qT6jefarx1a4ICs6KE3Adzgcn3q1GUdtuxnKcZK8vi773GS+JdSm0+LTbi4eeyiO5IHOVU88j35PNWJNJgutJXUtKvfOWNVW4hlG2SNznoBwV9/wA6zri1gxujIDHsKfpur6hpIu4LWYxRXUfkzpgESJnOOf5ihR09zQpTjL+Jr+a7EJiliGDkZq9b38xKC4P2hY8YikGVI/pSzSQ3LeZAvlhVB2k7j7nPrVeHy2kJUMjD8qUtVqYKUo7M0oLXRrlbpYVMN2QDBFKcqx3cjPqB69a7v4O+H7i98eT6vexuI9JiwqsMASMNqgD2G4/lXnc0QkPmIwDjkFTX0p8LtHk0j4e2L3O77VfZupN5yQDwg/BQPzrx81xLpYVpby0/z/A+gyKh9YxUW1pHV9n2/E7YUUUV8EfpYUUtFMBKWkopAKDSUtFACUUtFACVn64mrS+HdSh0OZYNUktpFtJWOBHKVOxjwehx2NaH0pHmS3ie4mbbFEpkdj2UDJP5CmJnwh8RtQ8SLctpPi/x+PEWpWdyY5rCNpXS2cDBbcyqme3y+tW/g/oHgXxN8QtC0zWn1ZNSecywyRSRLArx/vEXBBY5289Oa53U4j4msvFXjSXPzalGVPvO8jY/75UVPaxzeELDwL4+09D5kd9P5hH8bwTK2PxR8Vr0OJb3O/8AgvbSW/x98T2HQT2upw4/4HWF8EC51HxnYSDIm8L3yY/3Qpq7o8XxJsfi5q3jDwD4QvdSgvLm5a0uJbUmCSGZiQwJKg8Ec5rmfh7p/ijWPHM+geFtQTStXu7e5gleU7VKAZkjJwcZxjikVezR63+yjOrzeK4QesVrJj8XFfTleRfBb4R33w1XVb3VtTt7m81COOIQ2uTHEiknliBkkn0wAK9eqJas6KaajZiUUUtSaBRmjvRQAVpWjZtgPQkVm4q9Yt8rr6EGgCy4DEA8g8GvibxFp7aT4q1bS2GPst3JGPoGOP0xX22eBn0r5V+M+mmx+J93OF2pfQx3C+5xtP6rXPXXu3Pl+IqV6MKnZ/n/AMMedq211NXR7VQIq7Gcop9q5YM/P6y2Z3vw1vjDq91Ys3yzxiRR/tKef0P6V7FEdyAmvnbQb/8As3xDY3mcKkoD/wC6eD+hr6FtX+TGa9Ck7xPvuGsRz4V0nvF/g9f8zttGlE2lxA/eiOw/h0rwrxv4NstH1q8mt7kRQSzGWVXXCxRvk5z6A5r2Pw9Pi4ltm6Ou4fUVwfxr0q3/ALOs9Y8qMMwNlLM2dyqfmXGPcHr617eUVXDEqCdlLQ785ownhnUkr8up893N3bG8lFq7tDuIQyYDEdiRWrpPi7X9Gm83T719pUK0bncrKOxB4rnbuz8pjz8meHHINVd89uAy5ZD61+iOMZx5Zq6PzCLlCXPSdmeuWPxL024mih13Qg8Lblme2Hlgq3HKc579CK15rrw3PEkukz2kFhEo3mNNoBJOFKkbt3JxlhnB9K8TjvVfg8euanF8qRFPPOw8lFJwT71ySwFK6dNtfl9x6Ec0xCvGpFS+Wv3nqV7e+GNK2Xejard/ayCcWrnKv/eO7oPYE0V5YurLExEH3iuM4orSOFp2973vN2/yMZYvESd4rl8ldfqfbJPPTsKA59KkYDP4Cm4r80P1HUTf6qKbkehp2PajbTDUaW496AW7HFOwPSjFAAXfGDg03cx7ClIoxRoF2Advaglj0wKXFG00aBqIGIPPNODj0pNtJto0C7Blycgik2sBjAp2KTB9aLgPjDJz/WnFmYYY8VFg+po289aVirkyqAcgkmnbk7g5qDDHgZNKEk/uk/hSaGpE4dcdTSh1IwTn6VQubq1s0Z7u5ht1UZJlkCYHrya4vVfiv4O0wskF3Jqcw/htEyv/AH2cD8s1tSwtWs7UotnPWxtHDq9aaXqz0P5OoNRzTRW8JnnmjgiXq8jhVH4mvCtW+NWpzq0eiaZDYqeks581/wAuFH615zqmt6vrlz5+r6lPeuOnmvlV+g6D8BXt4fIK89ar5V97/r5nzmK4ow1LSgnN/cv8/wAD6ntfEmgX8jx2eu2Fw6dVS4XI/WsjXPiP4Q0BGFzqi3VwOBb2f71yfw4H4mvm62vhacwwQlypUvKgk6+meB9RVJ2jLBtoGOlejDh6lzXlJ2PJqcV1eRKEFzfOx63qHxm1e5Z003TLfS4yCUkucySEfTgZ/A0zT/i14lD+TOmn3eed8qeVgfUEV5VGY5pUSWYRKTgyMCQo9SBz+VdZ4bn8IaZDf/25pUutzPH+4ZXaNA2eg6EAjB3deOld1XLsLSp2VK/pv97/AMzz6ObYytVTlW5V5uy+5L9DpL74n+KZnka31KysI15UQQbyT6Etnj37+lZFr4g8YX+v2uuXN9cTRwSBh9oKrEwPBAUkLgjPPbrWRNLo8c+/T9MnEYyR9qn3HJ7HaAMDt39TVG5uVChZXIVRtWNDjA9Mdq0p4SlFWhTSv3Sv+H+Y6mNrSanVqN2d9G7X+f8Ake63vjLwC1qmo3epQyFiVMCoZmBHUbOmPQ4waff/ABJ0DRtNeWG/imuGjDw2aAF/mGUUheB788V86T3Al2KsKRqox8vVvcnvViyigVfMGUuFbch7cf1zjmuL+w6NlzSb8tDt/wBZq8m1CMV56/16Hpeh+PdXurrUr/xfcvc2DR+X9iiTYEY/d28jHf1NaeneJNF0TQ2vfCtpDDeX6/PDJkhJVbBMjsQMEZwAM815ZeX8k9zJcTSeZJLguT8xY9yTVK4vpZXMshxzklvX+QrpeWU5u9rJ20W2nS3X1OSOd1KUbX5mr2b31631tp02N/XNWvNfvPtfiGSS42EiMI20Jnso6YHsPqaU+JdRe0it9Ru5dRtoOILaZiY1IGASP4sdga55Lk8SFt/oQelIZg8gLHAz9a71hqdlG2i28vTseU8wqXclJ3e/n69zYjvJluMzDz3AwinlR6cD09Ks28P2mKdPtCwrKAJpyMyMc8xxAdSeMn88CqkWn30unvqMVpPJaI2wyxISob046U99I1z+yor4adcrZybkSZUJUAdRgdPxqJOF7Jpf5nVBztzOLa3+X9dT3/wHd+Hp/DltYaHIbb7MpD2ckoaQc8s3rk85FdJcwpJG6K8qyOOWhfY+P7ynoTXzd4ejh8Oa5YXt1qMltdq6uvkxmWXyyOSEHUY67j07Gvd9H8ZeFdaE0mma9bMIgJJEl/d7B0yQ2P0r4nMcHKlVdSm3KL1vZ9+5+g5Zj41qSp1UoyWlrra3Y1NL1OxvkniW+iujA3lyErskQ9MOp/n0NJdte6UHmsomvLcDItgcnOexJ46/Tisq5uvCx1QTprWmi6iQlyLhVYRnk/MDyO+DmqieMtFHi9NHi8QwySTIgig8ksjs3IKzLxyOx71wqjJvmhFtWu00/wBPz0PSeIgklOSTvZNNfr+Wp0FrrFlqhezbz9PvQvMMq7HHup5DD3Gadd3S6XEJbp2NqoAaZuqdsnA5+tXRaWU4WfakndXByPqD/UVAUu4nRIZEmtQSHjnzvx/st3HsR+Ncycb6bdv+CdPLK2u/climimjEsEqTIejI2Qafv9Tise50GK6t/wDiT3E2h3KZ2PAoUZyT8yHhlySfxpFvNc0+aUarp63NjHChF1a/NI0nRsxjtnnPar5FL4X8tn/kyHNxdpL57r/NG1nPek4qksJvES9t7xhBIMqhj2kfnzVa9uNUt/LFrp/2sMSGYShQo7ds80lC7sn+gSm4q7Wn3mmevFFZI1G+lsmNrYf6WUJVJnwgP+0Rz+lZNzrHiaysoITYpeXLShJ7mGIhIVPO5U6vjoTwK0jQlJ2TX3mM68Y6tP7v6/rc6z8aaVP94mud03WLxVMeoI0yKf8Aj5GBnngEDv8AStW91aw03T2v7+cWtqnWSX5R9B6n2FKVGcZcu/oUqsZR5novMuYpQSONtcPpHjq78WXt/beFNOiaG0ADXl85UEnpiMfMR16kdO1ac2iavqETRar4nvUikUK6WqJCp9duBuH5mtZ4eVOXLVfK+3X7l+plTxCqx5qK5l36fe/0uaVzr+i2morp81/F9tI3eQh3SAepA6fjS3Q12/t1bTJ4dPA+bMi+Y7+3ooPryajtdJ0zS7cQ6Tborquwu4LMR7k8t+dVb83tzayNBfNZBVBeaYhIoxnk+5xn9OaSULrk/H/L/hzS07Pn/D/P/hjQi1WS3smm1KSNHgH78KQSnfsSK4vV/jFYaNcxrc+H7xrWXIjnWRfmI6jHbjBxnoRXn/irxJpuneL7Gx026u5dIsyyXUqy8XjNyxU9Djj5vXPoK5iXUtIl+0Ravf3OoQXiLIVhHFo4Bxt3dSOF9MfhXvYfKYSSnUi2nr1X9d9fTc+bxedSi3ToySadruz/AD6dNPXY+h/D3xC8P+J4v+JbcJ9o/wCfaRtso/DHP4ZrjvGHxdudF1g6RoNhbajdRErO7FiiN/dGPvEd+1ea+ENdt/BFwLn7NDJe6gU8mS9iZFtockFyRycj+76da39W8UQ+Ibk2WtCPSRIpNtf6e+2KcZ6ZbGA3TJPynGcZNCy2lSrt8jlDzf8ATdiXmtWthklNRqX6L+kmzbsvipr+p2Q0s/ZbbXJX2AhwFVSONoPG/ttJ/PpTpfBkMqhtXmu5Lx4y1w8RJaV8Z5ByWb/63ArjjpOh+A/K1fUbeefVywktNPnlU7V/56y7M8HsM89a6/wf46uL3xddeGPFFlGLqViY7q2XZ5eBnDZ6rg8N19c1tUp+yi6mEVo7vu/TyX9XM6NX2slSxzvLZdlfa/m/6sJpXhrSdPhe71jSIrSzSPAWaf8AfbO7yv8AdU+ijntWJJ4l0uPUprDwbYIsk6GJLgQF5HkJ+VUXP3fc9+TXd+MfAV74knhA8R2lppkMYKL5eWZxyWbBAxjp6VLoHgSDwvDNqegWkOq6m0IW3ubiYBCxHJGB8q/TJNc8cZRcOepLmk+mtl63OqWCxCqezpRUYL7WnM/RL/gHParoo8D6FY+KtZ1ae48QFCBFw/mznkBj/cQdQOprktE8RJpwvPFWqN5199oCSSz7XaSRhnai9gF5J+gGK9PTwDfeIfCE0HjGea21Rp2nE4uVlVGIAyoAACccL+tQWfwg8MwJa2+oTXWoC1yfL/1SyueSzY5PYdegqqeNw6hKNaXNK+tl07LyIqYHFyqRlQjaNtLvW+131v8A11OJ8PvrE2s3njm4/wBHsrjK+fcgyO0ZOAQi9QMDngcV1mueN/C1np9vNc2lw1+48yO2aExyRyKepfPyjPQjOQa7O+s9Nj8NTWzW1vZWIUQuiyKkSjoVLH8qwvEPhzRNe0GG61rylW1jKpeIfKKgdPvdeABg8GuZ4mlXqKVSLSTtp26f19x2LC18PRlCjJOTV9e/V/5fiLpnxEhl8m5eEvZXC7oldDHMFHDEE/LIAc8A5wOM1tWurHVPE0wsb95IbJTFdWyhdoLcq2PvZHQ+ua+f9b8UxXluk2mMLFrUtapbhdvmQ9VYqMr1LZGccjArA0LxPqvh/WU1WwmK3EaMgyTg5GPmH8QHXB44Fd/9i88XOGjton/XbqjypcQKnOMJ+8rq7X9d+j9D69jAkXAY7vpxWRr/AIi0jwxZ/atavUgB+5Gp3SSH/ZXqf5V80ax4/wDFuu3CTXut3CeX91LZvJVfXhcfrXP3FxcXk7XN3cy3EzH5pJXLMfxNRRyCV0609Oy/z/4BGI4op8rVCm79G/8AL/gn0j/wtvwOIWl/tC5JH/LP7K24/Tt+tea+Mvi7fa3by6bodu+l2UgKSTM2Z5F9MjhB9OfevNTsCZz8xPStv/hHTpelw6z4ihkhgmfbBZZ2T3GByxyPkQcckZPb1r06eWYTDyUtW+if+Wh5E83x2Mg4K0V1a0083r+G5zyAhcqvy9M1Ys4Y7iZhPdxWkSDLO4LHrjAUck06a5e9njGxIo0G1IYl2qo/qfUnk96rTMEmCAHPuK9m7atszwbJSutUSXDQiYJbqXVeDI3RznqB2HtTYLW5vrlLWzgluJ5DhIokLMx9gKmZbNLZCUlefJ3AthcY4x3zmlOp3a3HnWe2wO3YBaZj4xg85yc9+aTcrWX4lLkbvJ/JHReJvDFt4U0nTbOW4gutZvQ0tz5codbdAQFT2Oc5PtXKRR2iXsaXryC3DYla3AZsd9ueCf0qMI5OcdepqRY8ckbjUU4OMLTld9zStXhKfNCNlpp6f59TT1rXLjVvs9pFvt9JsV8uztCxIjX+8fVz1J9+OKy1TPWpREOp5NKMjgCqhGMFyxOerXlVlzSeo3aFGaYck4A4qUoScmlwqjFVcyuQ/dPAyaTaScscn3pzN6cU0kZ60XKQ1mA46mmbSTk047c5JxTlKY45pF3sCpxhV605IiZQpIBJx9KQuccn8Kj807uDUsFc3Lm3s2tYWKAvHlSYxjd6cVljAYjAKE4YdM1LbXKhjFJnY3f+771HN8x+UFx6isorl0ZtOak1JKxWaMB8dRnp6VHtAYYGfrVyOF5HwARkdM097aVYy2M9fwpuSQ0pNXRnygEAgnIP509YEdd0zheOo5pxjUrlWBbuPSoTIsQwwJPpTv2HrsSLLAh8u2id2J/1jH+lLLsUFnwrHt6VX8yeXiMhFP8ACgwamSwlYKScxnqfSspNRerNLczNLwtZya/4q07Qodzi6nVW44VByx9sKDX2EqJGixxLtjQBVUdgBgCvDfgf4biXU9S8RswkEC/ZYeD8rNyx59gB+Ne518TneIVSuqcdo/m/6R+i8PYX2WGdV7y/Jf0xRRQKK8E+mFpKWigBKKKKAD60UUUAFFFFABWJ4u0e68Q+CNa0GyultLnULR7eOds4jLDGTjnGM9K26QlUUuzBVUZJJwAPUmmJnhV98Avs3wZfwToeqQSapc6jFf3V9cqY0fYCuFVckAA4A+tdF4N+Dei6X8PrHwt4ygtPERs76W+jO11jRnAGMZBPA78e1ej2WtaJqN1LaafrFjeXEKh5Ire4SRkUnAJCk4Ga+e/Hnxl8ZaJ8aJ/CWn3lnb6XBf28OBaq0jxvsLAsc/3j0xVK7Mmox1Po2ytLaws7ey0+1jt7W2QJDDEuEjUdAAOgrltB+G/gjwvrcms6N4ehttTcuWumd3kG85fBYnGc9hXj/wC09q+saPd+GotK1a/sLe4W5WVLadoxIVZMbtpGcAmur8H+MF8L/ss6Z4tuEa+ms7NsRzSkGaQzsigscnknrRZ2K5lez6HsXeivMfhB8Rdb+I9jrWpanpVnp1rZzxwQLbszFmKlm3FuuBt6Ada9PqWrFppq6Eo70tFAwoopKQCirVicTMPUVVqa1O25Q+vFAGn1Brwj9oPTcJoOrqOhktXP1AZf5NXvFebfGjTTf/C++nVcvYyx3I9gG2t+jGs6ivFnl5rS9rg6kfK/3anyzmrEJymPQ1VzU1u3zkeorz47n5dUV4lnGRXvnhXUf7Q8O2N0TlmjCv8A7w4P8q8DBr0z4aagWtrzTnb/AFTiVB7Nwf1A/Ou2i9bHtcOYj2eLdN7TX4rX/M9c0+48i+glzgKwz9Dwa0vHuiLr3gTVtPAzKYjLF7OnzDH5Y/GsCJty13VjKLrToJmwflw31HBrspzdOanHdO5+i1acatOVOWzVvvPit9R0+EFXcXJI5RBkj8egrMvZ/tbqbezW2XqQrZZvrXR+N9Ch8M+OtX0qGAxwRzl4V28bG+Zf0OPwrAVDNnakhI7BCc1+oU6ilBVFs1c/Iq16c5U0tU7fcZrRFTmT8jSeW5GFGB9K2l0u9kPy25Hu/wAo/WrcOhTEEyzAYHSPn9aJVYrdkRVSWyOZ8th/CVPsMZorrjoxWMv5ZRAPvE5P8qKzVePcrlqdj1XTf2gLD+0pLbXdORI0AXdZuWZW753cEfQ1o6l8aba4Bi8L2MUzMCEmuZQT9RGPT3Nc23wv8D+aXgsbmFiOsd039c1nN8GvCnnCe3vNUt3ByCs6tj81r8cjxtkXtFNwkl2advwkz7p4TM3TdNVV66X/AC/4JpWvxT8awy/vLi3ulHVZrdR+q4r0Lw98UNH1WeKz1SE6VdScBnbMLH03dV/H864BPAUUNq0Meu3jMfuySxxuyfoM/jVCH4ezRFhN4nkvATnE9uuR7fKRXs1OMeF8TaPM4N9VCSt9ysebh8JneGfNzc67Np3+b1X3n0cFJGQMj1FBQhS5GFHJY9BXzOml+J9MvGfTPH81kCQfKWB0U46ZG7n8az9e07xnrV69xJ41juGkBDrMZApz2CrwB7VyxzbKJPTFK3+GV/xX6ntfXK9v4Ov+JW+//gH1FDcW1yGNtcwzhTtYxSB9p9DjpU20ntXyn4Y0Lxf4VM8lhrtoJJxh2S4ZAcHIyCOfxrtbXxD4rSKM3/kXkgb5vK1AJx/X6cV0xxuWTV44qHo2k/xdvxJjj6qfLOjK/lqv8/wPdyuAScADqTRsYZ+U8V8r6xbeOdXuXSUXU1srb41+1o4zn0DYrqPDGr+JNOJtvE/hbU9YtcfLILtiyD0CbtprsbwDhzQxcJPspR/WSM4ZnUc+WdCUV3af6Jnuc2qaXb3MdrPqdpHcSnCRtMoZj9M1PNPFboXlbAHYDJP4CvnvxXKuuXVvdaf4L1LTZYF2bmfgjOeVUf1pdN8T+NdDsxHCs5t1JIW4gaXaMdATzgeldsMJhqkFKnXjfqnKP6NnNLOnTqyhUpPl6NJ/k0j3e01WG7lkjNtcW2xtqtMoAk9xgn9cVobWzwCfpXzTc/GvxJF+7Fo0Tn5fN/s5hz688Cuc1j4z+KNv2OXVb+UEYbygIxz6lQCar6gpe97SKXq3+SL/ALZivdVOcn6Jfmz6xu72z0+IzX93BaRjq00gQfqa43WPit4P0pSsF2+qT9o7Rcj8XOB/OvmYeJ7HUIfOupZVmKk7ZG3MxHbn/GsxfECTwSPbW5RxjG9ga9SjlWFWtSbl6K3+Z5OIzzGtWpU1H1d/8vyZ6x4m+JviHxErW1uf7KsT/wAsbdjvf/efqfoMCuVh1XVbYMsGqXkIb72ydlz+Rrm9K11G1P7FqYEeVyXAA2d8n1Fb1vd+H7u58kassAA5kkjITPpnr+le1Qq4OnD2cI8vlb/hz5jEU8fXn7ScnJ97/wDDWIp2luZDJPK80h6s7FifxNRrCxPArXgh0CTUI7P/AISSFTI+wSC3coD6k9gPXFdBZaD4XlvntpfE73bImXXT7Vm2k/dO49s+1dDx1FaJ7eT/AMjCOWYqb2WveS/zONFrIfvEIPUmpltIuhct7gVua/4U1C3tPM8M3kesyIjGVCnlyAg/wIfvcdgc8GuHh1zVvD2m3Uev6Rdfabgf6I1zE0W3qGbJ644wMYzU/Xabtyu/9eZqsrrq6mkvnf8ALQ3DaswPlx4HqxqL7Kgb95Jn/drkrfWdYjle7kuHwydXAI9RgdKpQ61qptpVS4bYz72cnlT9ewpvF2eqEsvla6Z6NbNFGdtvaCRz6rvaluruWMlJkMbD+FhtI/CneC/E8Ok6NcahqUk63aAraMm1UlJU/fbhsBsHg8+lS+EvHupadqd/d6vA2sR3aAt5pVsMOj7mVjkDpz+dc7xm7UL289zqjgNIqdS197K6RkveTMuFbaBWfNfKmcHzH9v8a6C+n+Hl7MxS81fTpD87IxinBJ5I4249uv0FcxfT+H7K/ijhuLu6tmyWfy1jYDtgZOT69K3WMg9FozneAmn70k16/wBMh82a5fc77QOgHFXRqi2se24cMvYk/NVafXtNvbwWVlaW+mWYZgs7IzyYOPvnJJ6dgMZNWrr4e68Ua7gkhubXk+eN6KeM5yygdKz+uR76myy9z06LsNn1i3jhEoKHcMqA2SecdO340umh9dvBAI7i6XqUt0yyj1A6fiax5PDWoom5RDKMZwkyk4+maetrr+nW8sKW1zDHcKA4TP7xeoHHUd6JV3JWuioYOnB3SZdgs9RjaeS2UMYHCtA0i725xwmct746Vp2U8llrMaeJNOurey8zbMkKbJUHtvGOPQ1zEKagGUraTKV6ERtkYrXfUtfv9Ki0ueS9ltoZC6o4chWPX8PrUuTWkZGnsqe8o6r5/eeweG5/DsF1d33grxzLbOflks9QjER2Z4YtkAqD1OMgGuj1Xx1qUPge+1PTNQgOoRypE72WyaDB6yEgZB7fMOvrXgOnXFxpmp22oJZRGS3O4b1yHI/vKeCOxFdpB8TdUMdwLnS9PdpiAri2QBE7pgDDDpjPT3rzauF56im7T23tf0emp7GHx9OnSdNXp3vte2vVa6fIqtFrvjm8tp7u+sVuYgIRczsIWm5J+Y/xkdOOeQKxrvSrzT7j7PqEb2pYFl81Cu8ZxkA84OK1rnxvHMrQPo8W6TLuYWCZPQNsUBQQO+M1l3fiHTbm/WW80LyEb7yQsyHGOozmvRp1+SXLol2X/D/oePiMPCpFSTbl3d1f8P1KbSrHCVX0+8e1Ns8RmWYyOMxsFK46n/Jqtc65pctuIINMbgnfMZcMwzxweBj9afBrunKZYxph8jOY08zB98n1raWJjtZnNTwklq5Jf16G1o/iPXNDnim0zWLqARHiMSkx4PJBU8YP0qbWPF19rniGHU76SZvKZT5KzuEwDlgOeAeeB0zXNtq1m5MkVmkK4wSzlsH/ABrPuJpSgePzGweu3A/SsXUoc3Py+96G6jiVD2an7vqeyav8SoLmZ7q01nVNODW21IQxlfzOcjOQoXphuvtVb/heeu6XFbxWt22sbdpka9gWMHjlcryf97ivD/tk4uBOkxWQ8c/56V12k6LqV5Bb6ze6TDfwSybokjlSIyFTghgP4TjHQGvPqUcPFWlFW87f8P8AievTxWLk7qdn5X/K9vwOw1L9oHxxLKslrb6bYoQQFWEybueuWP4VrJ+0drj6M8f9g2CageBOrMUAx12euffFedeIPEGpXUP2HUCsFjEzG3soUUxW47qpA/rXKi+haLymt1XH8SjDA/1rCOFw0435F8jR5hi4yajUfz/p2Pq7wP8AGfQNb8NtL4luotO1S1wsyhTicdnQDJ+o7Gn3fxr8JQNILKwvbtgPlbYsav8AiTkflXzLod9ZabrVreFo7q1DAT29yOJV7jA5+mOhruLTSvCWq273T61PpbyS7UgePzFRe7FuPl7etRTy7BuTnJSt26fhqdEs1zBwUabjddXv970O6vfjhdSYi0fwzaRSs3ys7GTOfYAZNTw+Ddf8UFPFHxM1xtMso2/dWbsIcD+SA/Qsa5Nr86AhsvBdjZNdzgL/AGwkvmuF7hd/+rJ9a5zUrHWbi4M+va55sjDfunnMxP0xmuuGGpx/gWp+e8vl2/rQ5J4ms9cTerbp8ME/N2V/y82es2Pj3wN4W1TytMuYF09ywuVs7R3aRuzGRiCQD2A713a+I7SSSD7FZyzC4CujcLuVuhyxz9cCvn7w7qfhzw/cfbDYTapdBcAyFPLUnuFwR+JNdBqPxemuNkVrpttaBgVZ8l5W4wcMMbfwrz8TgVKp+7Tfdt7/AKnr4PMfZ0m60orsop6fPYv/ABI8fi31EWuiXKQ6rbhoJ5oCSsQzkorE4LZ4J2/jXmWq+MvEfiJBb6zrdzcRA8Rs2EP1UYFLLo+n37PeWspjV+TErlyG79ck1WHh+1f5ft728nUCVOP0r2sNSw9GKSWq6tanz2MqYrEzlJy919E9CqlvPeFIPO2xx8BpHwkYPX6fh1rfsL3w54cRbi2tf7b1ZcESXa4toTznEecuRxgtx7Vi/wBmSRym3kvoWjQnhWJJ+i1aXT40XdBaTSuw+VpQoA+ozXXUlTkrX07HBShUpu6Wvd629EV5rjVdf1SSeXzr++nbJwCzN9AOgHp0FdX4Et4jqAn8S3aQ6BZSB3gmxIJZj0VE55HUnsBzXHzNqsbFJLyO0RhgrAQCR6YXmrDXLCxiieEJGn3Sy/Mx+nvWdXmqQ9mtE+3T0NaDhSqe1k22u/X1/XuejTat4envXvtejN6bt/MhuZUAurXkqm3B2SKuAdpxgVT8S6HN4gu1lsdRs7/VxCJTM0hSS/TGFCKfl3LjBXOc1xUszy2yiNchFxtYZxz2H1qORrkCKSNmiZRjfvxjnv71zxw/I1KMrNf1/X+ep3VMYppxlC6evn/w/Zvb00PUtG1LUtIt4tVEs0UMkMaNEGMoidRscHGfl4DYI+Xn0qTVfGk2naU8mj3smi6jGdqwwIHgugWzkJ0Rueo4PtXnB1DWLe4XUGvZPnOWcAAk+o45+tJHqV5cs9wrpKyk4L4J55PX+lYfU4ylzys/621OiWZNQ9lFNP8ArVWa/Afq3iLxrrjNHfalqFz5gZTGchSDjIwMDHA49q7XwX4t1ex0+Sz8Y391e2O5RHAGf7RHjj74x8mOqk9q4aTUtQkO2XIVeuMjJqp9lubhmlSd1Q8gdT/OuqpQp1YezcUl5fp2OCjiatCp7SEnJ+f69z0C71OPTtU+0eFr2+u9Pk3JPp+phfJIJzleeMHkcAg85rnr6y1G/UQHVpJrUSGRLe4lZvLLHk55BPv3rngl1b3KRTKoQn5WZ+v0GasvBOiZgdlkB6k549qIU/Z7PXuKrifbpqcXbtdr7v8ALY2F8JQpMRPqCSRA4zECCw/4EOKjn8LWas4jurgYPy5VT+ZrEe5u1bdLK6sPlB3YyfTFWE81nVRPMz4ztYfzrVOq/tnPzYaKt7L8Td0fwroq6qg13Upzp5HL2oCup99wPH05qtrGm+HUknk0vUZEDNmO1kjz5a56F93JA9uay/NVnKXFnhOvmbv1pqCwkLbBG7A87TnFSudT5nJ/hYb9jOnyRgl5u9/0O08PP4H0hluFW+vr1ustzFEBF/1zXJAbOPmPpxUnjDV7HXbmMQj/AEdPnYTIu+STGCzOpy3HGM4rmmk0iBoo4xI42Al8bSG7jFDS6bJ2O087RkgVy+zXtPa6t+Z3+2tR+rrlUfL+tTNe1SxBnNwAxyFCpnr1zmqNzcQuQ7tl14HckfWtzdpUSF2XKjqGXIHvzVhbrSQvyxxnd8uFQDNdvt5LdXPMeEpt6TSX3nLmeH7PvS3aRuhyenpmqZuLhs4AjBPRRXWrc2aSYtkbywpUxKwVfrx396S18cxaAlxHpVjtMymOTaBtYHvk9T6GlLESitI6+o4YWi3aVRJehyqyzFtu4N74qzG0pIHlbs+lS/8ACTQlWWDRdPhZmzuaLzG/U4/SqLx6jdXf2lVuGlPAKIRj2GBxVLErrp6s5pYaF9Hf0RcWWDcFeVEPP3jjpU/+ieWzvqFsgUZxuJJ+mBWc2g3THM7CB25xKQCfw60n9hFSN07Ov+wo5/Ws3iYvaQ44NX1TIptVGWW3iZ8HG5uPxxUIvnuSEmvBacYO2MnPvxyKuppELyeViaVh1ClaP7K01VYyKVK8sGnA2j3pOunszohhYw1si/BLBDYKt7aiUyD5LgAjI9eDipf7Ns7q7W1glmhuCAcOu9Wz3GOce/NZuzT2gEULK6K3QT8fXvW1pGoW2nhAA3lnCkryQM56/wBOhrJ1ZxV0zWNGnzJTsl/XoXLrwUsVmt5a3Fzfxr/rRDEFZAOS2Cc7ffH1p9rpelyQRT2ljnbwwlkLlx1JHbPbpWzH4w0i3RX8m4EyjJZen6ngVzt14m8NXbGV91mxLIVtlzvHY89D71jGrWfx3/r0PSlTwi1otPy/4LOa1+K1OqGLTo5PML8xxtuQey980XHh/wAT2lubibS7pY1XeWUBgB74JxWroXiPw3a3LBElt2kYoZHbeQO3QdPetyPxtob3UltDfOpVgqnBVWPsf61rPESg0o6rzMKdCnUTdTR+R59Dqs0TjeiuO/8ACa3rS6s71lihJikY/KJf6EVoza/p11qslgbbzpVUyNIUXAx/tVbivLaG381GeMN8wWCMNvHqAAc0SxKav+pl9Ugnb9CudKuQjFNjyDgqDt4PuajeG8gCvPphkAyN27J+uB1qlL40s0uDDJ5skQJXLxAE+vFa1nrlmxaQSIkSLkkkHA7e+faodV2uylh6a+FmYdNFwxlt7pYj1ZTGTj8hTP8AhGppMuLxCmMk+W2fyrYsPFVhqC3CgSRSW/LNIN3y568f5FPvvEMMVo1zADKqjOV6fie1YPHJSUb2b2NFhKduYy7fwuNoYrczHPOFCD9ea0E8NCNQ32gxIeqBsn+VNtfEgvYFC7Un6KvJXPue1dN4Kd9f8XWWnxxytb+YZZJsZUKnLDPp0H41nUxySd5r9Tajg6dSSUY3uey+CdBTw54PstOUsZCDPKz9S78nP0GB+FdHig8nNFfE1JupJzluz9HpU40oKnDZaBS0lFQaBRRRQAd6KKKACij2o7UAFFHSigAqK5tob2ynsrhcw3MbQyA91YFT+hqWimB8WfCC8l+H3x9GhX58mGWeXRrnPAyWxGx/4EqfnTfjAkdr+0ZqcjjBF5Zv/wCOR/4V3Pxw+EnivVPHf/CWeDNLkvlvY0e5jgdVkinTjeASM7gFPHcGvHvHl14n1H4jvfeM7D+zdcYWv2iDbt+6qhXIycFgASPetN9Tjl7q5T3D9q5k8jwrMoyBNdJ+YQ1wPiPxIYv2VvBXh2M4lvr64kdQefKhlfH4bnH5V6N+1TFHH4X8LzMpyL2UZPvED/SuH+GvgDwF4k8H6d4i8a+OPscUU0sK6XJcxQqqK5OMsdwDEknAHU0LYqV+dpHtXwC0N9F+DWmSzIUm1SSS/YEc7WO1P/HVB/GvUx0rk9J8f/D++1Wz8N6D4k066u3Xy7e0tGLAKi5wCBgAKPXtXWVmzojZKyFopKWkUFJRRQAU+M4kVvQimUooA2u9ZXiHT11fw1qelMA32u2kiH1KnH64rSjbdEreopxHIPpQTKKlFxfU+DtrJlHGHXhh6EdadG22RT71v+N9NGkeP9d08LtSO7dkH+yx3D9Grna8zZn5JVp8kpU300NCuj8FX32LxZa7mwlwDA349P1ArmVO5QfWpopHhlSaM4eNg6n3ByK3i7O5x4es6FaNVfZaZ9J2zZArr/D0paCa3PRTuH49a4LSLxLyxt7tD8s0auPxGa7bw5MBPLATy67h+Fd7P2aElJJrZnFfFXSYhfWOrKsQaVDAzOByw5XntwT+VeZQiK9MsdpODNCdkiDIG703dDXuXxM0ybUvh7qP2YA3FqBdR5XP3fvf+O5r5Uk8R3lpN9mdmRb0MGmU4yemMkAj1yPWvPxOKzGEl9XnpHVK3337ry0PKxGFo87lKO52t3pUtnayXd08awoNzOfur9cVxx8ZaKjgw29xKS7ARsNhXA6jHBH1rn7Dxb9iivxd6xK00qERW5/e7WzgEZ46etVJtekjg+2SROqgeUss4LSSKc5XIxjp2qXjM1xM71W/d25LxT/O/wB5wrD4eHwr77M6628bW9zeYs7LzQ+STHmTjHQjoPworzG48XarcLLE7IsZ4RduQv8An1ordYfMXrzNf9vNjboJ2svuR9gi1jYgG+TOP4SR/MU8WcXOLsNjtu/+tXPmWYyqChycLxzg8dTVdIrkTkmXYob5juIwM8EHOOvrX4L9Xk95Hte0X8p03kxdPtI/76FK1vAOWnwfqKwYrqVg0XKujHJb7pHt70NNeecEMUbIMZIPQ/nz9Kn6tP8AmKU49jSc2BJ3Xe4D2BqvJHpGMs6n/gAzWSZbtLkD7MGi5DMpPy/h+tLcfbiGEFrCzBhnex+73Ix3xWqw0l9ozc0+hde30aQEbxg+gIqA6VochI81h7bv/rVAzSwSqZLcESng5x/nrUxhk3DGzeR8wHr35rRU5LaTMrxf2UQvpGiqRtvWXvxJimGxtFb9zqco+kwqvcJIJVWSzMkij7wOF/Om/ZnkX93CiEDneP0/Wt1Sl1kyf+3UW2sXwWTWZyPTd/gajaz1Lgx38zD/AHz/AI1CunO0hH2c5GCfnIH50R2ro4ASeFckcyZB/Wr5JJfF+BLit7fiWBp+r8ZvZuf+mh/xqRLDVlPEzN/vHNVXF1HEZA1wwHICsST7YoP9pjHlyThu4EnI+tC5+6DTzL32XUn/ANZHCw/24gf6UjabI3+s07T5M9c2y/8AxNZmdeLMP9IAB4Ikz/WnJJrmwM09yu7jG4DFaKdWO07BaPVMstoEMxJk8O6W5Ixn7MvP/jtV38HaVJ8z+GNNP+7Fj+Qqwup6zEMGa5+Xg7SGBqVNb1MIXFy74PdRWkcVi4/DVa9JP/MOWm94/gikngzRAwP/AAjFvu9ULKf50+LwVokcxlh0GW2dhgvFeSKSPT71Wv8AhJdTYsiB1de/ljBoXxFrb4+X5QcDcoGfcVssyzOC93ESX/b8v8yfY0OsV9yGx+C9N3rIiajC6tuUrqUoIPt81bUGisisG1LUXBP3ZrkTL+Tgis3+39RVW863ZVXuEBz+tVZPFV6H2iJhx12cGqWbZxssRL/wJv8AMtQoR2j+Buy6M0pYLqEsQbqEt7fn/wAh1l3HglrnaD4k1GIB9/yxQDJ/BBmqY8U3G8bi4I6gRnj6+lWF8X7eWYcHHSt455ncNq7/AA/yB08PLeJl6t8J7fWfJF94s1KUQgrGHjjIUE5I4ArM/wCFOQwq0UHiq5ET43I1uCGx0/irqG8aushU2zEeoTIqUeKkckmBSf8Arma648T59Bfxn90f8jOWEwkt4/n/AJnn83wMuXyYfFigH+9aH+jV0nhv4Ypo1jNb6oNJ1lmO6OSa1bcp7Akk8ewxW6PE0R6wjOOgQ04eJbfPMG4+2a0/1uzzrUv/ANux/wAiVg8IndR/M5HWPhfd3t2k2mW+iaYqkllg87D59d2QPw9a6nQYviNo0EtnLeaXPZ7QIoo2ZQgHRfmXp2NWx4lgJIFsf1pf+EifdmKzDR/8CyK0XGWc25ZOLXnFCWBw8Zc8Lp+TODl8CeK5pbyabStCkkuWkZf38ii33dNmMDj3FYn/AArDxvGGKPaFiOq3WD+ZFet/8JDu+/YOAOpBOP5U+PXoXTd9inX/AHsj+ldS48zmK1UH8v8AgnO8pwb7/wBfI8fk8B/EZQq+TFJt6bbtf8arv4I+JhRkaxlKN1VbpDn/AMer2pfENnjLROoHqcf0p/8Ab1jyAjfUk4q4+IGbLenB/J//ACQnk+Ff2n/XyPD7bwJ40jhuEvdIugso6IVbpyOh55+nWmW/h3xfbOki+GL4tDzEem0/ga91XXYVGUYIRz9401vENwQSojY9gT1/St4+IWYfaow/H/MX9jYfpN/h/keDTeGvFt7NLdXXhq9kmdtxYxYYk9TTX8OeJeS/hrUGIA4aNmLe2a96Gu3zf8sLf8WP+FSLqt0x5itf1P8AStl4i45f8uIfe/8AMh5JQf22fP8AD4X1kx5m8O6nGd33Ft3OB65NRy+G9WSJwmkasGHALWrZ+vAr6IGo3Df8srUfgalF3IRl/LT/AHc1a8RMZ/z4X3sP7Eo/z/gfOFj4Z1r7M8n2O/gkDEMkllIQ47H7vT61pSaHqVtZ+YtvqNwJGDun2STk/THv3r3v7ceguFH40fb5RkLdlh+FTLxDxTd3QX3/APAL/sela3M/6+Z80yaPqI3GLw5dyN1VTbSnb9eKjaz1xV40S/UKCFjWCUKM/hX02up+WDvYsf8AeobWgpBGef8AaNV/xEStLfDr/wACf+RP9jU0v4n4HzHaaf4guJRBDpVxAxO7fOjxqPrkV0j+HdW0+1+3Xdpp+phPmkiWOTeB7cDcfavd21ed/wDVrn6sagbU9a3HyoYwvbLNUPj+q5XVBL/t7/gFrJ6SVnK/y/4J4/ouraJOJ/tvhCaF0UmNY42iHHQ525P0rMvLuG5klxYzpzu/dwyNj2BOTXuB1PWs4cQD8Wo+36vuB/0cr67mrqpeIlSmv4Cf/b//AADGeTRmrOb/APAUeAC/ngMfl2N869CdhG0flVtJrq4I+zRSru42y27A57dsYr3ldT1BDlxCR7MRTjrN3jhYj/wI1tLxIqP/AJh//Jv/ALUzWRU0rc/4f8E8DD6gJzHdWtwccEFGA/AAU6d48K39m3IycZETAiveU1eUsfOWPA7Kxz+tSjWICPmjb8Go/wCIlz/6Bl/4F/8Aak/6vwf/AC9/D/gngdtFc7ZGWCS1kXlFaKRi/HHIUgVDDFrDHzbm3lRS3RYWZj+AFfQa6zCeAkv/AH3Ug1eHuk2PrS/4iVUv/u3/AJN/9qX/AKv02kvafh/wTwCKApPLN9mvnVBwgtmBYn3xSLNqiyNs0u+UkYH7twPbtX0Kmp2p5zL+Yp39owDkGT8xSfiVU64df+BP/wCRBcO01tU/D/gnzis/iV2/e6QQ7cB/s7ZGO/StCK6vGkMc+gXxYDIYRsuT+IxXvv8AaseMgv8Ai1RtqrHhV/N6l+Jk/wDoHX/gT/8AkR/6vw/5+/h/wTwg3kihSmj3pJGSoibjnpnHNQzarfxTBYtCu2j3DL+Q/T8ua93bVLsfdiTHvIf8KBqt/wD884wP+uhrOXiZVeioW+b/AMilkEFvU/D/AIJ4xBNDdQMZRf26qduw2LsW7kgA9Ki0Sy1C/vLkXUL2dsDiIfZ33H3IxznivcBqmoj7qxZ/3zTW1fVV5/cn23msf+Ij4jX9z+P/AADZZLRVrv8AB/5nh+oReItHuDENPe7idfleG3kPOe6kHBH9avWhvLjS2lfSby2uQx2q0D7fqTjNevHW9UOATCvsGP8AhUbaldyHa92qH2z/AIVD8RcS9Y0rP1/S1hf2JRvfmdu39M8GkfxDJfQSy6JcTRgENss3b6ZJGR+FVZ9G8e3xuFgtLgQSMcDy2Xj2BGRX0F9qucc36j65/wAKja+MfD6ko/4Cf8KP+IiYlrWgm/V/5ELJKUXpI+drnwn43uIIzc6bfSBCMARsSCOh6frWxqGjeMZdHt7b7FeSvGQWb7O4c5HTP8Q55z6V7gdSiHJ1EH6D/wCtT0v7c8i9Lf5+lJ+IuITTWGWnm/8AIf8AYsNvaP8AA+frfwF4puBEJgbfcMhZIpmK+x2oQK2I/As1hcK9xcardHegYW2mSY9zkkce+Pwr24anbAf6/OPej+2bRjgSD9azl4kY7pRS+b/yLWSYe1m/6+88i8WWbXbWTeHfBmq2jWjnzNlrI4uemMl+3H6ms/8AsrVrjXFuf+EZ1yxtGULJDDaM3bqobgc/WvajrsattXZgHGSTTTrcjfc8sj8azh4h4+K0pL5tjnk+Gm9Zfckjx+4sb/8AtC2SLwV4iurJXPnCZdjFfVdq4B69c1dvJdWm8RW39n/DS/h0hAFaKa1Lu3HUt144/rmvVBqV433WiA9gad9q1E8rKB9FqKnH+Nq/HTX/AIFL/McMow8E1H8keUa3/wAJLc2rWlp4H1MQscsrw4U+mAoGKx00nX0Rdvw+u5TkEl4pOnp/9evbi+pPw1yR7bcf0pn2e4cHfOx/E1NPjyvTjyqjH/wKX+Y55TCb5m390f8AI8QNj4tWOUQ+BJraQ/6uaK3Ksv5+1Y3/AAjPjxS5g0fU4/MJLYyM/rX0WlhuAJkBH1NP/s1AOQD+Nbx8RMRH4aEP/Jn+pLyaD15n+H+R80SeDfHU0m+TQb92/vMRnP50q+CfHeMLoV6AOPvLx+tfSxsUB6Y49aPskKgE4+u6r/4iNjXtRh+P+Yf2LS6tnzWvgbx43I0G7BJzkug/9mp6/Drx0+QdCmAPXMsf/wAVX0f5UC5+XJHYGo99u3Pkuf8AgJpf8RGzDpRh90v/AJIP7Fo/zP8AD/I8X0jwDqtlGrXOjTNdkZJZoyq+w+bFS6l4b8dq4tbDTQ8a/wDLaORBuH58V7J+4wG+yt/37pTLGv3bVvwSuR8eZhKXNKlF+t/8xrJ6P8z/AA/yPJ7L4fazqdlLH4hk8jKAoIdpcPn1zjGOT61Rb4QTDka1ghuhhBJHbo+M17J9s28CzcfWP/61H2xh862hz7xf/WqY8d5lDSnTil6P/M1/snD/AGm2eWWnwwisrcKdt9KzDcZbf+HvjD8cVDd/B5J5BJaXN5ZAk5Xy0kB+mXBH5mvW49Tn3EfZtuBnJj/+tT21S6A4h491NY/68ZopuajG/wA/yvY0/s3DWseR2nwZljYu2rXmc8MsUY47/wAdXYvg9dRyxyW+vajDjg7VjBA9sPXqKavPjmMfTFKdXuQceT+hqpcd5q9Go/d/wRrLMKtdTySb4KSPdNKdZvJS2SWaKPJ/8fqpe/B/xAtubXSb5ChIO+chGB/4CTXsn9rzj70Lfgp/wp/9pSMOYmX/AICf8KFx7m9rWj/4C/8AMl5XhfM8e0L4VeKdBmN0yabqUrKyNBPIfLIPqepNdPp/hvxPandL4Q8Mkr8oG9iAvfrXavfryWD/AIBqal9GScsePUNUy44zOfxRj/4C/wDMqOX0Y7N/h/kcLc6D4za+YWuiaDZWYbesET4DPjhjgda734W+Gtb0+81bXfEa2wuZ9ttarA+4JEDubsO+B+FBuVZlARmJ6YVq9IsoEstPhtz8pRfmzxz3/WvfybiDG5lKca8YxhFatKzv01v6m1DA04VFNNtonpaga7tU+9On4HNRNqdoOjsfotejWznLqOlSvBf9vL/M9lUKktost/jRVA6tbg8JIfypp1aHtC/5ivPlxTk8d8Qvx/yNPqlZ/ZNGis7+14e8Lj8RThqtqeokH4VcOJ8ontiI/O6/NCeErL7JfoqquoWbf8ttv+8CKmSeB/uTI3/Aq9KjmeCr6Ua0Zekk/wBTKVKpHeLJKKXHekxXomYfjRRRQAVjeKrrW7Hwhqt54as1vdZht2azt2XcJZOMDGRnv3FbNFAj52z+1TrXOdP0SNu3+jxEf+htWHdfs9fEbxNq8mr+K/GGmvfTBRJO3mTOQBgdFUcCvqTtRVcxn7NPdnzqv7MLX0iya/8AEXUL0jssBb8jI5/lW3ZfswfDyAhru+1i9YdczJHn/vlf617hiii7H7OPY4Lwz8H/AIf+EdZt9Z0TR5Y9Rt9wjnmupJCuQVPBOOhPau+pKKVy0ktgooopDD8aKKKAClpKKANS0bNsvtkVK33TVWxbKOvoc1boA+YPjppptPiJHegYS/tEfPqyEqf0215Zivof9oHTjNoWj6sqf8e1w0Dn2dcj9Vr55PWvPqq02fmub0/Z4ya76/f/AMEswHMePSpgarW5+Zh+NWhRHY+cqK0meu/Du/8AtHh1bdmy9rIY/wDgJ5H8z+Vej2Nwbe7huB/Awz9O9eJfDm98nXZ7JjhbmLco/wBpf/rE17JC2UAr0IO8UfqOR1/bYKDe60+7/gWPQpYo7iF43G5JFKn3BGK8Yj8L6Rp8s9vHZAHcVfcc5wSO9eu6TcG40uJifmX5D+FcX4msVstV3mSTFwPM+UcZ7183xBOtSw6q0pNWetnbf/gnsTSepwF14C8JXVo1pLpC+S7+YyoxTLdc5HNVbv4ceD763itrvS5Z4YeY43upCF/8erqWMX/PWX0+7/8AWpRsJ2rJMc99v/1q+G/tbGX/AI0vvZg6UXujiB8J/h6CQfDSdD1ml/8AiqK7byySADK3HU8UVos3xn/P6X/gTF7Cn/KvuOcupLRZQq3MhZyF2nBfI5PBH5iqP2qy1KQWVrNfGdiTiPahyEJ+Xfg+nPGfepJbPRrlrm+t5IxdRgC1Nydq5I9s4w2T1+tIZdV0nTby/l8M/bppjsmeNhN5oPVxjoR3ryoTgmkrP5pdTO767EM+txhYbnybjycbSzwMHDf7oXn3x0609r4R6lhbZpm2B/lUrgAY6sdpX3/U1blW5vbWFBpf2Oa7hzFG7riRxjG8Z+XjPPX9KrBrvTGM19exxlGEYhX95GiEdNuAQcj8fWlzQcdNX5Na/cC1LEks0jqws5miZvKWQIdhO3cvzZ4JAPXI47Uy1uJzNdk281vtkWINGd6tgc8g5+p24HTNQSJ4rTUoJozaXiRQSEvNEYC0bdt6r2HI9Kq29pqP2ppXZlOGiWSJycKQOgZgQQfYg9eK15aVrcy+/wD4YTTR0kyfavM23cbSxRCQiKQNt5PBx04569+lUJYpxGWMsbSSEbAjg56AZ478Vn2Wm2VobqTzLoiMZZ0I4cqdxTLKB24OfWsmKM2kC3JvrzTjMqmFbyFJ4pAeGBwcZ7jn0NbU8PdXT0Jcu508cd0ltEJkch/lkVnUvjoeDg+vTJoa3k89kcEBQH3BhtPrjrj6GsKyj1qe8M1jMdQSHb5zzBUTkZGwgknvnIxkYOTSalrV/Z3Dxz3Npb2EBCu8TM0oz0yCMH5uOBx+dNYeTlyqzYnJI2ftZZnMbhXQ+WfkJUNyRk+vGfoKWZnkjgV90Uw/eEJyrDHUn0rF0651DULFry6v7eCAMCkjIQsecYV2VuV5wD1HtUI13S4dVS21HVdN8+PdEsiyBlgJ/utnlsDnvjgcjFbPDN6LUFNG+kVwSrRozLJncSygcEfw5z7celTImy7KxOVDEECWQbT29Ny88cjrXNReItPiLiW2MBChY5BI7qWz1wxzg8/Tg1sWFzaTgxyWslqMKiuJFlSQscEblY4x6nn8a56lJwXM1oUpJ7M0YLh5SgATJyCDkHrggdqjlZUkkt41+aMkBpRtDD1yM57cVUl0eeNJhDM91b2bFVtVnH2lc4+XeOHHoG4xmiCW+N+6uiNBHErMsi/vYlb5QzFcr1HB57Vm6V9Y2aQ79xdOlvZbgRTlY44iI/MyrbzjngHrmrfkQ75HVR8hUbsdj0z+PoD/ADrMufOslkmttPnuEjcbscfLnAJBJHP0B/KrKi6uIPLs5WWbcCQQNvP3gDgjH4c44pKCbWq1Bakm6Vobhm0ybckPzBdpZuf4cH+eKmRbiWCOK4s5IiWVkYEFiPRlwCpPP+JrJgXXvKuLmxnhV+RNCEVxGM4Ukja20/z7VqQ3V6ktqRJFcyRr5U1oh2TEddwZyf1GPeqdPo+v/DC9SCxt7ueJzObiFt7osMm0kjBHBXqPSnJpEjZ87U3XJG2NgFwP546/So5ry/mnMos3cRXPli1jbZcFAeWK/cH581WvdVsp7u0+3RXemTylj9klVUMQ3fMzbuOeOe/tVKnJ6208he70JP7HnZRKl9MV2hc4CnGep9fy5qOTQriRkVbkNOf4ggA4PGfUYzTriHVmvI20nXbf7BsZMybhtH8IYgkMOvKjOetSLc6vdKwltXAgfy57neI1dCDl13A4UYHUbu9WlpfmQ7K9rFdNGvl3MVRwCQAGB3H2P+OKnl06+QwtAiea2Plc47dsdai0ia6ls2lYG1tdhULcy7WdjwpUAHPsx4Iq/NftaeQJZYbeLDJG8oG0uD93KnC8D1NZy+Kz3Fyq1xi29yqqk8cRwQpb7w68gn1rTNlavGI1gWORTk5PAB6Zrn59auhqsttd6RK7gObfyELrKBgblK8lQeueTUset6SlrJfOJLdYyplZkZVU5KlSDg57Y46e1S6Ulq0CaRsLY6c4BRIpGxnKsRj1+nNWFttOEqjEeRt4BBKZ9ec1jNqflRW1y8EU1tLvOIZCXY46MhPHruGarNe2F4AZNMmkLShItkRZiAD04AGDjgnOGHesuRl3tudN5Ue0g2x5/iHO7nv+FJJGGf5JVDdMMfzrCSKzvrNp/tc8aRuwRQuCrA/dIbnjoeQcYNWFJErxtBcSO6mZY13K7R45GW+XdnpkjPpWXKmVc0ZLMFAoxycYxnj/ACKHsYGiVmgUFuCQvf6Vjw6rfDy4ruyktWf53WfaCg/hB2nPzc8gcEc4zUj6rN5qpFD5rISVVXBfb1DkdcdQeODTUFcVzRbTLVVBCIHJ2nC9/fH0qBrKRRhdmNwPy888/pSRX08kbhbbbLG4LiRgu1SMg8H5h24P1p0Mr3QWKyaOWVXCFQ2N3BwVJGMjnr+lLl1sPRkZtCihXJDhiOmMj04pqJIZ1XzHAx3HftRc215a2xeFncDGA671B3fdypyO/ODUL3s6aikIRW3sFUFsZ4+b5jwcHtkHiqUbq6FYvxoTG67pCyjIAA5HoDUTX0co8oJIXAz8yFcfiaieW/njjEMEscwfYwUoBjOCXIPCjqcZ/HmqkGoAxJ50ttC6tnErMwB75K+vrjofrW0YoGX1nwoYIW+XJ4O4/hUR1JVCDCnIHLDHJ6dKgkvp4rf7VcwxRBJNqyQyblkHqAMMOOSMGi4ljJy5RJHDSLGkisxUHGRj6Z9ec4603BbtE3Ly3Fq20iBSG6ZUEHHvT5L5oFYRQ/cP8IA9vassWQB81TJHCy+YFlUDbu/unGc8Zx7jioUSVwZHuZUhbCgquGVx14yVKlecdqn2Meo7s2TM+5iY5lPDentjr71HJ56sfvkcAgsef1rMbUIEuobH7TJ5jEhZSpPmgDttztPTrx9M0yLF67GwuGMS7l27SNjjliSO2B2zng8Zq/ZILltydw3ecrDIVWkbBP59KIo4zAqqZAw6KZM0kMbtduEuX3xZ3qwGxTjOSQB0IxnnPFU7mO4gSW5W3lht1dVIkQgqCc7hg45II/EVHIu4npqaaRyGTbGc8dGfOKALnLLgBh0Pr9eaqRzCe0a9jQRwDLLG2TKcNgjaPfn2FSyhoh9uaZjak7QiEMZPQg9Tx19Kr2XUV7jja3S2+9cR85+cEcUmy6QKUUkA92B/Ws43hFqHF5Iu51xJNCVRBnGCflAPbBI/WrRknmEZsrxJwCeBjDkY4U/mOT1pqnd2aGvIs7roMCsHzcjG4A/nSfaJzy0LgY3N3I9hjg1myjVDMYPPRzIu8QSoUlGOSPlzxj0GfqDSRXt4jtb3Igt5ljLDfKVDrnjr0zg9ap0UkFzRjvIjhk3AbsHHb8KnOpJny/mDY6bevpXPGG4uP9Nju4YGwfLjE+Vcd+Djvjpx+tRiG8ZootQeKGdirbfNZGUbfvdMHPYZ9/Sl9Wi1e4XZ0/2zsHUE5yG4K017nYhkaYKDxj/PtXOiLU4Z4oZYYZzNGwiMN4rt7E7RgZ77h+JxUKi9KmW/xGikYWN9+xuw6DOT9Mk1P1VId2dQL5lYBXBYZGGOM09dTRwCj72J5VWGR/8AWrN063tEYPc6xb21tGHLnIl2k8jPPGOhx+VRTQ2slm1ykkcsZYAwuyxsQOd+R1XuO/4iuf2UZWaKTZrHX7KJ1Es3llyQoZhzj0pT4g0zK7rlQcEgbstxWXd6YljLbxnS2vreZixnifOzgEZBblffP9ai3wxzR+bpKQwFlT7QXjKRg/L8xyT36+9DpQ6fmh8z2N9Nc00xM+9yFYAtjjmrL6xpEjL5UjSKfl3DsfSuaEN+97FHb2Re33NG8rsmSAcBgAACPrzyKjt9Ou7iNnktY7SaQAJC53OvzZJbGV6enbHNL2UbXv8AkVdpHUSajYgqqRySMCQduTj64qN7qzJzJYMykDkgnj1rMhj1VJGtVsVmhQKwmgb5inqFPp0yDUzDUWtluIVifbhWR8qR6kYHXqcd/wAKy9l2HzXL23TnlRV08gv1O04/+t+NReXZM6+VYsdw3H29+T/SqMh12KZM2ts1sRuWR5cNk9ABjH69/aoUk1lr8u6x2yx5JJKuGYngLgkj8R3/ABqlFpf8ETRossR+ZLVc5/un5WPQEe/17VK9uFAKIhPBbMfbv3qoj6krMrD9z/DLzhjjO33P+TUX2i/QKWmgR5H2qjMMEcZIPHPtUO99hXLTW100xMUUbjthQOfXPFNKXsWW+zkEnlQM9PTn9acdRtB5kL3EEk6N5TqAeAeMYPJH0oXUVt1MNwyrIsgHy5DEYPQdiPeizS2HZED3V8jZht5G542jketCXeoxyZKyAA8rsJz6dM1Ot3ZSSBhqBHJJUDkdODx/nFWyGW8jUwl1Y8kNjIwMY45/Cmo3V7AlfZleO9nLoHWTaR2U/wA6sRXpALeWxUHD/N0NMRdQimRJjkEYLNHg5HsD+uKbGbhryWOa3Xy/vKu3LFfXj3yBUeyvqh69yX7TGrhmhk28HdvwG9hzTTqn7kSrAyAn+J/ftUluLdwIorY20gBATYcg9eM/X0qdbUeZuiWOSUEI0GwDPUnHGc9+MVoqKtsPXoVBqJ8ppAxKY657fWpBex+X5ry/IRn5jjFK32V4Z2FlGYsl8henPXIH6ZyM1VMcUsQuUIUszYIPTscjHt0pcqWwalqK7t5DshnRznJG/OO5pIL+xmjdoTEzgDOc4bvk+lQPLalZEZAzKP8AlkFOQeg3Dv8A402yeCV5BBY+SQwPmDkS47E9PwPqKdrq4I1fMtU2L5p/ecqyDcvIz16frTDJarI0ZlbcMtken+FUY5lltIzDp6xB3bcgfLZBOQeMHB7e1IDcNw1h5ahiCJH2yKFyRx0OQKi2tki7mlmMIACCCMjHJx60rO0SkqGdQeowePoaoH7K0os0SMoUZ87z+7GNwPsMAntUP221nKwO9wrunmlkQ8jO0nnjr270ezC5pTAtGJDCQBjIBGc+2fWoyheQx/Zm2j+Ittx/jUEUxQn7Osslu0gCu4O1hjDbR1HOKkmv4pEUJaTyI+AwwA0Z75GRkjPY0nHl3DRj18tW3SbEc4HJOD2zUwiT7+Vz2C8gmqU0hQJI1tJIEzuiChjJg5AzyOR7VZeYb3cQqAzcJ93A74Bz7enWk4Rcb8xSRaxHkgNE3AbGf50pIVgFKsMAA44/z71VjUKxaWJl3sRkRk4474zwRTRI8cLQrsvZIk3KflQvgZAJ/TPepUOa1g2LRuCThLYDBIb09qUTW4YZsyztxgYBP9KroUkEUpKwyDJ8vf8AKR7+nIHP+NQSXhObdJYVI+dgZFUbgRkZ5Oa0gr6php1NiyLfbVUQFFQbt38q2Gkkc5d2Y+pOazdNPmW3nf3iQPcA9avV8xmNaUqzpp6I+lwNJQpKXVi0c0YpjSxJ9+RF+pFeYj0bD6Krtf2S9bmP8Dmom1SxH/LbP0U1ahJ9C1Tm9osu0lUDrFkP4nP/AAGkGsWef+Wn/fNV7KfYr2NT+VmjRVD+17L1f/vmnDVrA/8ALUj6qaPZT7C9jU/lZfSaaM5jlZfoatR6pdpwzCQf7QrIGo2LDi4UfXIqVbm2b7txGf8AgQrtw+YY7CfwKso+jdvu2MZ4dS+OH4G/Hq0bYEsRX3U5q5Hc28uNkqk+h4Nc0CD91gfpSmvrcFx1mNCyrpVF5qz+9afgzz55fSl8Oh1VJXNxXlxCfklbHoeRV+HVwSBPF/wJP8K+5wPG+W4m0a96b89V96/VI8+pgKsdY6mrQahiuYJ/9XKGPp3/ACqavtqNelXgqlGSlF9U7r8DhlFxdpKwdKKKK2JCilooASilooASilpKACilxRQBZsmxOVz95a0KyrZtt1GfU4rVoA4b4sab/aPwt1lVXdJbotyv/AGBP6Zr5IPXNfcuo2aahp9zYyjMdzC8TA+jAj+tfD00D208ttIMSQu0bA+qnB/lXJXWqZ8RxFStVhU7q33f8ONibbKp/CrmaoHI6VdQ7lDeorGJ8bWjszT0S/8A7N1+xvc4WKZd3+6eD+hr6Gt3BHByK+aMZBHrXvnhS+a/8N2F05yzRBW+q8H+VdtB7o+u4Xr2dSg/X9H+h6J4cnw81uT94bx/WjxbETo63Q6wOMnH8J4/nisrTbj7PfwzZ4BwfoeK66/tVvtPuLN8bZUK/j2rnx+HWJw86Pdfj0/E+7R5aLwB1GC+/pswOB35NRtdMkyq8m7cONq8MT0rGvQ6PMLSymiuY1EewSc7t2Dtz8ucc8gdKks7u/SVY2tVZ8kSZ5k4HBUdGz7V+Lyi4arv5Db6Gul0jNnnIyD2P40VmQTXQMhmeNkUnCohQKp9T60Uua+ojzy2+G80t2ZIfElzeWW5JINsmFdiucb+SfoCMVb0nV9P0bUW0261CW33sUYRJtKuARkbfvH2bPSnHx5No1uvh6GxEM9vshlnvBskBwOSqcA++fTrWHdajNqurSXbWoluZ3OCEChnPHAHTP617Eo1Y1nBrnWyTS/pnizqRgk4HeaVrs06mC6hinCjYJ4tqOf+Ac/pU+oQRX8azB/JmU7obrzXJ80A4Bx2x2965PQbK6trtdWu7dFZP3awbs7mDcqy9eRnHb34qDW/EUlhNcSW/k6aocvsyWBPTaM5P4CvP+q1KEvdsm+ltflubKvzR1Ej1Px/Prd/A+lMryWwd4onJi8tflHlgMNxz2zk9TVzb4ksdPW3+0WWqSRlWmjJUzwv2wuOmOGwTn2rBu/H+uauII4oUtFWMIXUE7+OoX+HiotBuIhqgu1JF0qnc5k2b17gnpycH8q7qj9neXItE/n/AJL5sy543tzM6V/Dvi65gudQOjBbbUQqskc7SCTb2ZCf3Z44IAI7Gta+sNP1LTF0jUdCGnXdrhIxbuHMDMMgc9jnnd165qfT/E8zWm22iJXJWWWKTzBHxwQR0b60xpdGj1c6no2qmS4Mq/6PqVzwrYwAGHKknscj6VCxT5VKOj003123tt67XN+SNtNTlX0D4h2I+0WGp2TJgEpHNiPaeCGZh+vPqCKr2yaw9lNZ+JdRn0+aSUxrHbBJFUqc7mJJ3cdO3frXSaprOr2Vqg1XTbq1FwN63sFwr+Wc8DK5Vh6q3XtXAXfhXx/qWvf2jpj2wyftFvKJRGrE/wAQVuc8cjGK9XDz9pTUcRJJ26dPv0/M55pRdoXPWI5Le2srIqbO7UxFNkq7JLlgR02jbkA9CO/UVl6t4fBg+xWvhjQ51xJKbWchH8zsNwUruwfY+9cXpWmfEnwx4qtNUumSSEHEsUP79SoA8xSMbsn/AAxwK706ZZ+IpzrGi3uoWc7Psnti+3aQOYwrDCsBxn/IycIYZX503ol/S7/h5muslotTyO6svEOhRM0yaLp8NzG0TzZSV1APzKWBJDeverWjaZolzbtcw+Kzbvbnz1gaEwwzkD5gpPyk8cAjnpXU3+meDbPw/q7xaEZ2SHmEoZLguWA3I3LBwx78EE5rz258Q+HZILrTtI8E3L3zQMjKY3aSLjg9flx14Ar0qUoYqHNTT7f1+ZySi4tXPQbbxj4asBaW8trFYXca7sxAyNKG5GTnHPH/ANatS/8AFHhnWIoL+1aWz1GAbSLWRChX+INkbsjrjPp0rzPwv8NNf1x7Rb2eO1sUlFxcaabopMwzzwB8hI98juB1q5r/AMMNW8PC5msrhZ7OZ38iJd0k7Yy2CuBkjjJz055rCeGw7bhTmuZ77Py/q3zNVKajfod/f3N/c6CraXctqN8rKiRQqBJOhzubaDj5cDJPrXJad/bqanJdK12kiuYpI5mYsSeFHUrjPHFYHg6z1Cy1ma61W5Fm1nE4kjNyMZxgBlHOOece3rXa3fim0WyXTFtLu41CzOIylvsi8tsFWDuQuCCCCD6cVwTw1WknCEVPu/60Jc1LV6G7pVpe21zc2ep6ZdrcN+8eQgFAGH3SxyRyDwCR7CrF6thpMllqevWiQJGgKBpGIcE8YY5J57rjFedv4g+IHkLo50mTSXmnDwzTwsQijncDjHOeSuf1rT1mLxRcRiHUrK58T6ZbsWiW3KoSxX767TyM9V46ColgEqjcpW5rdU2vna2vy9DRT00PRbrUPD1naRXEVxc3Czy+Yb7LgxZ5CHb29+c1jX48MQJbwS6a16uoFbhJIFEoGf48EEAEdQa5Twtb3+l3NpO3263tXYeXby3HMEhHRwMds8DPPBxW54kstW1fUI5oBbxacWXc/wAxCSBSWL/XBwOma5pU0qvJza9LaKy+W/fU0dW8b21NxtIutMWztPD11YxRFWkj+0FkS15PyKq53gjnoMVn3Nx4nsp7fR5I7S6nnLSu8fLmPvnIAZCffPatxk0O50u3sVm1JmjjC+cJVSR1x93genGRz71DqGzQdEM2mvfHynTmFjcmNO4kRiCB/tKTjuK43NSqOMJRcrf3ld27vr5LRvqb2VrxObnvvCRlhe4spfD400bGjlhMqyTKdwXgEqMdA2R+VWLq60zUETVdE0tdRdm85kMaMkqHjK5Hyvu4GB1BBrobPV9Cn0O8Oq29tfNdAMv2ZcKwx7d/frVGeLQmjtol0NbYWsm5A74lgIHygvjcyjsM4FdU8RS5eeq9ey+7XRJbdHfXuZtO2ljBt/EazQi7jCQ3m4eRZSHJbLAFc7TtbA4wMDH1rSnXXjMza5oUF5pkkm9xayZeEH+F0fAfpjIwTzj0rOvJb68uprnRha2V9auFMahIkuA3IJIwcnn5ueeDU9h8QNUtNLSeDw1dPJyt1JOdp6/MERuSB6nqRxWkIK6kkuTu3r5WV/1Ii/5mZVno91qmpKNR0H7LYWpZUnljEbR85ykbYz2+U8e9bU/ixoLldKg0xYpreFU8u2jMrsCciXaRtI7nB4psXivwzrusA3l8sFwiEgXMrxBiTwrocBvqen0q5d6JDbfZLpWh05WlxNISUiGfusu3I+vTtXP7WUpclWPorNfi/wDgIpOy0ZiTieBBf3/jaSRZZQhNzaRgncemQQevpjHtWrqFr4ii1Uaja6klzIyMTDdEosSgZwpyxPTPzfXNZq+ILe68QrLrmobrraQ6wRJkEcDOAVwQMZxnvyKrXvjXW1gmtrXwlJJp0371GlDvGF24Y5xz78gewrrqYWtd6px7WSv27W+9marQZqRafr+p28+oPpOl+ZBDsM7XPnFWJG0nv/3z0z17VhW8HiibVJrHU9OtGt2ZQ1x9oCLt9OOXHqOOa3PC2g+TjUp71Yr4wkKsU3ml42HPAAwMcYzW1b6PpErJq48QrqRifzJ9PJVNiEEAtFwwIbBGfSueDhJ8tJK0Vq3dpa9LO/yNOWT1ZiweG5rOYI93p6TTFisXmsrhgfmYIScL/sjAHY1LcW+opnT47mwltrm4GTkwMc87TjcSflxkfWtu9h0f7ZFfx2TSPblRD9oCvkkEHd/EfUAGsPX9atLcW51O38mS2lE0M1lD+9jB4bAB4XGcgnFc0asaklGTUn2S69NW9vkO6W5Hqv8AbWh7LnQra3uB5bKsKzBTbk9QzH/WDvnOR04qDT7vUtQ02a0ljFpIZkaOOOUMJWwOUIOOnBz6cGu3tYNBkt4LtheNazhZAtzAuJMjJOOhz1xisaKTwfHqN9d2MNhY3Of30qygKRnjcPuqfXGM1TxNNQk5pOS0tG7v+NvwKlC3Ux7KeTTr6RbuK5ndw8a2+5pGOOGzHnHXgk8Ci8XXNUmhu7DTYdBufLJkDbHDMBxgjLKMZ9R7cVWtIRrd/Pf6Bai31FwyFLiTaWUHl2TJ4zjBHXNbtha61pt1Mt8WVLortNogkRMDBAZ/mUnn1BzxWnPGEntHye/yS0+fzJpq6MVo/FVkunW39k2s81vGGN6J4ykjN18sMBk4x15zgip7p9SmsGeHw5YuBKq3EeMCUAczBicdsHnPepNb0+61aKS007UVt9NVj5sEyfM0iE4O5Tx/u/TrWdaaRrC2H2TTNXsFlSTJWEtGhU9QSDuDZ9RW6lCS9xpy7apA01o9hmseI/DiCx+0O0OWAFuJN6hhwFDg58vGCOnJPpWg1y+pXXm21rs+zuoEqXC7GO3AAOcfLkjjPWs/WdF1vV7a7+12mkLeZRBcToMzhQAu0qAMdtxGev1rhdUk1OLUJtAJurNFkVkgEojUZHzcbtnP3gQa6aNCjiXKMJardX/Rf8ExnNxd7Hqq/wBnwXTvrOozW96sedm4KEVeTtyCCG9vQinpZyX9zLqOk3KixhaNo/KnMUkgI5CR52AnkEjHPNeWW+nprFxFc6jc3+mXGTvb7EyxErwpViSHzwSMeuK9E0zRNcuZTcXd/b2dsjAAeSzCUYHO4YVFPZeSO4qKtPllypp909Lad+pcLy3OfuPFUui6q8TR3l3ZrKTHmX99bt2TC8n0LE/QVrv4nlvHsY3sI4yH3XC3ExEocnIAX+NSMHkkelchc+G/FYvLp9V1m10yOETNbpFJvABO7YdoHB67jngdO1VPCmm2suryPrk+Jrdc2wibcA6/MEAUYJb04HXNdP1WlUi+WSvbo/8AhkZKcovlsekX1nY3TPeWWnWy3HknylLKqlzlc7lztI75HtgdayoG8TQ6k97e6dYXEdouJLSKSPzIsfMu0kZBP057VTuNa1Czha+0xLMNOpeYSYjZhkqSFwFBBBHr7Uw+LvEGiv8Abry7tdQig2SbbKRZlRWJAVnUD5uDnP1rjp0aji+WPNbRXdn/AMA3clui1ceI7y80ItqWiJbxSsAsczCTzwW5k2EAMBj8xWzFpvhi+t4tl5cKo3Em0+WIMFALHCjGAR6VU/4TzwDrH2T7VoaLNEo8zzMmWJi2RtPDdzkcjkY9agm0XxFq9xJP4f1KRYPPLWqbWMscY6BhJz+FFWEYNRjeDfTXd9NU7jd097lyXw/e2uovd3KoIIwEEqXLFpAPutjH7tm/Qk00eIpTG39u2cUJldmgaQK4by8YToWbqeW6k1Jo19qcEElvrkMerMJOI53EJII4VhyM+2e3SuhXS/D2o6ElnqdjDaRyqXkj88eWjg5HJI9OME81i5uElCsk23ayv9+v9eZSXNsznd2m3CjXP7HW0uYtywyxMq7XA3fNx8vB78cH61LBcWT6cZL+aG5tbpRN/rx+9+bjDAgkgjJAJ7Zq9PA9lelrTWGisXXy3geQSPJkcOpxv3ZxycjHcVCtsT4jgh1TSbPMyBbaF4xIsjj+Lc2WJx/Ce+KHWp6Pm06au/npb9Qs07EB0+/s2il0PV4YkLNJ9juFOy4UEENkfMFPQ/T2qGbU9Q0vQTqF8ltaSMds7WzeaIgWIXIHJGc8AntxWnqfhF7e2k1C1sYoNjGMTTzFY4VPKmNU5Ubj0PHJqgt8tgsVkl2sNzcor7nQyHG3l0JBDDOcZx6dqpvnipbx36rT8fxFZxdjMkHhnWDp0c0yRSuC6SSW5WRGJ+/5aEEA9DnJxzWk8FvFZwLqGqPpy42iV38/exPy7lBAAODgcnntVfUNN8Ya5p9qkOq6dcNBvZ94dWlQddwwccdQOtU77TtG8RiwiN4k32UC3uZLKQIiD+8qOMflg8d6alCylze7f1t99kgb01Ql9rei6bfXsltrpgUggRLGqcHqvclfTuKt2GtwXbLJpemjUJJ4X3QyYlhQKvO7I2qccgmqc2k2Ph6e88QxWFxrCCOSNbiX94LcFdqsx+90yCSMc1yupa3q91BF4f0S0jsbe9RJmjgYiOUHozLyFxg5xjjtXTHDwqRVSDfe70X4WIclHc73TrrxZexypFodrp08Kh1mknURLEOuSOR2HHrVv7TcR2Mz+LZbWxywQPaM5jC9m3Hgk89eMcVw7/Dvx+ml/bbm4KKF/dTeefJIB6Agcsew46GorWyTRbg2Wpi61TU7p1UxrNuyO2wAkN+P6YqauCSjGz3tZJO79Lvbz1uT7Rw+JHoa6hpGp3dtLpaudL8l0Z1OySRsnBUgYx37Z96qStd2s0tyNc8mVMOkLReWjr0O5h35GMj16Vn3XjXQxZXOnaXosgvo22E3Q27QOGBHZvpxXPzzTpcy23iDUjZM/wArWXkgFVIBB6nKnI5PX3rnWFrK8pRVu1tdfkndfcVKrHodp9m1i5smuNO1S2kCgSeZJK0i4ycoG6qM+mfpSPHr9ncRXCLbXyS7XlSEDcgHBUnI4yfvEVQ0ptFg8Otp9xJJFErNNEdNdYlGTyzbeSxAGfTjFNsfGNhpt8ttDbT3jQ5ykoLFlAz8xPJyO+KxnRqRnyRtLvo7pef/AAL/AKDU1pdlqOPX5NRnuHhhFruEu03B/wBZ0IOMgLjoRjOPetieHW7i0Wdp0tI4PuGPEgYZJII2j5cnoGzXPzT3/iaZNQSa3MkEikCOPzHUZyAVY8/iPWnxWPjb+2LqfzrRLJSrIWIzMO6qOTG3v0+tYTiua0pRXk/lb1/pjUyzK3iAySRSaTZ3C5YIwlDF+eDhlAQ4z3Iz6VmwazZ2moKl7pCRtBmFpHy0wLndjdkgZIBHJzzzW5Dp3jR7+VdU+xwW8kgCNaxGR1BBPQ9RgYzzg9cVZgtfBUkVzpSajvvdm2U2zmAGQHjhcgHJGRzW+tK6nC2217W+7+mVq9vxKtvqdxPq1ze2yMsJYwCNyI/n2ghMgYznOScHnvUOgR3V/dyyyXc0brKizBCrFZM4IU5BHqAfTis2+8KT3VoLPTLe1sLtJGWadp5QZxnhWA9Dnnvx0rTt/Dfi2CaMfb53zGI9wbz4Dx9wqwzkHoT17EdKd6Em7STlpfv/AF6DUZHQw2mppfSk6xbm3V33QXDASxp6tsGGI6nIzVMav5cM6z22ZYiSFjn3klRy23IwpGCM9eOOaqaj4b13Za6fq0El884EzalDcMi2rA/cI2n5/b39qpz+FdM/tlbyy1m9idU8tnW5K+Vx8pOzO7J4wv1IrSWHpKahUaU+2q327Ib5lqkX7PWYNVsZbiyul06dItx80h5H28s2I+Rxx9B0pmhXGvi8vJJpIYrby8pLGkiiYdCMkYB9s89qpz+G7rQNRtpLdgi3AWSOO7jXzXlzg7WU/MOeh556U60/t/xBeGz1PVE0ia2PmfZ/ILfJnByjjaw6DHJ5pVaTUuVR0W7u1Yal/Nubkl3emSS1tfsV9psbZmjEqxPkgE5VwQCOvUCpVms/tqxxCNp4wJY0DYxk9ckHIOP/AK+K5PVvBsulRXWsSW1zrUkTmSNQwZkQH5CUH3scg9cDGBWBZnxRr1neyLFFodubnzXu0heOUMBkYdz8y4PrgdOKqFKNWnz05+6uvTt3bJcnF2aO4m1iCwtftqWMchWTyUhbh5A3QnHLBSOp4qOfWbtbKNEtI7WSVxGss5ITOc/M2NoAPOAM5rPuJIvC2jD7Ppk/iB0AQTRiSecK3c4ACDP8SVgweGvGPiOeNVu/7Gs5ZeI72YvKMjJLYHJHbPJyKI0IP3W1ba+mvp1CUp9DtYJ8G3h1FbVJnLbHtBuUtu+Yjj5cnpjk89KW5n1KXSYZdE04TeU3lyLfs0LbRwCCOT278j1riI/D3irwtfTadYanLdwKpmcRDzEjkJwu9G+6dvI78g1X03WPE76nHHrF7baMiTCARXryI7EH5tny5LHPTGBx+Lnlr9q+RptWbTdu/wDw+4lN7SudjcS38cEMWraJpVtqNyDFCvnKWuhzkAYJ4B6GpYtUubTS4nvLay0+FV3Msb+bGvOPTGfbn9KwG1XwSIZriaGObyg0ccglZGZc84wQQSeemeR15qlqfjgaVqdrY22ny/ZnjURPDECsgPICqoAb3PX3rL2M6z9nSg7/AOW9nf8ARlc/Kdcmq3OoaLNcQXFvIyfu1RJWVZFckZBZcL1PA6GrFne66bGSObTorS/BEkStMP3irwWAAwBjqabp3iawvNOFm8Atp5SHeCWPYIyeArDng9fzNY96dBsjDpOvajBfbpDJFPFcl/PycYdQflC9P8aydFxcvddr9tV6fduVKSSvc2X1jVjqEcsbWht1RTLIZwrxN/CQOeR22nB6U+D+3Le5Emq2lvCiyFWYTsrdDhs7SB1zg9axku9R08NLaaVDceUhQXjSZQ4/hZG6E44IPJ+tUtK1TxreRytdzWFnJKC8EALeZEOQrgjtngg5B56U5Um6anzRsu/+Xfv2GpXeh1cd3eTOTBdvPp7boleOLKb/AOIbtpBbGOvTnFZ6teRzXEMU0N9CCojuLIgtjr8w52EHrzisyx/4Ti/eJBqdtaSxllmQ/N+8B5Dcd88Y6ZBrZX4dW9i9lfz3Ut/PIDNcxC4ZCj4yOmDtB655Y9CKtYSMIP2s4pJLW93vbpbf5le9LZFi1u7CeO2v7O0uEnuY/LjnuY8+aQOhZe2f4eB+dLBbxSiSa70eGK/3FpmVCm/PU5Pc9fxrz+81HW9N1WWPTry8iwyxAuzb9uc5UBeQR0AOOtdHpeleIW1WLWtW1aa4tnDbQIliDHoAyg54znkUYik6UHVeitfr8umhphoOvWjSitW7f8E75dUhtoEgtLc7I12jccVA+rXr9GCD/ZFUAcjinYr4n2ULttXZ+pQw1KmklEke4uJf9ZM7fVqj/ClFGK0SS2NkkthMUYp2MCq8t7Zwf666hj/3nAqoxcnaKuROpCCvN2XmTYpcVkSeJtBiOG1OHP8Asnd/KqsnjPQI+ly8n+5Gxruhl+Mn8NKX3M8ypneW0vjxEF/28v8AM6HAoxXMHx1oSjpct9Iv/r00+PtF7QXR/wCAD/Gt1k+Pf/LlnG+J8oj/AMxMfvOpxRiuVHj3Rc8wXQ/4AP8AGpF8c6E3VrhPrF/hSeT49b0ZfcOPEuUS2xMfvt+Z0ysynKsV+hxVqPULyP7s7MPRua5iPxd4fk4+3hD/ALaMP6Vdi1rSJ/8AValbt7eYBXJVwGIj/EpSXqn/AJHdTzPL8RpCtCX/AG9F/qdJHrcg4mhDe6nFXodTs5MZkMZ9HGK5tXjkGUdWHqpzS815ssNB9LHS8NSmrx/A7BWDDcjBh2IOatw6jdQ8CTevo/NcMkkkTbo3ZD/snFaEWr3MYAk2yj/aGD+dVh5YrBz9phaji/J2/wCHOOrgOZW0Z3MWrwsP30bRn1XkVeinhnXMUiv7A8/lXBx61bt/rEeM+o5FXYby2lIMVwhPpnBr7DB8b5lh/dxUFUXfZ/etPwPGrZSlqk1+K/r5nZ4ornotQuohgSll9G5q3HrH/PWH8UP+NfaYPjfLMRZVW6b81dfer/ikeXPAVY7amrS1UTUbOTjzdh9HGKtIyuMowYeoOa+tw2PwuLV8PVjL0aZxzpzh8SsLRRRXaZhRRRQAA4dT6HNbNYxGa14zuiQ+oFACk4Ga+PfiPpn9k/ErXbYLtR7g3Cf7sgDfzJr7DIyMV83fHzT/ALP4y07UFXC3dnsY+rIx/owrCurxPneIKXNhVP8Ala/HQ8gqxAcpj0qv3qSBsS49a44vU/PaivEtivVvhrqBk0i5sGbJtpd6j/Zb/wCuDXlIrqPA169p4piiDYW6UxH3PUfyrqpO0jsybEewxsH0en3/APBse5o2RXd6dcfadMglz8xXB+o4rz6F8oDXWeGroNHNat1U71/rXW0fqyPOfGuiz2fjCWeLURb2Vx/pRiXbGd2CD82QTzzjv0rkzpfiL7Uv2TUdtsWy8qjZJHGBgqoGcknuMcda9N+KXg+28SaXZXbp/pFnIVEmQu1G6kk9gQDXA3c/iiwsDHZy2+pSNEI0DSBF44DDPBJHOD3r8tzmisPjJcrV3qk0lo+t/J33Go33Whm3eha7bwyr9unuVkky0JIWZRj+7nBP5HniiqbXvjWad7O/kt7CBmBFwJiCxHVQBz+Bx060V5CjNK0pR+++nyViOWL1scu+oSazOuneLdFs9I1lkVrWWzVnkmIGNko3njA+8ckVNquq6MHdre+SwmtQys8JBkLBfugZ4543duSa4zxg91Y+MLXU9IurH+0ZAJIoZh9lMqA4KOrHax7ZDAn61m3fw9+Ilvfs9j4dltlulWaM+YskUSvg4Lk4GM4yf/r19XTw1PFcmLTa7HkShJra5paj4h8W2epRpJJc6dfwful82fI56qcDA4zxmtLQ9Utblk0/VNGN8bkkRXNvy4Dcchm5APTHI9ao2Hwn8TXFtFPqev2cMwJla2VmmJYHj5x8vPr2yar3Xgr4hWV1a28qW9vayOALyGZdkYB3Ek8MAME49q05sFVvh4STlrs9TBwrQd7aHqmn6ppOk+HYLjUrWSzaVcxwyJ+9jCDn5euRivPbj7T4s8Xpa2mnzadFeXEcEc06BEzznBXg5HP4V2Gr3Gtjw032rVkv0523jxRl3IXBXcq5GfTPfrXF6JqPiTSPE8E2hyCS5mjJEE4DpKp65U9PY8Hjg1yYTLfZJzn8T8/6/EmpXhzqHQ96bRrXQ9Ch+zJHcLbyoDJH+7flCGc446evY+1cDbad4FvvGg1WDyLi4gHmPbhsxykniXae/B9u+Kqr4/8AEd74Y8SRan4Ris7a0sWU3MKSJllB2DJJDc54Ocg1wXgvWdGhu3n8VX9zvkYSxpYyrvU4x85xgcYwF5GOcUq2Cl7FwpycXbf+v0Opz1Vtj6phvdM1DSPJsBFEPLZXtygcIB1+Q9Rz096808S32kaMii8t5Uc7H+0WYZQFGQnDZCjOflDD6VyXgPV7C+1y/wBOk8Vi1RxLFaXd022UljwwzwrY9T3Ir2abTNc0bRgXvv7ZstpWWOa3VxImM7sA4Y9scZ4ri+o4mpJOq24Wtpp87fmdXOqkbpHiOvHxlrGp21vpkyGxliRlk83aI3/iUjqT9O1d3ZWOrf2DNJ4gv2LRxrJ9o05FhfcgwruWzvIHoAeOaZ4f8a+Gpr64/tLRrjSpkm+WMWxdFBPPQfKe/HHpVzWfFemXenNJ4ZWyu7fznhuk5IZTznHBUdiCM59q4sXTrUlDmUVBO22rXRu5nT9mk5X1ORm+Hk+nTS3Fszaoyt88F1cNCJeCQwZTz0PB9RzXnmueN57oJJpH2u0iddsqMf3Zbplc5OSODz/OvRbS18QeKZYfs9zL9ksh5Xmb8hQOo4AJOMYHPAHNdlpHhazVVjn0+C6iGQ630CvlCOwH3DmuzA88tZq/nfp6bdjnnFvSGiPG/Clz4mQWurX8ksOnTEiFXTicdCd38I69OTivUovEOg3FnM8USNfXAe6ZJFModwQhLbumc9u3pVzXbfwVoujR6U8TQx20UlzFbySknHOdpzkYJyM5AweDXmK+KrCGBGtmE0UbAbEkB3ZP5kk59fwrrxdOnFXo07z6W2+ZjG9OVr3OzuPDs1zexX3hS6XTb6aMR3S+WJEnC9NobcwwB3POB6VjeIvCesXerDU7nxRHGrFViSe33bkVQOq4568Y4yK0rbVtE1BYUsb6UXCoHuIpHZDE+B0fADAHI4Naeqa/ALPF1qSG0jIkV3Kj5tuCcnn171xLH1cL7uJlefRKzXlft+Zs4xmZWseJrzSdGt7KZHuxu3RyZKEYHII/75x+NcWPifPZXax3ZmlhUF0ihcKU9N2eox2NW/EuvjV/C2zSRdXUst2IebU+VIpU/LG/dlwCRwcV33hD4Y+EtU8P/briwOovtUfY7sjzIZABvXKkd8kEDGCOtdmHo0a0faYmHvO+g3RqSlozgfEfja/TQbaKGKC1eYrKNhjm3LzgbhnHuuetciPHPidvtSx362mn7TG9vIoYFCc7Txlv6dq9017wh4GsJ7C2vtOhuIFc26aTGpkS2Z8sJeMOB8pBBJHOeK8q13TfgreXp1HS/Gup6ZNE4KwJbtdIxH91WGcexNd1GlTjFQgtFto3ZfmROlNNtyOXs/EWuCyna2ne+tlcR72Y/um7DrkA5GK0tO+IviGymZrm8dUtmZZNxG3PQDOD0OfXNeg+EPhd4C1zTo9Z8N+J7n+0EkaVrSdFj845yqvET8i5HuMGr/iX9ni6vre91nT3hsrhUR4bRfutIzfvFcjPAJ4ZeoxxWawtCvJ+4mvQtUKqV46mf4G+JNlq9i+mR+GLcPb4U31lEIkhXBxvDdAcHkc+1dTd6HNe3kA/tqGIyqskM6qXhbPQZ4zzgckdR614frSjwai6RHr9rLf3cKPdfY3GIh837vcOGHuK6n4caZqHiiS4tdI8T7ktxEk1ioZW2u4BcNnaMHJGM9OlctfL1Wq+1S1Wi/rzuVTqTdqbWp2Wq61qnhSxuk1S1sdUvLRGniFqgHmoMZXaRuU9889D6GuLtfGV14miI1Gz1LS4ZpD5c8iqizN1KBmHB5yD0xWlPYeOrv49X3hzSNRe5sbKSMXl1NbiKKJdoYoMAjJ3YGOTkk969g/4VnoNxFex3UX2179xI6TOx/eYxlG42kj0GOBxTlhIRtCUI3Xne3y2NVCUro+YNdsLPQbqK5Z5b+2ndjmKQDzl7EPzg9iOT+dey+G/F/ii28GRXjeG317w2LVWDxBfOtcJhs/30HIyQcc89qoTfC74dReczX2r3ESyuEiilyY2HDAKUAPTqeuK8v1PxF4l0qTU/CWgO0ujpO8JuJZNnmpvHAXO1emCAOea78PJTaSmnJXvsvvWpzWdJt7I7Cy1LSNP0SO9EcEizsXkVJNzxkdMlsEcds4+tWE+NsFnb/YLLTXd+X3524XHU8EMo6kAdutcNqvgnWJPBMniRdDeOxilJlnivPtDQJtypaMKCE5+9zj2rhNKZdW1S00qOSQzTusakDKqpODjvxknHescPltJzlWk23qNKaSt+B6lda5bahqKWVxrifZ0jEkl+ke2LG3pGiAMAScEEEjpW/dv4T0c6VeWuqwXExhE1w0EZuIX5xhpAytGPqCc4Hse7034SeHhpb2q+ErUFFCQ3E0rNNL6lwTty3fGMZ46Vl6z8PfDdpoOpXEFkvh25tIGlBtCdjsg3BZIySGyVHoc4Oa4qmIw8JwpunJc22ll8/6ZoqMlq3cwdb+IKxOh0cGTbBuee5g8qSPr1QY7dGAGQelcdcR6hrGm3OrTSLJmVVa6efHlkH5kdOqgggg4xxgda4u1OpeJPEDxQXMMN1ckR4zgSH0J5wMDJP8AjXr2hfCuX7DLFe+JbtpLlFDQwYEaqvO05yWAPIPGMdKeJeEwDdWu0py6Ja/1/W5zqMq2xh6N421LTY9O0SxsptVupHaOESsPLA7jax+VcZ54xg812Do2tQSW0Phm2nuI4FDNCyK0L5yuyPOScZGW5NReGvgw2q6fezalDNGHfy4JLW7Dl0U/eO5cjJ7Zx2rM8W/Dq00e5ttUu2u5yhjt4/Nk2lNo4yVwTwOPyrKq6FK0UpJS1uk7NvXfY1UJxheTNrwzaeMtJ1y2vLiwS202ZjHtvG2eZ/sgj5lY4OOnQ9a9Tm1ObT2YQ2zhwp8pgwZgT7fxEc4AAzjOK4SO5vNQ0WZ9X1G4g2SgwzNPwxBw2c9OD1rkE8XHUDc2888r+UGiV2ctsHYpnnp/OuWdKNSMa9OyivJOV77p9DSNZU1ypM6l/E+l+JftkkVu0MgJiaaQLbl2I+8QByR7811Fjok1/wCFRDd3Cx20LZje2GZiAMZBAwc5x3znnpXn1n8T7HRbYRwW6mfecXE0IMwOMH/JH41seC/GMSW/2aK4uPs8jGURzdOT19h9PSsasfYwdbmnrvvfp16/caU5xk/eZvah4M0kNBPeT32n21phUnAYefhRwwO5cerYzUE+jWbaiz2cUdnekxu0rkXDuvUMDxww6EAfmK9Aez1nUFlm0ySO4sHiAUXDbRcBhz04GDx07HNeYx6V4lvLy6uba2R7m2Do9tOvllY48DYJM7SQMYHfrVTwOKqKMYK3nvfy811t+ZpUtB7XuRtrniiw1G6tzoMd9BG4eHUIY96omRndnJT0PGPQ0+71zVbmESaJGt1qAZhMgy24noSM4BHrwcHnNefSaug1OQ6hfak0EbAxxeasRR++OzBe2RV238TWOnRslrozWdneyHztRmiLyTY6lc/LkZ7DjOcZrV4RpKDvaK6bP79jl9sm3qW7aXQr5re68WajMl9JG1vhbg+UhJ4yCPvD2+UHscUmsW9pLYvoPhSOW71CB9sKJLGJjtJ3KWyC5YnIAXIxxXKaBplhqniZorzT5r3TN2LZlnczq3YgdDz2Ir31Le/0K0hurXSPsEiqykqqqyjHzMxPJJ9evWtvaujOMVGU11UUrLtf/gsdO8lqeHQeB/GF9Iza6bbSnSNm8qUEzSYOeSOCwz/ERwOtdBDo8OkwJp9pqEc6xF1FwsARpN3Ut8x3egz/AA/nVpNau/EWqSWFle2cEtvmK2N/IYWlT+5ubjIOcZwcEdag13wr4m0Pw3cXunpZ6lFE4aW5trkSmzHdTEQCR7849K7JUsViI88Gl6Lp+OqIunrBX8yW/wBW8JNYQmHT7WxmhCpOstqxMhQ8rFJu3HcBgZBIz1rUXx1aizWHw1YnT1WRZWnuVZp0jB/1bAcDI4OeMetfOP8AalzPqDXE7yXsz5B3ktgH0Hb8OlbsWr2QuvtN89zYSM6qkUcZEZUDqXJ4P5+pro+oyh7yd5d7J/cT7Wb2PoWfUm1C783xR/Y9vG5/dCWRv3mPunPHIHfPf0rEOqpLr19p2laSbu8JDJBdXHltat1IQ7huToQCM89SK4yzuJdbe0ihguNatpXcW1qnGXwAV3g/Jxg88EA4rU1nwl4808x3dxJZWNtENyFdsYhcdED7RuOOQc4IB7ivPoUVytYiXNJ9/wBL3aN7yeyNnV9Y1610ieA+HIbVvOZPtcrgvbzgAtnkAfL2bgggis6w8T63b6rpLG18wzZVJ7dVnV8/Kx5PCjPLdsda43VLWTW/Ck+o6vrskl7a5hhAcMZiOVDA8kc8N2H5V1GgaDcaN4YsdflRLXzbZpUnEpmEAHDDPQFueBn35qalHCRhzRi3y6ef39Vr5gua90et3lxrGhSXMF5bJK8kagSCUkqwOd23Htwc1jxa5a3MF5PJYwJuXcZLteJD0OMcjA71hT+O/E/i3TbK3s9OCOF8ldUYbdwBGRzw3vgHqa8svPGl/OZdP1Ro/Jhdt7AYMmMjbgYJ5rgeWylV5MO7RVvJpXb1S36mkq9teh7xo8Gm2DK0WqTfZHwZknG8l++yXghcf3hmsTxBqGgy6fdWenzQWyzXKeUsqFlICkuGZCOScY74zzXK+G/7T8VaRHFo4uL1rXarJF83k4UBTIvqQOG56V058CeKLLRLzUtQR5khO9t7ooVMckAdSPer+q1qcpyjFu/91L5qy/Ujmc1aK0NjSILKLRRaWMsV1p1wrxyQTyZZUPLq2eSCScdsH61heP7/AMIaB4eSXT4rzTtYmhaNJLNAomwQAh4K8YHOQwrP1S1e4ijtftTTRPGq77XMLyHORyOQedpx1/GtnT7rw74W8NxrrukxGMM5FvI3mjkD+Fs/vAc5Oe9c1Kq6dVurK93a2+q7b7vstupabkmopLzOY0PVviCnh54F1PUdF0iVSsTaquH8zHVAQCRng4HGc81leI/CzaisWp3Hiyzh12OGLzYIEdS6KpDFCQAWPsQOCK1/EXxY06dLaCPlYhhBMu/YB0Cjt9a7qx8P6d4t8PWN7Nay3cFxbCSG5t18p03jkD3BHTkZFd/13F037X2LUdlpdr/gGfLGb5U7nAWvg/xDrkqSanqFnbwxlnGoStl5k6qSidABx26/So4fhd4q1fWHt5/sNrZKqj7cbjeki/w7CnJ+mBiu18IfDWXw9qTXOqeIrt7C18xbeBgI8LIRkyHoeQOOmR26VtTQnTb2f7Dcy27MVmeMONiHswUjgnHNNZrh6DVSrLmv1Sa+9P8Aq+hf1fS7VvmecX/w/wBQ8ONcQ3PjS20++nZTb74l8iZOigZORk8HGSO471JrWg+MhbTLov2XxL9jRV1G2slVjBIOdvlH5mXoc4x1GKxvGGnSeIvGd3q+reIPs1g6q0caxltmFCs3OFUEg896Z4YbRfDGtRahZ+I5obtGBilKsglJ6+xA784+te5GFFP2s1d77aq+vbocUppS5enqZ2lWvii5kXUbGzuLG7Lsf3z7ASevB5A9sflivUbDWtV0bQ473XIIXtkAmLvuWUx52vwAd3J7gZrJtvH8MXiBota8OnW5Jyz7LZzI5778DjP1/Ss/xP8AEHSBeudD1m90qUuCLE2wBjOMFGJwT+JPWvKq4WvXcatSMbX7Nu3rZr/I1hKEVzRZ0HhrXNe1HWNQbT4U07w++Y7Vy+yRiehQf3/p04xWhLPpI1z7fc2Ud9ewKVNzIMMT06jBJ9zyO1eM6v8AE3WZJFt1tYUiWUTBFYhCy9H2g4JyM+ma07Xxot5JcrBot3ea5etsVV+QyEgFZwighm4IK985zmoq4Cs1F0JOLXS+nrbX8i41b6XO01PxnHaa9b6dbWzy3Es4McaOGZNwwsf+1k4wTyBWunibx3FcEafYLbzIcmNpgCuOu4DOe/GK8IttD13UdUuIltLi51Jmb5FVmkDZ5yOuf5V6V4Q8eeLdKmn0LULePVHb5FN9OI2g2g7grsRk4J4znjit1lMW41Ipua6rTXy2/MinWcpWk2jv7PxnBdSNcXV0i3MrNHMWDHgjnI6FCcjHUdsU+81rwc8kLafp1ja3URDqbgM7Pt6+UCwCn03fWvGfFPijS9E1F7XRtZg1gSxo/mRxkcMM4btkce/PauTsfEk99qUUWqMJoiNjShhGUX1zyMjP41jh8rxcU1KWnnZu/k3r9zVzSdZp2a1Poy48b28FvcwjUY0k3eZbtK24xqOuPVves7S/Eusa7qdlFGywpIwZpbhwEMR/5aELkhumF4Bz2qPw54A0KbwvNq2j6gfENw8ckYjWMuEwDlQcAqzD+8vI4UiuF8NazLF44+ywQtZQGKSMWUMRxI6jjcCM7upz7YqKuWVsPSdnz6Xt0flp3H7Wacebqe13ltfafOojmuLyORxC7RIp2kE5JBOQMEcDqKhudK1C5vLrSvErxR2kSEi5gBK3ELDhQh65z1yMYOaj1OfXtB0aDVmsxcM+VYyDJUqoZFJHQHJGDyMYzzVE+NdR17T4bXUIrW1uU3KJC4VQeqhuyZPGT0yK890IUpSjUpcstHG/4p6p/wDDas7HJbMl0zwzoGnaeg8M37affqpi43SoRkZbLNlWx6flVHWb7WtKmtp9VtkmtTOYYb62kUAuRkKVH3WIHXOOMcGuHudfmu/tFrp2ltFqMEv7t4JSFcn7yMS2Dxk5H9aoafaeKtQkefV7i/tbON90spKleegRO5wO3QAVrCn7rlipJ+787931+7c5XPpTX+R3+uS3N+iXc+pvdCQM81qbZncHGMDacMcDtWLY+CfDWvXcE9tqurTPboZfsktyxIGeSN43Jz1Hriu5+GcmieKo5riS1u/9GQExOmAr/dPzA5J4zzjrWh4n0HV9NnmvtOna8gkIG0gGeHg8DI+Ye3X+dbfVsXGg69Fu7e0X97d03f8AE3UU/eZ41490Xw54MvgzwyXUuqRGY+YwAXaQCu5epJwd2AOlXfBWiXXiC8sr2GfUtG0jzUnjt79VP2og87NuAVPTJAznoa7eXSTqFtbDW9Ps9VntX8+Cd1ymGQdj1BBBIIxke1O1a81H/QvJsjdYjZZvmVdvICKme2OuemBWTzODi6f2/tXem9rK/Wxm4Jyv0MHX9D8Lad4hS2uPErHVbpipiiGxChGVXg56gAHgZ6Vmf8IH4ctLSC71DWZ4PPkzGbqRnlCqfmVQOuc4y3T36VqXOn6Lqd9HrGpaBDDqZ2RCWabc6BDlcbTg/XjjrXNvDrWo6/NHe+GWNuMxwywT7pBz8rZyVP0wKuniYVJXpT5Eo2s2rX8t79fzFOKXS/3nXrp+oW1s6eEtUWWG8lWG2hmfzmtHBGSVwSeOOcjkcVbf4bSDUrm98Q+JJrjUfKjSOe0UQbMddy85AHAAxXD61pGuaDcpY2DK8KIrXVzDcgNA5PyrgZIPfI496kvPibr2kmC4lRL64U5mctu+hyeWz69OKueGxNL3aElzyeukdra38/uHzQWkker29pJZwQ2U0jzwQsQzyfu5yjHJb075watG68O21xDd3MNteTQZ8qRi2JFxwpyefXJHvivOrX4kQajq6XWslNPhM4PmM2fP4xz6LkEHj0rRuPC89zc22oaDrCKojG+PAkSRGyR+7IADDPrggZ4rgp0atGpJcyg+a6cktUtld3XqlsdKkmtFc0Nb1TxLG8ctpJYS24IaNktTK6NzyQOn1HarcVxPeKLqdpCZACI5EC+Xxggd8EgnnnmvM11XxBpcsH9o6KVG9/mnQrGhyVGwLx09eueOBzPeeM9aul2xvHbLjH7pefzNbyynEYmgqdFrV6u+mn3io57g8pqurilJytokr/nZHo8k8UCb55UiUdSzYFY934u0O1yBdG4YdoV3fr0rzGe4nuZPMuJnmY93Ymo66sNwpRjrXm36aL9f0PPxviLiZ6YSkorvL3n+Fl+Z21z4+kORZ6eB/tSv/QVjXHi/Xp8hbpYAe0SAfqc1hYpK9+jk2Bo/DSXz1/O58diuJ83xPx4iSXl7v/pNi1NqWpXJP2i/uJM/3pDiqpweoz9aO9JmvVhTjBWirLyPn6lWdV81STb83cTAzxR3pc0lXYzDFGKWloGM20oFOopiG4pCPanUUAPimliOYpXQ+qsRWjBr+s22PK1GbA7Mdw/WsulrGpQp1VapFP1VzpoYqvh3ehNx9G1+R1EHjfV4j++WGce67T+lakHj2E4F1p7r7xuD/PFcHRXlVciwFXeml6XX5H0OH4tznD/DXbX95KX5q/4np0PjLQpcB55ISf8AnpGePyzWlDq+l3IzBfwP7bwD+VeP0nXtXk1eFcLL+HOS+5/5H0mH8RMwh/GpRl6XT/Nr8D3GG8mQZhuGA/2WyKvx6xeL95kk/wB5f8K8CSWWM5jldD/ssRVyLV9ViP7vUbhf+2hP868qrwfJ/DUT9V/wWevDxEw0/wCPhWvSSf5pHvSa7/ftgf8AdarEeuWwOSssZ9R/9avCU8S64gwNQY/7yg/0qdfFmtj/AJeUP1jFcD4OxCd4yj97/wAjqjx1k8/ipVF8o/8AyR74niWNF+W8k+jLmrMfiyEffdW+qEV8/f8ACXa3j/XRf9+xTf8AhLdc6faU/CMV6uHynPMP/DxTX/bza+5poxnxdkUv+Xc38o//ACR9Gp4r00/fOPof8asp4i0hx/x8bfqM18yP4n1xxg3xH+6oH9KqvrWrSff1Gcj2fH8q+gof29D468H6x/yUTzK3FWUf8uqNT/yVfqz6rXWdKYZ+2xj65FdBYzRz2MUsUiyRsPlZTkEV8VPdXEhzJPI5/wBpya+mPg3fG7+GlpEzZa1uJYD7fNuH6NX02Bq4qcmsRKL9ItfnJmOCzyljq/sadNx0vrK/6I9Frxv4+6aZ/COm6ooybO72McfwyLj+YFeyniuP+Jmnf2p8M9ctUTdIluZ0+qEN/Q16k1eLR35hS9rhakPJ/hqfH9JnawPoaXqM9jTSK80/LC+OQCKntrl7O8gu4zh4HWQfgc1VgO6Eeo4qXFdCfU47uMrrdH0RY3CTQRyxnKSKGX6EZroNGuPs+qQufusdjfQ1554HvvtXhe03HLwZgb/gJ4/Qiu1ibgEHB7V6O6ufseFrKvSjVXVJnZeIdMfWPDmoabE2ySeFljY/wv1U/mBXgUXhTWdKubSe11K0nuCxMtvOrLyDklTyAPqOtfRNncfarGGcH7ygn6968J+IVnqVr48urTR4LiGa4Vbn7XI+YQjZBXBHBznBBzXyPEFCbgqsLdU7rp0+7X7ztTS1ZsizUK8OpTWjbwzSMPnY4HGQGwG55P8AhRXn19b6/NaeRJqyQxW6+ZPHZw/vG4/hds8c84HeivjYZZUrRU6c4xXRav8AFIpyXSNzP8UaBZeINRt4r6O2ktoXyfPiDFSQMKrdee4FdfpHh/SNPtLK1kj+0pkNHAWwI2wFwsZPoAMc9BXDWGvWtwlu15OPtJiXMmzcEY8ltv5DPavQNHEk6xRzLDM7/JtYbwxzwwPUEdx+XavRwuWwhQjSqybt5ux89Gu5Sehe1YWVhbhxBuRDtjRV5bIyuP5H0waijvPMijiuLWKQyKFaIqJFI5zu4x0OP60zVL2IXtzcX0qi33sqiR+F55xn171zt74x0WwK/wBmwvdsAfkPyRA9j0yTXw9SLhiZxwV7Xev6X6fm0d6qRWs2YviW+0nwffX2k2AKrfWwcWcrF44GbocHqODgZ4zXm8uswPdXf2acWupXbLI8kXCxKv8ACo9Dx+Arpdbvode11tZu7KBrtlVM8sqhRgYBOOgqvElrvbbbW5djuJ8leT69K/QoZnSp0owacnZXfmeNVhzzbjouhnRal4hskXTbO+SSCf576W5USRyc8R7W4Ydz7n2qWXRNG1ItcCxhtfJjd/NtwYVLBTgAdDzjoK7DRdP1DUZmkh8Ow6so+aQiHB/76GOamSDwsviNZrhrzRblrZ7Q2t8GEJViD8rMAUOR75p/2nCpo4uKfW10OGHn0enY8ig1m7tgsVwI8bVRVWMbUA9DjOfU967DSdcvZfDGoqJ5DFCVnEKynaVB+cbc9MHP4Va8UfD1pbZpNPZllP7xFZcg+uCOGB9RXntsdQ0q9jtLqFo/lkRxn5W3Aj8eK9+iqMofuTza3teb94zstE8SXd7rFtbSTLHaAiSY7sAqvJJ+grodHXTNdvmuLy0t4b+d8QMZDE8nHG4g5bOOmMc9a80snFhpIhLAT3QBx/cjznn/AHiPyHvXd+C4n1DxA10iIzswZxt4x6A+lZYhU1GTlsFGpKMlFansfhDxBpKaNNYx2UmnyJGTEZlKxSMAePm9T+frWHfeL7LRtOF9bpJG8kZ81GDm3C9TtbGAwPTnA5BPNUdZ0vVpr1ra1vLeys42DIU/eOz53A4HQKegzTvEngfRPGt/PPcalq9t9sIlvLaOYbLp1HABIJjXIztHGcV8zVzHCQUadGqlbsr/AHdLn1FKEpR/edDK1DxVoGq6CDraXV3DqsbJFZCJJFlY8DYwOd2cdK8Mutb0fRNTezhsJLYQMY5I1yJE7MDnGD616+fB3w/l0BdHtUu9GlSfdZX/ANtbzBcfwgbjjJIAxj8q8mk0Hw1401V7w+Jjo2qsrNdrqS5W4mB5Kuv8bcnDAc969jL68cRG6vb0t6d/+HMZYZVHdPQzrfxPanEslzMCxIKxtgxqD37HIr6D07Q/hrJ4cstVfUVHnyKY57lhJOhAGVRScbgSCcD+leIRfCDVZY4JLaWCXzWwUe4RJCCeNozyfoTg111z4K8aaPpunaVcadMtkZ2W1so2L7XxknaO+P4qjF4OjWalCbTXRdfUVN06ad4tnvuhafO11LHp8kF7CGG57dQQcDG9j/Cx/TpXMfE7xLqHhuwttI0XUrVZbnJuDbgs0QGMLnjbnuRg1zdt4W8ReAvDx1TTNSNtd3jhmk5Hk8cx7ehPXnvXOazcRaxepDeSCyuCcqZTthmP1/hP14rwMFhKFGpKSu6mtr6K3kvw1ubYirJQtBWZXHxO8XixMF276lIMgSj5SBxtI9GBHXvXGSQapqtxLeR6J5ErFmeSFNvmMxyS3bP0Ar0LStEferfZyQeQF6H3966VLF5N6eSueoAXBY+w9ac81VGT5YrXc8uU6s1yzdzzjwza6zpOoJcrGVkVSoKAlsHg816/Ya94ka18xr2ZGjZQgRz6ZzXJXdxPb3ohE7KgVZEaJtrqO+fXv1rqdHWaTS4zPcGbksrhcHHbP+Nc2ZVFLDrESdp3VrdgwzalaJzmv6Pa65rEmqappVnLcygDzFgVcgcduP8A9dbWia1qfh+Ippn2aKHgFfs6KG29MkAGtG+gjeKSX5UO3cu3gDjofxrA1kRWGmPKZdpC52dS/rgdq8mjjq8pJRm7vzZ1NuDumep+B7/T7+xvLgsYbyEvdyq7ktK3LFgT26jHYVW/t43czXTbleT5goJ4715Pba7cWtw9xYK0CsuD5nOQRzxU8F9qc+nyyT3/ANjjYmNdpCuw+nUD3q8c6uIoxpydrPV337fNanRHEK2p6J/ac95dTJb6bK5WQAyPGSJCeSV/vfXpXnXiH4YaPe6jNc/2Z9ilVjLJJHcNGXZjnOCTnn0HFUbSefTrf7JZX08cOc7VmbBP51ZbVbqJQ811sH96VqvDQjhL/VW1J9b7+q6mFSt7TdHa+G9X0zwPo8WkWr3WoI6sZ2lHGSOAAxORk89OK5Syk0zTNfm1nSbOHT7uYFWW2QLHH0+4vRenauj8K+FrLxXp7akNfjaJJPKdIUO9G64bPQHsehroLj4b6HsXZqN9AxGAw2Oufyr2o0cxqLnT5fR2LUZcqS2MW5+JesaP4euJZplkEksSmRV3C2hyfMIAywfBGN3HevKdT+L3n6pKiR3FzYs5Tdc4JlXP8S8jp25rR+J3wg1+3dvEfhyQ37sAt1bou0ycY3IueGx1UHB7Y6V4zpfh3V728EMmj3zNEu6RfJZSDngcjivcjg4YmlGGJd2vvCrOUV5HrGl+MtNutQWCJbeKJySwtbdWkXj+FQASe1ds1omoeFp9X8Eaxc6q5H+kWd1EY5Gxz8h6bh6AnNeY6DZaX4JDazq2mw3OoyLm0tnjy0JH8ZYnC/QAn6Ukvxb8Q2d5Fs1LbaRKFSAY+Q5yflHyj0FRDLcNTv7OPMznU1Jan0x8MvEGm3vhE2Ed6Lq6tAS9v8ySwBuSrK2Dwc9OKxfF2paDuWyl1UreRYws4byc54YoAdxHUNjtXlOt+LfDfibSU8TWNxNoGqi2kIaGcCaMIyjfIwADBsnA68elcpf+PdMF7NZjSfObcN2oNOwmcbRy2cqzd88dadaFaUfYqPTz2Olzajbse3eK9H06T4dXsaXtvNaNEZLa5ikDlmU7unXdwcjHrXnHhrwmviWGKSxurO0ntMYe7VvMnJ53YHCqO1cxfSsr2M9rdtLaXcIeJwME/MVbcOxBBH4V1UV5p3haygu7m2vby2eTy7u8hB8tATjZ7/nWNGl7JRUI2X3+pw1JqrUs1sZWvWVnomoxQRWts15Gv7yQZdcn05IJ9/Qiqtrr93Yh91ss4RQhEQOyJM5wfTvge9e4eH/C3hzxClxrWlajZ6jpW/MZhIeZsrgpJkZQjP171UuPhd4fi0uZdPF3bOjLtaS53K+TwrL8oIIzz2967alFThyyV0WsNVTujjrn4x6loWgJpGlOVt5I/MWVGG5GJ5A4yOnTjrXDXnxF8Q6x51tf67JawXp2szdCo7MQMlc9a6zxl8KrxY216wJuLRWIuLYHa1sAucg/xKPz+tcqnwg8YXg2S2VvYKV/dfb7hIpZsAnckf3j7DHNKlh1CmoNvRCl7aTs7/I9v+Hvg7wxa+E9P1G5trW+v7mFZZ55kWTcWP3VJ4AAI6Y9ea0dWg0u/wBLvdE1C3BgDbYvSHBJBU9e/TpzXBaT8QfBelLFpFzPLYW1lAiwPChmDEKFwF4OD8x559adZeMoPFK/2XcT3OjzySkWuoIn7qZh0Vx9COhyK+exP1+tLkpJQV2ua+69NbLsd8PZqNkWtHm1XQ7byNHtLd1ExZpoolEoQAbW2tjnOc813Ca5c6lZxx65JLcMvLeQ4GSRjjjgYJHFeS67d6npV2LXT9eh1KaLe1yscZPkhVyMHod3IB9jXAaD421211WWR7oeXKpLxyDduABP3uoNZLDZnySUKiVul7p+T3X4EqapOzPTfGHhCe6judY0tljFuAZVkbiNCcB2PfBI+tcp4b0/xBo94dTTxe8LxtkJbBhnB/iJxx7YrtfB/irRdd0mQTLtkkLRyIMjaOMZ9eefwq6/hnw7p2lvq2om81O2t/8AWAnj67VIz6cmssJiasb4OXuSW7a/LQzlC7U4I5vU10DxDrtrJryLZqoZnNnGES4GR80jjAH4DJzXsOiaX4N1zQJ9DSO2n06GEB7VF3KyY6gdue/XPesT4m+CYta+FFnrHgzS1S8sxFcwQW0efPiYBSpX+IgEEfQ15p8NfE9z4Nvbo6nptstxIxt5oUJUjaeRgcdcdBX0McudGpCUqjlBLZ6/Pv8AmdGkH7636m3e/D3RvDninTr3Tb+90/RhcGNyZSz2kwXKTr/eXGee3PNeu/Z9K8QeFW0m61AeIrbaDNIdhZ2U5DbRx1H/ANeuVi8OeMfF2oT6tqciNYnelpZ7RDiJhjDcZHB6evOa8pt2l8G69dNpM13o9tGXtZreUmZ3PRlXd0HvzRVoyg/aRfltuv69RxlGmtVoyW98IaX4m8VPa+F5XEyo7pFcBzA4QZIQZyM9MdDmvXfD3hnS7/SxcXmm3NvbX0atJpEiEJbkAZCKSNo3ZJUeo4rgbPxH4au9NXSrSz/spo42jifeVKMRwQ4Oc5965nSfFnjPQLuDQZ9bkExnV2WRTK8iNgHax4xjP0rz8LiazhJVaTvF3tLt5aP9SU4Lre/Y9A8ZeJfDPhrVZPDl+97bTKsckEiW6IkMZBwFYYOPoOtckmn/AAs1tIZtT2SXzNljp0x3Tjdg/KQpzg55Gfc1g3fww8VeLfEuo6tcXUEcUju8QWTc7jnagB4XsMnpXCf8Ijqsevz2etabq2k6dC6wyzNas/lMehdgMYz3GfavXwtbD4l81KSukr+XlcycJXu1oekeOzpXh/xJp9p4OebShBAkpwxSaNs8E9wcYPPNaK/HvxlCghv73TwzBo1nEWZB23MnRj+QyfwrUtfA8c/hgWR8Wi7xxMbksmxMYD4f5lZQcg556GvMfGHwp8TeHQuvSIutaF5YK3ljJnd6bh1Qe/I960wtZVJydGWnkVKnUh70NmZmtePtW1nzLd0lmlLncVTaHUHj5F6HuetNfW9X8QWsi6jI0kelQ/OwbJ2E8D8CcZ+ntWZYeIZvDyFNPsk1BD/rHkQq3XoCD0H+PFZUc0s1xJe6nG6+cxYIibMqf7ue1bywGHjBckUpfl/w55rlPmaktPXc9h+F3g7wh4xa/ivfOju7cCRAsg2bcdT3JB6jjivV9Jj1zwPMNHKHULHBdY7VjJJGD/GoxlfXB4NeCaB4z0TwxZp9hi+yXm0+c4JkaWQdMHjHHHoCe9b8vxv1TWNKKM8lrOjt+4GMSoVO35uMMDjPGCM9K87EU6yi0ot9nex00ZRSutGvxPcdR8T2t7LbWywGzvR86mbgTIejKD15wfUEeornNd0qLxMklpqcLXbSoVVlYq4wCeCuM45rwy68aaqTa614mulkk+/Zw28ZCjH8ZGcLkjqOoFT3HicXniOe3u7u8ttUM6tY3kTsY1jxuVcDpuB5brnHbNfO08lrLEKfN5trut7PT5u33noOcqi12PT7Dwbf6bqyXup68YreBx5dva/J8gOQkjnr7jn611M9r4X1m7me70TT7tpkIeK1T99IB/FjI6eoGfevO/DGuXHiTUy+qaBL4wtLS0dooZN0atJ1Rtx2hjnCnd0HTOOd648cf2DbNqHijwQ2hXdtEGt7u3UOIWHAETHcoPoDjPNerSwyWK5sVXTlr7i0fl5syUUlojI1rwxo0NoNC8P6xrwtL+83YMO6K2453PgZOQB1zXkOt2V1ptxe28unSz2UExQXJjbYzdMiQqM5r0S7+Lviu4t4fJ8K+dbXjN5Us0JQ3aMcE/LhV78r3qzqWn3ut+B7zRLXV73SYztxYXVwLy3I67VcZZRkD6V108RXo1vZ4m3K9mnf7+q/FeZM8PTau3Y8KjN1Jfx21pCxdxjaFyxJ7ACvRbVCNItk0qaXTtehj2Mzh28okkNsZFJXjsx43Niuz8GfDHUoLWOS0hRpYFxPfK4RjnnAyQSAOmK3ntTp8s9isqTeRgPs5Az7jp/jU43HyjFThTur6Pv5+hNlH4UZfhm68W6bqVvJcaskcVsrBWiIc3QIADM4wdvX5W+b1rs7O70SzhlabQbG/vZZTO11qC/aGBJywXPCjGcCuZkBtrhLhSfJ/wBXKhGQAejA9sH9Ca05YljSQMORGePSvmq+a4pzU4TaT6LZfJjU2jnLfwv4O1DxzNrN34aeKOZ2f7HA4+zHOfmK46dyAQM+ldAvw38BWGoG606yvWmx51viZ3jjbsGAAK7WHTPTFZAvDauXiwjrjnAOR9PSnjXp5nVSAm7qQ+AT688Cuujm+Mp2v70fP/MlShJWluV4fDniXwTc23jTTNZgWBpDK9vbs481C33VAB3A89Rxjmtrxz4l8Patc2c+q6VHpGtalarLaatcI4CRbsMJo0+YHggcHOfSsbxNeajdeHntY9QurdHC/aEiYKZ4xk7GbqF5J469wa8j1zXo9XxNHpl2stsqRC6lu3nZ1AwqNu6cdMdhX02CxixdLmjp3X9foDtCLjE9ZvPinc6Hp7eHNN8SxazY3MRW68+1McO454iLHcvGD0AzyAOa5fV/DWq63d2aiC4kgmiBY22ZI2YcDYVO05yDx0ya8yli+0um8mM4wo5bn/65ruNG8cT6Hp+peHdIZbB7NQzTmQv5zAhJsg9M5424+6PrV16Um41E9Vp6IiEvbRak9Eayw6Xpthc2l5qrfbYhsjgiLCSIg93wVOehGfxrv/BviHxBJpDTataW17pUbHaEiLTr06EdFHX5uteXaE+hzESSW10syLvaeeLcnHPQDH55/DrXf+G/Gsl1ot7sigsxaktGYgEEhI4T03cAg9u/FcmIoQjTtU66bd2TTck/d0PRI9OuONU0a8aJ5cXEYEbQTRjuDxjb9ePc1uS+M4ptGWK5ntNSlYbZ4kkUOCDxjbuRvfkfSvnzxr4l8RXVjolnq9xJb6VPGWtE88SmQA7fmYHnkYGTwK4K18R3C3ItoFNtGGKbVJG8D1aiOElQjKGFfLf7l8r7m/tpLWx9I3uu2dlMyWqTRW7kLCso7nqufY5x7Vj3WtX+GitrZVbd80snzKB0zxwAPWvGhr95awNHHezRpuyVBLA9w1a8XiWaysbC80bUrgXdwG84hzu3Agbfp0OPevClk3LUdSouZyfou/y/EPaXXY9DEd1cgkRPNcA4AiYMkh7kEdfpVVJJrbxBDp012+myTsqNtI3Ix6r7c8c1d8PeNdA0+8Nj44tJUup4lc3dkApgyMguB949DwOPevQtO8BfDrxbYv8A2VqltqEasrxNCwE8QxyGYHeSTzlvyr0aOUU6iv17f1/wSoRk1eJD/wAIpq1lHPLpmrW8t264zdxFTkdm2elcJr+hiOWzXxFpSW0xuFMLod0TMWGdjjsf7px9K7vT9QurHxnceENUnU6nCqm3kn3ILyMDhlZf4sDkHOSK6yfTYr+0msL2HzFk3ZSYDL88Er3+o6exrwY4SvSrSq+zsk9Gt9Pv6HdywnGyPB7HwrLrso164sZprFZmaGC0iLeY28hnJPygcY7nAFdqLTTrGQLeeHZpVlOElaaTBb0bpj/IqfWLjXPC08VrKxktE2fYpbR9iQx5A8uUHsvTIGSD612ulapamyac6vFcspAcpwpJOcAHjp6nOK9lYWnXl7SvJveyvZLy0OdRSbS3PNvH8GjWnhqxOn2RtZ7xw2FdsGMDJyCcHkivMxxXYePL59W8WSrbIBDbKIlVBgZ6seOOp/SuZ/s+6wSY8D3r3cLChhaXJF2T137n51m9WpisZJpXS0VvL/g3K1FWXsp413FcjrkVG0JCbs9OtdX1ilZNS3PHdGorpxehDRimvLFHje4GelSKFYZDAitVNN2TJdOaipOLsN/CkqTC92A+pprAAjpzVcyJtLew3FJipAuFVmIXccDJ6mnNHtGWIUe/FZ+3he1y/Z1NHyvUioqUxAY561N9gnxny2A+lL29PuV7GpZPlepTpas/Y5ugTJFR+S+cbDVxqwlsyJQlHdEVJV9tLvEjEhiJX27VXa3kXqpqI4inP4JJmkqFWHxRaIcUlTiB2GQpNC20rthVJPpV+0it2Zcsr2sQUc1YaznTloyo9TUbIEXcxAHrQqsXsxuM1uiOihSrNhXDH0BpxCpjeQuemTjNPnj3Dkne1mJS0jPFGu55FVR3Jq/a2aXMStHIHL8rt54rCviqVCPNN6G9LCV6ztCLKVOFbi+H59gcKWB7ircHhW7kk2lCD/d71xvNcKlfmN1l2Jb5VBnNUGugu9CmVwsCFz0xjmqz6BehMgDd1K1cMzwsoqbmlcqWXYlScVBuxj0Vdt9OmmuGgKsrqMklePzq/B4du7hlEW1gTgkH7v1rSWPw6dnNEvA4lK/IzCr334B3gfRta08tzDcJMB7MuP8A2WvL5fCEyrw5yOpPSuv+Gl/a+DdS1O6v5s21xbBVKHO51bgfkTSwucYT2ivOx7eU4LE4fGQnOOmqfzR9D1Fc26XVvLbyjKSo0bD2Iwf515a3xXtnlMgZIrUHkv1B9KS6+L9iiJJDbuYz1b3/AKV6FLPMJVnyap+aep+guUWtz5zvLGSxv7mykGHt5XhP1ViP6VVYYrrvEMKax4r1PVYpFhtrqYyj2LAE/rmsfUbHTdNsluLq+HznCbOScdawnj6Mans0236M/NZ5ViVNxjHTUz7U/My/jV0LVewbSbh0ki1SEDOCHO1h+FaDTWa3T2zkpggKw53k9MDrWkswpQfK739Dm/sfFTbtG1jtfh3d7J76wJ+8FmUfTg/0r0+GXCDNeI6dKdG1tJoryMSIpDIx6hhXZR6jq0sAZsojjPXBxUz4go0rRjFv+vM+2yZVKOGVGsrOLf3bntXhm8RrWa2aQZRtyj2P/wBesr4iWtvLodveXCu8cEu0hGPG7gHj3/nXnOk+J5tKvTJKrOoUqcfpU+t+Nhq+kXelPC3lXUZQtn5kPUEfQ4rysw4hw86boNfEumtn5/M92M4tGBqWu2diXna8jtp0UlJNp3Mf7o28fnRXNWnhLSHu2fULm5vJcEGNvl2H1or5t5jgKfuzTk+9rfmxKo+xk3fgW80KzRr/AFa0KqQjKh3M5HdAOo+uK2U8Y3dta21tY2MKvbAhLmX5pOfpx+ea8nuPEyzQpd/bGMdyoKFSQVcHDAk84rPtby/XW7e4hbJWQS5PzLkHPTvX0H1fEV02nyr8T56XLSloen3d7cahctNeSNLIx3Fic5J6/Sq0tvKIw7RCKJuhcda4fU9Wvku5J1OHlYsccAEnJwK2PD/iJXkSC4vXgc8ASfPGx989K8qtlNalHnhqhKrBuzZuCONgFQh2PGAOtYV34ttvDOuwvbKmoyxZZ7bAZE9nPQ/QV6ZZ2Ok6lot4+oaekEjRMHMRO4IDzIuOR/8Arrirn4J65qd+urw6zp8mitgp9jBG2PsCD0P170ZVToVeede65eh3QozVpo+pPC2uaT4i8K2OqaRDHFBLEr7EAHlnupA960Lmws7xPs+o28M8T5ASZAyt7c15V8MbqDwuX8OM+2JzsXzD8u8en1r1Aq7SgyTbixOI16fTFehhcVHEU7x1s7f5fgei1f3rbmReeCdHgtnGj7NMYDIjyTAT6FCePquDXjXi3QNMv7bU1uLUadq9ku+5RjuDDBIcHuDjhvwNey6zdto1u9xdXkboWBjjJ+ZfUe4xXlviLVYdT8UNrlvHPA7WhsRuIKSLyRkeoJrixWJp0Jc9J8s0/h6Pvf8AzOTEU6c48skeeeGPhq2pxpq+v3ZQTgOltF1C9sntxjgV6dbaZYaNafZ7KOOGNeu3v+PUmsyDW4o9KS6hgaSFMRlk5AYdR9au2Cza9dwW6TRafFK3z3E/zGMeu0d/rXymMxWMx9W1aVo3slokv67sijRhB2itSwZZZDtijLsBkYHWuO+IHi7VvC3hiO6s7aXzbmURC424WLvwfU4wPxr6B8NaV4d0eXbYXMNxMUAlkkctI3rz0wTg4A4rivjP8Or3x74PEfh6S0jls5TKkUqFWlIB+RW7Dk4/Cvqct4cw0rVKlRTa6KzX3noeystz5fn1efWrSKOadyfllj6fu5ByCD1Jz3960dL8Mx3WtXevzx+U1y3mPCo3Rwu3LEn/AHsn2zUOiaNd6FbxjXdMnt9SSbYlncR7cAfxHnJzyMfjXYmS6ugqzv5cTH/VRjavvwK9rEYxYKPIjw5KcJOPNuTaNeDTdThniZLieEHY8vzKmeoANepaf8RrxrUu9smIiiyM/wB3BOCQeo4ryeBUgZm6qo+6B0H+Na+nX5S62uo+zSDa6nkOD618pPGYhVPaRb/roa0akoOyPR/FniC1N3Po13BEJo5NrzQgASAcq23pnB6ivNdd03wrf200ZuRPMqmQIpy2ax/idqOji3txp98s102EmEbFvLVQAvP+eleV2Wotb3y3CyZCsCfmyT7fjXt4bAzxWJeNba10i10W1ycRWk7xZ0T6zrmhWvm2tvMsP3VAVwi+4p9l8W9YgeOO+RZ0Vs/N8rIfYit/XfjVdLoa6R4eshZQiERrLKFLx+uMZB46HrXi08nnytM5LM5LM5OST3r16uBw9dXq09TmhFLZ38z6I0Lxd4b8SySsJRFeiNQls6BGbbkn2fr+lT6t440zQ5xFNI3mAArHEQXH+8O1eH+G4IJikyXPkTwzjy5N20qdpPX8Kyru9aSZ33FiTkk8kn1rwp5NTrV2pSbiuj/zOpNpI980vxbP4nt7630horeaKMt5V0BiRO5BB4xTxf2ctu5mzb6lFhXjkbLEHqyn+IYr57We+CRmKVlyc8Dr7V1cWpam2j71YCSK2ZEcN8+3eBz6EZOKitksKbvTdk3/AFr1RVubc9LvNWsoAWaRUAOQW5OP90Vy2p65dXmUs38sE/ePLH/CuF026zfP507l3UjDDlj6V1EU1tkGSMgE846mvQw2WU6MryXM0clWThojQt5HRs3FxJI//PINk1um41DVLNg8Uj26gKzmPAz0AJHQ1zV9p+ivfIlhr6yTSqGW3Y7ZFY/w46VQsLzU/wC0PK0+5KS79giD4Y4Pp3qq+FhOPtFpYiPNfltc9Z+H17e+GvFMU6NK9lOhS7i4xs/ve5U8/nX0NapZ3sMbIySxzpuSVGyjqfQ1822NrdanIz3njCz0eK3XbMsduX28EMXJwASM9M4rb0L4k+FPDc0dhoEt9qFjtCGDBePPqGOCD6kDFceDxk6a/e+8m+ibt66HsQj7OKUj3K90tJdNubCRt1tOhUSq2TG2OD+BwQfavHdM8RSXFql9PM0t/cIYmhdsqCmRuC9icH8q7xPHWgz6W+oTat/ZsAQLJb3I2tHkEbhjrk968j8QXWl2niWDxVZahHPprxxvLFbjBjuCACOePmOW9OTVZjSpYxQdOa7ednuvyFUuldHrehSS3sEam2MvmYkYSYcxkjHGa0bnw7pGqWLxah4esrtThv3kKqwORkk4/wA4rzLTPHtwQdljHaRkACef5yoroJ9Ku/FMEkUviXUw0nyKbefyEU+yr1z6k1phMTzXp04aLq7W/UyU1s3dnlXxE+G/hHR9Rng03xVpNpcXR/5BmsTNtQsc5WRPu/8AAxgeteR+L9O1Cw1GKe50uPT4pI1jQQP5kUjRgKzK+SGyQDwehFemeKfgXqrz3N7a6tNcOqmTbIPMMmOoDdc+xrlbHRY9L06W0vbh7u1Mgka0OGVXA4YZ5B7HH0Ne/Tckld3ZlUr00rNWMWw8aX9to9tplsYVjsm3xz+UrOGZtzLkjkZA4+vrVRr3XtfmmuJZru5lkbcUDNIAPXA6flXqGnWfhf8AsdtUsvC9o0duqidTGWbB4JwScjPf3r0nwtrMOi6c8GiaFBYeYodGt08vef8AaHWuDE4qnhU5zjZd9DP3ajsna54v8NrLxZaeKnfRdVn0eZLeS5ZnU4nCDhCh4bceOff0ren+K3i3TvGV1c6zrcy6ckLPHZRIvlTZ5RGQggZJ+Y9Rg4r3K/u9HuLKC51jRZTq97AyLc2q7JH2/wAPmZAGM5wTXg3jrwHq0kkF3pOgX9zbOD5kkkQEy+gbaxDj/aAz60qFZYmCrJ6Pb+u50yvTSinc0B468Z+MND1K/wBC1S1iiSYO+n2p8u7twq43R8Z2Y5JB+tedG+vWu/tEt1cS3bfMZ5JSZA3c5zn8c17PoPwj0nTvhNfXU3iKws9WnHnG5lcrHARg7GzgoeMZ9z1rkvh54A1DxPLLrL2sWpadaTCGW3tbhfMnDA5KnsBx7nPHSrktHfboXOlKclyX1PNpIZZGDqckNna/8XvmrdlqdzEUlt7pZAr7gQ+QGH8jWp470VtI1G9k0dLm2iS7Nt9hvFxc2h2hhuHRgeQGHXFcta+GNVttSMjpKxeD7S0VuPNL84C/LnByc+wrV0tGpNGMcPNq76Htmm6va3F666gWNzeW8/2eXbkXD7DjJHAAXge+arfDz4fal4p0k3iaZGliMhJZzsMx77TjJH6V5xBPrWj6ml1ezXWnQu8SJYNIwBwAC5X6fqa+vvDd3FbaPaeVJsiSMIozgAAdADxXnvB8seWct9bot8kpW7HL6V4J/wCEacTanoDT20a8fZ2yo+u3npW4uleGNatbnT9Hums7tjhY2m3LLxnaQeldlHrSs4jkeNGcDbCzYk+o9aw9b8PaTrjSTGJtPukw8Wo25CMjdj6Eg+tcby6EdPjT77/KW50qyVkXfBHiC0tdFm064H2UaY3lPHnJTnt+Pb3rl9VsPDlx4vk8R6VpVva3RG0TbcsTjBbHQE+wrhbSw8aaH4hvtQ1S8Gr6bffLNfRx/Kzg/KeOh7HtWums2qw7rcNNycY6Z7189mOKxtCnHBU5PlXXr1sr9inVTSud7YazNaqGl1AqCed5rzrxX4F8S+NvEd7qujavYrNJ9yJ9xKqBxz0B/wAaYTd3x3TSYVeihvu1ftJbiwYSRSurdmRiK4MBjq+ClrPmV7tf5X2InKNRcsloeHz/AAp+KDXzpeafJaBWIEksn3sdwByatMvjDw/ZSS3Jmaa0OyCXUbfcGJ6iPdn0znNe0Ta3IZQLi5bcemTkmm6lrO7w5Jcy2BvrQA74iu5hjvivqaWf1MRVVP2Oj8/+AYKnGKbizzyPxH4u1zwnpsdzZyyTrJ5jzWQKiQA4VW2jCke3Wuktj4ovkgF/f3ltax/fguG8wY/uhT6+/wDOvONV+Kerw3MkfhlE0W0cYaOFQu76j1rrvDXj+48UeF77QL+ZDqZUPDcH5TIM/MpP0ruzHCyp0eeglHv5HPTqqc9ZM7GPRdF1bRr2WbWGvrKdzOloiqHglB6JJ12Z/hORXFa9oniBbKHwlpk+oNpUl01wGSV3wHXB8w+mR06c5rr/AAr4Rj0TTZ5pria6uZxv2o22NfYevuaseJfEWm+FtMlka4UzbcIgGSSewzXztLNXSrqjh26l9EehJSnBc7sc7oXgPwP4TSP/AISSY6pdS/OscwxGjegXv9W9Kh+InjnwhoGn6faT+ELHWLt4SYpGAjVecEbVGAMe1eStr1xc3pe7LypksSXJJH19qe9hPrnjXSLO6jdLQBm83b5gkRTuI3D16e2a+6nF04OVWWiV38jghUTnyxSt94aX4e0rx415d6XaX2ivEMosiCa1JJ5VXG1ge+MNXTad8JNGi2yavfXWpkADywxiQepGOcfjXqVpa2tjp8VnbQxQwRBfLWJcKgPYCiWM7CYo/lyQQOi8cV8Nic/xFWTVF8kfx+/c0dlsjiNX8A6TrVxGRfPYwW9ukMSBA/lquccnr17g9Kn8KfCqG18Sab4jutXj1M2VsImjVcL5y5VWIJzjZt4x1BqXV9S8stawAGTG6Rc4IA7f1rj9Y8RTpKsVhcPCVbcXQ4JPoPQVthnmGKh7CNSyafRbeu+ovrahufQjzzRIqo4GOQF6AfSo0uEd3guIVmhfKvG6hlYdwQeDXD+CPEk2u6bJb38+L6BcEngyL6n3rYutfii1W10vTI21G7eQCbZ9yBSeSzevtXyUsBWjXdBr3l/V7nZCoppSTPIvGGqxW2r3mjaJGlvZWsxjhjiJCpzzx3+tZP8AbdxGixxOwXG1xnBP416prHwJvIPEF9qOoeMdNt7e4kea1hGWnmQ/NjbwA3b0965G88MX+lWs8dv4Hv8AU5Wb5JridSoUdCEjIyT7tiv1mhKhhIqjVklKy3auzyq9CtKblJaHc/DLxtoDabHp3iC4YmwLNCjqTuB5BGOpHIwfqKutqE2oTXKaT4PTVo45GkNxMvky4Jzjgqfw5rxCS78R2cl099obaNEwVAkcbxBD6g8kn8SKuL421m2s3tY757iM/dklyXH+6x+YD/OK6o4eM05R1i+1geIlCKg+n9dTsNW8eyeTJaWmmWcZYFXDAuyDoQCTn86w/wDhMdZ8jyvPR02+XhkBO369a4OS+uXdpGk2knOFHFXpbuLyrV4pSssu/MYGRwABkfXNeFVymFO14p3b/wAwjW9p1OkfXr+QZeGF1HQ7cE/jXW+A9Hfxbqj3OqThNL0/GYiwVpnPITPZe59e1eVW4vGiM4u3O3jaZOfy9K2/DPiG+8N66mqwky7jtmiP3Zk7qR/L0Na0sBGMuZxTRUKkbq59SHwp4Sltmkl03y3YA+Z577gfrkiuI8b+A7HWdCmSze0FwhSSK6MapIyc/IwXG7vgj8RXQaPr66tYxX2hzQT2ZUrIJJZC8PfDIQ3OK53xvpV5q2hLqWkXx0u4srhHVLuTy42APBzzs+h4+laV8DSnFSpJRktmla3+a7o75NW2PIvB/gJL3UYNb1U/Z7eN90QuWJEwB/1mwcgD3JH1r3vSbDQNIXbZ6TYKxO5pI7VCzZzlsgZPzV4Vrl7q0Piu4sbuaW08pvKWNxukdM5G32IxgjtivRfDN0sMoK2aqQAEa8tpHLccgliP0H4V0YfnlFVKm7+5dkc8ZWbij065vTqNkkccsEWzJZY5xu68Yx3x+pNeX+NvA+j66DHDfQadqXL2zzAQpOT/AASDAGT2b7w757drcahdW9iZb7RIrCDBP220hjuYMerDaGUe5A+tc3rGtwWOg3FzqOp21xaTL5aJEGZH3A7SEYsOD3VvX0rueiuzpeqszwjX7bxJp0EGiazE9itqHMEdyo2gOwLFTzuBI4I49Ky2isUjRLiYQswwzr0ZuvQ+tWvFWqalcX02s3trJcLLDGglXIjLBQN2QMA8cjjkmn6D4E1XxVaw3l28elW6DzC13IEYq3Rgp/hPYmqjCDXNY4XCSd76GZKsTxr9nV9ob+9ux+VbnhTUrfS9UV9SR2iHzo8aBmicdGAPHr1BHrXeaV8FZbjTzLDqUKnkosbCYyAd8qcc+nWtj4c3Y0DV5J9Pur67sbSPzLzT3t1RZHztYfN09s45FOtyyhyN79h0+ZSTa+88m1XVL3Wtcnkeb7TO8m3eiACQjgHA9QBXZab4e8V+FrC5vYNJuGllUeZMmPMVD2XHIB7nqfpXpfiq48Ka3qFt4l07SrJrZ45GiukZopmlRcmJ1VcEDnnrwRXjk/xCvrdp7OzaNZVJZJohkvnnljwB6ce3FcEsOqkVT6dfM1bdOblcl0u9MXi37TfaxqFtqNnOqxQJDvcOp5GSwCgd85zXtOnfGySaeZbvTUvLQSts2DZIqDvnof0r5euNYu5JHS7kVJ5mLPMrEySk9mfJzU2naxcwJFaQ3TQRGTDS7clFPDY9R3xXPVoVkv3TsjdVUvh3Pp/UPFvhjXp4L/Qb2YycefaXEe5FB4O7PY9OM59qTTPE/hyWz/s+wmS1WBXkNtGxkwM5Y56n/CvnXQk1iDxlKLa+S5tNsqtKhwsqbT0HUZ4OKoWur39lcLKtvGypIGXK/OuOwbryOuc14tTKZV5TjCpZNJ2Wmrvv9w5V7Wbse/P4k8J4fy5SwGSZBGTuPUj3NV9W1RLeOKMWckEV1F5kLlB86kcEg5wP1ry0Xc7xQCdgI0/1b4/5Z/eX8QDg/SvUI/Etv4n1DTozBEkwMSQQbxHtRQAcD3GTisqeWUoe/KUperMHy9Iq/ocnfvqbQQLPOogdQymJefy7ke9Z2sRWo06SO0k86/jZM4YhGVs++M8da9D1PXfhrbX17pd8bvTryJiGWVQQSeQV259iO1ea3fhmPWbuS88La79tC7i1ncERzsc84H3XH0OfavVo005R3ilrtoybct72uYSJdwzvHexvA6DPOePqDz+NawvtKtHCSltRQ4O63lKZHcYIzn/PNJBb+IbW6j07WdMnkg6xeZGSAPZh0H402+0OwZDJGFgAHmFTIuQO55xxXrToxnu/uOdTe0kaXiI+Gf8AhFtP1PRjdHzZGikSQkZYDPJ5wR3x168VjaHfmWCeFoVeQbfJc5OMnp1rLmn0pbGJbGadjnMqSgAbvUY7YqG0l83i3Y5U4bb3rneGfs3F9y+dPZHVahdSsqSzRLmEkPE/Yg44rNuNRScKGkkeJW4R2596q+VdzMEkZ27qSTwPatrRtMt7W4hk1azbyWPDbfvH/Peso0I01qNSV0kdb4Fn0uKa2XUYWkWVm8hZgfnHf64r3K68L6PrFhHc6fD+4mTaRGcH3r5o1m21ptdNpa2eoTMqqYvLVmHlkfLz0xiu+8G618SvDVtPCLRJLOVSBDdyKhVsYBU5yDXj1qVKMm61RJS13V0+jX6o66fK/dlEbr+qWWieKpbZ9IWKO2DK5BG5Y/Xnk9jW5Zrp948XlGHEuCOOvfNeL+J9L8V3N2bzUzcXt24CynYdwx0x/eHuK3vA/iSx0aaG2127EVzDykZyxAHZscA+1cGLwC9gqmHqczW9ru/yK9nFys4q3oe2QeBdR1Nmm+1R2TbDsGzO70BJ/wAK8s8WaPJ4evtviSQLdJhgEkYLtJwDx/Ic07xD8bdWuppo9DmktbbbtSThWHvjnH51x8mgeN/F8Z1u8nl1GFceZMZhNIqnodgJIH5V6GGwbpQU6z5Irz1fl/TuaTVOXwK79Dr9B8PaZ4mmjng8VWlmkbjfKXZSq+nPQ+meDXoOsaNqWjuqWNlHqQDhUmj8sPImOMjPPueK8jsPh5e2M8s9wJTb7QUuEXCgZ5LL1BA7V64vhTVtCRdU0mV7yyRUJi3iRrhB1PAxWuJdLF0eXDrmt5v8f6Wo4Qi1aUTgPiFb6/FYxsLLybI8zxRKS+PUsOB9B+tY/h3whqnjSzt/sswXS7bKSzzHBjPoCPvnH+RXq3iDV9Tv9KvNK017iE+X5iW837lkJ6Yb0qt4L8Q26acPD+rWMFjcxZZhFwrP1ZjgbST14rhWb/VcG6dOn78Pn03tv8y3Tp3S2OJn8AeGNH1AiTVppZTnZEZtmDj19fYmuXlntrO7eGawklKn5GmyM+5GT/PFezeI9QWMJaaPbKZZhlGmiBBP1OQK8i8TT68Jo01HSnsk7FFG1j3wRSyzHYjGtLEPfu7P5JWOXERjBNxO68P6FaeKtOkltTpK3SJzbz5D/wCBz+Yrn0W50/XRp98wtBG21gx27B7GuBF5Oh4kaM9mB5q7bXFzepIovwpjXPztgv7D3r2q2DjyWTOWNRStoe4WU0ElnGtrcrIMffU5yfXNXZIblQ5kDdMsWXP4nNeJafruoaRNmKfeDgMrLlT9a2774hte7TcmYMFCnncAB7mvkamUYjn/AHTuu/8AmdiqxS2O9nvre3c7pRgfwj5qzpdYWdtkMZPPGa42PW7ebH70MW5BzmrhvYYkAaRVZjwM0LAezaU02xe0ubNxPcOn7xsKe3SmWMNx9vSeETGIYDYU4z2JrGn1q7lukM9xl0GeRnA9K1YPEl3FCY7Yhd/8QGf/ANVejToKmrNaeQuZHdRRS38i6dfswhkXBB+XcD7jnFEnw70t4XGn2TWxhcN8kjEP68bunvTdOgu9e0GC5d5S8fD7D8xx2rVTUltl2M/l7BgSRk7l/PrXLVxX1eapT0jLtp877HXBRaucZq/hvbbzpHfeWsZyIpVBH54zTvDVreCFo5rmE+cdoyAUC+/qKj1jVrudpo73UftyLlo5eMlT1Gev4HpUPheWa6v7SyhlWGJAEIYgZPU4z3ral7epTlSjLnSaetlpbur9SHbm0O90vQPDem2BgRDqJIJPm42cnkbewrm9a8C+C9VkjgOnPYckJ5U77WJ9jnH4V3VnpYkbbHLDLhuF2kOuO5J707WLe0soGuHX5im7BGGJ+nalisTjsPFYhVPVK2/l/VzoUY22PEbPw0ltDNp1t4csdKSUMgvp7lpZ89MjI/TjrU0nwseRDcw+KYpriPG5LiFlBHrkE10+ptbah9mb5YjnqwyQPSs6TWl0qQWNp5s0kgLYC5+tdsM3q1PflJc1vhUb/i3+pytq+i0KcHhHTf7PeCZ2F8GOLmNj5eOw2mr1iuvWTiO41KG4ijAMbICGz2zmq1tfXd4jtlYlPTcCM1dQSLHmTn1I6V4dbH4v3lOS18tvTsTdbmBd+Lmh8UvpF9au0k7Dy5VGBk+3p9K9A0rwxdXwNxHFC6DG4lsYHtXLSF2uVPlIQg4kYAsPoe1XIbyaE7kncY9GNc1WdKTi1FrT3rPd99tC4yXU3dXMWibpGtFmlkOwP/e460VHpz3+qsSssRjiGWMx5/Ad6KxWG5veUNH3Zo3J6xPkO8tFm0mzsdx2wrtLqfvHOT+tdJpdza6VpxWVfMmYBUBP3aj8P6Bdz6ZYKltNLOybuR0ye9bN94Q1W2mBubNwpHytjIr9hXIrRbPmK1RuUuybOfmmedi5GSeSTVW4vWsNhWPzbhvuRL39z6Cuhe00zRoPO1B5JLmTiG3TkuayrbQ/HXiO7a3GgAYOIyqBWVfQmtXKL22Fh6XOud7fmeu/DfxlYa3bRaNqN7Y6brdqdtvdSDBkiPVM9OD610Pirwr8TNBittW0TVrjULUyF5pLZBsK9iVXOa8svPhHqWkeHE1HULkWFypJlkJBVF9BjnNTeGviP4u8IaPNb+EtXu7+KEFpJLsfuUH+yprxfY4ec3ZX/r7j6KjWg4pVPdsdc3xE8IWfihG1u3aV2RUe5jBjIOOTsJ+XB/E12D/Gbw5psMSabqqXCjIjMo3OARwP/wBdfJus61q/irxBe61q0iz3U775JAAoJ+grKaRFO0LyOuDXMshhB3pzcX5GlSvCMuWKPqw61qGuOLhbhbmSc7grSAMR7CvMfFXjnV9M16bSobQWbQvjMq5Z/f6VyfhnxDHNDDpF7O0ZjcPa3Ct88TDt7ivWx4Zl8daHFe3gjvNRsZ8RzRrtLoex9cV48cvhgq/76PNF39fJ+fn2OfkT1PNbjxVqen6tBLpd35ctt+8k3AMrynknaeK9E8EfEaTxB4hs7LVdNUXzMR9otxtV1xk7l/rTdJ8MazYaw1jB4fgAJ+aa6iBLep5pNcuLD4dsx06xjuPEF3yX24SBCecVpjIYWtD6vGneq1o9mvNvt6k0qkpystj1q5vCFItzsbsc4xWvoPi6707ZFfN9pgHBH8WPrXhfiD4r2ei2ccEa/b9QZBnGAgOOua4+w+L+tXGoq13BAlsoLPHGOSB2BrwsDlOYUl7eiuW3W+50KU4ytFnqXizw/PrHiSbWUv1QM27Dnnr61gz3+k6exXUdbt02DB2fO/5DpXe6JpGieKtAs9et1e9t7lcvDJKQVPcYBqHXPgNoc+j3V34ZlfT79kLiKR96OeuOeRXbg4/WZeyxU2mvJfn/AMA5JUkm21dniuufFTRtPLWug6dLeTDj7RdDav4L1NcRdeMtf1OXzZ754+fuR/Io/KvTvDvhi4k1waNr2iGR848wKMD8a6nWfgL4f1G3eSwu5LG7xkKMFCa+toYfBYbRR17vX+vkZxqQ2tY+drrWNRhnEX2hGlZcFHXPBqJJZFiyowp6lema6bxN4M1vwNdCPUNISRHbi5B3Bh7H+ldBp3gbXrrQxrH9kzR2hUOpcAEj1x6V7kIU1FNNK5GKq8quldHnIiubhdwVlXsSOtK1tPEmQS3qOtdjPYbCVOB+NR2UWhyTbJ9WjEoOAg6E+5rWUIRWp58MW5v3UcmLybT47XEW8NMJ2jYZD7TgAj06/nWgBHdO8ttF1w4QdMHoKu63f6THd/Zv3U8luCFeLnA69e9RP4ktLG2tRBp0UxuFJ84sQRtJGMD/ADzXHKnezS3/AK/I9JOU0lyk7WICF3YKUX5AvG5sfpUEd9qtxDJA6JFKsflKdvYsDz60yfx8YobWa20C0N0oO9pcujMDwdh46Y4rL0/VLptVkv5lV1jXzWjPCsc9MelE8P7ty6VKpF3lY1rzTb2xtTqsUZZgu1WUZBb610fgjRPFniJGb+z/ADIBwJXUjP0NUL/xlqeq6VHZOsEVsDuMaKAq/SvZfhZ8WdKntrfRNZiisXhASKdQFV/qO1ZLmUNtTHl5o8sjmo/gxctcG5fUXtrzduGY8gH1BzXOa34E8Q+Hr5JLkF1lbdHdRE4Y/Xsa+yIns7lFlkSNxjKsMc1yfizQpb/wlqNuo2O4MkK5BIKnI+lKFZ311M50Zcvus+bP7O8UtpssDK0kEgxIw5IHfJ64xVzwh4Aln1aK+i1G3l8olltkk++ccA+2cV60uh3mh+H7JInH2y8iYtuORjHTHrzWfonwkktIf7Y+0z2zwfvdhkHz45I4rCrTpyhKK92/YmlOrGST1PEvEWseOLbxesevrcW9yF+zCGWLEZiPG0DoVPrXWWWk3E+praJY38thcKI3mSEtCuPuMD2x6mvbNQ01fFd9ZXt3aQPbWgCQmYAk+pFX7rxH4a8KLL9r1WO18hNzQ7gcj0C1xTw9JxUYLl0tovufyPSlW1UUrnhkuieMbS/m0qSxysz4SeQ7EI7YPQ/SvRNGh17R4EuNVtJAhUAzAZUY6HI6fjT9C+OXhG5jns7+3lNm8pMbSqCQO2RXouk+ItA1e3e70TUIprV+JYcjKk98VlCUqcLTtHvpYxng7S5ovQpx69Z3Gn8TxyXGDhBjvXmviTwdoF5rVte2SPa+aC00CHgn29K63XdMt/7VNxb2ixwfxPBjlvUDtWDrcz6Jp/2tM3EStgI2MqT7149XMsTUvSorV6Jr8zKpCLXv9CtZ6Zp+m2pjs7QRsRzuPJ/GrAuhbYeKPDY5z61w114m1zUZQIY0hTPAU1jaro3jG4gN9a308yNy0QbGPpXJDJMTWd8RK1+7uSq8IqyPqTR73TdY8Hi1nW2lHlkSwhwSOOfcH3r5g+KWsReC7+3tfBniPVrSQyFhBK2+JB3Ksec5xxU/hKy1iOznuJpZvtwOFhkk2hh9a8x+KR1CTU7JL2zksmiVv3bnI5Ocg9819Zl9KUJRoStZafcux1Qmq1mbV38XPEOrW2dUgsLjU1QLHqfkbZlwR1AO1/T5lPWuWs/Ems2XiO51C11a6spL5z9p+xt5IfPP3VwOvauNYyzZjRvnYgLtNd/B8PdYhNiWhe4llCnYn8Lehr2JUqVJWfU9Ohhq1Z3i72PQNO8cy6omhSeNNMj11tHuPOuJo1AuLlAuESVj/rAoG7H0Br1O4+Mvha0jjm0HwzeXAkUvlNsQRj/eXoB9K5Pw/wDBzUr6RtX8QgxSTtujjt5whiXGPm9SR6dK6nUfhJplvbItrbux2AFA42/mTXn1GtE2Z4qqoPkir26nlPxH8bT+KrjSrMWyRQW6l2xHy0hPJz16YH1rrPBvxXutMt0sPEMUctoke5JApD56Yx3NR6tpXh3RJJ764e3N3ECxYyh23Y6Z/oK8VvtdE9y889yWkJJA9PpQoSqJKPQ8xzi5OUIu59Fal8VPB15rFxcK95G1woVTs24wBt759cjvWpqfxDWa3g0/TtghiYGRBJhl3DglfT+Wa+V9Fu3uNehZ13iPdIcn0Ga1Lb7bYawdYhv1uJpBlwOnP8JrmxGAqTk4wm1pt3/Uqc+SN56XPQtY+IPig339nLci3jV9iqBuBGayL7X72XU20+0vJo1iOCFOASetdBpFra+I5LfWIbYBY4y9wmchHX/GrY+G93DeXGtRyo1m0ZuS7nB9cYrz6FKjdJws0vxuZOTSbepyWg/2+mvwGHUZoQZBvdnLDGeeO9fUfgyDw3c6XejWb5GJbKM7hdmB6187WNtdJMNQjgAhRsqGP3j6mszWrnW7bXHtFlkRLsCRUVuCDWmMwHta0ZxjFpb3W/8Aww8NiYqL5ke1+NfhjPdyyax4a1+K9ifaYoGl2tn0B6VR8N6P4k0qdrXX28lGBLRsdx2+xFZ3w+tL/R5IbzWriS5tmIURK3EZP8R+lfQCJp16VCmKR4wOrAkj1NeJUjTxEXQoySadl1+653xoxa9pG6Pnvxp8CdQnuU1Xwwvn2dwnmPG3DI3XA9a8flsLvw/fPZmG4tbtc7kkQq1fc15NqQjkgsmjVCMLuPSvPPEuoJNqSwX2mwSSwLhZioLMe/Jr2quYrB4blqJytpr1+ZzVsNTb5oux5h8Nde8Uaoz2twwjtLZCUuJQQd3Ye9VPEms6Jd+J7W18YaRJcRF96XVqWCBc4IYenfivRbS7s2k+QrCwPTgYqXUtTfTVWSR4Zo2HHmRq34c189hs0wsa7n7Dlb2aev8AkbJ/u+Vu5w1l4L0uy1XdZ2iXFjdfcMrBgV6jFb82mWOn+WYoliVQUAQBVGf/ANVdBpWu6V4ogMV3aRQRWfKyQgIB+Vea+N/iZovhy8l0y2s5b0P92QnIFXXw+Mx1XmpXkvu/U5oUFC7jrc6t76ONwpHJAHynk/hWJq+vtZTNBABPO5yER8PXEWXjnWtcZZ9J0ppQTtJ2cg+ldPYaVr18X1O78OyoUUkSEIsjfQZ5pwyTEU3epC/kmZyn0W5yniu8w9vcRNMLqaPM27GQfQEdq4m41a3tpEimcrLKdq5BIzXWa2NS1LVhHZ6TqBjCciaDbtbuMjr9axX8Laxbp9pubCYRlucpk19hhYRoUVCejOCVO9S819xoeG9fubDxBaQNGVErAJMnHPcGu5sde8QeJtBTTfC1imkywXZ86/U7ANpPK9y2eteaTapHommR3p0uVZjIUtzN3I6t7YqfRfiR4itZmu/tEKWkfWFEHzk9gPX3rysXgKlR+2pQXMrWu+vp1366Hp0YtLXQ+jNI0/8As+1Bmme8v3GZ7uY5kmbuSew9quSF8bhkDp64r5tv/jF4ymy9s1rbIDkARbj+ZqceJPiT8Sru6i0Jriy01Nu6FJAAvHIL8E5OTXz64axtWbqVZxV93e/6HQ6kYq9z2rWfF+h6JA39q6lDGMcREiRm9tgr548W+L7DV/Et3f2FqtrasFSGIIEwAMdBwMnJ/GuntPgP4/vLeWcR2kkmMgSXGGc+mTXF+Ifhl428NXKz6zoNzBCT/rFAkT/vpcivrsoyejgG5Rm3J/Jfcc83GqrS2MuLWbh9wFj5jDod3H41be+lYWkrwmN45drqDwwOP0606yhiV/KTavPIPX8a7LS/Cb63YyWcklqts0qyLIx2uCvYH8uOlfR1KSnG76HnwqU1O3LY5XUNTt7GdbcSs8hbBXpimwvrD2rXc+mXdvAAWMoGVC1RtQ2oeJg1vCZ7l3IVY08zJ6YA7V69Z/DzxhLErXVl9hiVOWupAsZDcbfqc9K4qnJThq7HWoqm1FRuebeGvGfjPS/Egm8LwXU6qQmEi3b19H6jn0NfRWh/FDRrq3Fr4+0a40V7gNHIFHm205HyNnGSuOhHOK+e5b/wx4R0m/ttJ1O9n8QTu9vKsTFILXa2OCeHPB5HTsa5eSa4ttN824uWWWYgxQsx3bTyWx2zx9a5eWU5e4uWO2qd35/0j03CMVsfa0a+HLOCwNjqdlqWjsPKk85hI0EQ5TJI3AY3Lu4/h+taI0LQ9Q0ORdOmttXi3F0tppBcJGe21j8y5HHXGce9fGHhvxFrkvhrX9LtZpDttg6Ddyq7sOB+BqPwb4gv9G1Ka/tZilxbBZVGflOGGeOh4NZU6dWk6l7OzWnql9wOMHa59WX8ui+EtOi1zS9VfTbePJltfMPlSqR0VWJ2SA9hwa8O8SeMI/EuriTQtOh0+2R8tC8Q2zykf6xl+6CemP51bv8ASW8YzJJoPiqC7d0aU6dfPtkR25bbkYOT+X0rLtfAHjmKGRYPCt55ncphhx+PNJ1FWjyx37f8A5pPl0S0OLl1zUJNTfzWFszTAy2u3bECvUeX05/xr0G++I+t+IhGNUsNId1I2TG12CMDsdvJHtisfVfDPie0ha91bwveRWsZBM00OCpPGCepX2NdJ4Z+DF3r+gpq8XiRNNecbooWiZ1x/tnIx+Rqq+NoYWCeIfItv6sW6Uqkbo0NGgnuI7i8j8ZxWk7xsgS1tmxsxk4AOVHueR1zUnh6TRdJmeO48Y2aSycyybi8ajqMA4EjA+pwD2Nbo+HXirT/AIbXmif2fBd3k6sWa0dMttYbfm4JyM8GvnPWTd6Vdy2UySQXcLFJI5DgofQj1qMPXhjJtU+j+9d15D+qTVm9T0zxN4hjsr/+z9EvLiHTY5VuIyzq2+bHMoK8AnPIrhBFe6x4h1XVru2RIolMpigTZECxwuAOgzzUOnHVb3QvMmtt0QOVYjk47imWfiLWNPleDT5SqyDbJblQ6yD0IPWux8/K4QtdeZko2k0aiaazbXkn3EAZYjr+FW0htYyGZSTjCgjOK6LVvAXjfRNHs/EGqaN/Z9lcxCRlklXEeegIJyCR261xz63aiZomhOOm4Nwa3jOEvdSPPqUqyep0GhK8viKCeyly5yoQngjBz+lc/d3N3b3BVWMsTZIKc4NVv7YmhmWSy2wsrY9/wNej2/w98R33g+712ys45YYkE3mRuMlcZbC9TjvWPsoxqOa6pfr/AJmijJRtIwtHu55NBe41UFIrc5CpgNKx+6nPrzk+grmrU3Ms7yjzPtMrbi2Tlfoa2rG3kOgF70iVlkaSM5yDgY5/OsePUriKRDhg5GSy1zYdKVWaiup01HLkXKbElheXVz595OC7ADfK3zNgYFdpovw/8QvYi+s1t70ld0SWt0u8/ga5bwnqGhSa8jeJpZGjB+6vRvrX1H4Ks/CU1sZPD9xDINg2rkFoiO+eooxM5UlyxWpzwozm7zPKf7T8Q6bo7WHi7Rr62018KJBlZVbP977pHsa5u7j8OeINTNppusxWjH/VpeowyfQuMjNfVVnp9ld27RzrFPtY70Y5Ga5/xJ4Js7hY7mysrMLE4Z1eFSWTuAw5B9DXm0qmKhacop37Pb5W/U65UIuNmz53u/hL4wQKbC3truOTB3xTLj8zWVL8P/GGhXLS3ukSpGo3M8YEqAe+3PFe0v4T1zR9xsdRZrcMdiSnOF7YOf51a0GxmuZbiSe4YyHGQzdfpXnV89r4eTp1Kab9WvzFHDwtpc810fwlrWqQq8moabYxSLkFpMOvttOMfnW7H4Kn8M6edTvHGoyqcqbdjJGPduOKzviVZa1ZXMd5oF7P5cSEzKr4IbPp3rzrS/iFrEeoQJeX1wu1sFkJQ/jtxn8a2hVxGY0OaFknuk9V5GsaVJPbU9Dm+K2r2V2IJLKC7jGF2S84HtivSdH8RaX4n0uG4vdAigdPvSSMPlPrknIFedR+I/DniW8NjqOlWthqDqDHqUEQXzj6kDFcP41uNe8JXwtWuY5oLhN0Utu5KOv88+1Yf2XCpL2dGKhJ7t63X9fMOaalZ6o2dd1/xZZX9zarfeVGWYIVVWUjPG1sfrXmE7v5zsqliSSTjvXqfhT+0NX8NK+o6X5kkh/czbMnPY4710HhD4Q3N7dSXmvqkcW8lXUgZH+6ele/hqVHDJxUUvRbnNzNys3c8ALuT80jbfrXZfDz+1Rr5j8O30dpfshIaabytw7gHofpX0Onw68MWKSSQ6dBcMFIzNgg/gwxXgXj5tG0vVpo9HWC0n2gstvkAHJyPauhzjWThbc6qF9dD6YsL2fTtFsrzxZe6eb2MBWml24564ZeCPrWh/wsTwzaXKWWr7bWNx+5vLfBicfUdK+GF1rUAxZ7uRkHABYkVLJrmoy2mwzFUB5IPB/CsVl8qcuai+W/Tp9x0JySPrfXtDttQsmNnrqajbiRntIYW2YUjOC3bnt0rz2w0PxHYasWfxNYu8EoY2sD7mT2DEY/I15d4W8baxoE8dzY3fnJGdzwSLlQPUVe+IXi3V77ULXVIPKsI7qIN/oo2hsdz71588vnKo1ZXl31WnrszNrW/U+ktU1a0u1tGu75GPl4O1QrR89D6msVpbSO68oqt5D99S3JHt/+qvmGDxxrAsw011JdGNsfM3IFXP8AhO9Vuo1jGoOgxgLu2/hmvLrcNYidV1VJa+v66hLnvse0+I18M2VpNdyacgPXk4Zz7H+leRzX0kupebbxpHGWyExwB6Vmvd6xfSokkhOSB+8fI/Wuk1TwhqtnpBuIXjefZuKxuGx9K9rBYB4SNqk+Zv7jjqOKaI7m/hyShUv3QHkVnSzDOVOQe9c/ZTR2t2rXrHecqyt1q3YwSSaqYUcMGyclsLivUhhY0loypU7bGstw8bKUBJNaUmqOIY2iyt1GxD45G3tWS+padbXIXPnOjDIXgfnWfe3k97qjzWaCFJG4QHpUyoKTWgoQfVWOqi166eSTzEjcy4BO3kfT0r0Dw5oV1qVvDcxzxKrdTJJtA+tcb4M8G+ItbS4v4dNF3DbDgMwXe3pWxqupeJ/CcCwarALNLgF0Ee0qMdV4715OJo88vZ0Un31saRp33Pb/AA7o+vaXKXtjbXkDY3RwuWOfUH1rR1z/AE+yks4pUsZznfHNBk59fUfUA18u/wDCxfEEUbDT9Qnt938avjFbVl8cvGKWwtrl7XV9nAa7hDOB/vDBrR5ZOVF00reTd/8AJnTDljpc7i48N6s8KTW8cdyiSNFMEkGFzzuz3FV7DStF0mVpL0XM8sh+9vKqh/2ax7H4vi7WdL3QIYrtlyk9u+0AehXofrWZP8VtR8Ryw6JDaRRWySj5Ao3N25NeY8uxUJOFPRJXbXV9tRyjFK6Z7Po/iOO3Xzl1MiCPlIXmVWc/7THnH0rZ1PW/tdrCGvLJFkyweLkMf7uTzmvkHxUdU0nUpIJ96bnO1t3DD1BrFi1bUGQR/b5goOdokOBXZUyipicPySqKz6pa/mCk4n1Fq97p+lpueUI8h24xyPeuY1G60x3tJba7Y3KyD514wD15rH8GzahrvgrUDczrci1Q7WcZZTjsTXoui/D+y1bwosWpyAmRBIHQ4ZCRXk0ckWHfvTd1+JyVKjvoY9zrumW0I+1XUEaqMA55NYs/j/QID5cLPJz1YcVLc/C+8ilitVi+227OVWXcPl+tWLn4J4QPFclT324bH4GtaWS4SP8AEm3cxVZ3tZnKal4+l85TYWrGMdSF+9VEeMfEcyFraxAA55FdBefDLxbosbXthPFfW8fzbBgNj6GiGZJEQ3WkBZu/O3BHrXprLsLTiuSCkhub3Rg/8JB4v1GJYbezljkByWjUiivQbDxFdRwgmxSFAdvmJg4+oorNYfl0hSjYrmb3P//Z"), linear-gradient(180deg, #6fb8ea 0%, #a9d8f2 34%, #eaf6e2 60%, #8fc96f 78%, #4e9e4a 100%); |
| | | background-size: cover; background-position: center; |
| | | } |
| | | .brand .logo .mark::after { |
| | | content: ""; position: absolute; left: 50%; top: 50%; |
| | | width: 10px; height: 10px; border: 2px solid #fff; border-radius: 50%; |
| | | transform: translate(-50%, -50%); |
| | | } |
| | | .brand .sub { margin-top: 4px; font-size: 12px; color: var(--text-sub); } |
| | | |
| | | /* æ¥è¯¢æ */ |
| | | .query-bar { display: flex; gap: 8px; margin-bottom: 14px; } |
| | | .wrap { max-width: 480px; margin: 0 auto; padding: 16px 16px 28px; } |
| | | |
| | | /* ========== æ¥è¯¢æ ========== */ |
| | | .query-bar { display: flex; gap: 10px; } |
| | | .query-bar input { |
| | | flex: 1; height: 42px; padding: 0 12px; |
| | | border: 1px solid var(--border); border-radius: 8px; |
| | | font-size: 14px; background: #fff; outline: none; |
| | | flex: 1; min-width: 0; height: 46px; padding: 0 14px; |
| | | border: 1px solid var(--line); border-radius: var(--radius); font-size: 15px; |
| | | background: #fff; outline: none; color: var(--text-strong); |
| | | transition: border-color .2s, box-shadow .2s; |
| | | } |
| | | .query-bar input:focus { border-color: var(--primary); } |
| | | .query-bar input::placeholder { color: var(--text-mute); } |
| | | .query-bar input:focus { border-color: var(--primary); box-shadow: 0 0 0 3px rgba(31, 122, 56, .1); } |
| | | .query-bar button { |
| | | height: 42px; padding: 0 18px; |
| | | border: none; border-radius: 8px; |
| | | background: var(--primary); color: #fff; font-size: 14px; |
| | | cursor: pointer; |
| | | flex: 0 0 auto; height: 46px; padding: 0 24px; |
| | | border: none; border-radius: var(--radius); font-size: 15px; font-weight: 600; |
| | | letter-spacing: 1px; color: #fff; cursor: pointer; |
| | | background: linear-gradient(180deg, var(--primary-light), var(--primary)); |
| | | box-shadow: 0 2px 6px rgba(31, 122, 56, .25); |
| | | transition: opacity .2s; |
| | | } |
| | | .query-bar button:active { background: var(--primary-light); } |
| | | .query-bar button:active { opacity: .85; } |
| | | |
| | | /* ç¶æ */ |
| | | .state { padding-top: 8px; } |
| | | .loading { text-align: center; padding: 48px 0; color: var(--text-sub); } |
| | | /* ========== ç¶ææç¤º ========== */ |
| | | .loading { text-align: center; padding: 48px 0; color: var(--text-sub); font-size: 15px; } |
| | | .spinner { |
| | | width: 32px; height: 32px; margin: 0 auto 12px; |
| | | width: 32px; height: 32px; margin: 0 auto 14px; |
| | | border: 3px solid var(--primary-bg); border-top-color: var(--primary); |
| | | border-radius: 50%; animation: spin .8s linear infinite; |
| | | } |
| | | @keyframes spin { to { transform: rotate(360deg); } } |
| | | |
| | | .empty-tip { |
| | | padding: 12px 16px; border-radius: 10px; background: #fff; |
| | | box-shadow: var(--card-shadow); font-size: 14px; color: var(--text-sub); |
| | | text-align: center; |
| | | margin-top: 16px; padding: 16px 18px; border-radius: var(--radius); |
| | | background: #fff; border: 1px solid var(--line); box-shadow: var(--shadow); |
| | | font-size: 15px; line-height: 1.7; color: var(--text-sub); text-align: center; |
| | | } |
| | | .empty-tip.error { color: var(--red); background: #fdecec; } |
| | | .empty-tip.primary { color: var(--primary); background: var(--primary-bg); } |
| | | .empty-tip.error { color: var(--red); background: #fdf3f3; border-color: #f3dcdc; } |
| | | .empty-tip.primary { color: var(--primary); background: var(--primary-bg); border-color: #d7ead9; } |
| | | |
| | | /* å¡ç */ |
| | | .card { |
| | | background: #fff; border-radius: 12px; box-shadow: var(--card-shadow); |
| | | margin-bottom: 12px; overflow: hidden; |
| | | /* ========== åºåï¼åè页ï¼ç»¿ç«æ¡æ é¢ + ç»çº¿ + ç½åºæè¾¹å¡çï¼ ========== */ |
| | | .sec { margin-top: 22px; } |
| | | .sec-hd { |
| | | position: relative; |
| | | display: flex; align-items: center; gap: 9px; |
| | | padding-bottom: 11px; |
| | | border-bottom: 1px solid var(--line); |
| | | font-size: 18px; font-weight: 700; letter-spacing: .3px; |
| | | color: var(--text); |
| | | } |
| | | .card .card-hd { |
| | | display: flex; align-items: center; gap: 8px; |
| | | padding: 12px 16px; border-bottom: 1px solid var(--border); |
| | | font-size: 15px; font-weight: 600; |
| | | .sec-hd::after { |
| | | content: ""; position: absolute; left: 0; bottom: -1px; |
| | | width: 46px; height: 2px; background: var(--primary); |
| | | } |
| | | .card .card-hd .bar { width: 4px; height: 16px; border-radius: 2px; background: var(--primary); } |
| | | .card .card-hd .count { margin-left: auto; font-size: 12px; font-weight: 400; color: var(--text-sub); } |
| | | .card .card-bd { padding: 12px 16px; } |
| | | .sec-hd .bar { width: 4px; height: 18px; border-radius: 2px; background: var(--primary); } |
| | | .sec-hd .count { margin-left: auto; font-size: 12px; font-weight: 400; color: var(--text-sub); } |
| | | .sec-hd .caret { font-size: 12px; color: var(--text-mute); transition: transform .2s; } |
| | | |
| | | /* ä¿¡æ¯è¡ */ |
| | | .kv { display: flex; padding: 6px 0; font-size: 14px; } |
| | | .kv .k { flex: 0 0 88px; color: var(--text-sub); } |
| | | .kv .v { flex: 1; word-break: break-all; } |
| | | .kv .v.dim { color: var(--text-sub); } |
| | | .sec.collapsible .sec-hd { cursor: pointer; } |
| | | .sec.collapsible:not(.open) .sec-hd .caret { transform: rotate(-90deg); } |
| | | .sec.collapsible .sec-bd { display: none; } |
| | | .sec.collapsible.open .sec-bd { display: block; } |
| | | |
| | | /* å¾½ç« */ |
| | | .badge { |
| | | display: inline-block; padding: 2px 8px; border-radius: 4px; |
| | | font-size: 12px; line-height: 18px; |
| | | .panel { |
| | | margin-top: 12px; padding: 15px 16px; |
| | | background: #fff; border: 1px solid var(--line); |
| | | border-radius: var(--radius); box-shadow: var(--shadow); |
| | | } |
| | | .badge.green { color: var(--green); background: #e8f5e9; } |
| | | |
| | | /* ========== åæ®µè¡ï¼æ ç¾å°ä¸å·æµ
è²ï¼å¼æ·±è²å ç²ï¼å½¢æå±çº§ ========== */ |
| | | .kv { display: flex; padding: 6px 0; font-size: 15px; line-height: 1.65; } |
| | | .kv .k { flex: 0 0 auto; padding-top: 1px; font-size: 13px; color: var(--text-sub); } |
| | | .kv .k::after { content: "ï¼"; } |
| | | .kv .v { flex: 1; min-width: 0; word-break: break-all; color: var(--text-strong); font-weight: 500; } |
| | | .kv .v.dim { color: var(--text-sub); font-weight: 400; } |
| | | .kv .v .link { color: var(--primary); text-decoration: none; border-bottom: 1px solid rgba(31,122,56,.35); } |
| | | |
| | | .tip { margin-top: 8px; font-size: 15px; line-height: 1.75; color: #374151; } |
| | | .meta { |
| | | margin-top: 10px; padding-top: 10px; |
| | | border-top: 1px dashed var(--line); |
| | | font-size: 12px; color: var(--text-sub); |
| | | } |
| | | |
| | | /* ========== é²ä¼ªæ¥è¯¢ï¼ç¶ææ¡ ========== */ |
| | | .verify { display: flex; gap: 10px; padding: 13px 14px; border-radius: var(--radius-sm); } |
| | | .verify.ok { background: linear-gradient(135deg, #eff8f1, #e2f2e6); border: 1px solid #cfe7d6; } |
| | | .verify.warn { background: linear-gradient(135deg, #fff9ec, #fdf1d6); border: 1px solid #eeddb4; } |
| | | .verify .vico { |
| | | flex: 0 0 22px; height: 22px; margin-top: 1px; |
| | | display: flex; align-items: center; justify-content: center; |
| | | border-radius: 50%; color: #fff; |
| | | } |
| | | .verify.ok .vico { background: var(--primary); } |
| | | .verify.warn .vico { background: #d2961b; } |
| | | .verify .vico svg { width: 13px; height: 13px; } |
| | | .verify .vtxt { flex: 1; min-width: 0; } |
| | | .verify .vt { font-size: 16px; font-weight: 700; line-height: 1.4; color: #1b4332; } |
| | | .verify.warn .vt { color: #8a5a00; } |
| | | .verify .vs { margin-top: 4px; font-size: 13px; line-height: 1.65; color: #5b6670; } |
| | | |
| | | /* ========== é²ä¼ªç¼ç ========== */ |
| | | .code-box { |
| | | display: flex; align-items: center; justify-content: space-between; gap: 10px; |
| | | margin-top: 12px; padding: 10px 12px; |
| | | background: #f8faf8; border: 1px dashed #cfe0d2; border-radius: var(--radius-sm); |
| | | } |
| | | .code-box .cl { flex: 0 0 auto; font-size: 13px; color: var(--text-sub); } |
| | | .code-box .cv { |
| | | font-family: var(--mono); font-size: 16px; font-weight: 700; |
| | | letter-spacing: .5px; color: #14532d; word-break: break-all; text-align: right; |
| | | } |
| | | |
| | | /* ========== æ¥è¯¢è®°å½ï¼ç»è®¡æ ¼ï¼ ========== */ |
| | | .stat-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; margin-top: 12px; } |
| | | .stat { padding: 9px 11px; background: #fafbfa; border: 1px solid var(--line); border-radius: var(--radius-sm); } |
| | | .stat .sl { font-size: 12px; color: var(--text-sub); } |
| | | .stat .sv { |
| | | margin-top: 3px; font-size: 13px; font-weight: 600; color: var(--text-strong); |
| | | font-variant-numeric: tabular-nums; |
| | | } |
| | | .stat.span2 { grid-column: 1 / -1; } |
| | | .stat.count { background: var(--primary-bg); border-color: #d7ead9; } |
| | | .stat.count .sv { font-size: 21px; font-weight: 800; color: var(--primary); letter-spacing: .5px; } |
| | | .stat.count .sv .u { margin-left: 3px; font-size: 13px; font-weight: 600; } |
| | | |
| | | /* ========== åºé¨è¯´æ ========== */ |
| | | .notice { |
| | | margin-top: 12px; padding-top: 10px; border-top: 1px dashed var(--line); |
| | | font-size: 12px; line-height: 1.75; color: var(--text-mute); |
| | | } |
| | | |
| | | /* ========== å¾½ç« ========== */ |
| | | .badge { display: inline-block; padding: 3px 9px; border-radius: 6px; font-size: 12px; line-height: 18px; } |
| | | .badge.green { color: var(--green); background: var(--primary-bg); } |
| | | .badge.red { color: var(--red); background: #fdecec; } |
| | | .badge.blue { color: var(--blue); background: #e3f2fd; } |
| | | .badge.gray { color: var(--gray); background: #f1f2f4; } |
| | | |
| | | .badge-big { display: inline-block; padding: 4px 12px; border-radius: 16px; font-size: 14px; } |
| | | .badge-big.green { color: #fff; background: var(--green); } |
| | | .badge-big.red { color: #fff; background: var(--red); } |
| | | .badge-big.gray { color: #fff; background: var(--gray); } |
| | | /* ========== æç»æ¡ç® ========== */ |
| | | .li { padding: 10px 0; border-bottom: 1px dashed var(--line); } |
| | | .li:first-child { padding-top: 0; } |
| | | .li:last-child { padding-bottom: 0; border-bottom: none; } |
| | | .li-hd { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; margin-bottom: 2px; } |
| | | .li-ttl { font-size: 14px; font-weight: 600; } |
| | | .li-time { margin-left: auto; font-size: 12px; color: var(--text-sub); } |
| | | .li-bd .kv { font-size: 13px; padding: 2px 0; } |
| | | .li-bd .kv .k { flex: 0 0 auto; min-width: 74px; } |
| | | |
| | | /* å表 */ |
| | | .scroll-list { max-height: 320px; overflow-y: auto; } |
| | | .scroll-list::-webkit-scrollbar { width: 4px; } |
| | | .scroll-list::-webkit-scrollbar-thumb { background: #d1d5db; border-radius: 2px; } |
| | | |
| | | .tbl-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; } |
| | | .mini-table { width: 100%; border-collapse: collapse; font-size: 13px; } |
| | | .mini-table th, .mini-table td { text-align: left; padding: 8px 6px; border-bottom: 1px solid var(--border); } |
| | | .mini-table th, .mini-table td { text-align: left; padding: 7px 6px; border-bottom: 1px solid var(--line); } |
| | | .mini-table th { color: var(--text-sub); font-weight: 400; background: #fafbf9; white-space: nowrap; } |
| | | .mini-table tr:last-child td { border-bottom: none; } |
| | | .mini-table td { word-break: break-all; } |
| | | .mini-table td { overflow-wrap: break-word; } |
| | | |
| | | .pill-list { display: flex; flex-wrap: wrap; gap: 8px; } |
| | | .pill { |
| | |
| | | padding: 6px 12px; border-radius: 16px; font-size: 13px; |
| | | background: #f3f4f6; |
| | | } |
| | | .pill .dot { width: 6px; height: 6px; border-radius: 50%; } |
| | | |
| | | .scroll-list { max-height: 300px; overflow-y: auto; } |
| | | .scroll-list::-webkit-scrollbar { width: 4px; } |
| | | .scroll-list::-webkit-scrollbar-thumb { background: #d1d5db; border-radius: 2px; } |
| | | |
| | | /* æ£åéªè¯å¡ï¼é¡¶é¨ï¼æ«ç ä¼å
å±ç¤ºï¼ */ |
| | | .verify-card { |
| | | border: 1px solid var(--primary-light); |
| | | background: linear-gradient(180deg, #eef8ee, #fff); |
| | | /* ========== å
¬å¸ä»ç» ========== */ |
| | | .company-stats { margin-bottom: 12px; } |
| | | .company-stats .pill { background: var(--primary-bg); color: var(--primary); font-weight: 600; } |
| | | .company-bd { font-size: 16px; color: #374151; line-height: 1.9; text-align: justify; } |
| | | .company-bd p { text-indent: 2em; } |
| | | .company-bd p + p { margin-top: 10px; } |
| | | .company-clip { position: relative; max-height: 164px; overflow: hidden; } |
| | | .company-clip::after { |
| | | content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 56px; |
| | | background: linear-gradient(180deg, rgba(255,255,255,0), #fff); |
| | | pointer-events: none; |
| | | } |
| | | .verify-card .card-bd { padding: 14px 16px; } |
| | | .verify-title { |
| | | display: flex; align-items: center; gap: 8px; |
| | | font-size: 16px; font-weight: 700; color: var(--primary); |
| | | margin-bottom: 4px; |
| | | } |
| | | .verify-title::before { content: ""; width: 5px; height: 16px; border-radius: 2px; background: var(--primary); } |
| | | .verify-sub { font-size: 12px; color: var(--text-sub); margin-bottom: 10px; } |
| | | .verify-badge { margin-bottom: 10px; } |
| | | .verify-stats { margin-top: 10px; border-top: 1px dashed var(--border); padding-top: 4px; } |
| | | .company-clip.open { max-height: none; } |
| | | .company-clip.open::after { display: none; } |
| | | .company-more { margin-top: 12px; text-align: center; } |
| | | .company-more a { color: var(--brand-blue); font-size: 15px; cursor: pointer; } |
| | | |
| | | /* 坿å å¡ç */ |
| | | .card.collapsible .card-hd { cursor: pointer; position: relative; padding-right: 30px; } |
| | | .card.collapsible .card-hd::after { |
| | | content: "â¾"; position: absolute; right: 12px; top: 50%; |
| | | transform: translateY(-50%); color: var(--text-sub); font-size: 12px; |
| | | transition: transform .2s; |
| | | /* ========== èç³»æä»¬ ========== */ |
| | | .contact-item { display: flex; gap: 12px; padding: 13px 0; } |
| | | .contact-item:first-child { padding-top: 0; } |
| | | .contact-item:last-child { padding-bottom: 0; } |
| | | .contact-item + .contact-item { border-top: 1px dashed var(--line); } |
| | | .contact-item .ico { |
| | | flex: 0 0 30px; height: 30px; |
| | | display: flex; align-items: center; justify-content: center; |
| | | border: 1px solid var(--primary); border-radius: 50%; |
| | | color: var(--primary); |
| | | } |
| | | .card.collapsible:not(.open) .card-hd::after { transform: translateY(-50%) rotate(-90deg); } |
| | | .card.collapsible .card-hd .count { margin-right: 16px; } |
| | | .card.collapsible .card-bd { display: none; } |
| | | .card.collapsible.open .card-bd { display: block; } |
| | | .contact-item .ico svg { width: 15px; height: 15px; } |
| | | .contact-item .txt { flex: 1; min-width: 0; } |
| | | .contact-item .lbl { font-size: 14px; font-weight: 700; letter-spacing: .3px; color: var(--primary); } |
| | | .contact-item .val { margin-top: 2px; font-size: 15px; line-height: 1.6; color: var(--text); word-break: break-all; } |
| | | .contact-item .val a { color: inherit; text-decoration: none; } |
| | | |
| | | footer { |
| | | max-width: 480px; margin: 0 auto; |
| | | padding: 20px 16px 28px; text-align: center; |
| | | font-size: 12px; color: #9ca3af; |
| | | padding: 20px 16px 32px; text-align: center; |
| | | font-size: 12px; line-height: 1.8; color: var(--text-mute); |
| | | } |
| | | </style> |
| | | </head> |
| | | <body> |
| | | |
| | | <div class="brand"> |
| | | <div class="logo"><span class="mark"></span>ç§åäº§åæº¯æº</div> |
| | | <div class="sub">æ¥æºå¯æ¥ · å»åå¯è¿½ · 责任å¯ç©¶</div> |
| | | </div> |
| | | <header class="hero"> |
| | | <div class="hero-top"> |
| | | <img class="hero-logo" src="data:image/png;base64,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" alt="塿²³ç§ä¸"> |
| | | <div class="hero-name">æ°çå¡éæ¨æ²³ç§ä¸è¡ä»½æéå
¬å¸</div> |
| | | </div> |
| | | <div class="hero-banner"></div> |
| | | </header> |
| | | |
| | | <div class="wrap"> |
| | | <main class="wrap"> |
| | | <!-- æå¨æ¥è¯¢æ ï¼æ code åæ°æ¶æç¤ºè¾å
¥ï¼æåæ°æ¶èªå¨æ¥è¯¢ --> |
| | | <div class="query-bar"> |
| | | <input id="codeInput" type="text" placeholder="请è¾å
¥è¿½æº¯ç ï¼è¢ç / æçç / æ¹æ¬¡ç ï¼" autocomplete="off"> |
| | |
| | | </div> |
| | | |
| | | <section id="state" class="state"></section> |
| | | </div> |
| | | |
| | | <footer>æ¬ç³»ç»æ°æ®ä»
ç¨äºäº§å溯æºï¼è¯·éè¿æ£è§æ¸ éè´ä¹°ã</footer> |
| | | <!-- å
¬å¸ä»ç»ï¼å¸¸é©»ï¼ --> |
| | | <section class="sec"> |
| | | <div class="sec-hd"> |
| | | <span class="bar"></span><span class="ttl">å
¬å¸ä»ç»</span> |
| | | <span class="count">æ°ç · 彿æ§è¡</span> |
| | | </div> |
| | | <div class="sec-bd"> |
| | | <div class="panel"> |
| | | <div class="pill-list company-stats"> |
| | | <span class="pill">æç« 2002 å¹´</span> |
| | | <span class="pill">注åèµæ¬ 1.1 亿å
</span> |
| | | <span class="pill">èªä¸»åç§ 61 个</span> |
| | | <span class="pill">ç åå¢é 16 人</span> |
| | | </div> |
| | | <div class="company-bd company-clip" id="companyClip"> |
| | | <p>æ°çå¡éæ¨æ²³ç§ä¸è¡ä»½æéå
¬å¸äº2002å¹´12æ30æ¥å¨æ°çç»´å¾å°èªæ²»åºå·¥å屿³¨åæç«ï¼æ¯ä¸å®¶éåä½ç©ç§åï¼æ£è±ãå°éº¦ã水稻çï¼è²ãç¹ãæ¨ãå ãéãç§æä¸ºä¸ä½ç彿æ§è¡å
¬å¸ãå
¬å¸èµ·å§æ³¨åèµæ¬6500ä¸å
ï¼2015å¹´å¢èµå注åèµæ¬è¾¾1.1亿å
ï¼ç±æ°åå¼åãéå¹³é«ç§ãå¡éæ¨å¤§å¦ç§æå
¬å¸ãå·´æ¥ä¸°åç§ä¸åå®¶è¡ä¸åä½ç»æãæä¸æ¥æä¸¤å®¶æ§è¡åå
¬å¸ï¼å嫿¯ä¸»è¥ç产ãå å·¥ãæ¹åéå®åä½ç©ç§åå
è¡£åç塿²³å¤ä¸°å
¨èµåå
¬å¸ï¼ä»¥å以åä½ç©ç§åç产ãç»è¥åå䏿æ¯å¼åãæ¨å¹¿ãæå¡ä¸ºä¸»çä¼½å¸å¡æ²³ç§ä¸å
¬å¸ã</p> |
| | | <p>å
¬å¸èªæç«ä»¥æ¥ï¼å§ç»åæä»¥åä¸ç§å产ä¸åç»è¥ä¸ºç®æ ï¼å
¨åæé âè²ç§è½å强ãç产å å·¥ææ¯å
è¿ãå¸åºè¥éç½ç»å¥å
¨ãææ¯æ¨å¹¿æå¡å°ä½âï¼âè²ç¹æ¨âä¸ä½åãâ产å¦ç âç¸ç»åçç°ä»£åä½ç©ç§åç»è¥ä¼ä¸ãå
¬å¸æ¥æå¼ºæåç16人ç åå¢éï¼åæç§ç åæ°çååæ§ï¼åæèªè²ä¸ºä¸»ï¼åæ¶éè¿å»ºç«èåçæè¯éªç«ï¼ææ§å¼æºï¼å¸¸å¹´å¤èä¸ç§é¢é¢å£«ãä¸å½åå¤§ãæµå¤§ã䏿£æç12åå½å
å«å导å¨å
ç顶级æ£è±ä¸å®¶å¢éï¼ä¸ä¸å¸åç§æå¼å±äºè¿ç»åäºå¹´çé¢ä¼åä½ï¼è§£å³äº§ä¸å沿信æ¯åä¼è´¨ç§è´¨èµæºâçæ¿âé®é¢ãç®åï¼å
¬å¸æ¥æèªæç¥è¯äº§æåç§61个ï¼å
¶ä¸æ£è±åç§46个ï¼ç²®é£åç§15个ãååå¨ç§ä¸é¢åççªåºè¡¨ç°ï¼å
¬å¸ç¸ç»§è£è·å
µå¢åå½å®¶åä¸äº§ä¸åéç¹é¾å¤´ä¼ä¸ã髿°ææ¯ä¼ä¸ã3Aä¿¡ç¨ä¼ä¸ãæ°çåçãä¸å½åçï¼å½å®¶ãèªæ²»åº3A级æ ååè¯å¥½è¡ä¸ºè¯ç¹ä¼ä¸ãä¸å½ç§ä¸ä¿¡ç¨éª¨å¹²ä¼ä¸ãèªæ²»åºä¼ä¸ææ¯ä¸å¿ãæ°ç产å¦ç èåå¼å示èåºå°ãå
µå¢é¦æ¹åæ°åä¼ä¸ãå
¨å½åå¦åä½ç©è¯ç§å±ç¤ºç¤ºèåºå°çè£èªç§°å·ãèª2020å¹´èµ·ï¼å
¬å¸æ£è±ååç§åéå®è¿ç»ä½å±
å
¨å½æ¦é¦ï¼2022å¹´å
¥éå½å®¶åä½ç©ç§ä¸æ£è±è¡¥çæ¿éµåä¼ä¸ï¼2023å¹´1æè£è·æ°çåä½ç©ç§ä¸ä¼å¿ä¼ä¸ï¼2025å¹´7æè£è·å
µå¢åæ°ååâä¸ç²¾ç¹æ°âä¼ä¸ç§°å·ï¼2025å¹´8æâæºéæ£æ°åç§éè²åæè´¨å¢æå
³é®ææ¯éæåºç¨âè·å¾å
µå¢ç§æè¿æ¥å¥ä¸çå¥ï¼2026å¹´è£è·å
¨å½æ£è±ç§åè²ç¹æ¨ç产ç»è¥Aè¯ã</p> |
| | | </div> |
| | | <div class="company-more" id="companyMoreWrap"><a id="companyMore">ç¹å»æ¥çæ´å¤</a></div> |
| | | </div> |
| | | </div> |
| | | </section> |
| | | |
| | | <!-- èç³»æä»¬ï¼å¸¸é©»ï¼ --> |
| | | <section class="sec"> |
| | | <div class="sec-hd"> |
| | | <span class="bar"></span><span class="ttl">èç³»æä»¬</span> |
| | | </div> |
| | | <div class="sec-bd"> |
| | | <div class="panel"> |
| | | <div class="contact-item"> |
| | | <span class="ico"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z"/><circle cx="12" cy="10" r="3"/></svg></span> |
| | | <span class="txt"><span class="lbl">å
¬å¸å°å</span><div class="val">æ°çé¿æå°å¸å泥湾大é1865å·</div></span> |
| | | </div> |
| | | <div class="contact-item"> |
| | | <span class="ico"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M22 16.9v3a2 2 0 0 1-2.2 2 19.8 19.8 0 0 1-8.6-3.1 19.5 19.5 0 0 1-6-6A19.8 19.8 0 0 1 2.1 4.2 2 2 0 0 1 4.1 2h3a2 2 0 0 1 2 1.7c.1 1 .4 1.9.7 2.8a2 2 0 0 1-.5 2.1L8.1 9.9a16 16 0 0 0 6 6l1.3-1.3a2 2 0 0 1 2.1-.4c.9.3 1.8.6 2.8.7a2 2 0 0 1 1.7 2z"/></svg></span> |
| | | <span class="txt"><span class="lbl">èç³»çµè¯</span><div class="val">è¡æ¿ç®¡çé¨ï¼<a href="tel:09974615802">0997-4615802</a></div></span> |
| | | </div> |
| | | <div class="contact-item"> |
| | | <span class="ico"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M3 9.5 12 3l9 6.5V20a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><path d="M9.5 22v-6h5v6"/></svg></span> |
| | | <span class="txt"><span class="lbl">å
¬å¸ç½å</span><div class="val"><a href="https://www.talimu.net" target="_blank" rel="noopener">www.talimu.net</a></div></span> |
| | | </div> |
| | | <div class="contact-item"> |
| | | <span class="ico"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M21 11.5a8.4 8.4 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.4 8.4 0 0 1-3.8-.9L3 21l1.9-5.7a8.4 8.4 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.4 8.4 0 0 1 3.8-.9h.5a8.5 8.5 0 0 1 8 8z"/></svg></span> |
| | | <span class="txt"><span class="lbl">微信å
¬ä¼å·</span><div class="val">塿²³ç§ä¸ä¹å®¶</div></span> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </section> |
| | | </main> |
| | | |
| | | <footer> |
| | | æ¬ç³»ç»æ°æ®ä»
ç¨äºäº§å溯æºï¼è¯·éè¿æ£è§æ¸ éè´ä¹°ã<br> |
| | | æ°çå¡éæ¨æ²³ç§ä¸è¡ä»½æéå
¬å¸ |
| | | </footer> |
| | | |
| | | <script> |
| | | (function () { |
| | | 'use strict'; |
| | | |
| | | // ========== 页é¢å¯é
置项 ========== |
| | | // ç产ç»è¥è
ï¼è¿½æº¯æ¥è¯¢åºåå±ç¤ºï¼ |
| | | var COMPANY_NAME = 'æ°çå¡éæ¨æ²³ç§ä¸è¡ä»½æéå
¬å¸'; |
| | | // 追溯ç½åï¼å¤ç½è®¿é®å°åï¼ä¸å
è£
/äºç»´ç ä¸å°å¶çä¸è´ï¼ |
| | | var TRACE_URL = 'http://1.95.78.124:9008/'; |
| | | |
| | | var STATE = document.getElementById('state'); |
| | | var CODE_INPUT = document.getElementById('codeInput'); |
| | | var SEARCH_BTN = document.getElementById('searchBtn'); |
| | | |
| | | var BATCH_STATUS = { 10: ['è稿', 'gray'], 20: ['ç产ä¸', 'blue'], 30: ['已宿', 'green'], 40: ['å·²ä½åº', 'red'] }; |
| | | var BAG_STATUS = { 10: ['å·²çæ', 'gray'], 20: ['已导åºå°å·', 'blue'], 30: ['å·²ä½åº', 'red'] }; |
| | | var QUALITY_RESULT = { 0: ['å¤çä¸', 'gray'], 1: ['åæ ¼', 'green'], 2: ['ä¸åæ ¼', 'red'] }; |
| | | var WORKER_TYPE = { 10: 'ç»é¿', 20: 'æä½å·¥', 30: 'å
è£
å·¥', 40: 'è´¨æ£å', 50: 'å
¶ä»' }; |
| | | var FLOW_DIRECTION = { 1: ['å
¥åº', 'green'], 2: ['åºåº', 'blue'] }; |
| | | var FLOW_BIZ_TYPE = { |
| | | 110: 'éè´å
¥åº', 111: 'éè´å
¥åºåæ¶', 112: 'è°æ¨åºåº', 113: 'è°æ¨å
¥åº', |
| | | 114: 'å
¶ä»åºåº', 115: 'å
¶ä»å
¥åº', 116: 'çäº§é¢æ', 117: 'ç产éæ', |
| | | 118: 'ç产å
¥åº', 119: 'éå®åºåº', 120: 'éå®éè´§å
¥åº', 121: 'å¤ååæ', |
| | | 122: 'å¤åå
¥åº', 123: 'ç产æ¶è', 124: '产å产åº', 125: 'ä¾åºåéè´§åºåº', |
| | | 126: 'åºåè°æ´å
¥åº', 127: 'åºåè°æ´åºåº' |
| | | }; |
| | | var SOURCE_TYPE = { BAG: 'è¢ç ', PALLET: 'æçç ', BATCH: 'æ¹æ¬¡ç ' }; |
| | | |
| | | // ========== å·¥å
·å½æ° ========== |
| | | function esc(v) { |
| | |
| | | return esc(String(s).replace('T', ' ').replace(/\.\d+$/, '').slice(0, 16)); |
| | | } |
| | | |
| | | function fmtDay(s) { |
| | | if (!s) return '-'; |
| | | return esc(String(s).replace('T', ' ').slice(0, 10)); |
| | | } |
| | | |
| | | function fmtNum(v) { |
| | | return (v === null || v === undefined) ? '-' : esc(v); |
| | | return (v === null || v === undefined || v === '') ? '-' : esc(v); |
| | | } |
| | | |
| | | // è¡¨æ ¼çªåï¼æ°é / æ¥æï¼ä¸æ¢è¡ï¼é¿å
æ°å被æè¡ |
| | | function nw(html) { |
| | | return '<span style="white-space:nowrap">' + html + '</span>'; |
| | | } |
| | | |
| | | function statusBadge(map, key) { |
| | |
| | | return '<span class="badge ' + item[1] + '">' + esc(item[0]) + '</span>'; |
| | | } |
| | | |
| | | function card(title, countHtml, bodyHtml, opts) { |
| | | opts = opts || {}; |
| | | var collapsible = !!opts.collapsible; |
| | | var open = collapsible && !!opts.open; |
| | | var hd = '<div class="card-hd"' + |
| | | (collapsible ? ' onclick="this.parentNode.classList.toggle(\'open\')"' : '') + |
| | | '><span class="bar"></span>' + esc(title) + |
| | | (countHtml ? '<span class="count">' + countHtml + '</span>' : '') + |
| | | '</div>'; |
| | | return '<div class="card' + (collapsible ? ' collapsible' : '') + (open ? ' open' : '') + '">' + |
| | | hd + '<div class="card-bd">' + bodyHtml + '</div>' + '</div>'; |
| | | } |
| | | |
| | | function kv(k, v, dim) { |
| | | return '<div class="kv"><span class="k">' + esc(k) + '</span><span class="v' + (dim ? ' dim' : '') + '">' + v + '</span></div>'; |
| | | } |
| | | |
| | | function isEmptyList(list) { |
| | | return !list || list.length === 0; |
| | | } |
| | | |
| | | // åºåï¼ç»¿ç«æ¡æ é¢ + ç»çº¿ + ç½åºæè¾¹é¢æ¿ |
| | | function sec(title, countHtml, bodyHtml, opts) { |
| | | opts = opts || {}; |
| | | var collapsible = !!opts.collapsible; |
| | | var cls = 'sec' + (collapsible ? ' collapsible' : '') + (collapsible && opts.open ? ' open' : ''); |
| | | return '<section class="' + cls + '">' + |
| | | '<div class="sec-hd"><span class="bar"></span><span class="ttl">' + esc(title) + '</span>' + |
| | | '<span class="count">' + (countHtml || '') + '</span>' + |
| | | (collapsible ? '<span class="caret">â¾</span>' : '') + |
| | | '</div>' + |
| | | '<div class="sec-bd"><div class="panel">' + bodyHtml + '</div></div>' + |
| | | '</section>'; |
| | | } |
| | | |
| | | function table(heads, rows) { |
| | | var h = '<div class="tbl-wrap"><table class="mini-table"><thead><tr>'; |
| | | heads.forEach(function (t) { h += '<th>' + esc(t) + '</th>'; }); |
| | | h += '</tr></thead><tbody>'; |
| | | rows.forEach(function (cells) { |
| | | h += '<tr>'; |
| | | cells.forEach(function (c) { h += '<td>' + c + '</td>'; }); |
| | | h += '</tr>'; |
| | | }); |
| | | return h + '</tbody></table></div>'; |
| | | } |
| | | |
| | | function li(titleHtml, timeHtml, bodyHtml) { |
| | | return '<div class="li"><div class="li-hd">' + titleHtml + |
| | | (timeHtml ? '<span class="li-time">' + timeHtml + '</span>' : '') + |
| | | '</div><div class="li-bd">' + bodyHtml + '</div></div>'; |
| | | } |
| | | |
| | | // ========== æ¥è¯¢ ========== |
| | |
| | | if (res.code === 0) { |
| | | renderResult(res.data); |
| | | } else { |
| | | var msg = res.msg || 'æ¥è¯¢å¤±è´¥ï¼è¯·ç¨åéè¯'; |
| | | renderState('<div class="empty-tip error">' + esc(msg) + '</div>'); |
| | | renderState('<div class="empty-tip error">' + esc(res.msg || 'æ¥è¯¢å¤±è´¥ï¼è¯·ç¨åéè¯') + '</div>'); |
| | | } |
| | | }) |
| | | .catch(function () { |
| | |
| | | window.scrollTo({ top: 0, behavior: 'smooth' }); |
| | | } |
| | | |
| | | // ========== ç»ææ¸²æï¼ä¿¡æ¯åºå模ååï¼åç»æ°æ°æ®æºå¨æ¤è¿½å åºåï¼ ========== |
| | | // ========== ç»ææ¸²æ ========== |
| | | function renderResult(d) { |
| | | if (!d) { |
| | | renderState('<div class="empty-tip error">æªæ¥è¯¢å°è¯¥è¿½æº¯ç ï¼è¯·æ ¸å¯¹äºç»´ç æèç³»å®æ¹</div>'); |
| | | return; |
| | | } |
| | | var html = ''; |
| | | html += buildVerifyCard(d); |
| | | html += buildItemCard(d); |
| | | html += buildBatchCard(d); |
| | | html += buildQualityCard(d); |
| | | html += buildWorkerCard(d); |
| | | html += buildInboundCard(d); |
| | | html += buildPalletCard(d); |
| | | html += buildBagCard(d); |
| | | html += buildOptionalCard(d); |
| | | html += sec('é²ä¼ªæ¥è¯¢', null, fakePanel(d), null); |
| | | html += sec('追溯æ¥è¯¢', null, tracePanel(d), null); |
| | | // ç产æç»æå åºï¼æ¹æ¬¡/è´¨æ£/人å/æç/è¢ç /éè´æ¥æº/ç§åæµå/å å·¥æµè½¬ï¼æéæ±ä¸å±ç¤ºï¼ |
| | | // detailSections ä¿ç以便åç»æéå¼å¯ |
| | | STATE.innerHTML = html || '<div class="empty-tip">ææ è¿½æº¯æ°æ®</div>'; |
| | | window.scrollTo({ top: 0, behavior: 'smooth' }); |
| | | } |
| | | |
| | | // åºå0ï¼æ£åéªè¯ï¼é¡¶é¨ï¼æ«ç ä¼å
å±ç¤ºéªè¯ç»è®ºä¸æ¥è¯¢ç»è®¡ï¼ |
| | | function stripUrl(v) { |
| | | if (!v) return v; |
| | | if (/^https?:\/\//i.test(v)) { |
| | |
| | | return v; |
| | | } |
| | | |
| | | function buildVerifyCard(d) { |
| | | var typeLabel = { BAG: 'è¢ç ', PALLET: 'æçç ', BATCH: 'æ¹æ¬¡ç ' }[d.sourceType] || '追溯ç '; |
| | | var code = stripUrl(d.requestCode) || d.batchCode || d.tempCode || '-'; |
| | | var bagNo = '-'; |
| | | if (d.sourceType === 'BAG' && d.bags) { |
| | | for (var i = 0; i < d.bags.length; i++) { |
| | | if (d.bags[i].code === code) { |
| | | bagNo = d.bags[i].bagNo; |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | var statsHtml = '<div class="verify-stats">'; |
| | | if (d.antiFake && d.antiFake.scanCount > 0) { |
| | | statsHtml += kv('累计æ¥è¯¢', esc(d.antiFake.scanCount) + ' 次') + |
| | | kv('馿¬¡æ¥è¯¢', fmtDate(d.antiFake.firstScanTime)) + |
| | | kv('æè¿æ¥è¯¢', fmtDate(d.antiFake.lastScanTime)); |
| | | } else { |
| | | statsHtml += kv('累计æ¥è¯¢', 'ææ æ¥è¯¢è®°å½'); |
| | | } |
| | | statsHtml += '</div>'; |
| | | return '<div class="card verify-card">' + |
| | | '<div class="card-bd">' + |
| | | '<div class="verify-title">æ£åéªè¯</div>' + |
| | | '<div class="verify-badge"><span class="badge-big green">â
æ£åéªè¯éè¿</span></div>' + |
| | | '<div class="verify-sub">该追溯ç 为æ£è§æ¸ é产åï¼æº¯æºä¿¡æ¯ç宿æ</div>' + |
| | | kv('追溯类å', typeLabel) + |
| | | kv(typeLabel, text(code)) + |
| | | (d.sourceType === 'BAG' ? kv('è¢å·', bagNo) : '') + |
| | | kv('æ¹æ¬¡å·', text(d.batchCode)) + |
| | | kv('åç§', text(d.itemName)) + |
| | | statsHtml + |
| | | '</div></div>'; |
| | | // 追溯ç ï¼æ«ç å¼ â æ¹æ¬¡ç â ä¸´æ¶æ¹æ¬¡ç |
| | | function resolveCode(d) { |
| | | return stripUrl(d.requestCode) || d.batchCode || d.tempCode || ''; |
| | | } |
| | | |
| | | // åºå1ï¼åç§ä¿¡æ¯ |
| | | function buildItemCard(d) { |
| | | if (!d.itemCode && !d.itemName && !d.itemSpecification) return ''; |
| | | return card('åç§ä¿¡æ¯', null, |
| | | kv('åç§åç§°', text(d.itemName)) + |
| | | kv('è§æ ¼', text(d.itemSpecification)) + |
| | | kv('åç§ç¼ç ', text(d.itemCode)), |
| | | { collapsible: true, open: true } |
| | | ); |
| | | } |
| | | // åºå1ï¼é²ä¼ªæ¥è¯¢ï¼éªè¯ç¶ææ¡ + é²ä¼ªç¼ç + 对åºäº§å + æ¥è¯¢è®°å½ï¼ |
| | | function fakePanel(d) { |
| | | var code = resolveCode(d); |
| | | var af = d.antiFake || {}; |
| | | var n = Number(af.scanCount || 0); |
| | | var repeated = n > 0; |
| | | var icon = repeated |
| | | ? '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round"><path d="M12 7.5v6"/><path d="M12 17h.01"/></svg>' |
| | | : '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><path d="M4 12.5l5.5 5.5L20 6.5"/></svg>'; |
| | | var title = repeated ? '该é²ä¼ªç 已被æ¥è¯¢ ' + n + ' 次' : '馿¬¡æ¥è¯¢ · æªè§å¼å¸¸'; |
| | | var desc = repeated |
| | | ? 'æ¤ç æ¤å已被æ¥è¯¢è¿ï¼é¦æ¬¡æ¥è¯¢æ¶é´ä¸º ' + fmtDate(af.firstScanTime) + 'ãè¥é¦æ¬¡æ¥è¯¢å¹¶éæ¬äººæä½ï¼è¯·æ³¨æäº§åæ¥æºã' |
| | | : '该é²ä¼ªç æ¤åæ²¡ææ¥è¯¢è®°å½ï¼å
è£
æªè¢«éå¤ä½¿ç¨ã'; |
| | | var name = [d.itemName, d.itemSpecification, d.itemUnitMeasureName].filter(Boolean).join(' '); |
| | | |
| | | // åºå2ï¼çäº§æ¹æ¬¡ |
| | | function buildBatchCard(d) { |
| | | if (!d.batchCode && !d.tempCode) return ''; |
| | | var status = statusBadge(BATCH_STATUS, d.batchStatus); |
| | | return card('çäº§æ¹æ¬¡', status, |
| | | kv('æ¹æ¬¡å·', text(d.batchCode)) + |
| | | kv('ç¶æ', status) + |
| | | kv('çäº§æ¥æ', fmtDate(d.produceDate)) + |
| | | kv('产线', text(d.lineName ? (d.lineName + (d.lineCode ? ' / ' + d.lineCode : '')) : d.lineCode)) + |
| | | kv('责任人', text(d.ownerUserName)) + |
| | | kv('è®¡åæ°é', fmtNum(d.planQuantity) === '-' ? '-' : fmtNum(d.planQuantity)) + |
| | | kv('å·²çæè¢ç ', fmtNum(d.bagQuantity)) + |
| | | kv('å·²çææç', fmtNum(d.palletQuantity)) + |
| | | kv('å
¥åºæ¶é´', fmtDate(d.inboundTime)) + |
| | | (d.remark ? kv('夿³¨', text(d.remark)) : ''), |
| | | { collapsible: true, open: true } |
| | | ); |
| | | } |
| | | |
| | | // åºå3ï¼ç§åè´¨æ£ |
| | | function buildQualityCard(d) { |
| | | var q = d.quality; |
| | | if (!q) return ''; |
| | | var result = QUALITY_RESULT[q.result]; |
| | | var badge = result |
| | | ? '<span class="badge-big ' + result[1] + '">' + esc(result[0]) + '</span>' |
| | | : '<span class="badge-big gray">æªç¥</span>'; |
| | | |
| | | var rows = ''; |
| | | if (q.indicators && q.indicators.length) { |
| | | rows = '<table class="mini-table"><thead><tr><th>ææ </th><th>æ£æµå¼</th><th>æ åèå´</th><th>ç»æ</th></tr></thead><tbody>'; |
| | | q.indicators.forEach(function (i) { |
| | | var range = (i.minValue !== null && i.minValue !== undefined && i.maxValue !== null && i.maxValue !== undefined) |
| | | ? esc(i.minValue) + ' ~ ' + esc(i.maxValue) : '-'; |
| | | var pass = (i.pass === true) |
| | | ? '<span class="badge green">åæ ¼</span>' |
| | | : (i.pass === false ? '<span class="badge red">ä¸åæ ¼</span>' : '<span class="badge gray">--</span>'); |
| | | rows += '<tr><td>' + text(i.indicatorName) + '</td><td>' + text(i.value) + '</td><td>' + range + '</td><td>' + pass + '</td></tr>'; |
| | | }); |
| | | rows += '</tbody></table>'; |
| | | } |
| | | |
| | | return card('ç§åè´¨æ£', badge, |
| | | kv('æ£éªç»è®º', badge) + |
| | | kv('æ£éªå', text(q.inspectorName)) + |
| | | kv('æ£éªæ¶é´', fmtDate(q.inspectedAt)) + |
| | | (q.reason ? kv('ä¸åæ ¼åå ', text(q.reason)) : '') + |
| | | (rows ? '<div style="margin-top:8px">' + rows + '</div>' : ''), |
| | | { collapsible: true, open: false } |
| | | ); |
| | | } |
| | | |
| | | // åºå4ï¼ç产人å |
| | | function buildWorkerCard(d) { |
| | | if (isEmptyList(d.workers)) return ''; |
| | | var html = '<div class="pill-list">'; |
| | | d.workers.forEach(function (w) { |
| | | var name = w.userName || '-'; |
| | | var type = w.workerTypeName || (WORKER_TYPE[w.workerType] || ''); |
| | | var color = { 10: 'var(--blue)', 20: 'var(--green)', 30: 'var(--primary-light)', 40: 'var(--red)', 50: 'var(--gray)' }[w.workerType] || 'var(--gray)'; |
| | | html += '<span class="pill"><span class="dot" style="background:' + color + '"></span>' + |
| | | esc(type) + 'ï¼' + esc(name) + '</span>'; |
| | | }); |
| | | html += '</div>'; |
| | | return card('ç产人å', null, html, { collapsible: true, open: false }); |
| | | } |
| | | |
| | | // åºå5ï¼æ«ç å
¥åºäºä»¶ |
| | | function buildInboundCard(d) { |
| | | var e = d.inbound; |
| | | if (!e) return ''; |
| | | return card('æ«ç å
¥åº', null, |
| | | kv('äºä»¶å·', text(e.eventId)) + |
| | | kv('å
¥åºæ°é', fmtNum(e.quantity)) + |
| | | kv('设å¤ç¼ç ', text(e.deviceCode)) + |
| | | kv('产线', text(e.lineCode)) + |
| | | kv('å
¥åºæ¶é´', fmtDate(e.eventTime)), |
| | | { collapsible: true, open: false } |
| | | ); |
| | | } |
| | | |
| | | // åºå6ï¼æç |
| | | function buildPalletCard(d) { |
| | | if (isEmptyList(d.pallets)) return ''; |
| | | var countHtml = 'å
± ' + esc(d.palletCount || d.pallets.length) + ' 个'; |
| | | var rows = '<table class="mini-table"><thead><tr><th>æçç </th><th>åºå·</th><th>å·²è£
/å¯è£
</th></tr></thead><tbody>'; |
| | | d.pallets.forEach(function (p) { |
| | | rows += '<tr><td>' + text(p.code) + '</td><td>' + fmtNum(p.palletNo) + '</td><td>' + |
| | | fmtNum(p.bagCount) + ' / ' + fmtNum(p.capacity) + '</td></tr>'; |
| | | }); |
| | | rows += '</tbody></table>'; |
| | | return card('æçä¿¡æ¯', countHtml, rows, { collapsible: true, open: false }); |
| | | } |
| | | |
| | | // åºå7ï¼è¢ç ï¼ä¸è¢ä¸ç ï¼ |
| | | function buildBagCard(d) { |
| | | if (d.bagTotal === null || d.bagTotal === undefined || d.bagTotal === 0) return ''; |
| | | var countHtml = 'å
± ' + esc(d.bagTotal) + ' 个' + (d.bags && d.bags.length < d.bagTotal ? 'ï¼å±ç¤ºå ' + esc(d.bags.length) + ' 个ï¼' : ''); |
| | | var rows = '<table class="mini-table"><thead><tr><th>è¢ç </th><th>è¢å·</th><th>æç</th><th>ç¶æ</th></tr></thead><tbody>'; |
| | | (d.bags || []).forEach(function (b) { |
| | | rows += '<tr><td>' + text(b.code) + '</td><td>' + fmtNum(b.bagNo) + '</td><td>' + text(b.palletCode) + '</td><td>' + |
| | | statusBadge(BAG_STATUS, b.status) + '</td></tr>'; |
| | | }); |
| | | rows += '</tbody></table>'; |
| | | return card('è¢ç ä¿¡æ¯', countHtml, |
| | | '<div class="scroll-list">' + rows + '</div>', |
| | | { collapsible: true, open: false } |
| | | ); |
| | | } |
| | | |
| | | // åºå8ï¼å¯éæ©å±ï¼éè´æ¥æº / éå®å»å / å å·¥æµè½¬ï¼ï¼ææ°æ®æå±ç¤º |
| | | function buildOptionalCard(d) { |
| | | var html = ''; |
| | | if (!isEmptyList(d.purchaseSources)) { |
| | | var rows = '<table class="mini-table"><thead><tr><th>éè´å
¥åºå</th><th>ä¾åºå</th><th>æ°é</th><th>æ¥æ</th></tr></thead><tbody>'; |
| | | d.purchaseSources.forEach(function (s) { |
| | | rows += '<tr><td>' + text(s.receiptCode) + '</td><td>' + text(s.vendorName) + '</td><td>' + fmtNum(s.receivedQuantity) + '</td><td>' + fmtDate(s.receiptDate) + '</td></tr>'; |
| | | }); |
| | | rows += '</tbody></table>'; |
| | | html += card('éè´æ¥æº', null, rows, { collapsible: true, open: false }); |
| | | } |
| | | if (!isEmptyList(d.salesTargets)) { |
| | | var rows2 = '<table class="mini-table"><thead><tr><th>éå®åºåºå</th><th>客æ·</th><th>æ°é</th><th>æ¥æ</th></tr></thead><tbody>'; |
| | | d.salesTargets.forEach(function (s) { |
| | | rows2 += '<tr><td>' + text(s.outCode || s.salesOrderCode || '') + '</td><td>' + text(s.customerName) + '</td><td>' + fmtNum(s.quantity) + '</td><td>' + fmtDate(s.outTime) + '</td></tr>'; |
| | | }); |
| | | rows2 += '</tbody></table>'; |
| | | html += card('éå®å»å', null, rows2, { collapsible: true, open: false }); |
| | | } |
| | | if (!isEmptyList(d.processTraces)) { |
| | | var rows3 = '<table class="mini-table"><thead><tr><th>èç¹</th><th>说æ</th><th>æ¶é´</th></tr></thead><tbody>'; |
| | | d.processTraces.forEach(function (t) { |
| | | rows3 += '<tr><td>' + text(t.nodeName) + '</td><td>' + text(t.description) + '</td><td>' + fmtDate(t.processTime) + '</td></tr>'; |
| | | }); |
| | | rows3 += '</tbody></table>'; |
| | | html += card('å å·¥æµè½¬', null, rows3, { collapsible: true, open: false }); |
| | | } |
| | | var html = '<div class="verify ' + (repeated ? 'warn' : 'ok') + '">' + |
| | | '<span class="vico">' + icon + '</span>' + |
| | | '<div class="vtxt"><div class="vt">' + title + '</div><div class="vs">' + desc + '</div></div>' + |
| | | '</div>'; |
| | | html += '<div class="code-box"><span class="cl">é²ä¼ªç¼ç </span><span class="cv">' + esc(code || '-') + '</span></div>'; |
| | | html += kv('对åºåç§', text(name)); |
| | | html += d.batchCode |
| | | ? kv('å¯¹åºæ¹æ¬¡', text(d.batchCode)) |
| | | : kv('å¯¹åºæ¹æ¬¡', 'å°æªç»å®æ¹æ¬¡', true); |
| | | html += '<div class="stat-grid">' + |
| | | '<div class="stat span2 count"><div class="sl">该ç 累计被æ¥è¯¢æ¬¡æ°</div>' + |
| | | '<div class="sv">' + n + '<span class="u">次</span></div></div>' + |
| | | '<div class="stat"><div class="sl">馿¬¡æ¥è¯¢æ¶é´</div><div class="sv">' + fmtDate(af.firstScanTime) + '</div></div>' + |
| | | '<div class="stat"><div class="sl">æè¿æ¥è¯¢æ¶é´</div><div class="sv">' + fmtDate(af.lastScanTime) + '</div></div>' + |
| | | '</div>'; |
| | | html += '<div class="notice">' + (repeated |
| | | ? 'åä¸é²ä¼ªç 被é夿¥è¯¢ï¼å¯è½æå³çå
è£
被å¤å¶ãè¯·æ ¸å¯¹å
è£
ä¸å°å¶çé²ä¼ªç¼ç 䏿¬é¡µæ¾ç¤ºæ¯å¦ä¸è´ï¼å¦æçé®è¯·èç³»å®æ¹æ ¸å®ã' |
| | | : 'è¯·æ ¸å¯¹å
è£
ä¸å°å¶çé²ä¼ªç¼ç 䏿¬é¡µæ¾ç¤ºæ¯å¦ä¸è´ï¼å¹¶ç¡®è®¤å
è£
å®å¥½ã') + '</div>'; |
| | | return html; |
| | | } |
| | | |
| | | // ========== åå§å ========== |
| | | // åºå2ï¼è¿½æº¯æ¥è¯¢ï¼æªå½å
¥æ¹æ¬¡æ¶åªå±ç¤ºåç§ä¿¡æ¯ + æç¤ºï¼ |
| | | function tracePanel(d) { |
| | | var code = resolveCode(d); |
| | | var name = [d.itemName, d.itemSpecification].filter(Boolean).join(' '); |
| | | var unbound = d.batchBound === false; |
| | | var batchRows = unbound |
| | | ? '<div class="notice">该追溯ç å°æªå½å
¥çäº§æ¹æ¬¡ï¼æ¹æ¬¡å·ãçäº§æ¥æã产线çä¿¡æ¯å¾
å®åï¼å½åå±ç¤ºè¯¥ç 对åºçåç§ä¿¡æ¯ã</div>' |
| | | : kv('æ¹æ¬¡å·', text(d.batchCode)) + |
| | | kv('çäº§æ¥æ', fmtDate(d.produceDate)) + |
| | | kv('产线', text(d.lineName || d.lineCode)); |
| | | return kv('åç§åç§°', text(name)) + |
| | | kv('计éåä½', text(d.itemUnitMeasureName)) + |
| | | kv('ç产ç»è¥è
', esc(COMPANY_NAME)) + |
| | | kv('åå
è¯å«ä»£ç ', text(code || '-')) + |
| | | kv('追溯ç½å', '<a class="link" href="' + esc(TRACE_URL) + '">' + esc(TRACE_URL) + '</a>') + |
| | | kv('追溯类å', esc(SOURCE_TYPE[d.sourceType] || '追溯ç ')) + |
| | | batchRows; |
| | | } |
| | | |
| | | // åºå3~ï¼ç产æç»ï¼æå ï¼ææ°æ®æå±ç¤ºï¼ |
| | | function detailSections(d) { |
| | | var html = ''; |
| | | |
| | | // çäº§æ¹æ¬¡ä¿¡æ¯ |
| | | var batchBody = |
| | | kv('æ¹æ¬¡ç¶æ', d.batchStatusName ? statusBadge({ v: [d.batchStatusName, 'blue'] }, 'v') : text(d.batchStatus)) + |
| | | kv('è®¡åæ°é', fmtNum(d.planQuantity)) + |
| | | kv('å·²çæè¢ç ', fmtNum(d.bagQuantity)) + |
| | | kv('å·²çææç', fmtNum(d.palletQuantity)) + |
| | | kv('å
¥åºæ¶é´', fmtDate(d.inboundTime)) + |
| | | kv('ä¸´æ¶æ¹æ¬¡ç ', text(d.tempCode)) + |
| | | kv('夿³¨', text(d.remark)); |
| | | html += sec('çäº§æ¹æ¬¡ä¿¡æ¯', null, batchBody, { collapsible: true, open: false }); |
| | | |
| | | // è´¨æ£ä¿¡æ¯ |
| | | if (d.quality) { |
| | | var q = d.quality; |
| | | var qBody = |
| | | kv('è´¨æ£ç»è®º', q.resultName ? '<span class="badge ' + (q.result === 1 ? 'green' : 'red') + '">' + esc(q.resultName) + '</span>' : '-') + |
| | | kv('æ£éªå', text(q.inspectorName)) + |
| | | kv('æ£éªæ¶é´', fmtDate(q.inspectedAt)) + |
| | | (q.reason ? kv('ä¸åæ ¼åå ', text(q.reason)) : ''); |
| | | if (!isEmptyList(q.indicators)) { |
| | | var rows = q.indicators.map(function (i) { |
| | | var hasMin = i.minValue !== null && i.minValue !== undefined; |
| | | var hasMax = i.maxValue !== null && i.maxValue !== undefined; |
| | | var range = '-'; |
| | | if (hasMin && hasMax) range = fmtNum(i.minValue) + ' ~ ' + fmtNum(i.maxValue); |
| | | else if (hasMin) range = '⥠' + fmtNum(i.minValue); |
| | | else if (hasMax) range = '⤠' + fmtNum(i.maxValue); |
| | | var pass = i.pass === null || i.pass === undefined |
| | | ? '-' |
| | | : '<span class="badge ' + (i.pass ? 'green' : 'red') + '">' + (i.pass ? 'åæ ¼' : 'ä¸åæ ¼') + '</span>'; |
| | | return [text(i.indicatorName), fmtNum(i.value), range, pass]; |
| | | }); |
| | | qBody += '<div style="margin-top:8px">' + table(['æ£æµé¡¹', 'æ£æµå¼', 'æ åèå´', 'ç»è®º'], rows) + '</div>'; |
| | | } |
| | | html += sec('è´¨æ£ä¿¡æ¯', null, qBody, { collapsible: true, open: false }); |
| | | } |
| | | |
| | | // ç产人å |
| | | if (!isEmptyList(d.workers)) { |
| | | var wBody = d.workers.map(function (w) { |
| | | return li('<span class="li-ttl">' + text(w.userName) + '</span>' + |
| | | (w.workerTypeName ? '<span class="badge gray">' + esc(w.workerTypeName) + '</span>' : ''), |
| | | null, |
| | | w.remark ? kv('夿³¨', text(w.remark)) : ''); |
| | | }).join(''); |
| | | html += sec('ç产人å', d.workers.length + ' 人', '<div class="scroll-list">' + wBody + '</div>', { collapsible: true, open: false }); |
| | | } |
| | | |
| | | // æçä¿¡æ¯ |
| | | if (!isEmptyList(d.pallets)) { |
| | | var pRows = d.pallets.map(function (p) { |
| | | return [text(p.code), fmtNum(p.palletNo), fmtNum(p.bagCount), fmtNum(p.capacity)]; |
| | | }); |
| | | html += sec('æçä¿¡æ¯', 'å
± ' + fmtNum(d.palletCount || d.pallets.length) + ' 个', |
| | | '<div class="scroll-list">' + table(['æçç ', 'åºå·', 'å·²è£
è¢', 'å¯è£
è¢'], pRows) + '</div>', |
| | | { collapsible: true, open: false }); |
| | | } |
| | | |
| | | // è¢ç å表 |
| | | if (!isEmptyList(d.bags)) { |
| | | var bBody = d.bags.map(function (b) { |
| | | return li('<span class="li-ttl">' + text(b.code) + '</span>' + |
| | | (b.statusName ? '<span class="badge gray">' + esc(b.statusName) + '</span>' : ''), |
| | | fmtDate(b.inboundTime), |
| | | kv('è¢å·', fmtNum(b.bagNo)) + (b.palletCode ? kv('æçç ', text(b.palletCode)) : '')); |
| | | }).join(''); |
| | | var bagCountText = 'å
± ' + fmtNum(d.bagTotal || d.bags.length) + ' è¢' + |
| | | (Number(d.bagTotal) > d.bags.length ? 'ï¼æ¾ç¤ºå ' + d.bags.length + ' æ¡ï¼' : ''); |
| | | html += sec('è¢ç å表', bagCountText, '<div class="scroll-list">' + bBody + '</div>', { collapsible: true, open: false }); |
| | | } |
| | | |
| | | // éè´æ¥æº |
| | | if (!isEmptyList(d.purchaseSources)) { |
| | | var psRows = d.purchaseSources.map(function (s) { |
| | | return [text(s.receiptCode), text(s.vendorName), nw(fmtNum(s.receivedQuantity)), nw(fmtDay(s.receiptDate))]; |
| | | }); |
| | | html += sec('éè´æ¥æº', null, table(['éè´å
¥åºå', 'ä¾åºå', 'æ°é', 'æ¥æ'], psRows), { collapsible: true, open: false }); |
| | | } |
| | | |
| | | // ç§åæµåä¿¡æ¯ï¼ä»
éå®åºåº bizType=119ï¼ |
| | | var salesFlows = (d.seedFlows || []).filter(function (f) { return f.bizType === 119; }); |
| | | if (!isEmptyList(salesFlows)) { |
| | | var sfBody = salesFlows.map(function (f) { |
| | | var qty = (f.quantity === null || f.quantity === undefined) ? '-' : fmtNum(Math.abs(Number(f.quantity))); |
| | | var wh = [f.warehouseName, f.locationName].filter(Boolean).join(' / ') || '-'; |
| | | return li(statusBadge(FLOW_DIRECTION, f.type) + '<span class="li-ttl">' + esc(FLOW_BIZ_TYPE[f.bizType] || '') + '</span>', |
| | | fmtDate(f.transactionTime), |
| | | kv('æ¥æºåå·', text(f.bizCode)) + |
| | | kv('客æ·', text(f.clientName)) + |
| | | kv('æ°é', qty) + |
| | | kv('ä»åº/åºåº', text(wh))); |
| | | }).join(''); |
| | | html += sec('ç§åæµåä¿¡æ¯', null, '<div class="scroll-list">' + sfBody + '</div>', { collapsible: true, open: false }); |
| | | } else if (!isEmptyList(d.salesTargets)) { |
| | | var stRows = d.salesTargets.map(function (s) { |
| | | return [text(s.salesCode || s.salesOrderCode || ''), text(s.clientName), nw(fmtNum(s.quantity)), nw(fmtDay(s.salesDate))]; |
| | | }); |
| | | html += sec('ç§åæµåä¿¡æ¯', null, table(['éå®åºåºå', '客æ·', 'æ°é', 'æ¥æ'], stRows), { collapsible: true, open: false }); |
| | | } |
| | | |
| | | // å å·¥æµè½¬ |
| | | if (!isEmptyList(d.processTraces)) { |
| | | var ptBody = d.processTraces.map(function (t) { |
| | | return li('<span class="li-ttl">' + text(t.nodeName) + '</span>', fmtDate(t.processTime), |
| | | t.description ? kv('说æ', text(t.description)) : ''); |
| | | }).join(''); |
| | | html += sec('å å·¥æµè½¬', null, '<div class="scroll-list">' + ptBody + '</div>', { collapsible: true, open: false }); |
| | | } |
| | | |
| | | return html; |
| | | } |
| | | |
| | | // ========== äº¤äº ========== |
| | | // æå åºåï¼æ é¢ç¹å»å±å¼/æ¶èµ· |
| | | STATE.addEventListener('click', function (e) { |
| | | var hd = e.target.closest ? e.target.closest('.sec.collapsible .sec-hd') : null; |
| | | if (hd) hd.parentNode.classList.toggle('open'); |
| | | }); |
| | | |
| | | SEARCH_BTN.addEventListener('click', function () { query(CODE_INPUT.value); }); |
| | | CODE_INPUT.addEventListener('keydown', function (e) { if (e.key === 'Enter') query(CODE_INPUT.value); }); |
| | | |
| | | // å
¬å¸ä»ç»ï¼å
容è¶
åºå¯æå é«åº¦æ¶ææ¾ç¤ºâç¹å»æ¥çæ´å¤â |
| | | (function initCompanyToggle() { |
| | | var clip = document.getElementById('companyClip'); |
| | | var wrap = document.getElementById('companyMoreWrap'); |
| | | var more = document.getElementById('companyMore'); |
| | | if (clip.scrollHeight <= clip.clientHeight + 4) { |
| | | clip.classList.add('open'); |
| | | wrap.style.display = 'none'; |
| | | return; |
| | | } |
| | | more.addEventListener('click', function () { |
| | | var open = clip.classList.toggle('open'); |
| | | more.textContent = open ? 'æ¶èµ·' : 'ç¹å»æ¥çæ´å¤'; |
| | | }); |
| | | })(); |
| | | |
| | | var initialCode = new URLSearchParams(location.search).get('code') || ''; |
| | | CODE_INPUT.value = initialCode; |
| | |
| | | query(initialCode); |
| | | } else { |
| | | renderState('<div class="empty-tip">æ«ç æè¾å
¥è¿½æº¯ç ï¼å³å¯æ¥è¯¢äº§åå
¨ç¨æº¯æºä¿¡æ¯</div>'); |
| | | CODE_INPUT.focus(); |
| | | } |
| | | })(); |
| | | </script> |