39 lines
2.1 KiB
Python
39 lines
2.1 KiB
Python
"""Explicit weight-to-warehouse assignments; unassigned comparisons stay separate."""
|
||
|
||
from decimal import Decimal
|
||
import re
|
||
|
||
|
||
def allocations(text,codes,weight_pattern,to_kg):
|
||
if len(codes)<2:return None
|
||
code='('+'|'.join(re.escape(code) for code in sorted(codes,key=len,reverse=True))+r')(?![A-Za-z0-9])'
|
||
forward=weight_pattern.pattern+r'\s*(?:货物)?\s*(?:发到|发往|送到|发|到|去)?\s*'+code
|
||
reverse=code+r'\s*(?:[::]|分配|发|重)?\s*'+weight_pattern.pattern
|
||
entries=[];used=[]
|
||
for pattern,backwards in ((forward,False),(reverse,True)):
|
||
for match in re.finditer(pattern,text,re.I):
|
||
if any(match.start()<end and match.end()>start for start,end in used):continue
|
||
values=match.groups()
|
||
destination,value,unit=values if backwards else (values[2],values[0],values[1])
|
||
piece_weight=to_kg(value,unit)
|
||
weight_start=match.start(2 if backwards else 1)
|
||
carton=re.search(r'(第)?(\d+)\s*(?:箱|件)\s*(每(?:箱|件))?\s*$',text[:weight_start])
|
||
boxes=(1 if carton.group(1) else int(carton.group(2))) if carton else None
|
||
pieces=([{'count':boxes,'weight':str(piece_weight),'dims':None,'dim_unit':'cm','position':weight_start}]
|
||
if carton and (boxes==1 or carton.group(3)) else None)
|
||
weight=piece_weight*boxes if pieces else piece_weight
|
||
entries.append({'warehouse':destination.upper(),'weight':weight,'boxes':boxes,'packages':pieces})
|
||
used.append(match.span())
|
||
if len(entries)<2:return None
|
||
totals={}
|
||
for entry in entries:
|
||
code=entry['warehouse']
|
||
if code not in totals:
|
||
totals[code]=entry
|
||
continue
|
||
total=totals[code]
|
||
total['weight']+=entry['weight']
|
||
total['boxes']=total['boxes']+entry['boxes'] if total['boxes'] is not None and entry['boxes'] is not None else None
|
||
total['packages']=(total['packages']+entry['packages']) if total['packages'] and entry['packages'] else None
|
||
return [{**entry,'weight':str(entry['weight'])} for entry in totals.values()]
|