feat(mes): 补生产准备检查与仓储收发存汇总接口,附 CFWJ 演示数据种子脚本
- 生产主计划新增 /mes/pro-mps/preparation-check:按 BOM 展开物料需求,对比现有库存与在途采购,
给出齐套结论;同时检查工艺路线各工序绑定设备的可用状态,输出可直接展示的结论摘要。
- 库存事务新增 /mes/wm/transaction/summary:按物料+仓库汇总期初、本期入库、本期出库、期末数量,
未指定时间时默认统计近三个月,保证期初不总是 0。
- 物料需求的库存查询按 mes_md_item.id → mdm_item.id 换算后再查 mes_wm_material_stock,
修复本地物料 id 两套口径下准备检查库存恒为 0 的问题。
- 设备状态枚举补充 valueOfStatus,供准备检查解析设备状态名称。
- scripts/cfwj-demo-seed-20261103:覆盖 7 大模块的演示数据生成脚本(仅本地 CFWJ 库),
含主数据与采购→入库→检验、销售→计划→工单→报工→入库→出货两条完整链路。
Co-Authored-By: Claude Code <noreply@anthropic.com>
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | # è¯åäºéï¼CFWJï¼æ¼ç¤ºæ°æ®çæèæ¬ |
| | | |
| | | é¢åãä¸å°ä¼ä¸æ°ååæ°´å¹³è¯æµææ ï¼2024 å¹´çï¼ãäºçº§ææ ï¼çæè¦ç 7 大ä¸å¡æ¨¡å |
| | | ï¼è®¡åæç¨ãç产管æ§ã设å¤ç®¡çãéè´ç®¡çãä»å¨ç©æµãè¥é管çã人åèµæºï¼ç宿´æ¼ç¤ºæ°æ®ã |
| | | |
| | | ## åªå
è®¸å¨æ¬å°åºæ§è¡ |
| | | |
| | | èæ¬è¿æ¥çåºåæ»ä¸ºï¼ |
| | | |
| | | ``` |
| | | 127.0.0.1:3306 / CFWJ / root / 123456 |
| | | ``` |
| | | |
| | | **ä¸¥ç¦æ `DB` é
ç½®æ¹æå®¢æ·ç产åºååæ§è¡**ï¼èæ¬ç¬¬ä¸æ¥å°±ä¼æåºå® id å é¤å¹¶éæä¸å¡åæ®ã |
| | | |
| | | ## æ§è¡é¡ºåº |
| | | |
| | | ```bash |
| | | python3 seed_cfwj.py # ä¸»æ°æ®ï¼ç©æãåç±»ãåä½ãä»åºãå·¥èºè·¯çº¿ãBOMãå·¥ä½ã客æ·ä¾åºåãç¨æ· |
| | | python3 seed_cfwj_docs.py # ä¸å¡é¾è·¯ï¼éè´âå°è´§âå
¥åºâæ£éªï¼éå®âMPSâå·¥åâæ¥å·¥âå
¥åºâåºè´§ï¼è®¾å¤ï¼èå¤èªé
¬ |
| | | ``` |
| | | |
| | | ä¸¤ä¸ªèæ¬é½å¯é夿§è¡ï¼å
æåºå® id æ¸
çèªå·±åå
¥çè¡ï¼åéæ°æå
¥ï¼æ¶é´æ³ç± `id + md5` |
| | | æ¨å¯¼å¹¶è½å¨å·¥ä½æ¥å·¥ä½æ¶æ®µï¼å æ¤éè·ç»æç¨³å®ã |
| | | |
| | | ## æ°æ®é¾è·¯ |
| | | |
| | | | é¾è·¯ | è¦ç表 | |
| | | |------|--------| |
| | | | éè´å
¥åº | erp_purchase_request(_items) â erp_purchase_order(_items) â mes_wm_arrival_notice(_line) â mes_wm_item_receipt(_line) â mes_wm_batch â mes_qc_iqc | |
| | | | ç产 | erp_sale_order(_items) â mes_pro_mps â mes_pro_work_order(_process) â mes_pro_feedback â mes_pro_card â mes_wm_product_receipt(_line) â mes_qc_ipqc | |
| | | | éå®åºåº | mes_wm_product_sales(_line) â mes_qc_oqc â mes_wm_transaction | |
| | | | åºå | mes_wm_transactionï¼42 æ¡ï¼éæ¡æ±æ»æ mes_wm_material_stockï¼14 è¡ï¼ï¼æ¶ååæ±æ»é¡µçææ«æ°ä¸ç°æéä¸è´ | |
| | | | è´¨é | mes_qc_{template,indicator,template_indicator,iqc,ipqc,oqc,rqc,defect,ncr} | |
| | | | è®¾å¤ | mes_dv_{subject,checkplan,checkrecord,maintenrecord,repair,spare,metering} | |
| | | | 人å | hrm_attendance_recordï¼300 æ¡ï¼ãhrm_salary_calculationï¼10 æ¡ï¼ãhrm_salary_paymentï¼1 æ¡ï¼ | |
| | | |
| | | å¾
æ£ä»»å¡é¡µéè¦çãå·²å°è´§æªæ£éªãï¼å°è´§éç¥ 6/7ï¼ä¸ãå·²åºåºæªæ£éªãï¼éå®åºåºå 4ãéè´§æ£éª RQCï¼å¨ |
| | | `seed_cfwj_docs.py` 第 13 èè¡¥å
ã |
| | | |
| | | ## ç©æ id å£å¾ |
| | | |
| | | `mes_md_item.id` ä¸ `mdm_item.id` 卿¬åºå·²ç»ä¸ä¸ºåä¸å¥ idï¼1001â1016ï¼ï¼ |
| | | ä»å¨/ERP è¡¨ç´æ¥åè¿å¥ idï¼MES ç产表ä¹ååä¸å¥ï¼é¿å
ä¸¤å¥ id äº¤åæ¥è¯¢æ¶åºååä¸å°ã |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | #!/usr/bin/env python3 |
| | | """CFWJ æ¼ç¤ºæ°æ®çæï¼ä¸»æ°æ® + ä¸å¡é¾è·¯ï¼ä»
æ¬å° CFWJ åºï¼""" |
| | | import pymysql, datetime, hashlib |
| | | |
| | | DB = dict(host='127.0.0.1', port=3306, user='root', password='123456', database='CFWJ', charset='utf8mb4', autocommit=False) |
| | | conn = pymysql.connect(**DB) |
| | | cur = conn.cursor() |
| | | |
| | | def workday(d): |
| | | while d.weekday() >= 5: |
| | | d -= datetime.timedelta(days=1) |
| | | return d |
| | | |
| | | def ts(base, seed, day_offset=0, hour_min=8, hour_max=18): |
| | | """æ seed æ´¾çä¸ä¸ªè½å¨å·¥ä½æ¶æ®µå
çç宿æ¶é´""" |
| | | h = int(hashlib.md5(str(seed).encode()).hexdigest(), 16) |
| | | d = workday(base + datetime.timedelta(days=day_offset)) |
| | | minutes = (h % ((hour_max - hour_min) * 60)) + hour_min * 60 |
| | | return datetime.datetime.combine(d, datetime.time(minutes // 60, minutes % 60, (h >> 8) % 60)) |
| | | |
| | | def clean(table, ids): |
| | | fmt = ','.join(['%s'] * len(ids)) |
| | | cur.execute(f"DELETE FROM {table} WHERE id IN ({fmt})", ids) |
| | | |
| | | def ins(table, cols, rows): |
| | | if not rows: |
| | | return |
| | | ph = ','.join(['%s'] * len(cols)) |
| | | sql = f"INSERT INTO {table} ({','.join(cols)}) VALUES ({ph})" |
| | | cur.executemany(sql, rows) |
| | | |
| | | BASE = datetime.date(2026, 8, 3) |
| | | |
| | | # ---------------- åä½ ---------------- |
| | | unit_rows = [ |
| | | (1, 'PCS', 'ä»¶', 1, None, 1, 0), (2, 'KG', 'åå
', 1, None, 1, 0), |
| | | (3, 'M', 'ç±³', 1, None, 1, 0), (4, 'SET', 'å¥', 1, None, 1, 0), |
| | | (5, 'BOX', 'ç®±', 1, None, 1, 0), (6, 'L', 'å', 1, None, 1, 0), |
| | | (7, 'T', 'å¨', 1, None, 1, 0), (8, 'GE', '个', 1, None, 1, 0), |
| | | ] |
| | | for t in ('mes_md_unit_measure', 'mdm_unit_measure'): |
| | | clean(t, [r[0] for r in unit_rows]) |
| | | ins(t, ['id', 'code', 'name', 'primary_flag', 'primary_id', 'change_rate', 'status'], |
| | | [(r[0], r[1], r[2], r[3], r[4], r[5], r[6]) for r in unit_rows]) |
| | | |
| | | # ---------------- åç±» ---------------- |
| | | cats = [ |
| | | (1, 'MYL', 'åæ', 1), (2, 'BCP', 'åæå', 2), (3, 'CP', 'æå', 3), (4, 'FL', 'è¾
æ', 4), |
| | | ] |
| | | clean('mdm_item_category', [c[0] for c in cats]) |
| | | ins('mdm_item_category', ['id', 'parent_id', 'code', 'name', 'item_type', 'item_or_product', 'sort', 'status'], |
| | | [(c[0], 0, c[1], c[2], c[3], 'PRODUCT' if c[3] == 3 else 'ITEM', c[0], 0) for c in cats]) |
| | | |
| | | clean('mes_md_item_type', [c[0] for c in cats]) |
| | | ins('mes_md_item_type', ['id', 'code', 'name', 'parent_id', 'item_or_product', 'sort', 'status'], |
| | | [(c[0], c[1], c[2], 0, 'PRODUCT' if c[3] == 3 else 'ITEM', c[0], 0) for c in cats]) |
| | | |
| | | # ---------------- ç©æ ---------------- |
| | | # (mdm_id, code, name, spec, unit_id, item_type, price, category_id) |
| | | items = [ |
| | | (1001, 'CP-FLP-050', 'æ³å
°ç DN50', 'DN50 PN16', 1, 3, 120, 3), |
| | | (1002, 'CP-FLP-100', 'æ³å
°ç DN100', 'DN100 PN16', 1, 3, 185, 3), |
| | | (1003, 'CP-ZCZ-6205', 'è½´æ¿åº§ 6205', '6205 é¸é', 1, 3, 260, 3), |
| | | (1004, 'CP-LZQ-045', 'èè½´å¨ LZ-45', 'LZ-45 45#é¢', 4, 3, 340, 3), |
| | | (1005, 'CP-VH-100', 'éé¨å£³ä½ VH-100', 'VH-100 ä¸éé¢', 1, 3, 520, 3), |
| | | (1006, 'CP-GB-200', 'é½¿è½®ç®±ä½ GB-200', 'GB-200 é¸é', 1, 3, 980, 3), |
| | | (1007, 'BCP-FLP-050', 'æ³å
°æ¯å¯ DN50', 'DN50 é»é ', 1, 2, 80, 2), |
| | | (1008, 'BCP-FLP-100', 'æ³å
°æ¯å¯ DN100', 'DN100 é»é ', 1, 2, 120, 2), |
| | | (1009, 'MYL-GB-060', '45#颿£', 'Ï60', 2, 1, 6.5, 1), |
| | | (1010, 'MYL-ZT-250', 'é¸éé', 'HT250', 2, 1, 4.8, 1), |
| | | (1011, 'MYL-BXG-3', 'ä¸é颿¿', '304 3mm', 2, 1, 22, 1), |
| | | (1012, 'MYL-LS-M8', 'èºæ ', 'M8Ã30', 8, 1, 0.6, 1), |
| | | (1013, 'MYL-LM-M8', 'èºæ¯', 'M8', 8, 1, 0.3, 1), |
| | | (1014, 'MYL-MFQ-40', 'å¯å°å', 'O-40 ä¸è
', 8, 1, 1.2, 1), |
| | | (1015, 'FL-QXY-20', 'ååæ¶²', '20L/æ¡¶', 6, 4, 18, 4), |
| | | (1016, 'FL-FXQ-15', 'é²éæ¼', '15kg/æ¡¶', 2, 4, 26, 4), |
| | | ] |
| | | clean('mdm_item', [i[0] for i in items]) |
| | | ins('mdm_item', ['id', 'code', 'name', 'specification', 'category_id', 'unit_measure_id', 'item_type', |
| | | 'status', 'purchase_price', 'sales_price', 'cost_price', 'is_batch_managed', 'is_serial_managed'], |
| | | [(i[0], i[1], i[2], i[3], i[7], i[4], i[5], 0, i[6], round(i[6] * 1.35, 2), round(i[6] * 0.8, 2), 1 if i[5] == 3 else 0, 0) |
| | | for i in items]) |
| | | |
| | | mes_items = [] |
| | | for idx, i in enumerate(items): |
| | | mes_items.append((i[0], i[0], i[1], i[2], i[3], i[4], i[7], 0)) |
| | | clean('mes_md_item', [m[0] for m in mes_items]) |
| | | ins('mes_md_item', ['id', 'mdm_item_id', 'code', 'name', 'specification', 'unit_measure_id', 'item_type_id', 'status'], |
| | | mes_items) |
| | | |
| | | # ---------------- ä»åº / åºåº / åºä½ ---------------- |
| | | whs = [ |
| | | (1, 'WH-RAW', 'åæä»', 1), (2, 'WH-SEMI', 'åæåä»', 2), |
| | | (3, 'WH-FIN', 'æåä»', 3), (4, 'WH-AUX', 'è¾
æä»', 4), |
| | | ] |
| | | clean('mes_wm_warehouse', [w[0] for w in whs]) |
| | | ins('mes_wm_warehouse', ['id', 'code', 'name', 'warehouse_type', 'frozen'], |
| | | [(w[0], w[1], w[2], w[3], 0) for w in whs]) # warehouse_type 1~4 ä¸ä»åºæ§è´¨å¯¹åº |
| | | |
| | | locs = [(101, 'LC-RAW-A', 'åæAåº', 1), (102, 'LC-RAW-B', 'åæBåº', 1), |
| | | (103, 'LC-SEMI-A', 'åæåAåº', 2), (104, 'LC-FIN-A', 'æåAåº', 3), |
| | | (105, 'LC-AUX-A', 'è¾
æAåº', 4)] |
| | | clean('mes_wm_warehouse_location', [l[0] for l in locs]) |
| | | ins('mes_wm_warehouse_location', ['id', 'code', 'name', 'warehouse_id', 'frozen'], |
| | | [(l[0], l[1], l[2], l[3], 0) for l in locs]) |
| | | |
| | | areas = [] |
| | | aid = 201 |
| | | for l in locs: |
| | | for n in (1, 2): |
| | | areas.append((aid, f'AR-{l[0]}-{n:02d}', f'{l[2]}-{n}å·ä½', l[0])) |
| | | aid += 1 |
| | | clean('mes_wm_warehouse_area', [a[0] for a in areas]) |
| | | ins('mes_wm_warehouse_area', ['id', 'code', 'name', 'location_id', 'status'], |
| | | [(a[0], a[1], a[2], a[3], 0) for a in areas]) |
| | | # ä»åºé»è®¤åºä½ï¼åæ 201, åæå 205, æå 207, è¾
æ 209 |
| | | AREA = {1: 201, 2: 205, 3: 207, 4: 209} |
| | | LOC = {1: 101, 2: 103, 3: 104, 4: 105} |
| | | |
| | | # ---------------- ä¾åºå ---------------- |
| | | sup = [ |
| | | (1, 'V001', 'åå±±é¢éè´¸ææéå
¬å¸', 'åå±±é¢é', 'å¼ å»ºå½', '13803150001'), |
| | | (2, 'V002', 'æ²³åæéé¸é å', 'æéé¸é ', 'ææµ·æ³¢', '13803150002'), |
| | | (3, 'V003', '天津ä¸é颿ææéå
¬å¸', 'æ´¥ä¸é', 'ç丽', '13803150003'), |
| | | (4, 'V004', 'ç³å®¶åºæ åä»¶æéå
¬å¸', 'ç³æ ä»¶', 'å强', '13803150004'), |
| | | (5, 'V005', 'åå±±è¾
æä¾åºç«', 'è¾
æç«', 'èµµæ', '13803150005'), |
| | | ] |
| | | clean('srm_supplier', [s[0] for s in sup]) |
| | | ins('srm_supplier', ['id', 'code', 'name', 'short_name', 'type', 'legal_person', 'contact_name', 'contact_mobile', 'status'], |
| | | [(s[0], s[1], s[2], s[3], 1, s[4], s[4], s[5], 0) for s in sup]) |
| | | clean('mes_md_vendor', [s[0] for s in sup]) |
| | | ins('mes_md_vendor', ['id', 'code', 'name', 'nickname', 'status', 'contact1_name', 'contact1_telephone'], |
| | | [(s[0], s[1], s[2], s[3], 0, s[4], s[5]) for s in sup]) |
| | | |
| | | # ---------------- å®¢æ· ---------------- |
| | | cust = [ |
| | | (1, 'åå±±åè¿æºæ¢°æéå
¬å¸', 'åè¿æºæ¢°', '13903150001', 121, 243), |
| | | (2, 'æ²³åé«è¾¾éå·¥æéå
¬å¸', 'é«è¾¾éå·¥', '13903150002', 121, 244), |
| | | (3, '天津滨海è£
å¤å¶é æéå
¬å¸', '滨海è£
å¤', '13903150003', 121, 245), |
| | | (4, 'å京京è¯ç²¾å¯æºæ¢°æéå
¬å¸', '京è¯ç²¾å¯', '13903150004', 121, 246), |
| | | (5, '秦ç岿¸¯æºè®¾å¤æéå
¬å¸', '秦港设å¤', '13903150005', 121, 247), |
| | | (6, 'å山德éå·¥ä¸è®¾å¤æéå
¬å¸', 'å¾·éå·¥ä¸', '13903150006', 121, 248), |
| | | ] |
| | | clean('crm_customer', [c[0] for c in cust]) |
| | | ins('crm_customer', ['id', 'name', 'mobile', 'owner_user_id', 'owner_time', 'follow_up_status', 'lock_status', |
| | | 'deal_status', 'customer_type', 'level', 'source', 'creator', 'create_time'], |
| | | [(c[0], c[1], c[3], c[4], ts(BASE, c[0]), 1, 0, 1, 1, 2, 1, '1', ts(BASE, 900 + c[0])) for c in cust]) |
| | | |
| | | # ---------------- å·¥å / è½¦é´ / å·¥åº / å·¥ä½ ---------------- |
| | | clean('mes_md_factory', [1]) |
| | | ins('mes_md_factory', ['id', 'code', 'name', 'address', 'status'], [(1, 'F001', 'è¯åäºéå·¥å', 'åå±±å¸', 0)]) |
| | | clean('mes_md_workshop', [1]) |
| | | ins('mes_md_workshop', ['id', 'code', 'factory_id', 'name', 'status'], [(1, 'WS001', 1, 'æºå 工车é´', 0)]) |
| | | |
| | | procs = [(1, 'OP-CUT', '䏿'), (2, 'OP-TURN', '车å'), (3, 'OP-MILL', 'é£å'), (4, 'OP-DRILL', 'é»å'), |
| | | (5, 'OP-ASSY', 'è£
é
'), (6, 'OP-QC', 'ç»æ£')] |
| | | clean('mes_pro_process', [p[0] for p in procs]) |
| | | ins('mes_pro_process', ['id', 'code', 'name', 'status'], [(p[0], p[1], p[2], 0) for p in procs]) |
| | | |
| | | wss = [(1, 'WS-CUT-01', '䏿工ä½', 1), (2, 'WS-TURN-01', '车åå·¥ä½', 2), (3, 'WS-MILL-01', 'é£åå·¥ä½', 3), |
| | | (4, 'WS-DRILL-01', 'é»åå·¥ä½', 4), (5, 'WS-ASSY-01', 'è£
é
å·¥ä½', 5), (6, 'WS-QC-01', 'æ£éªå·¥ä½', 6)] |
| | | clean('mes_md_workstation', [w[0] for w in wss]) |
| | | ins('mes_md_workstation', ['id', 'code', 'name', 'workshop_id', 'process_id', 'warehouse_id', 'location_id', 'area_id', 'status'], |
| | | [(w[0], w[1], w[2], 1, w[3], 1, LOC[1], AREA[1], 0) for w in wss]) |
| | | |
| | | # ---------------- å·¥èºè·¯çº¿ ---------------- |
| | | routes = [(1, 'RT-FLP', 'æ³å
°çå 工工èºè·¯çº¿'), (2, 'RT-ZCZ', 'è½´æ¿åº§å 工工èºè·¯çº¿')] |
| | | clean('mes_pro_route', [r[0] for r in routes]) |
| | | ins('mes_pro_route', ['id', 'code', 'name', 'status'], [(r[0], r[1], r[2], 0) for r in routes]) |
| | | |
| | | # 路线产åï¼æ³å
°ç 2001ã2002ï¼è½´æ¿åº§ 2003 |
| | | rps = [(1, 1, 1001, 3, AREA[3]), (2, 1, 1002, 3, AREA[3]), (3, 2, 1003, 3, AREA[3])] |
| | | clean('mes_pro_route_product', [r[0] for r in rps]) |
| | | ins('mes_pro_route_product', ['id', 'route_id', 'item_id', 'warehouse_id', 'location_id', 'area_id', 'quantity'], |
| | | [(r[0], r[1], r[2], 3, LOC[3], r[4], 1) for r in rps]) |
| | | |
| | | # è·¯çº¿å·¥åº |
| | | rp_rows = [] |
| | | rid = 1 |
| | | for route_id, proc_ids in [(1, [1, 2, 4, 5, 6]), (2, [1, 3, 4, 5, 6])]: |
| | | for sort, pid in enumerate(proc_ids, start=1): |
| | | rp_rows.append((rid, route_id, pid, sort, 98.0)) |
| | | rid += 1 |
| | | clean('mes_pro_route_process', [r[0] for r in rp_rows]) |
| | | ins('mes_pro_route_process', ['id', 'route_id', 'process_id', 'sort', 'yield_rate'], |
| | | [(r[0], r[1], r[2], r[3], r[4]) for r in rp_rows]) |
| | | |
| | | # è·¯çº¿ææ BOMï¼æ³å
°çæ¯ä»¶ç¨ 45#颿£ 2.5kgãååæ¶² 0.2Lãèºæ 4 个ãèºæ¯ 4 个 |
| | | bom_rows = [ |
| | | (1, 1, 1, 1001, 1009, 2.5), (2, 1, 1, 1002, 1009, 4.0), |
| | | (3, 1, 2, 1001, 1015, 0.2), (4, 1, 2, 1002, 1015, 0.3), |
| | | (5, 1, 5, 1001, 1012, 4), (6, 1, 5, 1001, 1013, 4), (7, 1, 5, 1001, 1014, 2), |
| | | (8, 1, 5, 1002, 1012, 6), (9, 1, 5, 1002, 1013, 6), (10, 1, 5, 1002, 1014, 2), |
| | | (11, 2, 1, 1003, 1010, 3.2), (12, 2, 3, 1003, 1015, 0.25), |
| | | (13, 2, 5, 1003, 1012, 4), (14, 2, 5, 1003, 1013, 4), |
| | | ] |
| | | clean('mes_pro_route_product_bom', [b[0] for b in bom_rows]) |
| | | ins('mes_pro_route_product_bom', ['id', 'route_id', 'process_id', 'product_id', 'item_id', 'quantity'], |
| | | bom_rows) |
| | | |
| | | # ---------------- è®¾å¤ ---------------- |
| | | mt = [(1, 'MT-CNC', 'æ°æ§è®¾å¤'), (2, 'MT-AUX', 'è¾
å©è®¾å¤')] |
| | | clean('mes_dv_machinery_type', [m[0] for m in mt]) |
| | | ins('mes_dv_machinery_type', ['id', 'code', 'name', 'status', 'sort'], [(m[0], m[1], m[2], 0, m[0]) for m in mt]) |
| | | |
| | | machs = [ |
| | | (1, 'EQ-CUT-01', 'æ°æ§å岿º', 1, 1, 2), (2, 'EQ-TURN-01', 'æ°æ§è½¦åº CK6140', 2, 2, 2), |
| | | (3, 'EQ-MILL-01', 'ç«å¼é£åº X5032', 3, 3, 2), (4, 'EQ-DRILL-01', 'æèé»åº Z3050', 4, 4, 2), |
| | | (5, 'EQ-ASSY-01', 'æ¶²åè£
é
å°', 5, 5, 2), (6, 'EQ-QC-01', 'ä¸åæ æµé仪', 6, 6, 2), |
| | | ] |
| | | clean('mes_dv_machinery', [m[0] for m in machs]) |
| | | ins('mes_dv_machinery', ['id', 'code', 'name', 'machinery_type_id', 'workshop_id', 'process_id', 'workstation_id', |
| | | 'status', 'enable_date', 'purchase_date'], |
| | | [(m[0], m[1], m[2], m[3], 1, m[4], m[4], m[5], datetime.date(2024, 3, 1), datetime.date(2024, 2, 1)) for m in machs]) |
| | | |
| | | # ---------------- åå·¥ ---------------- |
| | | emp_names = [('E001', 'èµµç£', 243), ('E002', 'æä¸å¨', 244), ('E003', 'å·¨å
è', 245), ('E004', '马èå¨', 246), |
| | | ('E005', 'åé', 247), ('E006', 'éæµ·è¹', 248), ('E007', '许海è±', 249), ('E008', 'éå±±è¯', 250), |
| | | ('E009', 'éæ
§æ
§', 251), ('E010', 'ä½åç ', 252)] |
| | | clean('hrm_employee', list(range(1, 11))) |
| | | ins('hrm_employee', ['id', 'user_id', 'dept_id', 'employee_no', 'name', 'gender', 'hire_date', 'employee_status', |
| | | 'base_salary', 'creator', 'create_time'], |
| | | [(i + 1, e[2], 126, e[0], e[1], 1 if i % 2 == 0 else 2, datetime.date(2023, 1 + i, 5 + i), 1, 6500 + i * 300, '1', ts(BASE, 300 + i)) |
| | | for i, e in enumerate(emp_names)]) |
| | | |
| | | conn.commit() |
| | | print('MASTER OK: units/categories/items/warehouses/vendors/customers/route/machinery/employees') |
| | | cur.execute("SELECT COUNT(*) FROM mes_md_item"); print('mes items', cur.fetchone()[0]) |
| | | cur.execute("SELECT COUNT(*) FROM mdm_item"); print('mdm items', cur.fetchone()[0]) |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | #!/usr/bin/env python3 |
| | | """CFWJ æ¼ç¤ºæ°æ®çæï¼äºï¼ï¼ä¸å¡åæ®é¾è·¯ ââ ä»
æ¬å° CFWJ åº""" |
| | | import pymysql, datetime, hashlib |
| | | |
| | | DB = dict(host='127.0.0.1', port=3306, user='root', password='123456', database='CFWJ', charset='utf8mb4', autocommit=False) |
| | | conn = pymysql.connect(**DB) |
| | | cur = conn.cursor() |
| | | |
| | | def workday(d): |
| | | while d.weekday() >= 5: |
| | | d -= datetime.timedelta(days=1) |
| | | return d |
| | | |
| | | def ts(base, seed, hour_min=8, hour_max=18): |
| | | h = int(hashlib.md5(str(seed).encode()).hexdigest(), 16) |
| | | d = workday(base) if isinstance(base, datetime.date) else workday(base.date()) |
| | | minutes = (h % ((hour_max - hour_min) * 60)) + hour_min * 60 |
| | | return datetime.datetime.combine(d, datetime.time(minutes // 60, minutes % 60, (h >> 8) % 60)) |
| | | |
| | | def D(y, m, dd): |
| | | return datetime.date(y, m, dd) |
| | | |
| | | def clean(table, ids): |
| | | if not ids: |
| | | return |
| | | fmt = ','.join(['%s'] * len(ids)) |
| | | cur.execute(f"DELETE FROM {table} WHERE id IN ({fmt})", ids) |
| | | |
| | | def ins(table, cols, rows): |
| | | if not rows: |
| | | return |
| | | ph = ','.join(['%s'] * len(cols)) |
| | | quoted = ','.join(f'`{c}`' for c in cols) |
| | | cur.executemany(f"INSERT INTO {table} ({quoted}) VALUES ({ph})", rows) |
| | | |
| | | ADMIN = '1' |
| | | UNIT = {1001: 1, 1002: 1, 1003: 1, 1004: 4, 1005: 1, 1006: 1, |
| | | 1007: 1, 1008: 1, 1009: 2, 1010: 2, 1011: 2, 1012: 8, 1013: 8, |
| | | 1014: 8, 1015: 6, 1016: 2} |
| | | SHORT = {1001: 'æ³å
°ç DN50', 1002: 'æ³å
°ç DN100', 1003: 'è½´æ¿åº§ 6205', 1004: 'èè½´å¨ LZ-45', |
| | | 1005: 'éé¨å£³ä½ VH-100', 1006: 'é½¿è½®ç®±ä½ GB-200', 1007: 'æ³å
°æ¯å¯ DN50', 1008: 'æ³å
°æ¯å¯ DN100', |
| | | 1009: '45#颿£', 1010: 'é¸éé', 1011: 'ä¸é颿¿', 1012: 'èºæ M8x30', 1013: 'èºæ¯ M8', |
| | | 1014: 'å¯å°å O-40', 1015: 'ååæ¶²', 1016: 'é²éæ¼'} |
| | | AREA = {1: 201, 2: 205, 3: 207, 4: 209} |
| | | LOC = {1: 101, 2: 103, 3: 104, 4: 105} |
| | | |
| | | # ==================== 1. éå®è®¢å ==================== |
| | | sale_orders = [ |
| | | # id, no, status, customer, sale_user, date, items[(mdm_item, qty, price)], prod_status, out_status |
| | | (1, 'SO20260805001', 20, 1, 243, D(2026, 8, 5), [(1001, 300, 120), (1002, 150, 185)], 1, 2), |
| | | (2, 'SO20260812002', 20, 2, 244, D(2026, 8, 12), [(1003, 200, 260), (1004, 80, 340)], 1, 2), |
| | | (3, 'SO20260902003', 20, 3, 245, D(2026, 9, 2), [(1001, 500, 120), (1005, 60, 520)], 0, 1), |
| | | (4, 'SO20260915004', 20, 4, 246, D(2026, 9, 15), [(1002, 260, 185), (1006, 40, 980)], 0, 0), |
| | | (5, 'SO20261008005', 10, 5, 247, D(2026, 10, 8), [(1003, 120, 260), (1001, 180, 120)], 0, 0), |
| | | (6, 'SO20261020006', 20, 6, 248, D(2026, 10, 20), [(1004, 100, 340)], 0, 0), |
| | | (7, 'SO20261027007', 0, 1, 243, D(2026, 10, 27), [(1005, 90, 520)], 0, 0), |
| | | (8, 'SO20261102008', 20, 2, 244, D(2026, 11, 2), [(1006, 25, 980), (1002, 120, 185)], 0, 0), |
| | | ] |
| | | MPS_LINK = { # (order_id, item_idx) -> mps_id |
| | | (1, 0): 1, (2, 0): 2, (3, 0): 3, (4, 0): 4, (1, 1): 5, (8, 1): 6, |
| | | } |
| | | so_rows, soi_rows = [], [] |
| | | soi_id = 0 |
| | | for o in sale_orders: |
| | | oid, no, status, cust, user, day, items, prod_status, out_status = o |
| | | total_count = sum(i[1] for i in items) |
| | | total_price = round(sum(i[1] * i[2] for i in items), 2) |
| | | so_rows.append((oid, no, 1, status, cust, user, ts(day, 100 + oid), |
| | | total_count, total_price, total_price, round(total_price * 1.13, 2), 100, 0, |
| | | total_count if out_status == 2 else (200 if oid == 3 else 0), out_status, prod_status, |
| | | '客æ·è®¢å', ADMIN, ts(day, 200 + oid))) |
| | | for idx, (item, qty, price) in enumerate(items): |
| | | soi_id += 1 |
| | | tp = round(qty * price, 2) |
| | | soi_rows.append((soi_id, oid, item, UNIT[item], price, qty, tp, 13, round(tp * 0.13, 2), 1, |
| | | MPS_LINK.get((oid, idx)), ADMIN, ts(day, 300 + oid * 10 + idx))) |
| | | clean('erp_sale_order', [r[0] for r in so_rows]) |
| | | clean('erp_sale_order_items', [r[0] for r in soi_rows]) |
| | | ins('erp_sale_order', ['id', 'no', 'sale_type', 'status', 'customer_id', 'sale_user_id', 'order_time', |
| | | 'total_count', 'total_price', 'total_product_price', 'total_tax_price', 'discount_percent', |
| | | 'discount_price', 'out_count', 'out_status', 'production_status', 'remark', 'creator', 'create_time'], so_rows) |
| | | ins('erp_sale_order_items', ['id', 'order_id', 'product_id', 'product_unit_id', 'product_price', 'count', 'total_price', |
| | | 'tax_percent', 'tax_price', 'need_production', 'mps_id', 'creator', 'create_time'], soi_rows) |
| | | print('sale orders', len(so_rows), 'items', len(soi_rows)) |
| | | |
| | | # ==================== 2. éå®ç®æ ==================== |
| | | st_rows = [] |
| | | for i, uid in enumerate([243, 244, 245, 246, 247, 248], start=1): |
| | | st_rows.append((i, f'2026å¹´10æéå®ç®æ -{uid}', 3, '2026-10', datetime.datetime(2026, 10, 1), datetime.datetime(2026, 10, 31, 23, 59, 59), |
| | | 1, uid, 800000 + i * 50000, 900000 + i * 50000, 1000000 + i * 50000, 5, 12, 0, |
| | | 'æåº¦ä¸ªäººç®æ ', ADMIN, ts(D(2026, 9, 28), 400 + i))) |
| | | clean('crm_sales_target', [r[0] for r in st_rows]) |
| | | ins('crm_sales_target', ['id', 'name', 'period_type', 'period_value', 'start_time', 'end_time', 'target_dimension', |
| | | 'target_user_id', 'contract_target', 'receivable_target', 'business_target', 'customer_target', |
| | | 'contract_count_target', 'status', 'remark', 'creator', 'create_time'], st_rows) |
| | | |
| | | # ==================== 3. éè´ç³è¯· / éè´è®¢å ==================== |
| | | # (id, no, status, user, date, items[(item, qty, price)]) |
| | | prs = [ |
| | | (1, 'PR20260804001', 20, 249, D(2026, 8, 4), [(1009, 6000, 6.5), (1012, 20000, 0.6), (1013, 20000, 0.3), (1014, 8000, 1.2)]), |
| | | (2, 'PR20260822002', 20, 249, D(2026, 8, 22), [(1010, 4000, 4.8), (1011, 1500, 22), (1015, 300, 18), (1016, 200, 26)]), |
| | | (3, 'PR20260917003', 10, 250, D(2026, 9, 17), [(1009, 3000, 6.5), (1012, 10000, 0.6)]), |
| | | (4, 'PR20261021004', 0, 250, D(2026, 10, 21), [(1010, 2000, 4.8)]), |
| | | ] |
| | | pr_rows, pri_rows = [], [] |
| | | pri_id = 0 |
| | | for p in prs: |
| | | pid, no, status, user, day, items = p |
| | | total_price = round(sum(i[1] * i[2] for i in items), 2) |
| | | pr_rows.append((pid, no, status, user, 126, ts(day, 500 + pid), 'çäº§å¤æ', 1, '常è§éè´', |
| | | None, sum(i[1] for i in items), total_price, total_price, round(total_price * 1.13, 2), |
| | | 0, ADMIN, ts(day, 600 + pid))) |
| | | for item, qty, price in items: |
| | | pri_id += 1 |
| | | tp = round(qty * price, 2) |
| | | pri_rows.append((pri_id, pid, item, UNIT[item], price, qty, tp, 13, round(tp * 0.13, 2), |
| | | datetime.datetime.combine(day + datetime.timedelta(days=7), datetime.time(17, 0)), |
| | | ADMIN, ts(day, 700 + pri_id))) |
| | | clean('erp_purchase_request', [r[0] for r in pr_rows]) |
| | | clean('erp_purchase_request_items', [r[0] for r in pri_rows]) |
| | | ins('erp_purchase_request', ['id', 'no', 'status', 'request_user_id', 'request_dept_id', 'request_time', 'request_reason', |
| | | 'purchase_category', 'purpose', 'supplier_id', 'total_count', 'total_price', 'total_product_price', |
| | | 'total_tax_price', 'in_status', 'creator', 'create_time'], pr_rows) |
| | | ins('erp_purchase_request_items', ['id', 'request_id', 'product_id', 'product_unit_id', 'product_price', 'count', 'total_price', |
| | | 'tax_percent', 'tax_price', 'demand_time', 'creator', 'create_time'], pri_rows) |
| | | |
| | | # éè´è®¢åï¼id, no, vendor, date, [(item, qty, price, request_item_id)] |
| | | pos = [ |
| | | (1, 'PO20260806001', 1, D(2026, 8, 6), [(1009, 6000, 6.5, 1)]), |
| | | (2, 'PO20260806002', 4, D(2026, 8, 6), [(1012, 20000, 0.6, 2), (1013, 20000, 0.3, 3), (1014, 8000, 1.2, 4)]), |
| | | (3, 'PO20260824003', 2, D(2026, 8, 24), [(1010, 4000, 4.8, 5)]), |
| | | (4, 'PO20260824004', 5, D(2026, 8, 24), [(1015, 300, 18, 7), (1016, 200, 26, 8)]), |
| | | (5, 'PO20260824005', 3, D(2026, 8, 24), [(1011, 1500, 22, 6)]), |
| | | ] |
| | | po_rows, poi_rows = [], [] |
| | | poi_id = 0 |
| | | for pid, no, vendor, day, items in pos: |
| | | total_price = round(sum(i[1] * i[2] for i in items), 2) |
| | | po_rows.append((pid, no, 20, vendor, ts(day, 800 + pid), sum(i[1] for i in items), total_price, total_price, |
| | | round(total_price * 1.13, 2), 100, 0, 0, 2, '常è§éè´', ADMIN, ts(day, 900 + pid))) |
| | | for item, qty, price, req_item in items: |
| | | poi_id += 1 |
| | | tp = round(qty * price, 2) |
| | | poi_rows.append((poi_id, pid, req_item, item, UNIT[item], price, qty, tp, 13, round(tp * 0.13, 2), qty, |
| | | ADMIN, ts(day, 950 + poi_id))) |
| | | clean('erp_purchase_order', [r[0] for r in po_rows]) |
| | | clean('erp_purchase_order_items', [r[0] for r in poi_rows]) |
| | | ins('erp_purchase_order', ['id', 'no', 'status', 'supplier_id', 'order_time', 'total_count', 'total_price', |
| | | 'total_product_price', 'total_tax_price', 'discount_percent', 'discount_price', 'deposit_price', |
| | | 'in_status', 'remark', 'creator', 'create_time'], po_rows) |
| | | ins('erp_purchase_order_items', ['id', 'order_id', 'request_item_id', 'product_id', 'product_unit_id', 'product_price', |
| | | 'count', 'total_price', 'tax_percent', 'tax_price', 'in_count', 'creator', 'create_time'], poi_rows) |
| | | print('purchase req/order ok') |
| | | |
| | | # ==================== 4. å°è´§éç¥ / éè´å
¥åº / æ¹æ¬¡ ==================== |
| | | notices = [ # id, code, po_id, vendor, date |
| | | (1, 'AN20260806001', 1, 1, D(2026, 8, 6)), |
| | | (2, 'AN20260807002', 2, 4, D(2026, 8, 7)), |
| | | (3, 'AN20260825003', 3, 2, D(2026, 8, 25)), |
| | | (4, 'AN20260826004', 4, 5, D(2026, 8, 26)), |
| | | (5, 'AN20260904005', 5, 3, D(2026, 9, 4)), |
| | | ] |
| | | # å°è´§æç» = 对åºéè´è®¢åæç»ï¼å PO item ç product/countï¼ |
| | | poi_by_po = {} |
| | | for r in poi_rows: |
| | | poi_by_po.setdefault(r[1], []).append(r) |
| | | an_rows, anl_rows = [], [] |
| | | anl_id = 0 |
| | | for nid, code, po_id, vendor, day in notices: |
| | | po = [x for x in po_rows if x[0] == po_id][0] |
| | | an_rows.append((nid, code, f'{po[1]} å°è´§éç¥', po_id, po[1], vendor, ts(day, 1100 + nid), 4, ADMIN, ts(day, 1200 + nid))) |
| | | for r in poi_by_po[po_id]: |
| | | anl_id += 1 |
| | | anl_rows.append((anl_id, nid, r[0], r[3], r[6], r[6], 1, ADMIN, ts(day, 1300 + anl_id))) |
| | | clean('mes_wm_arrival_notice', [r[0] for r in an_rows]) |
| | | clean('mes_wm_arrival_notice_line', [r[0] for r in anl_rows]) |
| | | ins('mes_wm_arrival_notice', ['id', 'code', 'name', 'purchase_order_id', 'purchase_order_code', 'vendor_id', |
| | | 'arrival_date', 'status', 'creator', 'create_time'], an_rows) |
| | | ins('mes_wm_arrival_notice_line', ['id', 'notice_id', 'purchase_order_item_id', 'item_id', 'arrival_quantity', |
| | | 'qualified_quantity', 'iqc_check_flag', 'creator', 'create_time'], anl_rows) |
| | | |
| | | batches = [ # id, code, item, date, vendor, po_code, lot |
| | | (1, 'BT20260806001', 1009, D(2026, 8, 6), 1, 'PO20260806001', 'L260806A'), |
| | | (2, 'BT20260807002', 1012, D(2026, 8, 7), 4, 'PO20260806002', 'L260807B'), |
| | | (3, 'BT20260807003', 1013, D(2026, 8, 7), 4, 'PO20260806002', 'L260807C'), |
| | | (4, 'BT20260825004', 1010, D(2026, 8, 25), 2, 'PO20260824003', 'L260825D'), |
| | | (5, 'BT20260826005', 1015, D(2026, 8, 26), 5, 'PO20260824004', 'L260826E'), |
| | | ] |
| | | soft_clean = lambda t, ids: cur.execute(f"DELETE FROM {t} WHERE id IN ({','.join(['%s']*len(ids))})", ids) |
| | | soft_clean('mes_wm_batch', [b[0] for b in batches]) |
| | | ins('mes_wm_batch', ['id', 'code', 'item_id', 'produce_date', 'receipt_date', 'vendor_id', 'purchase_order_code', |
| | | 'lot_number', 'quality_status', 'vendor_name', 'creator', 'create_time'], |
| | | [(b[0], b[1], b[2], b[3] - datetime.timedelta(days=10), b[3], b[4], b[5], b[6], 1, |
| | | f'ä¾åºå{b[4]}', ADMIN, ts(b[3], 1400 + b[0])) for b in batches]) |
| | | |
| | | receipts = [ # id, code, notice, po, vendor, date |
| | | (1, 'IR20260806001', 1, 1, 1, D(2026, 8, 6)), |
| | | (2, 'IR20260807002', 2, 2, 4, D(2026, 8, 7)), |
| | | (3, 'IR20260825003', 3, 3, 2, D(2026, 8, 25)), |
| | | (4, 'IR20260826004', 4, 4, 5, D(2026, 8, 26)), |
| | | (5, 'IR20260904005', 5, 5, 3, D(2026, 9, 4)), |
| | | ] |
| | | ir_rows, irl_rows = [], [] |
| | | irl_id = 0 |
| | | for rid, code, po, vendor, day in notices: |
| | | notice = rid |
| | | pono = [x for x in po_rows if x[0] == po][0][1] |
| | | ir_rows.append((rid, code, f'{pono} éè´å
¥åº', None, notice, pono, po, vendor, ts(day, 1500 + rid), 4, ADMIN, ts(day, 1600 + rid))) |
| | | for r in poi_by_po[po]: |
| | | irl_id += 1 |
| | | irl_rows.append((irl_id, rid, r[0], r[3], UNIT[r[3]], r[6], r[6], ADMIN, ts(day, 1700 + irl_id))) |
| | | clean('mes_wm_item_receipt', [r[0] for r in ir_rows]) |
| | | clean('mes_wm_item_receipt_line', [r[0] for r in irl_rows]) |
| | | ins('mes_wm_item_receipt', ['id', 'code', 'name', 'iqc_id', 'notice_id', 'purchase_order_code', 'purchase_order_id', |
| | | 'vendor_id', 'receipt_date', 'status', 'creator', 'create_time'], ir_rows) |
| | | ins('mes_wm_item_receipt_line', ['id', 'receipt_id', 'purchase_order_item_id', 'item_id', 'enter_unit_measure_id', |
| | | 'enter_quantity', 'received_quantity', 'creator', 'create_time'], irl_rows) |
| | | print('receipts', len(ir_rows), 'lines', len(irl_rows)) |
| | | |
| | | # ==================== 5. çäº§é¢æå / ç产å
¥åºå / éå®åºåºå / æé¡¹å
¥åº ==================== |
| | | # 颿ï¼work_order -> items |
| | | issues = [ |
| | | (1, 'PI20260810001', 1, D(2026, 8, 10), [(1009, 750), (1012, 1200), (1013, 1200), (1014, 600), (1015, 60)]), |
| | | (2, 'PI20260814002', 4, D(2026, 8, 14), [(1009, 600), (1012, 900), (1013, 900), (1014, 300), (1015, 45)]), |
| | | (3, 'PI20260906003', 2, D(2026, 9, 6), [(1010, 640), (1012, 800), (1013, 800), (1015, 50)]), |
| | | (4, 'PI20260923004', 3, D(2026, 9, 23), [(1009, 1250), (1012, 2000), (1013, 2000), (1014, 1000), (1015, 100)]), |
| | | ] |
| | | iss_rows, issl_rows = [], [] |
| | | issl_id = 0 |
| | | for iid, code, wo, day, items in issues: |
| | | iss_rows.append((iid, code, f'å·¥å {wo} çäº§é¢æ', wo, ts(day, 1800 + iid), 4, 1, ADMIN, ts(day, 1900 + iid))) |
| | | for item, qty in items: |
| | | issl_id += 1 |
| | | wh = 4 if item in (1015, 1016) else 1 |
| | | issl_rows.append((issl_id, iid, item, UNIT[item], qty, qty, ADMIN, ts(day, 1950 + issl_id))) |
| | | clean('mes_wm_product_issue', [r[0] for r in iss_rows]) |
| | | clean('mes_wm_product_issue_line', [r[0] for r in issl_rows]) |
| | | ins('mes_wm_product_issue', ['id', 'code', 'name', 'work_order_id', 'issue_date', 'status', 'issue_type', |
| | | 'creator', 'create_time'], iss_rows) |
| | | ins('mes_wm_product_issue_line', ['id', 'issue_id', 'item_id', 'enter_unit_measure_id', 'enter_quantity', |
| | | 'quantity', 'creator', 'create_time'], issl_rows) |
| | | |
| | | precepts = [ # id, code, wo, date, item, qty |
| | | (1, 'PRC20260812001', 1, D(2026, 8, 12), 1001, 300), |
| | | (2, 'PRC20260816002', 4, D(2026, 8, 16), 1002, 150), |
| | | (3, 'PRC20260908003', 2, D(2026, 9, 8), 1003, 200), |
| | | (4, 'PRC20261005004', 3, D(2026, 10, 5), 1001, 250), |
| | | ] |
| | | prc_rows, prcl_rows = [], [] |
| | | for pid, code, wo, day, item, qty in precepts: |
| | | prc_rows.append((pid, code, f'å·¥å {wo} ç产å
¥åº', wo, ts(day, 2000 + pid), 4, item, ADMIN, ts(day, 2100 + pid))) |
| | | prcl_rows.append((pid, pid, item, qty, ADMIN, ts(day, 2150 + pid))) |
| | | clean('mes_wm_product_receipt', [r[0] for r in prc_rows]) |
| | | clean('mes_wm_product_receipt_line', [r[0] for r in prcl_rows]) |
| | | ins('mes_wm_product_receipt', ['id', 'code', 'name', 'work_order_id', 'receipt_date', 'status', 'item_id', |
| | | 'creator', 'create_time'], prc_rows) |
| | | ins('mes_wm_product_receipt_line', ['id', 'receipt_id', 'item_id', 'quantity', 'creator', 'create_time'], prcl_rows) |
| | | |
| | | sales = [ # id, code, sale_order, client, date, [(item, qty)] |
| | | (1, 'PS20260815001', 1, 1, D(2026, 8, 15), [(1001, 300), (1002, 150)]), |
| | | (2, 'PS20260910002', 2, 2, D(2026, 9, 10), [(1003, 200), (1004, 80)]), |
| | | (3, 'PS20261008003', 3, 3, D(2026, 10, 8), [(1001, 200), (1005, 50)]), |
| | | ] |
| | | ps_rows, psl_rows = [], [] |
| | | psl_id = 0 |
| | | for sid, code, so, client, day, items in sales: |
| | | sono = [x for x in sale_orders if x[0] == so][0][1] |
| | | ps_rows.append((sid, code, f'{sono} éå®åºåº', client, so, sono, ts(day, 2200 + sid), 'çç»ç', '13900000001', |
| | | 'åå±±å¸è·¯ååº', 'å¾·é¦ç©æµ', f'DB{2026}{sid:04d}', 4, ADMIN, ts(day, 2300 + sid))) |
| | | for idx, (item, qty) in enumerate(items): |
| | | psl_id += 1 |
| | | soi_map = {(1, 1001): 1, (1, 1002): 2, (2, 1003): 3, (2, 1004): 4, (3, 1001): 5, (3, 1005): 6} |
| | | psl_rows.append((psl_id, sid, soi_map.get((so, item)), item, UNIT[item], qty, qty, 0, 1, ADMIN, ts(day, 2350 + psl_id))) |
| | | clean('mes_wm_product_sales', [r[0] for r in ps_rows]) |
| | | clean('mes_wm_product_sales_line', [r[0] for r in psl_rows]) |
| | | ins('mes_wm_product_sales', ['id', 'code', 'name', 'client_id', 'sale_order_id', 'sales_order_code', 'sales_date', |
| | | 'contact_name', 'contact_telephone', 'contact_address', 'carrier', 'shipping_number', |
| | | 'status', 'creator', 'create_time'], ps_rows) |
| | | ins('mes_wm_product_sales_line', ['id', 'sales_id', 'sale_order_item_id', 'item_id', 'enter_unit_measure_id', |
| | | 'enter_quantity', 'quantity', 'oqc_check_flag', 'quality_status', 'creator', 'create_time'], psl_rows) |
| | | |
| | | misc = (1, 'MR20261010001', D(2026, 10, 10), |
| | | [(1004, 120, 3), (1005, 90, 3), (1006, 20, 3), (1007, 60, 2), (1008, 40, 2)]) |
| | | clean('mes_wm_misc_receipt', [1]) |
| | | clean('mes_wm_misc_receipt_line', list(range(1, 6))) |
| | | ins('mes_wm_misc_receipt', ['id', 'code', 'name', 'type', 'receipt_date', 'status', 'remark', 'creator', 'create_time'], |
| | | [(misc[0], misc[1], 'æååºåè¡¥å½', 1, ts(misc[2], 2400), 4, 'æåç»å', ADMIN, ts(misc[2], 2410))]) |
| | | ins('mes_wm_misc_receipt_line', ['id', 'receipt_id', 'item_id', 'quantity', 'warehouse_id', 'location_id', 'area_id', |
| | | 'creator', 'create_time'], |
| | | [(i + 1, 1, item, qty, wh, LOC[wh], AREA[wh], ADMIN, ts(misc[2], 2420 + i)) |
| | | for i, (item, qty, wh) in enumerate(misc[3])]) |
| | | |
| | | # ==================== 6. åºåäºå¡ + åºå ==================== |
| | | in_rows = [] # (item, qty, wh, date, biz_type, biz_id, biz_code, seed) |
| | | out_rows = [] |
| | | # éè´å
¥åº |
| | | for rid, code, po, vendor, day in notices: |
| | | for r in poi_by_po[po]: |
| | | wh = 4 if r[3] in (1015, 1016) else 1 |
| | | in_rows.append((r[3], r[6], wh, day, 110, rid, code, 2500 + r[0])) |
| | | # ç产å
¥åº |
| | | for pid, code, wo, day, item, qty in precepts: |
| | | in_rows.append((item, qty, 3, day, 118, pid, code, 2600 + pid)) |
| | | # æé¡¹å
¥åº |
| | | for i, (item, qty, wh) in enumerate(misc[3]): |
| | | in_rows.append((item, qty, wh, misc[2], 115, 1, misc[1], 2700 + i)) |
| | | # çäº§é¢æï¼åºåºï¼ |
| | | for iid, code, wo, day, items in issues: |
| | | for item, qty in items: |
| | | wh = 4 if item in (1015, 1016) else 1 |
| | | out_rows.append((item, qty, wh, day, 116, iid, code, 2800 + iid * 10 + item % 10)) |
| | | # éå®åºåº |
| | | for sid, code, so, client, day, items in sales: |
| | | for item, qty in items: |
| | | out_rows.append((item, qty, 3, day, 119, sid, code, 2900 + sid * 10 + item % 10)) |
| | | |
| | | tx_rows = [] |
| | | tx_id = 0 |
| | | for item, qty, wh, day, biz_type, biz_id, biz_code, seed in in_rows: |
| | | tx_id += 1 |
| | | tx_rows.append((tx_id, 1, biz_type, biz_id, biz_code, item, qty, None, wh, LOC[wh], AREA[wh], ts(day, seed), ADMIN, ts(day, seed))) |
| | | for item, qty, wh, day, biz_type, biz_id, biz_code, seed in out_rows: |
| | | tx_id += 1 |
| | | tx_rows.append((tx_id, 2, biz_type, biz_id, biz_code, item, -qty, None, wh, LOC[wh], AREA[wh], ts(day, seed), ADMIN, ts(day, seed))) |
| | | clean('mes_wm_transaction', [r[0] for r in tx_rows]) |
| | | ins('mes_wm_transaction', ['id', 'type', 'biz_type', 'biz_id', 'biz_code', 'item_id', 'quantity', 'batch_id', |
| | | 'warehouse_id', 'location_id', 'area_id', 'transaction_time', 'creator', 'create_time'], tx_rows) |
| | | |
| | | # åºå = äºå¡æ±æ» |
| | | agg = {} |
| | | for t in tx_rows: |
| | | key = (t[5], t[8]) # item, warehouse |
| | | agg[key] = agg.get(key, 0) + float(t[6]) |
| | | stock_rows = [] |
| | | sid = 0 |
| | | for (item, wh), qty in sorted(agg.items()): |
| | | if abs(qty) < 1e-9: |
| | | continue |
| | | sid += 1 |
| | | stock_rows.append((sid, item, wh, LOC[wh], AREA[wh], round(qty, 3), 0, 0, 0, ADMIN, |
| | | ts(D(2026, 10, 10), 3000 + sid))) |
| | | clean('mes_wm_material_stock', list(range(1, 200))) |
| | | ins('mes_wm_material_stock', ['id', 'item_id', 'warehouse_id', 'location_id', 'area_id', 'quantity', 'frozen_quantity', |
| | | 'reserved_quantity', 'in_transit_quantity', 'creator', 'create_time'], stock_rows) |
| | | print('transactions', len(tx_rows), 'stock rows', len(stock_rows)) |
| | | |
| | | # ==================== 7. MPS / å·¥å / å·¥åå·¥åº / æ¥å·¥ / æµè½¬å¡ ==================== |
| | | mps = [ |
| | | # id, code, status, so, so_item, mes_product, qty, produced, client, request_date, plan_start, issue, finish, wo, wo_code |
| | | (1, 'MPS20260805001', 2, 1, 1, 1001, 300, 300, 1, D(2026, 8, 20), D(2026, 8, 8), D(2026, 8, 8), D(2026, 8, 12), 1, 'WO20260808001'), |
| | | (2, 'MPS20260812002', 2, 2, 3, 1003, 200, 200, 2, D(2026, 8, 28), D(2026, 8, 15), D(2026, 8, 15), D(2026, 9, 8), 2, 'WO20260815002'), |
| | | (3, 'MPS20260902003', 1, 3, 5, 1001, 500, 250, 3, D(2026, 9, 30), D(2026, 9, 5), D(2026, 9, 5), None, 3, 'WO20260905003'), |
| | | (4, 'MPS20260915004', 5, 4, 7, 1002, 260, 0, 4, D(2026, 10, 15), D(2026, 9, 20), None, None, None, None), |
| | | (5, 'MPS20260805005', 2, 1, 2, 1002, 150, 150, 1, D(2026, 8, 22), D(2026, 8, 10), D(2026, 8, 10), D(2026, 8, 16), 4, 'WO20260810004'), |
| | | (6, 'MPS20261102006', 0, 8, 14, 1002, 120, 0, 2, D(2026, 11, 30), D(2026, 11, 10), None, None, None, None), |
| | | ] |
| | | mps_rows = [] |
| | | for m in mps: |
| | | mid, code, status, so, soi, prod, qty, produced, client, req, plan, issue, finish, wo, wocode = m |
| | | sono = [x for x in sale_orders if x[0] == so][0][1] |
| | | mps_rows.append((mid, code, status, so, sono, soi, prod, qty, produced, 1, client, req, plan, issue, finish, |
| | | wo, wocode, 0, 1, ts(plan, 3100 + mid), ADMIN, ts(plan, 3200 + mid))) |
| | | clean('mes_pro_mps', [r[0] for r in mps_rows]) |
| | | ins('mes_pro_mps', ['id', 'code', 'status', 'sale_order_id', 'sale_order_no', 'sale_order_item_id', 'product_id', |
| | | 'quantity', 'quantity_produced', 'unit_measure_id', 'client_id', 'request_date', 'plan_start_date', |
| | | 'issue_date', 'finish_date', 'work_order_id', 'work_order_code', 'merge_flag', 'audit_user_id', |
| | | 'audit_time', 'creator', 'create_time'], mps_rows) |
| | | |
| | | wos = [ |
| | | # id, code, mes_product, name, qty, produced, client, route, start, finish, status, so_code |
| | | (1, 'WO20260808001', 1001, 'æ³å
°ç DN50', 300, 300, 1, 1, D(2026, 8, 8), D(2026, 8, 12), 2, 'SO20260805001'), |
| | | (2, 'WO20260815002', 1003, 'è½´æ¿åº§ 6205', 200, 200, 2, 2, D(2026, 8, 15), D(2026, 9, 8), 2, 'SO20260812002'), |
| | | (3, 'WO20260905003', 1001, 'æ³å
°ç DN50', 500, 250, 3, 1, D(2026, 9, 5), None, 1, 'SO20260902003'), |
| | | (4, 'WO20260810004', 1002, 'æ³å
°ç DN100', 150, 150, 1, 1, D(2026, 8, 10), D(2026, 8, 16), 2, 'SO20260805001'), |
| | | ] |
| | | wo_rows = [] |
| | | for w in wos: |
| | | wid, code, prod, name, qty, produced, client, route, start, finish, status, so_code = w |
| | | wo_rows.append((wid, code, name, 1, 1, 1, 1, so_code, prod, qty, produced, qty, client, route, |
| | | ts(start, 3300 + wid), ts(start, 3400 + wid), 249, finish, status, None, ADMIN, ts(start, 3500 + wid))) |
| | | clean('mes_pro_work_order', [r[0] for r in wo_rows]) |
| | | ins('mes_pro_work_order', ['id', 'code', 'name', 'type', 'factory_id', 'workshop_id', 'order_source_type', |
| | | 'order_source_code', 'product_id', 'quantity', 'quantity_produced', 'quantity_scheduled', |
| | | 'client_id', 'route_id', 'request_date', 'actual_start_time', 'start_user_id', 'finish_date', |
| | | 'status', 'remark', 'creator', 'create_time'], wo_rows) |
| | | |
| | | route_procs = {1: [1, 2, 4, 5, 6], 2: [1, 3, 4, 5, 6]} |
| | | wop_rows = [] |
| | | wop_id = 0 |
| | | for w in wos: |
| | | wid, route = w[0], w[7] |
| | | proc_ids = route_procs[route] |
| | | for sort, pid in enumerate(proc_ids, start=1): |
| | | wop_id += 1 |
| | | nxt = proc_ids[sort] if sort < len(proc_ids) else None |
| | | wh = 1 |
| | | wop_rows.append((wop_id, wid, pid, sort, 98.0, nxt, wh, LOC[wh], AREA[wh], ADMIN, ts(w[8], 3600 + wop_id))) |
| | | clean('mes_pro_work_order_process', [r[0] for r in wop_rows]) |
| | | ins('mes_pro_work_order_process', ['id', 'work_order_id', 'process_id', 'sort', 'yield_rate', 'next_process_id', |
| | | 'warehouse_id', 'location_id', 'area_id', 'creator', 'create_time'], wop_rows) |
| | | |
| | | feedbacks = [ |
| | | # id, code, wo, mes_item, qty, qualified, status, date, process, user |
| | | (1, 'FB20260810001', 1, 1001, 150, 150, 4, D(2026, 8, 10), 5, 249), |
| | | (2, 'FB20260812002', 1, 1001, 150, 150, 4, D(2026, 8, 12), 5, 250), |
| | | (3, 'FB20260816003', 4, 1002, 150, 150, 4, D(2026, 8, 16), 5, 249), |
| | | (4, 'FB20260908004', 2, 1003, 200, 198, 4, D(2026, 9, 8), 5, 250), |
| | | (5, 'FB20261005005', 3, 1001, 250, 250, 3, D(2026, 10, 5), 5, 251), |
| | | ] |
| | | fb_rows = [] |
| | | for f in feedbacks: |
| | | fid, code, wo, item, qty, qualified, status, day, proc, user = f |
| | | fb_rows.append((fid, code, 1, 1, ts(day, 3700 + fid), proc, 1, proc, wo, item, qty, qty, qualified, |
| | | qty - qualified, 0 if status == 4 else qty, user, status, ADMIN, ts(day, 3750 + fid))) |
| | | clean('mes_pro_feedback', [r[0] for r in fb_rows]) |
| | | ins('mes_pro_feedback', ['id', 'code', 'type', 'channel', 'feedback_time', 'workstation_id', 'route_id', 'process_id', |
| | | 'work_order_id', 'item_id', 'scheduled_quantity', 'feedback_quantity', 'qualified_quantity', |
| | | 'unqualified_quantity', 'uncheck_quantity', 'feedback_user_id', 'status', 'creator', 'create_time'], fb_rows) |
| | | |
| | | cards = [(1, 'CARD20260808001', 1, 1001, 'B-WO1', 300, 2, D(2026, 8, 8)), |
| | | (2, 'CARD20260815002', 2, 1003, 'B-WO2', 200, 2, D(2026, 8, 15)), |
| | | (3, 'CARD20260905003', 3, 1001, 'B-WO3', 250, 1, D(2026, 9, 5)), |
| | | (4, 'CARD20260810004', 4, 1002, 'B-WO4', 150, 2, D(2026, 8, 10))] |
| | | clean('mes_pro_card', [c[0] for c in cards]) |
| | | ins('mes_pro_card', ['id', 'code', 'work_order_id', 'item_id', 'batch_code', 'transfered_quantity', 'status', |
| | | 'creator', 'create_time'], |
| | | [(c[0], c[1], c[2], c[3], c[4], c[5], c[6], ADMIN, ts(c[7], 3800 + c[0])) for c in cards]) |
| | | |
| | | andon = [(1, 5, 249, 1, 2, '设å¤å¼åï¼ç³è¯·ç¹æ£', 2, 20, D(2026, 8, 11)), |
| | | (2, 3, 250, 3, 3, 'æ¥æå°ºå¯¸åå·®ï¼å¾
确认', 1, 20, D(2026, 9, 26))] |
| | | clean('mes_pro_andon_record', [a[0] for a in andon]) |
| | | ins('mes_pro_andon_record', ['id', 'workstation_id', 'user_id', 'work_order_id', 'process_id', 'reason', 'level', |
| | | 'status', 'handle_time', 'handler_user_id', 'creator', 'create_time'], |
| | | [(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], ts(a[8], 3900 + a[0]), 249, ADMIN, ts(a[8], 3950 + a[0])) for a in andon]) |
| | | print('mps/wo/feedback ok') |
| | | |
| | | # ==================== 8. è´¨æ£ ==================== |
| | | templates = [(1, 'QC-TPL-IQC', 'æ¥ææ£éªæ¹æ¡', '1', 'GB/T 2828.1 æ£å¸¸æ£éªä¸æ¬¡æ½æ ·'), |
| | | (2, 'QC-TPL-IPQC', 'è¿ç¨æ£éªæ¹æ¡', '2', 'GB/T 2828.1 æ£å¸¸æ£éªä¸æ¬¡æ½æ ·'), |
| | | (3, 'QC-TPL-OQC', 'åºè´§æ£éªæ¹æ¡', '3', 'GB/T 2828.1 æ£å¸¸æ£éªä¸æ¬¡æ½æ ·')] |
| | | clean('mes_qc_template', [t[0] for t in templates]) |
| | | ins('mes_qc_template', ['id', 'code', 'name', 'types', 'default_execute_standard', 'status', 'creator', 'create_time'], |
| | | [(t[0], t[1], t[2], t[3], t[4], 0, ADMIN, ts(D(2026, 7, 20), 4000 + t[0])) for t in templates]) |
| | | |
| | | inds = [ |
| | | (1, 'QC-APPEAR', 'å¤è§', 3, 'æ ', 1, 'è¡¨é¢æ åä¼¤ãæ éè'), |
| | | (2, 'QC-SIZE', '尺寸å
¬å·®', 1, 'mm', 2, 'Ï60±0.5'), |
| | | (3, 'QC-MAT', 'æè´¨æ¥å', 5, None, 3, 'éè´§æè´¨å'), |
| | | (4, 'QC-DIM', 'å 工尺寸', 1, 'mm', 4, 'æå¾çº¸å
¬å·®'), |
| | | (5, 'QC-HARD', '硬度', 1, 'HB', 5, 'HB170~210'), |
| | | (6, 'QC-PACK', 'å
è£
å¤è§', 3, None, 6, 'å
è£
å®å¥½æ ç ´æ'), |
| | | ] |
| | | clean('mes_qc_indicator', [i[0] for i in inds]) |
| | | ins('mes_qc_indicator', ['id', 'code', 'name', 'item_type', 'type', 'unit_text', 'sort_order', 'tool', 'remark', |
| | | 'result_specification', 'creator', 'create_time'], |
| | | [(i[0], i[1], i[2], 1, i[3], i[4], i[5], '游æ å¡å°º/ç®æµ', None, i[6], ADMIN, ts(D(2026, 7, 20), 4100 + i[0])) for i in inds]) |
| | | |
| | | ti = [(1, 1, 1, 1, None, None, None, 'è¡¨é¢æ åä¼¤ãæ éè'), |
| | | (2, 1, 2, 2, 60.5, 61, 59, 'Ï60±0.5mm'), |
| | | (3, 1, 3, 3, None, None, None, 'éè´§æè´¨å'), |
| | | (4, 2, 4, 1, None, None, None, 'æå¾çº¸å
¬å·®'), |
| | | (5, 2, 5, 2, 210, 210, 170, 'HB170~210'), |
| | | (6, 3, 6, 1, None, None, None, 'å
è£
å®å¥½æ ç ´æ'), |
| | | (7, 3, 1, 2, None, None, None, 'è¡¨é¢æ å伤')] |
| | | clean('mes_qc_template_indicator', [r[0] for r in ti]) |
| | | ins('mes_qc_template_indicator', ['id', 'template_id', 'indicator_id', 'sort_order', 'judge_flag', 'standard_value', |
| | | 'threshold_max', 'threshold_min', 'remark', 'creator', 'create_time'], |
| | | [(r[0], r[1], r[2], r[3], 1, r[4], r[5], r[6], r[7], ADMIN, ts(D(2026, 7, 21), 4200 + r[0])) for r in ti]) |
| | | |
| | | iqcs = [ # id, code, receipt, item, vendor, received, date, qualified |
| | | (1, 'IQC20260806001', 1, 1009, 1, 6000, D(2026, 8, 6), 6000), |
| | | (2, 'IQC20260807002', 2, 1012, 4, 20000, D(2026, 8, 7), 19920), |
| | | (3, 'IQC20260825003', 3, 1010, 2, 4000, D(2026, 8, 25), 4000), |
| | | ] |
| | | clean('mes_qc_iqc', [r[0] for r in iqcs]) |
| | | ins('mes_qc_iqc', ['id', 'code', 'name', 'template_id', 'source_doc_type', 'source_doc_id', 'source_doc_code', 'vendor_id', |
| | | 'vendor_name', 'item_id', 'received_quantity', 'check_quantity', 'qualified_quantity', |
| | | 'unqualified_quantity', 'check_result', 'receive_date', 'inspect_date', 'inspector_user_id', |
| | | 'status', 'execute_standard', 'creator', 'create_time'], |
| | | [(r[0], r[1], f'{SHORT[r[3]]} æ¥ææ£éª', 1, 100, r[2], f'IR2026080{r[0]}001', r[4], f'ä¾åºå{r[4]}', r[3], |
| | | r[5], min(r[5], 200), r[7], r[5] - r[7], 1 if r[5] == r[7] else 2, r[6], ts(r[6], 4300 + r[0]), 249, 4, |
| | | 'GB/T 2828.1 æ£å¸¸æ£éªä¸æ¬¡æ½æ ·', ADMIN, ts(r[6], 4350 + r[0])) for r in iqcs]) |
| | | iqcl = [] |
| | | for i, r in enumerate(iqcs, start=1): |
| | | iqcl.append((i * 2 - 1, r[0], 1, 'ç®æµ', 'å¤è§æ£æ¥', None, None, None, None, 'æ å伤éè', ADMIN, ts(r[6], 4400 + i))) |
| | | iqcl.append((i * 2, r[0], 2, '游æ å¡å°º', 'æµé', 60.0, 1, 61.0, 59.0, 'Ï60±0.5', ADMIN, ts(r[6], 4450 + i))) |
| | | clean('mes_qc_iqc_line', [r[0] for r in iqcl]) |
| | | ins('mes_qc_iqc_line', ['id', 'iqc_id', 'indicator_id', 'tool', 'check_method', 'standard_value', 'unit_measure_id', |
| | | 'max_threshold', 'min_threshold', 'remark', 'creator', 'create_time'], iqcl) |
| | | |
| | | ipqcs = [ # id, code, feedback, wo, item, qty, qualified, date |
| | | (1, 'IPQC20260810001', 1, 1, 1001, 150, 150, D(2026, 8, 10)), |
| | | (2, 'IPQC20260908002', 4, 2, 1003, 200, 198, D(2026, 9, 8)), |
| | | (3, 'IPQC20261005003', 5, 3, 1001, 250, 250, D(2026, 10, 5)), |
| | | ] |
| | | clean('mes_qc_ipqc', [r[0] for r in ipqcs]) |
| | | ins('mes_qc_ipqc', ['id', 'code', 'name', 'type', 'template_id', 'source_doc_type', 'source_doc_id', 'source_doc_code', |
| | | 'work_order_id', 'workstation_id', 'process_id', 'item_id', 'check_quantity', 'qualified_quantity', |
| | | 'unqualified_quantity', 'check_result', 'inspect_date', 'inspector_user_id', 'status', |
| | | 'execute_standard', 'creator', 'create_time'], |
| | | [(r[0], r[1], f'{SHORT[r[4]]} è¿ç¨æ£éª', 2, 2, 304, r[2], f'FB2026{r[0]}', r[3], 5, 5, r[4], r[5], r[6], |
| | | r[5] - r[6], 1 if r[5] == r[6] else 2, ts(r[7], 4500 + r[0]), 250, 4, |
| | | 'GB/T 2828.1 æ£å¸¸æ£éªä¸æ¬¡æ½æ ·', ADMIN, ts(r[7], 4550 + r[0])) for r in ipqcs]) |
| | | ipql = [] |
| | | for i, r in enumerate(ipqcs, start=1): |
| | | ipql.append((i * 2 - 1, r[0], 4, '游æ å¡å°º', 'æµé', None, 1, None, None, 'æå¾çº¸å
¬å·®', ADMIN, ts(r[7], 4600 + i))) |
| | | ipql.append((i * 2, r[0], 5, '硬度计', 'æç¹', 190, None, 210, 170, 'HB170~210', ADMIN, ts(r[7], 4650 + i))) |
| | | clean('mes_qc_ipqc_line', [r[0] for r in ipql]) |
| | | ins('mes_qc_ipqc_line', ['id', 'ipqc_id', 'indicator_id', 'tool', 'check_method', 'standard_value', 'unit_measure_id', |
| | | 'max_threshold', 'min_threshold', 'remark', 'creator', 'create_time'], ipql) |
| | | |
| | | oqcs = [ # id, code, sales, item, client, out_qty, date, qualified |
| | | (1, 'OQC20260815001', 1, 1001, 1, 300, D(2026, 8, 15), 300), |
| | | (2, 'OQC20260910002', 2, 1003, 2, 200, D(2026, 9, 10), 200), |
| | | ] |
| | | clean('mes_qc_oqc', [r[0] for r in oqcs]) |
| | | ins('mes_qc_oqc', ['id', 'code', 'name', 'template_id', 'source_doc_type', 'source_doc_id', 'source_doc_code', 'client_id', |
| | | 'item_id', 'out_quantity', 'check_quantity', 'qualified_quantity', 'unqualified_quantity', |
| | | 'check_result', 'out_date', 'inspect_date', 'inspector_user_id', 'status', 'execute_standard', |
| | | 'creator', 'create_time'], |
| | | [(r[0], r[1], f'{SHORT[r[3]]} åºè´§æ£éª', 3, 119, r[2], f'PS2026{r[0]}', r[4], r[3], r[5], r[5], r[7], |
| | | r[5] - r[7], 1, r[6], ts(r[6], 4700 + r[0]), 250, 4, 'GB/T 2828.1 æ£å¸¸æ£éªä¸æ¬¡æ½æ ·', ADMIN, ts(r[6], 4750 + r[0])) |
| | | for r in oqcs]) |
| | | oqcl = [] |
| | | for i, r in enumerate(oqcs, start=1): |
| | | oqcl.append((i * 2 - 1, r[0], 6, 'ç®æµ', 'å¤è§æ£æ¥', None, None, None, None, 'å
è£
å®å¥½', ADMIN, ts(r[6], 4800 + i))) |
| | | oqcl.append((i * 2, r[0], 1, 'ç®æµ', 'å¤è§æ£æ¥', None, None, None, None, 'æ å伤', ADMIN, ts(r[6], 4850 + i))) |
| | | clean('mes_qc_oqc_line', [r[0] for r in oqcl]) |
| | | ins('mes_qc_oqc_line', ['id', 'oqc_id', 'indicator_id', 'tool', 'check_method', 'standard_value', 'unit_measure_id', |
| | | 'max_threshold', 'min_threshold', 'remark', 'creator', 'create_time'], oqcl) |
| | | |
| | | defects = [(1, 'DF-01', '表é¢å伤', 1, 3), (2, 'DF-02', '尺寸è¶
å·®', 1, 2), |
| | | (3, 'DF-03', 'æ¯åºæªæ¸
', 1, 3), (4, 'DF-04', 'æè´¨ä¸ç¬¦', 1, 1)] |
| | | clean('mes_qc_defect', [d[0] for d in defects]) |
| | | ins('mes_qc_defect', ['id', 'code', 'name', 'type', 'level', 'creator', 'create_time'], |
| | | [(d[0], d[1], d[2], d[3], d[4], ADMIN, ts(D(2026, 7, 22), 4900 + d[0])) for d in defects]) |
| | | |
| | | defrec = [(1, 2, 2, 2, '尺寸è¶
å·®', 2, 8, D(2026, 8, 7)), |
| | | (2, 2, 2, 3, 'æ¯åºæªæ¸
', 3, 12, D(2026, 8, 7))] |
| | | clean('mes_qc_defect_record', [d[0] for d in defrec]) |
| | | ins('mes_qc_defect_record', ['id', 'qc_type', 'qc_id', 'name', 'level', 'quantity', 'creator', 'create_time'], |
| | | [(d[0], d[1], d[2], d[4], d[5], d[6], ADMIN, ts(d[7], 4950 + d[0])) for d in defrec]) |
| | | |
| | | ncr = (1, 'NCR20260807001', 'èºæ æ¥æå°ºå¯¸è¶
å·®', 1, 2, 'IQC20260807002', 1012, 2, 80, |
| | | 'èºæ M8x30 æ¥æä¸ 80 ä»¶å¤å¾è¶
å·®', 1, 126, 250, D(2026, 8, 8), 'å¤å®éè´§', 249, D(2026, 8, 9), |
| | | 'å·²éä¾åºåï¼ä¾åºåè¡¥å', 'ä¾åºå模å
·ç£¨æ', 'è¦æ±ä¾åºåæ´æ¢æ¨¡å
·å¹¶å
¨æ£', 'è¿è´§æ£éªå ä¸¥æ½æ£', 250, D(2026, 8, 12), |
| | | 'å·²éç¯', 4, D(2026, 8, 7)) |
| | | clean('mes_qc_ncr', [ncr[0]]) |
| | | ins('mes_qc_ncr', ['id', 'code', 'name', 'qc_type', 'qc_id', 'qc_code', 'item_id', 'defect_level', 'unqualified_quantity', |
| | | 'defect_description', 'disposition', 'responsible_dept_id', 'reviewer_user_id', 'review_date', |
| | | 'review_opinion', 'handler_user_id', 'handle_date', 'handle_result', 'root_cause', 'corrective_action', |
| | | 'preventive_action', 'close_user_id', 'close_date', 'close_opinion', 'status', 'creator', 'create_time'], |
| | | [(ncr[0], ncr[1], ncr[2], ncr[3], ncr[4], ncr[5], ncr[6], ncr[7], ncr[8], ncr[9], ncr[10], ncr[11], ncr[12], |
| | | ts(ncr[13], 5000), ncr[14], ncr[15], ts(ncr[16], 5010), ncr[17], ncr[18], ncr[19], ncr[20], ncr[21], |
| | | ts(ncr[22], 5020), ncr[23], ncr[24], ADMIN, ts(ncr[25], 5030))]) |
| | | print('qc ok') |
| | | |
| | | # ==================== 9. 设å¤ç®¡ç ==================== |
| | | subjects = [(1, 'SUB-APPEAR', '设å¤å¤è§', 1, 'æ£æ¥è®¾å¤è¡¨é¢æ¯å¦æ¸
æ´ãæ æ²¹æ±¡ãæ éè', 'è¡¨é¢æ¸
æ´'), |
| | | (2, 'SUB-LUBE', '润æ»ç³»ç»', 1, 'æ£æ¥æ²¹ä½ãæ²¹è´¨åæ¶¦æ»ç¹', 'æ²¹ä½å¨å»åº¦çº¿å
'), |
| | | (3, 'SUB-ELEC', 'çµæ°ç³»ç»', 1, 'æ£æ¥çº¿è·¯ãæé®ãæç¤ºç¯', 'æ 裸é²çº¿è·¯'), |
| | | (4, 'SUB-SAFE', 'å®å
¨é²æ¤', 1, 'æ£æ¥é²æ¤ç½©ãæ¥åæé®', '鲿¤é½å
¨ææ'), |
| | | (5, 'SUB-PRECISE', 'ç²¾åº¦æ£æ¥', 1, 'æ£æ¥åè½´å®ä½ç²¾åº¦', '符ååºåæ å'), |
| | | (6, 'SUB-CLEAN', 'æ¸
æ´ä¿å
»', 2, 'æ¸
çéå±ãæ¦æå¯¼è½¨', 'æ éå±å 积')] |
| | | clean('mes_dv_subject', [s[0] for s in subjects]) |
| | | ins('mes_dv_subject', ['id', 'code', 'name', 'type', 'content', 'standard', 'status', 'creator', 'create_time'], |
| | | [(s[0], s[1], s[2], s[3], s[4], s[5], 0, ADMIN, ts(D(2026, 7, 25), 5100 + s[0])) for s in subjects]) |
| | | |
| | | plans = [(1, 'CP20260901001', 'æºåºæ¥å¸¸ç¹æ£è®¡å', 1, D(2026, 9, 1), D(2027, 8, 31), 1, 1), |
| | | (2, 'CP20260901002', 'æºåºæåº¦ä¿å
»è®¡å', 2, D(2026, 9, 1), D(2027, 8, 31), 3, 1)] |
| | | clean('mes_dv_check_plan', [p[0] for p in plans]) |
| | | ins('mes_dv_check_plan', ['id', 'code', 'name', 'type', 'start_date', 'end_date', 'cycle_type', 'cycle_count', |
| | | 'status', 'creator', 'create_time'], |
| | | [(p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], 1, ADMIN, ts(D(2026, 8, 28), 5200 + p[0])) for p in plans]) |
| | | |
| | | pm_rows = [(i, 1, i, ADMIN, ts(D(2026, 8, 28), 5300 + i)) for i in range(1, 7)] |
| | | clean('mes_dv_check_plan_machinery', [r[0] for r in pm_rows]) |
| | | ins('mes_dv_check_plan_machinery', ['id', 'plan_id', 'machinery_id', 'creator', 'create_time'], pm_rows) |
| | | |
| | | ps_rows = [] |
| | | ps_id = 0 |
| | | for plan, subj_ids in [(1, [1, 2, 3]), (2, [4, 5, 6])]: |
| | | for sid in subj_ids: |
| | | ps_id += 1 |
| | | ps_rows.append((ps_id, plan, sid, ADMIN, ts(D(2026, 8, 28), 5400 + ps_id))) |
| | | clean('mes_dv_check_plan_subject', [r[0] for r in ps_rows]) |
| | | ins('mes_dv_check_plan_subject', ['id', 'plan_id', 'subject_id', 'creator', 'create_time'], ps_rows) |
| | | |
| | | records = [] |
| | | rec_id = 0 |
| | | for day in (D(2026, 9, 15), D(2026, 10, 20)): |
| | | for mach in range(1, 7): |
| | | rec_id += 1 |
| | | records.append((rec_id, 1, mach, ts(day, 5500 + rec_id), 249, 20, ADMIN, ts(day, 5550 + rec_id))) |
| | | clean('mes_dv_check_record', [r[0] for r in records]) |
| | | ins('mes_dv_check_record', ['id', 'plan_id', 'machinery_id', 'check_time', 'user_id', 'status', 'creator', 'create_time'], records) |
| | | lines = [] |
| | | lid = 0 |
| | | for r in records: |
| | | for sid in (1, 2, 3): |
| | | lid += 1 |
| | | lines.append((lid, r[0], sid, 1, 'æ£å¸¸', ADMIN, ts(r[3].date(), 5600 + lid))) |
| | | clean('mes_dv_check_record_line', [r[0] for r in lines]) |
| | | ins('mes_dv_check_record_line', ['id', 'record_id', 'subject_id', 'check_status', 'check_result', 'creator', 'create_time'], lines) |
| | | |
| | | mrec = [] |
| | | for mach in range(1, 7): |
| | | mrec.append((mach, 2, mach, ts(D(2026, 10, 12), 5700 + mach), 250, 4, ADMIN, ts(D(2026, 10, 12), 5750 + mach))) |
| | | clean('mes_dv_mainten_record', [r[0] for r in mrec]) |
| | | ins('mes_dv_mainten_record', ['id', 'plan_id', 'machinery_id', 'mainten_time', 'user_id', 'status', 'creator', 'create_time'], mrec) |
| | | mlines = [] |
| | | mid = 0 |
| | | for r in mrec: |
| | | for sid in (4, 5, 6): |
| | | mid += 1 |
| | | mlines.append((mid, r[0], sid, 1, 'å·²ä¿å
»', ADMIN, ts(D(2026, 10, 12), 5800 + mid))) |
| | | clean('mes_dv_mainten_record_line', [r[0] for r in mlines]) |
| | | ins('mes_dv_mainten_record_line', ['id', 'record_id', 'subject_id', 'status', 'result', 'creator', 'create_time'], mlines) |
| | | |
| | | repairs = [(1, 'RP20261012001', '车åºä¸»è½´å¼åç»´ä¿®', 2, D(2026, 10, 12), D(2026, 10, 13), D(2026, 10, 14), 8, 249, 250, 4), |
| | | (2, 'RP20261018002', 'é»åºè¿ç»ææå¡æ»ç»´ä¿®', 4, D(2026, 10, 18), D(2026, 10, 18), D(2026, 10, 19), 3, 250, 249, 4)] |
| | | clean('mes_dv_repair', [r[0] for r in repairs]) |
| | | ins('mes_dv_repair', ['id', 'code', 'name', 'machinery_id', 'require_date', 'finish_date', 'confirm_date', 'duration_hours', |
| | | 'accepted_user_id', 'confirm_user_id', 'status', 'creator', 'create_time'], |
| | | [(r[0], r[1], r[2], r[3], ts(r[4], 5900 + r[0]), ts(r[5], 5910 + r[0]), ts(r[6], 5920 + r[0]), r[7], r[8], r[9], |
| | | r[10], ADMIN, ts(r[4], 5930 + r[0])) for r in repairs]) |
| | | rl = [(1, 1, 5, '主轴轴æ¿ç£¨æ', 'æ´æ¢è½´æ¿å¹¶éæ°è°æ´é´é', ADMIN, ts(D(2026, 10, 12), 5940)), |
| | | (2, 2, 4, 'ææä¸æç¼ºæ²¹å¡æ»', 'æ¸
æ´ä¸æå¹¶å 注润æ»è', ADMIN, ts(D(2026, 10, 18), 5950))] |
| | | clean('mes_dv_repair_line', [r[0] for r in rl]) |
| | | ins('mes_dv_repair_line', ['id', 'repair_id', 'subject_id', 'malfunction', 'description', 'creator', 'create_time'], rl) |
| | | |
| | | spares = [(1, 'SP-BEAR-6205', 'ä¸»è½´è½´æ¿ 6205', '6205', '个', 'å¤ä»¶åºA-01', 24, 8), |
| | | (2, 'SP-BELT-A', 'ä¼ å¨ç®å¸¦ Aå', 'A-1200', 'æ¡', 'å¤ä»¶åºA-02', 15, 5), |
| | | (3, 'SP-OIL-46', 'æ¶²åæ²¹ 46#', '18L/æ¡¶', 'æ¡¶', 'å¤ä»¶åºB-01', 12, 4), |
| | | (4, 'SP-FUSE-10A', 'ä¿é©ç®¡ 10A', '10A', '个', 'å¤ä»¶åºB-02', 50, 20), |
| | | (5, 'SP-SEAL-O40', 'æ²¹å° O-40', 'O-40', '个', 'å¤ä»¶åºA-03', 30, 10)] |
| | | clean('mes_dv_spare_part', [s[0] for s in spares]) |
| | | ins('mes_dv_spare_part', ['id', 'code', 'name', 'specification', 'unit', 'location', 'stock_quantity', 'safety_quantity', |
| | | 'status', 'creator', 'create_time'], |
| | | [(s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], 0, ADMIN, ts(D(2026, 8, 1), 6000 + s[0])) for s in spares]) |
| | | mov = [(1, 'REQ20261012001', 1, 2, 1, 1, D(2026, 10, 12)), |
| | | (2, 'REQ20261018002', 4, 2, 2, 2, D(2026, 10, 18)), |
| | | (3, 'REQ20261020003', 3, 1, 1, None, D(2026, 10, 20))] |
| | | clean('mes_dv_spare_movement', [m[0] for m in mov]) |
| | | ins('mes_dv_spare_movement', ['id', 'request_key', 'spare_part_id', 'spare_part_code', 'spare_part_name', 'unit', 'type', |
| | | 'quantity', 'before_quantity', 'after_quantity', 'repair_id', 'machinery_name', |
| | | 'operator_user_id', 'remark', 'creator', 'create_time'], |
| | | [(m[0], m[1], m[2], spares[m[2] - 1][1], spares[m[2] - 1][2], spares[m[2] - 1][4], m[3], m[4], |
| | | spares[m[2] - 1][6], spares[m[2] - 1][6] + (m[4] if m[3] == 2 else -m[4]), |
| | | m[5], f'设å¤{m[2]}', 249, 'ç»´ä¿®é¢ç¨' if m[3] == 2 else 'éè´å
¥åº', ADMIN, ts(m[6], 6100 + m[0])) for m in mov]) |
| | | |
| | | meter = [(1, 'MT-001', '游æ å¡å°º 0-150', '0-150mm', 'ä¸ä¸°', 1, '0.02mm', '0-150mm', 8, D(2026, 3, 10), D(2026, 9, 10), D(2027, 3, 10)), |
| | | (2, 'MT-002', 'å¤å¾ååå°º 0-25', '0-25mm', 'ä¸ä¸°', 2, '0.001mm', '0-25mm', 10, D(2026, 4, 15), D(2026, 10, 15), D(2027, 4, 15)), |
| | | (3, 'MT-003', '硬度计 TH110', 'TH110', 'æ¶ä»£', 7, '±3HB', '170-210HB', 7, D(2026, 5, 20), D(2026, 11, 20), D(2027, 5, 20))] |
| | | clean('mes_dv_metering', [m[0] for m in meter]) |
| | | ins('mes_dv_metering', ['id', 'code', 'name', 'specification', 'brand', 'category', 'precision', 'range', 'check_cycle_count', |
| | | 'use_date', 'last_check_date', 'next_check_date', 'status', 'creator', 'create_time'], |
| | | [(m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8], m[9], m[10], m[11], 0, ADMIN, ts(D(2026, 3, 1), 6200 + m[0])) |
| | | for m in meter]) |
| | | mcheck = [(1, 1, 'JC20260910001', D(2026, 9, 10), 'åå±±å¸è®¡éæ', 1, 'CERT-2026-0910'), |
| | | (2, 2, 'JC20261015002', D(2026, 10, 15), 'åå±±å¸è®¡éæ', 1, 'CERT-2026-1015')] |
| | | clean('mes_dv_metering_check', [c[0] for c in mcheck]) |
| | | ins('mes_dv_metering_check', ['id', 'metering_id', 'check_code', 'check_date', 'check_org', 'check_result', 'cert_no', |
| | | 'check_user_id', 'check_user_name', 'next_check_date', 'creator', 'create_time'], |
| | | [(c[0], c[1], c[2], c[3], c[4], c[5], c[6], 249, 'èµµç£', c[3] + datetime.timedelta(days=180), ADMIN, ts(c[3], 6300 + c[0])) |
| | | for c in mcheck]) |
| | | print('dv ok') |
| | | |
| | | # ==================== 10. 人åèµæº ==================== |
| | | EMP_USERS = [(243, 'èµµç£'), (244, 'æä¸å¨'), (245, 'å·¨å
è'), (246, '马èå¨'), (247, 'åé'), |
| | | (248, 'éæµ·è¹'), (249, '许海è±'), (250, 'éå±±è¯'), (251, 'éæ
§æ
§'), (252, 'ä½åç ')] |
| | | cur.execute("DELETE FROM hrm_attendance_record WHERE user_id IN (%s)" % ','.join(['%s'] * 10), [u[0] for u in EMP_USERS]) |
| | | att_rows = [] |
| | | day = D(2026, 9, 21) |
| | | seed = 7000 |
| | | while day <= D(2026, 10, 31): |
| | | if day.weekday() < 5: |
| | | for uid, name in EMP_USERS: |
| | | seed += 1 |
| | | h = int(hashlib.md5(f'{uid}-{day}'.encode()).hexdigest(), 16) |
| | | in_min = h % 25 - 10 # -10 ~ +14 åé |
| | | out_min = (h >> 8) % 40 - 5 |
| | | ci = datetime.datetime.combine(day, datetime.time(8, 0)) + datetime.timedelta(minutes=in_min) |
| | | co = datetime.datetime.combine(day, datetime.time(17, 30)) + datetime.timedelta(minutes=out_min) |
| | | if h % 13 == 0: |
| | | co = datetime.datetime.combine(day, datetime.time(19, 0)) + datetime.timedelta(minutes=h % 30) |
| | | hours = round((co - ci).total_seconds() / 3600, 2) |
| | | att_rows.append((uid, 126, day, ci, co, 1, 1, hours, max(0, round(hours - 8, 2)), 'åå±±å¸è¯åäºéååº', |
| | | 'æ£å¸¸åºå¤', 1, ADMIN, ci)) |
| | | day += datetime.timedelta(days=1) |
| | | ins('hrm_attendance_record', ['user_id', 'dept_id', 'date', 'clock_in_time', 'clock_out_time', 'clock_in_type', |
| | | 'clock_out_type', 'work_hours', 'overtime_hours', 'location', 'remark', 'data_source', |
| | | 'creator', 'create_time'], att_rows) |
| | | print('attendance', len(att_rows)) |
| | | |
| | | cur.execute("DELETE FROM hrm_salary_calculation WHERE period = '2026-10'") |
| | | sal_rows = [] |
| | | for i, (uid, name) in enumerate(EMP_USERS): |
| | | base = 6500 + (i % 10) * 300 |
| | | perf = 800 + (i % 5) * 200 |
| | | overtime = round(20 + (i % 6) * 6, 2) |
| | | meal, trans, other = 300, 200, 100 |
| | | social = round(base * 0.105, 2) |
| | | fund = round(base * 0.07, 2) |
| | | tax = round(max(0, (base + perf + overtime * 30 - social - fund - 5000) * 0.03), 2) |
| | | actual = round(base + perf + overtime * 30 + meal + trans + other - social - fund - tax, 2) |
| | | status = 20 if i < 6 else 10 |
| | | sal_rows.append((f'SC202610{i + 1:04d}', '2026-10', uid, 126, base, perf, round(overtime * 30, 2), meal, trans, other, |
| | | social, fund, tax, 0, 0, actual, 31, overtime, 176, status, |
| | | ts(D(2026, 11, 1), 7100 + i), 249, ts(D(2026, 11, 2), 7200 + i) if status == 20 else None, |
| | | ADMIN, ts(D(2026, 11, 1), 7300 + i))) |
| | | ins('hrm_salary_calculation', ['no', 'period', 'user_id', 'dept_id', 'base_salary', 'performance_salary', 'overtime_pay', |
| | | 'meal_allowance', 'transport_allowance', 'other_allowance', 'social_security_deduction', |
| | | 'housing_fund_deduction', 'tax_deduction', 'other_deduction', 'leave_deduction', |
| | | 'actual_salary', 'work_days', 'overtime_hours', 'total_work_hours', 'status', |
| | | 'confirm_time', 'confirm_user_id', 'payment_time', 'creator', 'create_time'], sal_rows) |
| | | cur.execute("DELETE FROM hrm_salary_payment WHERE period = '2026-10'") |
| | | ins('hrm_salary_payment', ['no', 'period', 'total_amount', 'total_count', 'payment_method', 'payment_time', 'status', |
| | | 'remark', 'creator', 'create_time'], |
| | | [('SP2026100001', '2026-10', sum(float(r[15]) for r in sal_rows[:6]), 6, 1, ts(D(2026, 11, 5), 7400), 10, |
| | | '10æå·¥èµï¼ç¬¬ä¸æ¹ï¼', ADMIN, ts(D(2026, 11, 5), 7450))]) |
| | | print('salary ok') |
| | | |
| | | # ==================== 13. å¾
æ£ä»»å¡è¡¥å
ï¼è¡¥è´§å°è´§ + éè´§æ£éªï¼ ==================== |
| | | # å¾
æ£ä»»å¡é¡µéè¦ãå·²å°è´§æªæ£éªãä¸ãå·²åºåºæªæ£éªãä¸¤ç±»æ°æ®ï¼ä¸»é¾è·¯çåæ®é½å·²æ£éªå®ï¼è¿éè¡¥å æ¡ |
| | | extra_notices = [ # id, code, po_id, vendor, date, [(item, qty)] |
| | | (6, 'AN20261028006', 3, 2, D(2026, 10, 28), [(1010, 500)]), |
| | | (7, 'AN20261029007', 4, 5, D(2026, 10, 29), [(1015, 80), (1016, 60)]), |
| | | ] |
| | | ex_an, ex_anl = [], [] |
| | | ex_anl_id = 20 |
| | | for nid, code, po_id, vendor, day, items in extra_notices: |
| | | pono = [x for x in po_rows if x[0] == po_id][0][1] |
| | | ex_an.append((nid, code, f'{pono} 补货å°è´§éç¥', po_id, pono, vendor, ts(day, 1100 + nid), 2, ADMIN, ts(day, 1200 + nid))) |
| | | for item, qty in items: |
| | | poi = [r for r in poi_by_po[po_id] if r[3] == item][0] |
| | | ex_anl.append((ex_anl_id, nid, poi[0], item, qty, qty, 1, ADMIN, ts(day, 1300 + ex_anl_id))) |
| | | ex_anl_id += 1 |
| | | clean('mes_wm_arrival_notice', [r[0] for r in ex_an]) |
| | | clean('mes_wm_arrival_notice_line', [r[0] for r in ex_anl]) |
| | | ins('mes_wm_arrival_notice', ['id', 'code', 'name', 'purchase_order_id', 'purchase_order_code', 'vendor_id', |
| | | 'arrival_date', 'status', 'creator', 'create_time'], ex_an) |
| | | ins('mes_wm_arrival_notice_line', ['id', 'notice_id', 'purchase_order_item_id', 'item_id', 'arrival_quantity', |
| | | 'qualified_quantity', 'iqc_check_flag', 'creator', 'create_time'], ex_anl) |
| | | |
| | | ex_ps = (4, 'PS20261028004', 4, 4, D(2026, 10, 28), [(1002, 100), (1006, 20)]) |
| | | sid, code, so, client, day, items = ex_ps |
| | | sono = [x for x in sale_orders if x[0] == so][0][1] |
| | | soi_by_item = {r[2]: r[0] for r in soi_rows if r[1] == so} |
| | | ex_ps_row = (sid, code, f'{sono} éå®åºåº', client, so, sono, ts(day, 2200 + sid), 'åç»ç', '13900000004', |
| | | 'å京å¸å¤§å
´åº', 'é¡ºä¸°ç©æµ', f'SF2026102{sid:03d}', 1, ADMIN, ts(day, 2300 + sid)) |
| | | ex_psl_rows = [(20 + i, sid, soi_by_item.get(item), item, UNIT[item], qty, qty, 1, 0, ADMIN, ts(day, 2350 + i)) |
| | | for i, (item, qty) in enumerate(items)] |
| | | clean('mes_wm_product_sales', [sid]) |
| | | clean('mes_wm_product_sales_line', [r[0] for r in ex_psl_rows]) |
| | | ins('mes_wm_product_sales', ['id', 'code', 'name', 'client_id', 'sale_order_id', 'sales_order_code', 'sales_date', |
| | | 'contact_name', 'contact_telephone', 'contact_address', 'carrier', 'shipping_number', |
| | | 'status', 'creator', 'create_time'], [ex_ps_row]) |
| | | ins('mes_wm_product_sales_line', ['id', 'sales_id', 'sale_order_item_id', 'item_id', 'enter_unit_measure_id', |
| | | 'enter_quantity', 'quantity', 'oqc_check_flag', 'quality_status', 'creator', 'create_time'], ex_psl_rows) |
| | | |
| | | # éè´§æ£éªï¼å®¢æ·éåæ³å
°ç 10 ä»¶ï¼8 ä»¶åæ ¼ 2 ä»¶å伤 |
| | | rqc_row = (1, 'RQC20261026001', 'æ³å
°ç DN50 éè´§æ£éª', 1, 120, 1, None, 'PS20260815001', 1, 1001, 'BT20260806001', |
| | | 10, 8, 2, None, None, None, None, None, None, 3, ts(D(2026, 10, 26), 5100), 250, 4, None, None, |
| | | 'GB/T 2828.1 æ£å¸¸æ£éªä¸æ¬¡æ½æ ·', None, None, None, ADMIN, ts(D(2026, 10, 26), 5050)) |
| | | clean('mes_qc_rqc', [rqc_row[0]]) |
| | | ins('mes_qc_rqc', ['id', 'code', 'name', 'template_id', 'source_doc_type', 'source_doc_id', 'source_line_id', |
| | | 'source_doc_code', 'type', 'item_id', 'batch_code', 'check_quantity', 'qualified_quantity', |
| | | 'unqualified_quantity', 'critical_rate', 'major_rate', 'minor_rate', 'critical_quantity', |
| | | 'major_quantity', 'minor_quantity', 'check_result', 'inspect_date', 'inspector_user_id', 'status', |
| | | 'sampling_location', 'certificate_no', 'execute_standard', 'audit_user_id', 'approve_user_id', |
| | | 'remark', 'creator', 'create_time'], [rqc_row]) |
| | | rqcl = [ |
| | | (1, 1, 1, 'ç®æµ', 'å¤è§æ£æ¥', None, None, None, None, None, None, None, '表é¢å伤 2 ä»¶', ADMIN, ts(D(2026, 10, 26), 5100)), |
| | | (2, 1, 2, '游æ å¡å°º', 'æµé', 30, 1, None, None, None, None, None, 'å°ºå¯¸åæ ¼', ADMIN, ts(D(2026, 10, 26), 5120)), |
| | | ] |
| | | clean('mes_qc_rqc_line', [r[0] for r in rqcl]) |
| | | ins('mes_qc_rqc_line', ['id', 'rqc_id', 'indicator_id', 'tool', 'check_method', 'standard_value', 'unit_measure_id', |
| | | 'max_threshold', 'min_threshold', 'critical_quantity', 'major_quantity', 'minor_quantity', |
| | | 'remark', 'creator', 'create_time'], rqcl) |
| | | print('pending-inspect extra ok') |
| | | |
| | | conn.commit() |
| | | print('DOCS OK') |
| | |
| | | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| | | import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.pro.mps.vo.MesProMpsPageReqVO; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.pro.mps.vo.MesProMpsPreparationCheckRespVO; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.pro.mps.vo.MesProMpsRespVO; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.pro.mps.vo.MesProMpsSaveReqVO; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.pro.workorder.vo.MesProWorkOrderItemRespVO; |
| | |
| | | return success(mpsService.getMpsItemList(id)); |
| | | } |
| | | |
| | | @GetMapping("/preparation-check") |
| | | @Operation(summary = "ç产å夿£æ¥ï¼ç©æã设å¤ï¼") |
| | | @Parameter(name = "id", description = "MPS ç¼å·", required = true) |
| | | @PreAuthorize("@ss.hasPermission('mes:pro-mps:query')") |
| | | public CommonResult<MesProMpsPreparationCheckRespVO> getPreparationCheck(@RequestParam("id") Long id) { |
| | | return success(mpsService.getPreparationCheck(id)); |
| | | } |
| | | |
| | | @PostMapping("/generate-purchase-request") |
| | | @Operation(summary = "æ ¹æ®ç产主计åè¾
æç¼ºå£çæéè´ç³è¯·å") |
| | | @Parameter(name = "id", description = "MPS ç¼å·", required = true) |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.mes.controller.admin.pro.mps.vo; |
| | | |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.util.ArrayList; |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * MES ç产主计å - ç产å夿£æ¥ç»æ Response VO |
| | | * |
| | | * åºäºçäº§è®¡åæ£æ¥ç©æã设å¤ä¸¤ç±»ç产è¦ç´ æ¯å¦é½å¤ |
| | | */ |
| | | @Schema(description = "管çåå° - ç产å夿£æ¥ç»æ Response VO") |
| | | @Data |
| | | public class MesProMpsPreparationCheckRespVO { |
| | | |
| | | @Schema(description = "计åç¼å·", example = "1") |
| | | private Long mpsId; |
| | | |
| | | @Schema(description = "计ååå·", example = "MPS20261103001") |
| | | private String mpsCode; |
| | | |
| | | @Schema(description = "产åç¼å·", example = "1") |
| | | private Long productId; |
| | | |
| | | @Schema(description = "产ååç§°", example = "æ³å
°ç") |
| | | private String productName; |
| | | |
| | | @Schema(description = "è®¡åæ°é", example = "100") |
| | | private BigDecimal quantity; |
| | | |
| | | @Schema(description = "ç©ææ¯å¦é½å¤") |
| | | private Boolean materialReady; |
| | | |
| | | @Schema(description = "è®¾å¤æ¯å¦é½å¤") |
| | | private Boolean equipmentReady; |
| | | |
| | | @Schema(description = "æ¯å¦å¯ä»¥è¿è¡ç产") |
| | | private Boolean ready; |
| | | |
| | | @Schema(description = "æ£æ¥ç»è®ºè¯´æï¼ä¾å¦ã3 é¡¹ç©æç缺ã2 å°è®¾å¤ä¸å¯ç¨ã") |
| | | private String summary; |
| | | |
| | | @Schema(description = "ç©ææ£æ¥æç»") |
| | | private List<MaterialCheck> materials = new ArrayList<>(); |
| | | |
| | | @Schema(description = "è®¾å¤æ£æ¥æç»") |
| | | private List<EquipmentCheck> equipments = new ArrayList<>(); |
| | | |
| | | @Schema(description = "ç©ææ£æ¥æç»") |
| | | @Data |
| | | public static class MaterialCheck { |
| | | |
| | | @Schema(description = "ç©æç¼å·") |
| | | private Long itemId; |
| | | @Schema(description = "ç©æç¼ç ") |
| | | private String itemCode; |
| | | @Schema(description = "ç©æåç§°") |
| | | private String itemName; |
| | | @Schema(description = "è§æ ¼") |
| | | private String specification; |
| | | @Schema(description = "åä½") |
| | | private String unitMeasureName; |
| | | @Schema(description = "éæ±æ°é") |
| | | private BigDecimal requiredQuantity; |
| | | @Schema(description = "ç°æåºå") |
| | | private BigDecimal stockQuantity; |
| | | @Schema(description = "å¨ééè´æ°é") |
| | | private BigDecimal purchaseOrderQuantity; |
| | | @Schema(description = "ç¼ºå£æ°é") |
| | | private BigDecimal shortageQuantity; |
| | | @Schema(description = "æ¯å¦å
è¶³") |
| | | private Boolean sufficient; |
| | | |
| | | } |
| | | |
| | | @Schema(description = "è®¾å¤æ£æ¥æç»") |
| | | @Data |
| | | public static class EquipmentCheck { |
| | | |
| | | @Schema(description = "å·¥åºç¼å·") |
| | | private Long processId; |
| | | @Schema(description = "å·¥åºåç§°") |
| | | private String processName; |
| | | @Schema(description = "设å¤ç¼å·") |
| | | private Long machineryId; |
| | | @Schema(description = "设å¤ç¼ç ") |
| | | private String machineryCode; |
| | | @Schema(description = "设å¤åç§°") |
| | | private String machineryName; |
| | | @Schema(description = "设å¤ç¶æï¼1-åæº 2-çäº§ä¸ 3-ç»´æ¤ä¸ï¼") |
| | | private Integer status; |
| | | @Schema(description = "设å¤ç¶æåç§°") |
| | | private String statusName; |
| | | @Schema(description = "æ¯å¦å¯ç¨") |
| | | private Boolean available; |
| | | @Schema(description = "ä¸å¯ç¨åå ") |
| | | private String reason; |
| | | |
| | | } |
| | | |
| | | } |
| | |
| | | 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.wm.transaction.vo.MesWmStockSummaryReqVO; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.wm.transaction.vo.MesWmStockSummaryRespVO; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.wm.transaction.vo.MesWmTransactionPageReqVO; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.wm.transaction.vo.MesWmTransactionRespVO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.md.unitmeasure.MesMdUnitMeasureDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.mdm.MesMdmItemDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.transaction.MesWmTransactionDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseAreaDO; |
| | |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseLocationDO; |
| | | import cn.iocoder.yudao.module.mes.enums.MesBizTypeConstants; |
| | | import cn.iocoder.yudao.module.mes.enums.wm.MesWmTransactionTypeEnum; |
| | | import cn.iocoder.yudao.module.mes.service.md.unitmeasure.MesMdUnitMeasureService; |
| | | import cn.iocoder.yudao.module.mes.service.mdm.MesMdmItemService; |
| | | import cn.iocoder.yudao.module.mes.service.wm.transaction.MesWmTransactionService; |
| | | import cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseAreaService; |
| | |
| | | private MesWmWarehouseLocationService locationService; |
| | | @Resource |
| | | private MesWmWarehouseAreaService areaService; |
| | | @Resource |
| | | private MesMdUnitMeasureService unitMeasureService; |
| | | |
| | | @GetMapping("/page") |
| | | @Operation(summary = "è·ååºåäºå¡æµæ°´å页") |
| | |
| | | return success(new PageResult<>(voList, pageResult.getTotal())); |
| | | } |
| | | |
| | | @GetMapping("/summary") |
| | | @Operation(summary = "è·åä»å¨æ¶ååæ±æ»ï¼æç©æ + ä»åºï¼") |
| | | @PreAuthorize("@ss.hasPermission('mes:wm-transaction:query')") |
| | | public CommonResult<PageResult<MesWmStockSummaryRespVO>> getStockSummary(@Valid MesWmStockSummaryReqVO reqVO) { |
| | | PageResult<MesWmStockSummaryRespVO> pageResult = transactionService.getStockSummaryPage(reqVO); |
| | | if (pageResult.getList().isEmpty()) { |
| | | return success(PageResult.empty(pageResult.getTotal())); |
| | | } |
| | | // å
³èç©æãä»åºãåä½åç§° |
| | | Map<Long, MesMdmItemDO> itemMap = mdmItemService.getItemMap( |
| | | convertSet(pageResult.getList(), MesWmStockSummaryRespVO::getItemId)); |
| | | Map<Long, MesWmWarehouseDO> warehouseMap = warehouseService.getWarehouseMap( |
| | | convertSet(pageResult.getList(), MesWmStockSummaryRespVO::getWarehouseId)); |
| | | Map<Long, MesMdUnitMeasureDO> unitMap = unitMeasureService.getUnitMeasureMap( |
| | | itemMap.values().stream().map(MesMdmItemDO::getUnitMeasureId) |
| | | .filter(java.util.Objects::nonNull).collect(Collectors.toSet())); |
| | | for (MesWmStockSummaryRespVO vo : pageResult.getList()) { |
| | | MesMdmItemDO item = itemMap.get(vo.getItemId()); |
| | | |
| | | if (item != null) { |
| | | vo.setItemCode(item.getCode()); |
| | | vo.setItemName(item.getName()); |
| | | vo.setSpecification(item.getSpecification()); |
| | | MesMdUnitMeasureDO unit = unitMap.get(item.getUnitMeasureId()); |
| | | if (unit != null) { |
| | | vo.setUnitMeasureName(unit.getName()); |
| | | } |
| | | } |
| | | MesWmWarehouseDO warehouse = warehouseMap.get(vo.getWarehouseId()); |
| | | if (warehouse != null) { |
| | | vo.setWarehouseName(warehouse.getName()); |
| | | } |
| | | } |
| | | return success(pageResult); |
| | | } |
| | | |
| | | /** |
| | | * è·åä¸å¡ç±»ååç§° |
| | | */ |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.mes.controller.admin.wm.transaction.vo; |
| | | |
| | | import cn.iocoder.yudao.framework.common.pojo.PageParam; |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | import lombok.EqualsAndHashCode; |
| | | import lombok.ToString; |
| | | import org.springframework.format.annotation.DateTimeFormat; |
| | | |
| | | import java.time.LocalDateTime; |
| | | |
| | | import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; |
| | | |
| | | /** |
| | | * ä»å¨æ¶ååæ±æ»æ¥è¯¢ Request VO |
| | | */ |
| | | @Schema(description = "管çåå° - ä»å¨æ¶ååæ±æ»æ¥è¯¢ Request VO") |
| | | @Data |
| | | @EqualsAndHashCode(callSuper = true) |
| | | @ToString(callSuper = true) |
| | | public class MesWmStockSummaryReqVO extends PageParam { |
| | | |
| | | @Schema(description = "ç©æID", example = "1") |
| | | private Long itemId; |
| | | |
| | | @Schema(description = "ä»åºID", example = "1") |
| | | private Long warehouseId; |
| | | |
| | | @Schema(description = "æå/æ¥è¯¢å¼å§æ¶é´") |
| | | @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) |
| | | private LocalDateTime startTime; |
| | | |
| | | @Schema(description = "ææ«/æ¥è¯¢ç»ææ¶é´") |
| | | @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) |
| | | private LocalDateTime endTime; |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.mes.controller.admin.wm.transaction.vo; |
| | | |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | |
| | | import java.math.BigDecimal; |
| | | |
| | | /** |
| | | * ä»å¨æ¶ååæ±æ» Response VO |
| | | */ |
| | | @Schema(description = "管çåå° - ä»å¨æ¶ååæ±æ» Response VO") |
| | | @Data |
| | | public class MesWmStockSummaryRespVO { |
| | | |
| | | @Schema(description = "ç©æID", example = "1") |
| | | private Long itemId; |
| | | @Schema(description = "ç©æç¼ç ", example = "MAT001") |
| | | private String itemCode; |
| | | @Schema(description = "ç©æåç§°", example = "æ³å
°ç") |
| | | private String itemName; |
| | | @Schema(description = "è§æ ¼", example = "DN100") |
| | | private String specification; |
| | | @Schema(description = "åä½", example = "ä»¶") |
| | | private String unitMeasureName; |
| | | |
| | | @Schema(description = "ä»åºID", example = "1") |
| | | private Long warehouseId; |
| | | @Schema(description = "ä»åºåç§°", example = "æåä»") |
| | | private String warehouseName; |
| | | |
| | | @Schema(description = "æåæ°é") |
| | | private BigDecimal openingQuantity; |
| | | @Schema(description = "æ¬æå
¥åºæ°é") |
| | | private BigDecimal inQuantity; |
| | | @Schema(description = "æ¬æåºåºæ°é") |
| | | private BigDecimal outQuantity; |
| | | @Schema(description = "ææ«æ°é") |
| | | private BigDecimal closingQuantity; |
| | | |
| | | } |
| | |
| | | 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.transaction.vo.MesWmStockSummaryRespVO; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.wm.transaction.vo.MesWmTransactionPageReqVO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.transaction.MesWmTransactionDO; |
| | | import com.baomidou.mybatisplus.core.metadata.IPage; |
| | | import org.apache.ibatis.annotations.Mapper; |
| | | import org.apache.ibatis.annotations.Param; |
| | | import org.apache.ibatis.annotations.Select; |
| | | |
| | | import java.time.LocalDateTime; |
| | | |
| | | /** |
| | | * MES åºåäºå¡æµæ°´ Mapper |
| | |
| | | } |
| | | |
| | | /** |
| | | * æ¶ååæ±æ»ï¼ææåãæ¬æå
¥åºãæ¬æåºåºãææ«å个å£å¾æãç©æ + ä»åºãæ±æ» |
| | | */ |
| | | @Select(""" |
| | | <script> |
| | | SELECT t.item_id AS itemId, |
| | | t.warehouse_id AS warehouseId, |
| | | COALESCE(SUM(CASE WHEN t.transaction_time < #{startTime} THEN t.quantity ELSE 0 END), 0) AS openingQuantity, |
| | | COALESCE(SUM(CASE WHEN t.transaction_time >= #{startTime} AND t.transaction_time <= #{endTime} AND t.quantity > 0 THEN t.quantity ELSE 0 END), 0) AS inQuantity, |
| | | COALESCE(SUM(CASE WHEN t.transaction_time >= #{startTime} AND t.transaction_time <= #{endTime} AND t.quantity < 0 THEN -t.quantity ELSE 0 END), 0) AS outQuantity, |
| | | COALESCE(SUM(CASE WHEN t.transaction_time <= #{endTime} THEN t.quantity ELSE 0 END), 0) AS closingQuantity |
| | | FROM mes_wm_transaction t |
| | | WHERE t.deleted = 0 |
| | | AND t.transaction_time <= #{endTime} |
| | | <if test="itemId != null"> AND t.item_id = #{itemId}</if> |
| | | <if test="warehouseId != null"> AND t.warehouse_id = #{warehouseId}</if> |
| | | GROUP BY t.item_id, t.warehouse_id |
| | | ORDER BY t.item_id, t.warehouse_id |
| | | </script> |
| | | """) |
| | | IPage<MesWmStockSummaryRespVO> selectStockSummaryPage(IPage<MesWmStockSummaryRespVO> page, |
| | | @Param("itemId") Long itemId, |
| | | @Param("warehouseId") Long warehouseId, |
| | | @Param("startTime") LocalDateTime startTime, |
| | | @Param("endTime") LocalDateTime endTime); |
| | | |
| | | /** |
| | | * æ¥æ¾èæçº¿è¾¹åºåºåè®°å½å¯¹åºçåå§åºåºä»åºä¿¡æ¯ |
| | | * <p> |
| | | * éè¿èæçº¿è¾¹åºç materialStockIdï¼æ¾å°é¦æ¬¡å
¥åºäºå¡ï¼INï¼ï¼ |
| | |
| | | |
| | | public static final Integer[] ARRAYS = Arrays.stream(values()).map(MesDvMachineryStatusEnum::getStatus).toArray(Integer[]::new); |
| | | |
| | | public static MesDvMachineryStatusEnum valueOfStatus(Integer status) { |
| | | return Arrays.stream(values()).filter(e -> e.status.equals(status)).findFirst().orElse(null); |
| | | } |
| | | |
| | | /** |
| | | * ç¶æå¼ |
| | | */ |
| | |
| | | import java.util.ArrayList; |
| | | import java.util.Collections; |
| | | import java.util.HashMap; |
| | | import java.util.HashSet; |
| | | import java.util.LinkedHashMap; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | |
| | | convertSet(itemMap.values(), MesMdItemDO::getItemTypeId)); |
| | | |
| | | // 2. æ¹éæ¥è¯¢åºåï¼æ itemId æ±æ»å¯ç¨éï¼å¨åº - å»ç» - å ç¨ï¼ |
| | | // åºå表åçæ¯ mdm_item_idï¼è BOM å±å¼å¾å°çæ¯ mes_md_item.idï¼éè¦å
æ¢ç®åæ¥åºå |
| | | Map<Long, BigDecimal> stockMap = new HashMap<>(); |
| | | List<MesWmMaterialStockDO> stockList = materialStockMapper.selectListByItemIds(requirements.keySet()); |
| | | Map<Long, Long> mesToMdmItemId = new HashMap<>(); |
| | | for (MesMdItemDO item : itemMap.values()) { |
| | | if (item.getMdmItemId() != null) { |
| | | mesToMdmItemId.put(item.getId(), item.getMdmItemId()); |
| | | } |
| | | } |
| | | List<MesWmMaterialStockDO> stockList = materialStockMapper.selectListByItemIds( |
| | | new HashSet<>(mesToMdmItemId.values())); |
| | | for (MesWmMaterialStockDO stock : stockList) { |
| | | BigDecimal available = nullToZero(stock.getQuantity()) |
| | | .subtract(nullToZero(stock.getFrozenQuantity())) |
| | |
| | | continue; |
| | | } |
| | | BigDecimal requiredQty = entry.getValue(); |
| | | BigDecimal stockQty = stockMap.getOrDefault(item.getId(), BigDecimal.ZERO); |
| | | BigDecimal stockQty = stockMap.getOrDefault( |
| | | mesToMdmItemId.getOrDefault(item.getId(), item.getId()), BigDecimal.ZERO); |
| | | BigDecimal purchaseQty = purchaseOrderQtyMap.getOrDefault(item.getId(), BigDecimal.ZERO); |
| | | MesProWorkOrderItemRespVO vo = new MesProWorkOrderItemRespVO() |
| | | .setItemId(item.getId()).setQuantity(requiredQty) |
| | |
| | | |
| | | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.pro.mps.vo.MesProMpsPageReqVO; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.pro.mps.vo.MesProMpsPreparationCheckRespVO; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.pro.mps.vo.MesProMpsSaveReqVO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.pro.mps.MesProMpsDO; |
| | | import jakarta.validation.Valid; |
| | |
| | | List<cn.iocoder.yudao.module.mes.controller.admin.pro.workorder.vo.MesProWorkOrderItemRespVO> getMpsItemList(Long id); |
| | | |
| | | /** |
| | | * ç产å夿£æ¥ï¼åºäºçäº§è®¡åæ£æ¥ç©æãè®¾å¤æ¯å¦é½å¤ |
| | | * |
| | | * @param id MPS ç¼å· |
| | | * @return æ£æ¥ç»æ |
| | | */ |
| | | MesProMpsPreparationCheckRespVO getPreparationCheck(Long id); |
| | | |
| | | /** |
| | | * æ ¹æ®è®¡åçè¾
æç¼ºå£çæéè´ç³è¯·åï¼èç¨¿ï¼ |
| | | * |
| | | * @param id MPS ç¼å· |
| | |
| | | import cn.iocoder.yudao.module.erp.api.purchase.dto.ErpPurchaseOrderItemRespDTO; |
| | | import cn.iocoder.yudao.module.erp.api.purchase.dto.ErpPurchaseRequestCreateReqDTO; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.pro.mps.vo.MesProMpsPageReqVO; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.pro.mps.vo.MesProMpsPreparationCheckRespVO; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.pro.mps.vo.MesProMpsSaveReqVO; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.pro.workorder.vo.MesProWorkOrderItemRespVO; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.pro.workorder.vo.MesProWorkOrderSaveReqVO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.dv.machinery.MesDvMachineryDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.pro.mps.MesProMpsDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.pro.mps.MesProMpsMergeItemDO; |
| | |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.pro.route.MesProRouteProductBomDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.pro.route.MesProRouteProductDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.pro.route.MesProRouteProcessDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.pro.process.MesProProcessDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder.MesProWorkOrderDO; |
| | | import cn.iocoder.yudao.module.mes.enums.dv.MesDvMachineryStatusEnum; |
| | | import cn.iocoder.yudao.module.mes.enums.md.autocode.MesMdAutoCodeRuleCodeEnum; |
| | | import cn.iocoder.yudao.module.mes.enums.pro.MesProMpsStatusEnum; |
| | | import cn.iocoder.yudao.module.mes.enums.pro.MesProFeedbackStatusEnum; |
| | | import cn.iocoder.yudao.module.mes.enums.pro.MesProWorkOrderSourceTypeEnum; |
| | | import cn.iocoder.yudao.module.mes.enums.pro.MesProWorkOrderStatusEnum; |
| | | import cn.iocoder.yudao.module.mes.service.dv.machinery.MesDvMachineryService; |
| | | import cn.iocoder.yudao.module.mes.service.md.autocode.MesMdAutoCodeRecordService; |
| | | import cn.iocoder.yudao.module.mes.service.pro.material.MesProMaterialRequirementService; |
| | | import cn.iocoder.yudao.module.mes.service.pro.process.MesProProcessService; |
| | | import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService; |
| | | import cn.iocoder.yudao.module.mes.service.pro.route.MesProRouteProductService; |
| | | import cn.iocoder.yudao.module.mes.service.pro.route.MesProRouteProcessService; |
| | |
| | | private MesProWorkOrderProcessService workOrderProcessService; |
| | | @Resource |
| | | private MesProMaterialRequirementService materialRequirementService; |
| | | @Resource |
| | | private MesProProcessService processService; |
| | | @Resource |
| | | private MesDvMachineryService machineryService; |
| | | @Resource |
| | | private ErpPurchaseOrderApi purchaseOrderApi; |
| | | @Resource |
| | |
| | | } |
| | | |
| | | @Override |
| | | public MesProMpsPreparationCheckRespVO getPreparationCheck(Long id) { |
| | | MesProMpsDO mps = validateMpsExists(id); |
| | | MesProMpsPreparationCheckRespVO result = new MesProMpsPreparationCheckRespVO(); |
| | | result.setMpsId(mps.getId()); |
| | | result.setMpsCode(mps.getCode()); |
| | | result.setProductId(mps.getProductId()); |
| | | result.setQuantity(mps.getQuantity()); |
| | | MesMdItemDO product = itemService.getItem(mps.getProductId()); |
| | | result.setProductName(product != null ? product.getName() : String.valueOf(mps.getProductId())); |
| | | |
| | | // 1. ç©ææ£æ¥ï¼éæ± - å¯ç¨åºå - å¨ééè´ |
| | | List<MesProWorkOrderItemRespVO> materialItems = getMpsItemList(id); |
| | | int materialShortageCount = 0; |
| | | for (MesProWorkOrderItemRespVO item : materialItems) { |
| | | MesProMpsPreparationCheckRespVO.MaterialCheck check = new MesProMpsPreparationCheckRespVO.MaterialCheck(); |
| | | check.setItemId(item.getItemId()); |
| | | check.setItemCode(item.getItemCode()); |
| | | check.setItemName(item.getItemName()); |
| | | check.setSpecification(item.getItemSpecification()); |
| | | check.setUnitMeasureName(item.getUnitMeasureName()); |
| | | check.setRequiredQuantity(nullToZero(item.getQuantity())); |
| | | check.setStockQuantity(nullToZero(item.getStockQuantity())); |
| | | check.setPurchaseOrderQuantity(nullToZero(item.getPurchaseOrderQuantity())); |
| | | BigDecimal supply = nullToZero(item.getStockQuantity()).add(nullToZero(item.getPurchaseOrderQuantity())); |
| | | BigDecimal shortage = nullToZero(item.getQuantity()).subtract(supply); |
| | | if (shortage.compareTo(BigDecimal.ZERO) < 0) { |
| | | shortage = BigDecimal.ZERO; |
| | | } |
| | | check.setShortageQuantity(shortage); |
| | | check.setSufficient(shortage.compareTo(BigDecimal.ZERO) <= 0); |
| | | if (!Boolean.TRUE.equals(check.getSufficient())) { |
| | | materialShortageCount++; |
| | | } |
| | | result.getMaterials().add(check); |
| | | } |
| | | result.setMaterialReady(materialShortageCount == 0); |
| | | |
| | | // 2. è®¾å¤æ£æ¥ï¼æäº§åçå·¥èºè·¯çº¿éå·¥åºæ¥æ¾ç»å®è®¾å¤ |
| | | List<MesProRouteProcessDO> routeProcesses = routeProcessService.getRouteProcessListByProductId(mps.getProductId()); |
| | | int equipmentUnavailableCount = 0; |
| | | if (CollUtil.isEmpty(routeProcesses)) { |
| | | MesProMpsPreparationCheckRespVO.EquipmentCheck check = new MesProMpsPreparationCheckRespVO.EquipmentCheck(); |
| | | check.setProcessName("å·¥èºè·¯çº¿"); |
| | | check.setAvailable(false); |
| | | check.setReason("äº§åæªé
置工èºè·¯çº¿ï¼æ æ³ç¡®å®æé设å¤ï¼è¯·å
å¨ãå·¥èºè·¯çº¿ãä¸ç»´æ¤è¯¥äº§åçå·¥èºè·¯çº¿å忣æ¥"); |
| | | result.getEquipments().add(check); |
| | | equipmentUnavailableCount++; |
| | | } else { |
| | | Map<Long, MesProRouteProcessDO> processIdMap = routeProcesses.stream() |
| | | .filter(rp -> rp.getProcessId() != null) |
| | | .collect(Collectors.toMap(MesProRouteProcessDO::getProcessId, rp -> rp, (a, b) -> a)); |
| | | Map<Long, MesProProcessDO> processMap = processService.getProcessMap(processIdMap.keySet()); |
| | | // 设å¤ä¸å·¥åº/å·¥ä½çç»å®ï¼ä¼å
å设å¤ä¸çå·¥åº IDï¼å
¶æ¬¡åéå·¥ä½ IDï¼å岿°æ®ä¸ä¸¤è
ä¸è´ï¼ |
| | | List<MesDvMachineryDO> machineries = machineryService.getMachineryList(); |
| | | Map<Long, List<MesDvMachineryDO>> machineryMap = machineries.stream() |
| | | .filter(m -> m.getProcessId() != null || m.getWorkstationId() != null) |
| | | .collect(Collectors.groupingBy(m -> m.getProcessId() != null ? m.getProcessId() : m.getWorkstationId())); |
| | | for (MesProRouteProcessDO rp : routeProcesses) { |
| | | MesProProcessDO process = processMap.get(rp.getProcessId()); |
| | | String processName = process != null ? process.getName() : String.valueOf(rp.getProcessId()); |
| | | List<MesDvMachineryDO> boundMachineries = machineryMap.get(rp.getProcessId()); |
| | | if (CollUtil.isEmpty(boundMachineries)) { |
| | | MesProMpsPreparationCheckRespVO.EquipmentCheck check = new MesProMpsPreparationCheckRespVO.EquipmentCheck(); |
| | | check.setProcessId(rp.getProcessId()); |
| | | check.setProcessName(processName); |
| | | check.setAvailable(false); |
| | | check.setReason("è¯¥å·¥åºæªç»å®è®¾å¤ï¼è¯·å°ã设å¤åºç¡ä¿¡æ¯ç®¡çã为该工åºç»å®è®¾å¤"); |
| | | result.getEquipments().add(check); |
| | | equipmentUnavailableCount++; |
| | | continue; |
| | | } |
| | | for (MesDvMachineryDO machinery : boundMachineries) { |
| | | MesProMpsPreparationCheckRespVO.EquipmentCheck check = new MesProMpsPreparationCheckRespVO.EquipmentCheck(); |
| | | check.setProcessId(rp.getProcessId()); |
| | | check.setProcessName(processName); |
| | | check.setMachineryId(machinery.getId()); |
| | | check.setMachineryCode(machinery.getCode()); |
| | | check.setMachineryName(machinery.getName()); |
| | | check.setStatus(machinery.getStatus()); |
| | | MesDvMachineryStatusEnum statusEnum = MesDvMachineryStatusEnum.valueOfStatus(machinery.getStatus()); |
| | | check.setStatusName(statusEnum != null ? statusEnum.getName() : "æªç¥"); |
| | | boolean available = statusEnum != MesDvMachineryStatusEnum.MAINTENANCE; |
| | | check.setAvailable(available); |
| | | if (available) { |
| | | check.setReason(statusEnum == MesDvMachineryStatusEnum.PRODUCING ? "设å¤å ç¨ä¸ï¼æäº§æ¶é确认å¯ç¨æ¶æ®µ" : null); |
| | | } else { |
| | | check.setReason("设å¤å¤äºç»´æ¤ä¸ï¼è¯·çå¾
ç»´æ¤å®æææ¹æ´¾å
¶ä»è®¾å¤"); |
| | | equipmentUnavailableCount++; |
| | | } |
| | | result.getEquipments().add(check); |
| | | } |
| | | } |
| | | } |
| | | result.setEquipmentReady(equipmentUnavailableCount == 0); |
| | | boolean ready = Boolean.TRUE.equals(result.getMaterialReady()) && Boolean.TRUE.equals(result.getEquipmentReady()); |
| | | result.setReady(ready); |
| | | StringBuilder summary = new StringBuilder(); |
| | | if (materialShortageCount > 0) { |
| | | summary.append(materialShortageCount).append(" é¡¹ç©æç缺"); |
| | | } |
| | | if (equipmentUnavailableCount > 0) { |
| | | if (summary.length() > 0) { |
| | | summary.append("ï¼"); |
| | | } |
| | | summary.append(equipmentUnavailableCount).append(" 项设å¤ä¸å¯ç¨"); |
| | | } |
| | | if (summary.length() == 0) { |
| | | summary.append("ç©æã设å¤åå·²å¤é½ï¼å¯ä»¥å®æç产"); |
| | | } |
| | | result.setSummary(summary.toString()); |
| | | return result; |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public Long generatePurchaseRequest(Long id) { |
| | | MesProMpsDO mps = validateMpsExists(id); |
| | |
| | | package cn.iocoder.yudao.module.mes.service.wm.transaction; |
| | | |
| | | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.wm.transaction.vo.MesWmStockSummaryReqVO; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.wm.transaction.vo.MesWmStockSummaryRespVO; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.wm.transaction.vo.MesWmTransactionPageReqVO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.transaction.MesWmTransactionDO; |
| | | import cn.iocoder.yudao.module.mes.service.wm.transaction.dto.MesWmTransactionSaveReqDTO; |
| | |
| | | */ |
| | | PageResult<MesWmTransactionDO> getTransactionPage(MesWmTransactionPageReqVO pageReqVO); |
| | | |
| | | /** |
| | | * ä»å¨æ¶ååæ±æ»ï¼æç©æ + ä»åºï¼ |
| | | * |
| | | * @param reqVO æ¥è¯¢æ¡ä»¶ï¼ç©æãä»åºãèµ·æ¢æ¶é´ï¼ |
| | | * @return æ±æ»åé¡µç»æ |
| | | */ |
| | | PageResult<MesWmStockSummaryRespVO> getStockSummaryPage(@Valid MesWmStockSummaryReqVO reqVO); |
| | | |
| | | } |
| | |
| | | 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.transaction.vo.MesWmStockSummaryReqVO; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.wm.transaction.vo.MesWmStockSummaryRespVO; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.wm.transaction.vo.MesWmTransactionPageReqVO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.mdm.MesMdmItemDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.batch.MesWmBatchDO; |
| | |
| | | import cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseDefaultService; |
| | | import cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseLocationService; |
| | | import cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseService; |
| | | import com.baomidou.mybatisplus.core.metadata.IPage; |
| | | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
| | | import jakarta.annotation.Resource; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | |
| | | return transactionMapper.selectPage(pageReqVO); |
| | | } |
| | | |
| | | @Override |
| | | public PageResult<MesWmStockSummaryRespVO> getStockSummaryPage(MesWmStockSummaryReqVO reqVO) { |
| | | // æªæå®æ¶é´æ¶é»è®¤ç»è®¡è¿ä¸ä¸ªæï¼æå为两个æå 1 æ¥ 0 ç¹ï¼ææ«ä¸ºå½åæ¶é´ |
| | | LocalDateTime endTime = reqVO.getEndTime() != null ? reqVO.getEndTime() : LocalDateTime.now(); |
| | | LocalDateTime startTime = reqVO.getStartTime() != null ? reqVO.getStartTime() |
| | | : endTime.toLocalDate().withDayOfMonth(1).minusMonths(2).atStartOfDay(); |
| | | if (startTime.isAfter(endTime)) { |
| | | throw new ServiceException(400, StrUtil.format( |
| | | "æ¥è¯¢å¼å§æ¶é´[{}]æäºç»ææ¶é´[{}]ï¼è¯·è°æ´æ¶é´èå´åéè¯", |
| | | startTime, endTime)); |
| | | } |
| | | IPage<MesWmStockSummaryRespVO> page = transactionMapper.selectStockSummaryPage( |
| | | new Page<>(reqVO.getPageNo(), reqVO.getPageSize()), |
| | | reqVO.getItemId(), reqVO.getWarehouseId(), startTime, endTime); |
| | | return new PageResult<>(page.getRecords(), page.getTotal()); |
| | | } |
| | | |
| | | // ==================== ç§ææ ¡éªæ¹æ³ ==================== |
| | | |
| | | /** |