import sys,json,csv from pathlib import Path from decimal import Decimal from collections import defaultdict P=Path(__file__).parent if (P/'shipping-complete-result.json').exists(): import runpy runpy.run_path(str(P/'verify_shipping_complete.py'),run_name='__main__') sys.exit(0) sys.path.insert(0,str(P.parent/'iqc-import-20261012/deps')) import pymysql before=json.loads((P/'shipping-drafts-locked-before.json').read_text(encoding='utf8')) r=json.loads((P/'shipping-drafts-result.json').read_text(encoding='utf8')) canonical=lambda x:json.loads(json.dumps(x,default=str)) c=pymysql.connect(host='36.213.150.237',port=10000,user='root',password=sys.stdin.readline().strip(),database='mom-hm',charset='utf8mb4',cursorclass=pymysql.cursors.DictCursor) with c.cursor() as q: tables={} for t in before['tables']: q.execute('SELECT * FROM `'+t+'` WHERE deleted=0 ORDER BY id');tables[t]={x['id']:x for x in q.fetchall()} draftids={o['order_id'] for o in r['orders']} for t,rows in before['tables'].items(): for old in rows: new=canonical(tables[t][old['id']]);diff={k for k in old if old[k]!=new[k]} assert not diff or t=='erp_sale_order' and old['id'] in draftids and diff<={'out_status','updater','update_time'},(t,old['id'],diff) if t not in ['mes_wm_sales_notice','mes_wm_sales_notice_line','mes_wm_product_sales','mes_wm_product_sales_line']: assert len(rows)==len(tables[t]),('Unexpected records',t) assert len(tables['mes_wm_sales_notice'])==23 and len(tables['mes_wm_product_sales'])==23 assert len(tables['mes_wm_sales_notice_line'])==75 and len(tables['mes_wm_product_sales_line'])==75 for o in r['orders']: order=tables['erp_sale_order'][o['order_id']];notice=tables['mes_wm_sales_notice'][o['notice_id']];sales=tables['mes_wm_product_sales'][o['sales_id']] assert notice['status']==3 and notice['out_status']==0 and sales['status']==0 and order['out_status']==1 and order['out_count']==0 assert notice['sale_order_id']==sales['sale_order_id']==order['id'] and sales['notice_id']==notice['id'] and notice['client_id']==sales['client_id']==order['customer_id'] assert not sales['carrier'] and not sales['shipping_number'] for l in o['lines']: nl=tables['mes_wm_sales_notice_line'][l['notice_line_id']];sl=tables['mes_wm_product_sales_line'][l['sales_line_id']];src=tables['erp_sale_order_items'][l['order_item_id']] assert nl['sale_order_item_id']==sl['sale_order_item_id']==src['id'] and sl['notice_line_id']==nl['id'] and sl['sales_id']==sales['id'] assert nl['quantity']==sl['quantity']==src['count'] and sl['enter_quantity']==src['count'] and sl['enter_unit_measure_id']==src['product_unit_id'] assert src['out_count']==0 and nl['out_count']==0 and sl['quality_status'] is None and sl['material_stock_id'] is None needs=defaultdict(Decimal);units={};nos=defaultdict(set) for o in r['orders']: for l in o['lines']: key=(l['item_id'],l['sale_unit_id'],l['primary_unit_id']);needs[key]+=Decimal(l['quantity']);nos[key].add(o['no']) q.execute('SELECT id,name FROM mes_md_unit_measure WHERE deleted=0');units={x['id']:x['name'] for x in q.fetchall()} checks=[] for (id,su,pu),qty in needs.items(): item=tables['mdm_item'][id];stocks=[x for x in tables['mes_wm_material_stock'].values() if x['item_id']==id] available=sum(max(Decimal(0),(x['quantity'] or Decimal(0))-(x['frozen_quantity'] or Decimal(0))-(x['reserved_quantity'] or Decimal(0))) for x in stocks if x['frozen'] in [0,b'\x00']) checks.append({'item_id':id,'code':item['code'],'name':item['name'],'spec':item['specification'],'sale_unit':units.get(su),'primary_unit':units.get(pu),'need':str(qty),'available_primary':str(available),'shortfall_same_unit':str(max(Decimal(0),qty-available)) if su==pu else '需先确认单位换算','orders':'/'.join(sorted(nos[(id,su,pu)])),'issue':'单位换算待确认' if su!=pu else ('库存不足' if available