完善报价业务问答与连续追问,补齐订单列表和人工转接
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
"""Amounts come from the active book; explicit customer-approved fee policies live here."""
|
||||
|
||||
from decimal import Decimal
|
||||
import re
|
||||
|
||||
from .pricing import dims_to_cm
|
||||
|
||||
|
||||
def document(book,required,service=None):
|
||||
rows=[d for d in book['documents'] if (not service or d['sheet'] in (service,'海派'))
|
||||
and all(term in d['content'] for term in required)]
|
||||
return rows[0]['content'] if rows else ''
|
||||
|
||||
|
||||
def amount(text,pattern):
|
||||
match=re.search(pattern,text,re.I)
|
||||
return Decimal(match.group(1)) if match else None
|
||||
|
||||
|
||||
def material_fee(book):
|
||||
text=document(book,('铁铝','附加费'))
|
||||
return amount(text,r'铁铝制品[^\n]*?[¥¥]\s*(\d+(?:\.\d+)?)\s*/KG')
|
||||
|
||||
|
||||
def specimens(intent):
|
||||
if intent.get('packages'):
|
||||
return [{**p,'dims':p.get('dims') or intent.get('dims'),
|
||||
'dim_unit':p.get('dim_unit') if p.get('dims') else intent.get('dim_unit','cm')} for p in intent['packages']]
|
||||
if intent.get('boxes')==1 and intent.get('weight'):
|
||||
return [{'count':1,'weight':intent['weight'],'dims':intent.get('dims'),'dim_unit':intent.get('dim_unit','cm')}]
|
||||
return []
|
||||
|
||||
|
||||
def limit_fees(intent,book):
|
||||
"""Maximum per-piece limit fee, not the sum of overlapping weight/size charges.
|
||||
|
||||
The malformed 0<length<274 rule does not create a new threshold. Only two
|
||||
independently explicit large-piece conditions can establish that tier.
|
||||
"""
|
||||
normal=document(book,('正常货物',))
|
||||
cleaned=re.sub(r'\s+','',normal).replace('<','<').upper()
|
||||
limits=[amount(cleaned,p) for p in (r'0KG<单件重量<(\d+)KG',r'0CM<最长单边长度<(\d+)CM',
|
||||
r'0CM<第二边<(\d+)CM',r'最长边<(\d+)CM')]
|
||||
normal_fee=amount(document(book,('超重收',)),r'超重收\s*[++]?\s*(\d+(?:\.\d+)?)')
|
||||
size_text=document(book,('普通超尺寸',))
|
||||
size_fee=amount(size_text,r'加收\s*(\d+(?:\.\d+)?)\s*RMB/件')
|
||||
large_text=document(book,('大尺寸货物','任意2个'))
|
||||
large_fee=amount(large_text,r'加收\s*(\d+(?:\.\d+)?)\s*RMB/件')
|
||||
huge=document(book,('超大件货物',))
|
||||
huge_fee=amount(huge,r'加收\s*USD\s*(\d+(?:\.\d+)?)')
|
||||
result={'cny':Decimal(0),'items':[],'notes':[]}
|
||||
if not all(limits) or normal_fee is None:return result
|
||||
max_weight,max_length,max_second,max_girth=limits
|
||||
for piece in specimens(intent):
|
||||
weight=Decimal(piece['weight']);count=piece['count']
|
||||
dims=sorted([Decimal(str(x)) for x in dims_to_cm(piece['dims'],piece['dim_unit'])],reverse=True) if piece['dims'] else []
|
||||
length,second,girth=(dims[0],dims[1],dims[0]+2*(dims[1]+dims[2])) if dims else (None,None,None)
|
||||
if weight>68 or (dims and (length>270 or girth>419)):
|
||||
result['notes'].append('该件可能超出承运尺寸或重量,需人工确认是否接收。'+(f'原表超大件若接收的附加费为{huge_fee:g}USD/件。' if huge_fee else ''))
|
||||
continue
|
||||
candidates=[]
|
||||
if weight>max_weight:candidates.append(normal_fee)
|
||||
if dims and (length>max_length or second>max_second or girth>max_girth) and size_fee is not None:candidates.append(size_fee)
|
||||
if large_fee is not None and max_weight<weight<68 and dims and 330<girth<419:
|
||||
candidates.append(large_fee)
|
||||
elif dims and (length>=243 or girth>=330):
|
||||
result['notes'].append('该件接近大尺寸档,原表有一处长度条件不清,适用档位需人工确认。')
|
||||
if candidates:
|
||||
fee=max(candidates)*count
|
||||
result['cny']+=fee
|
||||
result['items'].append(f'超重/超尺寸按最高项{max(candidates):g}元/件×{count}件={fee:g}元')
|
||||
return result
|
||||
|
||||
|
||||
def charge_details(intent,rate,remote,book):
|
||||
from .quote_engine import quantity
|
||||
|
||||
result={'cny':Decimal(0),'items':[],'notes':[]}
|
||||
charged=quantity(intent,rate)
|
||||
if charged is None:return result
|
||||
if rate['kind']=='parcel' and remote:
|
||||
if remote['fee'] is not None:
|
||||
fee=charged*Decimal(remote['fee']);result['cny']+=fee
|
||||
result['items'].append(f'偏远费{remote["fee"]}元/KG×{charged:g}KG={fee:g}元')
|
||||
else:result['notes'].append('遥远地址的附加费需单独确认,当前金额未包含该项。')
|
||||
if rate['unit']=='kg' and intent.get('material')=='metal':
|
||||
per_kg=material_fee(book)
|
||||
if per_kg is not None:
|
||||
fee=charged*per_kg;result['cny']+=fee
|
||||
result['items'].append(f'铁铝附加费{per_kg:g}元/KG×{charged:g}KG={fee:g}元')
|
||||
if rate['kind']=='parcel':
|
||||
limits=limit_fees(intent,book)
|
||||
result['cny']+=limits['cny'];result['items']+=limits['items'];result['notes']+=limits['notes']
|
||||
if intent.get('address_type')=='non_fba':
|
||||
result['notes'].append('非亚马逊地址还需核对住宅/商业派送附加费,原表此项需单独询价。')
|
||||
return result
|
||||
Reference in New Issue
Block a user