Files
baiyue-logistics-chat/logistics_chat/quote_comparison.py
T

89 lines
4.9 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""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