import json
|
from collections import defaultdict,Counter
|
from read_links import P,encode
|
|
def build(snapshot):
|
data={t:{r['id']:dict(r) for r in v['rows']} for t,v in snapshot['tables'].items()}
|
customers=data['crm_customer'];changes=[];conflicts=[]
|
def get(t,id):return data.get(t,{}).get(id)
|
def code(t,val,field='code'):
|
return [r for r in data.get(t,{}).values() if val and r.get(field)==val]
|
def candidates(table,row):
|
evidence=[]
|
def add(t,source,field='client_id'):
|
if source and source.get(field) in customers:evidence.append({'table':t,'id':source['id'],'field':field,'customer_id':source[field]})
|
def one(t,id,field='client_id'):add(t,get(t,id),field)
|
if table=='mes_pro_mps':one('erp_sale_order',row.get('sale_order_id'),'customer_id')
|
elif table=='mes_pro_work_order':
|
for m in data['mes_pro_mps'].values():
|
if m.get('work_order_id')==row['id']:add('mes_pro_mps',m)
|
if row.get('order_source_type')==1:
|
for o in code('erp_sale_order',row.get('order_source_code'),'no'):add('erp_sale_order',o,'customer_id')
|
if row.get('parent_id'):one('mes_pro_work_order',row['parent_id'])
|
elif table=='mes_pro_task':one('mes_pro_work_order',row.get('work_order_id'))
|
elif table=='mes_wm_batch':
|
one('mes_pro_work_order',row.get('work_order_id'));one('mes_pro_task',row.get('task_id'))
|
for o in code('erp_sale_order',row.get('sales_order_code'),'no'):add('erp_sale_order',o,'customer_id')
|
elif table in ('mes_wm_sales_notice','mes_wm_product_sales','mes_wm_return_sales'):
|
one('erp_sale_order',row.get('sale_order_id'),'customer_id')
|
if table=='mes_wm_product_sales':one('mes_wm_sales_notice',row.get('notice_id'))
|
elif table=='mes_qc_oqc':
|
if row.get('source_doc_type')==119:one('mes_wm_product_sales',row.get('source_doc_id'))
|
for l in data.get('mes_wm_product_sales_line',{}).values():
|
if l.get('oqc_id')==row['id']:one('mes_wm_product_sales',l.get('sales_id'))
|
elif table in ('crm_contract','crm_sale_quotation'):
|
one('crm_business',row.get('business_id'),'customer_id')
|
if table=='crm_sale_quotation':one('crm_contract',row.get('contract_id'),'customer_id')
|
elif table in ('crm_invoice','crm_receivable','crm_receivable_plan','erp_sale_order'):
|
one('crm_contract',row.get('contract_id'),'customer_id')
|
return evidence
|
targets=['crm_contract','crm_sale_quotation','erp_sale_order','crm_invoice','crm_receivable','crm_receivable_plan',
|
'mes_pro_mps','mes_pro_work_order','mes_pro_task','mes_wm_sales_notice','mes_wm_product_sales','mes_wm_return_sales','mes_wm_batch','mes_qc_oqc']
|
for table in targets:
|
for r in data.get(table,{}).values():
|
f='client_id' if table.startswith('mes_') else 'customer_id'
|
ev=candidates(table,r);ids={x['customer_id'] for x in ev}
|
if len(ids)>1:
|
conflicts.append({'table':table,'id':r['id'],'reason':'上下游存在多个客户','evidence':ev});continue
|
if len(ids)==1:
|
wanted=next(iter(ids))
|
if r.get(f) not in customers:
|
changes.append({'table':table,'id':r['id'],'field':f,'before':r.get(f),'after':wanted,
|
'customer_name':customers[wanted]['name'],'evidence':ev,'source_before':dict(r)})
|
r[f]=wanted
|
elif r[f]!=wanted:
|
conflicts.append({'table':table,'id':r['id'],'reason':'既有客户与上下游不同','current':r[f],'evidence':ev})
|
unresolved=[];optional=[]
|
for table in ['mes_pro_mps','mes_pro_work_order','mes_pro_task','mes_wm_batch','mes_qc_oqc']:
|
for r in data.get(table,{}).values():
|
if r.get('client_id') not in customers:
|
x={'table':table,'id':r['id'],'code':r.get('code'),'reason':'缺少可唯一确认客户的订单关联'}
|
if table=='mes_wm_batch' and not (r.get('work_order_id') or r.get('task_id') or r.get('sales_order_code')):optional.append(x)
|
else:unresolved.append(x)
|
assert not conflicts,encode(conflicts)
|
return {'state':snapshot['state'],'changes':changes,'conflicts':conflicts,'unresolved':unresolved,'unallocated_stock_batches':optional,
|
'summary':{'change_count':len(changes),'by_table':dict(Counter(r['table'] for r in changes)),
|
'by_customer':dict(Counter(r['customer_name'] for r in changes)),'unresolved':len(unresolved),
|
'stock_batches_without_customer_requirement':len(optional),'new_customers_required':0}}
|
|
if __name__=='__main__':
|
s=json.loads((P/'snapshot.json').read_text(encoding='utf8'));p=build(s)
|
(P/'plan.json').write_text(encode(p),encoding='utf8');print(encode(p['summary']))
|