89 lines
4.9 KiB
Python
89 lines
4.9 KiB
Python
"""Compare calculable CNY costs on the same destination and billing basis."""
|
||
|
||
from decimal import Decimal,ROUND_HALF_UP
|
||
|
||
from .quote_fees import charge_details
|
||
|
||
|
||
def speed_differences(intent, book, rates, fees):
|
||
from .quote_engine import quantity, select_timed_rates,select_cheapest_rates,reference_days
|
||
|
||
groups = {}
|
||
for rate in rates:
|
||
key = (rate['origin'], rate['zone'], rate['kind'], rate['unit'], rate['tax'])
|
||
groups.setdefault(key, []).append(rate)
|
||
result = []
|
||
for (origin, zone, kind, unit, tax), candidates in groups.items():
|
||
costs = []
|
||
cheapest=intent.get('selection')=='fastest_cheapest'
|
||
comparison=(select_cheapest_rates(intent,book,candidates,fees) if cheapest
|
||
else select_timed_rates(candidates,slowest=True))
|
||
selections=(select_timed_rates(candidates),comparison)
|
||
for selected in selections:
|
||
values = []
|
||
for rate in selected:
|
||
amount = quantity(intent, rate)
|
||
if amount is not None:
|
||
total=amount * Decimal(rate['price']) + charge_details(intent, rate, fees, book)['cny']
|
||
values.append(total.quantize(Decimal('.01'),rounding=ROUND_HALF_UP))
|
||
costs.append(values)
|
||
fast, slow = costs
|
||
if not fast or not slow:
|
||
continue
|
||
low, high = min(fast) - max(slow), max(fast) - min(slow)
|
||
timing=[]
|
||
for selected in selections:
|
||
bounds=[reference_days(rate) for rate in selected if reference_days(rate)]
|
||
timing.append((min(value[0] for value in bounds),max(value[1] for value in bounds)) if bounds else None)
|
||
result.append({'origin':origin,'zone':zone,'kind':kind,'unit':unit,'tax':tax,
|
||
'low':low,'high':high,'timing':timing,'cheapest':cheapest})
|
||
return result
|
||
|
||
|
||
def speed_difference_lines(intent, book, rates, fees):
|
||
from .quote_engine import number
|
||
|
||
lines=[]
|
||
for row in speed_differences(intent,book,rates,fees):
|
||
label=' · '.join(value for value in (row['origin'],row['zone'],'包税' if row['tax']=='included' else '不包税',
|
||
'海派' if row['kind']=='parcel' else '海卡/海铁') if value)
|
||
difference=number(row['low']) if row['low']==row['high'] else number(row['low'])+'至'+number(row['high'])
|
||
pair='最快与最便宜方案' if row['cheapest'] else '快慢方案'
|
||
lines.append(f'- {label},{pair}可计算运费差额为{difference}元。')
|
||
return lines
|
||
|
||
|
||
def render_difference(intent,book,destinations,remote_fees):
|
||
from .quote_engine import match_rates,number,exact_number
|
||
from .quote_language import translate_quote
|
||
|
||
groups={}
|
||
for destination,fees in zip(destinations,remote_fees):
|
||
part=destination.get('allocation')
|
||
billing=({**intent,'weight':part['weight'],'packages':part.get('packages'),'dims':None,'cbm':None,'boxes':part.get('boxes')}
|
||
if part else intent)
|
||
if part and intent.get('metal_chargeable_weight') is not None:
|
||
billing.update(metal_chargeable_weight=None,metal_scope='partial')
|
||
for row in speed_differences(billing,book,match_rates(billing,book,destination),fees):
|
||
key=(row['origin'],row['kind'],row['unit'],row['tax'],row['low'],row['high'],tuple(row['timing']),
|
||
row['cheapest'],destination['warehouse'] or destination['postal'],billing.get('weight'))
|
||
groups.setdefault(key,[]).append(row['zone'])
|
||
if not groups:
|
||
return ('Please provide weight, carton dimensions and routes with numeric reference transit times to compare costs.'
|
||
if intent.get('english') else '请提供重量、箱规及有明确数值时效的渠道,继续核算方案差额。')
|
||
lines=['按当前条件,同一交仓地、区域、计费单位和税费口径比较。']
|
||
for (origin,kind,unit,tax,low,high,timing,cheapest,destination,weight),zones in groups.items():
|
||
labels=[origin,destination or '/'.join(dict.fromkeys(zone for zone in zones if zone)),
|
||
'包税' if tax=='included' else '不包税','海派' if kind=='parcel' else '海卡/海铁']
|
||
difference=number(low) if low==high else number(low)+'至'+number(high)
|
||
pair='最快与最便宜方案' if cheapest else '快慢方案'
|
||
line='- '+' · '.join(label for label in labels if label)+f',{pair}可计算运费差额为{difference}元。'
|
||
if weight:line+=f'按{exact_number(weight)}KG核算。'
|
||
if all(timing):
|
||
days=[number(bounds[0]) if bounds[0]==bounds[1] else number(bounds[0])+'–'+number(bounds[1]) for bounds in timing]
|
||
line+='参考时效分别约'+days[0]+'天、'+days[1]+'天。'
|
||
lines.append(line)
|
||
lines.append('回复“展开报价明细”可查看单价和各方案总价。')
|
||
text='\n'.join(lines)
|
||
return translate_quote(text) if intent.get('english') else text
|