import sys,json from pathlib import Path from decimal import Decimal P=Path(__file__).parent if (P/'source-order-regroup-result.json').exists(): import runpy runpy.run_path(str(P/'verify_source_orders.py'),run_name='__main__') sys.exit(0) sys.path.insert(0,str(P.parent/'iqc-import-20261012/deps')) import pymysql plan=json.loads((P/'import-plan.json').read_text(encoding='utf8')) result=json.loads((P/'import-result.json').read_text(encoding='utf8')) before=json.loads((P/'locked-before-import.json').read_text(encoding='utf8')) D=Decimal 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) def canonical(x):return json.loads(json.dumps(x,default=str)) report={'existing_rows_unchanged':{},'counts':{},'sums':{},'errors':[],'notes':['数据库读回核验;未执行线上HTTP界面验证','两票合并记录未拆分金额;缺原票附件的回款通过合同关联,原票号保存在备注','未约定账期,计划日期为开票或销售日后30天测算','报价状态按代码和前端CONVERTED=10,未采用过期表注释50']} with c.cursor() as q: for t,b in before['tables'].items(): q.execute('SELECT * FROM `'+t+'` ORDER BY id');current={r['id']:canonical(r) for r in q.fetchall()} changed=[r['id'] for r in b['rows'] if current.get(r['id'])!=r] report['existing_rows_unchanged'][t]={'rows':len(b['rows']),'changed_ids':changed} assert not changed,(t,changed) for t,prefix in [('crm_sale_quotation','BJ-'),('crm_contract','HT-'),('erp_sale_order','XSDD-'),('crm_invoice','KP-'),('crm_receivable','HK-')]: q.execute('SELECT COUNT(*) n,SUM('+('price' if t in ['crm_invoice','crm_receivable'] else 'total_price')+') amount FROM `'+t+'` WHERE no LIKE %s AND deleted=0',(prefix+'202609-L%',));r=q.fetchone();report['counts'][t]=r['n'];report['sums'][t]=str(r['amount']) assert r['n']==plan['counts'][{'crm_sale_quotation':'sales','crm_contract':'sales','erp_sale_order':'sales','crm_invoice':'invoices','crm_receivable':'receivables'}[t]] if t not in ['crm_invoice']:assert r['amount']==D(plan['totals']['received' if t=='crm_receivable' else 'gross']) q.execute("SELECT COUNT(*) n,SUM(p.price) amount FROM crm_receivable_plan p JOIN crm_contract c ON c.id=p.contract_id WHERE c.no LIKE 'HT-202609-L%%' AND p.deleted=0 AND c.deleted=0");r=q.fetchone();assert r['n']==plan['counts']['plans'] and r['amount']==D(plan['totals']['outstanding']);report['counts']['crm_receivable_plan']=r['n'];report['sums']['crm_receivable_plan']=str(r['amount']) for g,r in zip(plan['groups'],result['groups']): q.execute('SELECT id,owner_user_id,deleted FROM crm_customer WHERE id=%s',(r['customer_id'],));customer=q.fetchone();assert customer and customer['deleted']==0 and customer['owner_user_id']==291 q.execute('SELECT COUNT(*) n FROM crm_permission WHERE biz_type=2 AND biz_id=%s AND user_id=291 AND deleted=0',(r['customer_id'],));assert q.fetchone()['n']>0 q.execute('SELECT id,customer_id,audit_status,total_price,order_id,order_no FROM crm_contract WHERE id=%s AND deleted=0',(r['contract_id'],));ct=q.fetchone();assert ct['audit_status']==20 and ct['customer_id']==r['customer_id'] and ct['order_id']==r['order_id'] q.execute('SELECT id,contract_id,customer_id,status,total_price,order_time FROM erp_sale_order WHERE id=%s AND deleted=0',(r['order_id'],));order=q.fetchone();assert order['status']==20 and order['contract_id']==ct['id'] and order['customer_id']==ct['customer_id'] and order['total_price']==ct['total_price'] and str(order['order_time'])==g['day'] for a,l in zip(g['lines'],r['lines']): q.execute('SELECT id,status FROM mdm_item WHERE id=%s AND deleted=0',(l['item_id'],));assert q.fetchone()['status']==0 q.execute('SELECT id,status FROM mes_md_unit_measure WHERE id=%s AND deleted=0',(l['unit_id'],));assert q.fetchone()['status']==0 for t,id,unit,parentkey,parent in [('crm_contract_product',l['contract_product_id'],'item_unit_id','contract_id',ct['id']),('crm_sale_quotation_product',l['quotation_product_id'],'item_unit_id','quotation_id',r['quotation_id']),('erp_sale_order_items',l['order_item_id'],'product_unit_id','order_id',r['order_id'])]: q.execute('SELECT * FROM `'+t+'` WHERE id=%s AND deleted=0',(id,));item=q.fetchone();assert item['count']==D(a['quantity']) and item[unit]==l['unit_id'] and item[parentkey]==parent and item['total_price'] is not None if r['invoice_id']: q.execute('SELECT * FROM crm_invoice WHERE id=%s AND deleted=0',(r['invoice_id'],));inv=q.fetchone();assert inv['audit_status']==20 and inv['contract_id']==ct['id'] and inv['customer_id']==ct['customer_id'] and inv['price']==ct['total_price'] and inv['invoice_no']=='/'.join(g['invoice_numbers']) and str(inv['invoice_time'])==g['day'] if r['receivable_id']: q.execute('SELECT * FROM crm_receivable WHERE id=%s AND deleted=0',(r['receivable_id'],));rc=q.fetchone();assert rc['audit_status']==20 and rc['contract_id']==ct['id'] and rc['price']==D(g['received']) and str(rc['return_time'])==g['day'] and rc['invoice_id'] is None if r['plan_id']: q.execute('SELECT * FROM crm_receivable_plan WHERE id=%s AND deleted=0',(r['plan_id'],));rp=q.fetchone();assert rp['contract_id']==ct['id'] and rp['receivable_id'] is None and rp['price']==D(g['outstanding']) and str(rp['return_time'])==g['plan_day'] for type,id in [(5,ct['id']),(9,r['quotation_id']),(10,r['invoice_id']),(7,r['receivable_id']),(8,r['plan_id'])]: if id:q.execute('SELECT COUNT(*) n FROM crm_permission WHERE biz_type=%s AND biz_id=%s AND user_id=291 AND level=1 AND deleted=0',(type,id));assert q.fetchone()['n']==1 for code,id in result['new_items'].items(): q.execute('SELECT m.code,m.status,s.mdm_item_id,s.unit_measure_id FROM mdm_item m JOIN mes_md_item s ON s.id=m.id WHERE m.id=%s AND m.deleted=0 AND s.deleted=0',(id,));m=q.fetchone();assert m['code']==code and m['status']==0 and m['mdm_item_id']==id q.execute("SELECT SUM(CASE WHEN `count`<0 THEN 1 ELSE 0 END) negative_lines FROM erp_sale_order_items i JOIN erp_sale_order o ON o.id=i.order_id WHERE o.no LIKE 'XSDD-202609-L%%' AND i.deleted=0 AND o.deleted=0");report['included_return_lines']=int(q.fetchone()['negative_lines']);assert report['included_return_lines']==1 q.execute("SELECT COUNT(*) n FROM crm_sale_quotation WHERE no IN ('BJ-202609-L062','BJ-202609-L071')");assert q.fetchone()['n']==0 c.close();report['passed']=True (P/'verification-result.json').write_text(json.dumps(report,ensure_ascii=False,default=str,indent=2),encoding='utf8') print(json.dumps({'passed':True,'counts':report['counts'],'sums':report['sums'],'existing_rows_checked':sum(v['rows'] for v in report['existing_rows_unchanged'].values()),'included_return_lines':report['included_return_lines']},ensure_ascii=False))