"""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