云
昨天 74b0d9c5ab1dc316b29f8525dcffe45225d4c43c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
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']))