Files
baiyue-logistics-chat/tests/test_quote_changes.py
T

215 lines
12 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.
"""Relative quantity and condition edits keep the previously confirmed quote basis."""
from pathlib import Path
import tempfile
import unittest
from unittest.mock import patch
from logistics_chat import create_app,db
from logistics_chat.quote_data import import_snapshot
from test_quote_timing import timing_snapshot
from test_quotes import frames
class QuoteChangeTests(unittest.TestCase):
def setUp(self):
folder=tempfile.TemporaryDirectory();self.addCleanup(folder.cleanup)
root=Path(folder.name)
self.app=create_app({'TESTING':True,'DATABASE':root/'test.db','UPLOAD_DIR':root/'uploads',
'BACKUP_DIR':root/'backups','LOG_DIR':root/'logs','DEEPSEEK_API_KEY':'','RATE_LIMIT_PER_MIN':1000})
self.client=self.app.test_client()
self.client.post('/api/visitor/session',json={'key':'5'*64})
self.cid=self.client.post('/api/new_chat').json['id']
with self.app.app_context():
c=db.connect();import_snapshot(c,timing_snapshot(),activate=True);c.commit();c.close()
def ask(self,question):
with patch('logistics_chat.ai_client.post_completion') as model:
events=frames(self.client.post('/stream_chat',json={'msg':question,'conv_id':self.cid}))
model.assert_not_called()
self.assertEqual(events[-1],{'d':1},events)
self.assertFalse(any(event.get('e') for event in events),events)
return events[0]['t']
def test_weight_increments_are_added_and_absolute_changes_replace_the_total(self):
self.ask('美国1000KG义乌美东普船海派报价')
self.assertIn('1100KG = 6600元',self.ask('再加100KG,其他不变'))
self.assertIn('900KG = 5400元',self.ask('再减掉200KG'))
self.assertIn('900KG = 5400元',self.ask('那一共多少钱'))
self.assertIn('800KG = 4800元',self.ask('减到800KG'))
self.assertIn('900KG = 5400元',self.ask('增加0.1吨,总重900KG'))
def test_invalid_or_unitless_changes_stay_pending_until_a_new_total_is_confirmed(self):
self.ask('美国30KG义乌美西普船海派报价')
self.assertIn('调整后的总重需要大于0',self.ask('减去40KG'))
text=self.ask('换成美东')
self.assertIn('请提供调整后的总重',text)
self.assertNotIn('KG =',text)
self.assertIn('20KG = 120元',self.ask('总重20KG'))
self.assertIn('请提供调整后的总重',self.ask('再加100'))
self.assertNotIn('KG =',self.ask('具体多少'))
self.assertIn('50KG = 300元',self.ask('新总重50KG'))
def test_relative_quantity_without_a_confirmed_starting_value_requests_a_total(self):
self.assertIn('原来的总重',self.ask('再加100KG'))
self.assertIn('调整后的总重',self.ask('美国普船海派'))
self.assertIn('200KG = 800元',self.ask('总重200KG,义乌美西'))
def test_uniform_cartons_add_and_remove_without_losing_the_previous_cartons(self):
self.ask('美国10箱,每箱20KG,义乌美西普船海派报价')
self.assertIn('240KG = 960元',self.ask('再加2箱,每箱20KG'))
text=self.ask('减少1箱')
self.assertIn('220KG = 880元',text)
self.assertIn('共11箱',text)
self.assertIn('220KG = 880元',self.ask('那一共呢'))
def test_added_carton_dimensions_apply_to_the_added_cartons_only(self):
self.ask('美国1箱,每箱20KG,30x30x30cm,义乌美西普船海派报价')
text=self.ask('再加1箱,每箱10KG,60x50x40cm')
self.assertIn('40KG = 160元',text)
self.assertNotIn('50KG =',text)
def test_each_carton_minimum_remains_in_effect_after_addition(self):
self.ask('美国2箱,每箱5KG,义乌美西普船海派报价')
self.assertIn('36KG = 144元',self.ask('再加1箱,每箱5KG'))
def test_declared_new_totals_are_validated_after_a_carton_change(self):
self.ask('美国10箱每箱20KG,义乌美西普船海派报价')
self.assertIn('240KG = 960元',self.ask('再加2箱每箱20KG,总重240KG'))
self.assertIn('增减箱数推算的总重',self.ask('再加1箱每箱20KG,总重300KG'))
self.assertNotIn('KG =',self.ask('换成华南'))
self.assertIn('300KG',self.ask('总重300KG,共13箱'))
def test_heterogeneous_carton_removal_requires_the_updated_breakdown(self):
self.ask('美国1箱10KG,1箱30KG,义乌美西普船海派报价')
self.assertIn('不同箱规',self.ask('减少1箱'))
self.assertNotIn('KG =',self.ask('具体多少钱'))
self.assertIn('30KG = 120元',self.ask('现在1箱30KG'))
def test_rejected_services_remain_excluded_until_explicitly_selected_again(self):
self.ask('美国1000KG义乌美东海运最便宜报价')
text=self.ask('不走普船了,改成美森正班')
self.assertIn('1000KG = 10000元',text)
self.assertNotIn('普船海派',text)
text=self.ask('不要美森,走普船')
self.assertIn('1000KG = 6000元',text)
self.assertNotIn('美森',text)
self.ask('不走普船')
text=self.ask('改成华南')
self.assertNotIn('普船海派',text)
self.assertNotIn('美森',text)
self.assertIn('合德海派',text)
self.assertIn('普船海派',self.ask('那还是普船吧'))
self.assertIn('美森正班海派',self.ask('全部渠道报价'))
def test_tax_corrections_and_pending_conflicts_are_not_reversed(self):
self.ask('美国1000KG义乌美东海派报价')
self.assertIn('1000KG = 6000元',self.ask('不要不包税,我要包税'))
self.assertIn('没有匹配',self.ask('不是包税,是不包税'))
self.assertIn('1000KG = 6000元',self.ask('那还是包税吧'))
self.assertIn('1000KG = 6000元',self.ask('不是包税吗?'))
self.assertIn('明确选择包税',self.ask('不要包税,也不要不包税'))
self.assertNotIn('KG =',self.ask('换成华南'))
self.assertIn('1000KG = 6000元',self.ask('要包税'))
def test_new_batch_with_rejections_resets_old_shipping_conditions(self):
self.ask('美国1000KG义乌美东普船海派报价')
text=self.ask('新的一批美国30KG海派报价,不走普船')
self.assertIn('美国 30KG',text)
self.assertIn('华南',text)
self.assertIn('美西',text)
self.assertNotIn('普船海派',text)
self.assertNotIn('1000KG',text)
def test_calendar_questions_preserve_route_and_request_the_missing_dates(self):
self.ask('美国1000KG义乌美东普船海派报价')
for question in ('什么时候能到','大概哪天能收到'):
text=self.ask(question)
self.assertIn('25-30天左右提取',text)
self.assertIn('预计开船日期',text)
text=self.ask('快一点呢')
self.assertIn('美森正班海派',text)
self.assertNotIn('普船海派',text)
text=self.ask('那比慢的贵多少')
self.assertIn('运费差额为4000元',text)
def test_ambiguous_plan_reference_keeps_context_for_a_named_selection(self):
self.ask('美国1000KG海运最快和最慢报价')
self.assertIn('1000KG',self.ask('这个多少钱'))
self.assertIn('请指定方案名称',self.ask('第二个方案呢'))
self.assertIn('1000KG = 4000元',self.ask('便宜的那个'))
self.assertIn('1000KG = 4000元',self.ask('一共呢'))
def test_tied_speed_costs_produce_a_range_without_mixing_tax_or_units(self):
from logistics_chat.quote_comparison import speed_difference_lines
from logistics_chat.quote_data import load_book
from logistics_chat.quote_intent import parse_intent
base={'origin':'义乌','zone':'美东','kind':'parcel','unit':'kg','tax':'included'}
rates=[{**base,'service':name,'price':price,'eta':eta} for name,price,eta in (
('快线A','8','12-15天'),('快线B','10','12-15天'),
('慢线A','5','30-35天'),('慢线B','6','30-35天'))]
rates.append({**base,'service':'自税线','tax':'excluded','price':'999','eta':'20天'})
rates.append({**base,'service':'按方线','unit':'cbm','price':'999','eta':'20天'})
with self.app.app_context():
book=load_book()
intent=parse_intent('美国1000KG义乌美东海派报价',set())
lines=speed_difference_lines(intent,book,rates,None)
self.assertTrue(any(' · 包税 · ' in line and '2000至5000元' in line for line in lines),lines)
self.assertTrue(any('不包税' in line and '差额为0元' in line for line in lines),lines)
self.assertEqual(len(lines),2)
self.assertEqual(speed_difference_lines(intent,book,[{**rates[0],'eta':'未提供时效'}],None),[])
def test_polite_relative_edits_and_unrecognized_adjustments_do_not_replace_the_total(self):
self.ask('美国1000KG义乌美东普船海派报价')
self.assertIn('1100KG = 6600元',self.ask('那我再加一百公斤'))
self.assertIn('900KG = 5400元',self.ask('请帮我减少200KG'))
self.assertIn('调整后的总重',self.ask('这批货后面增加100KG'))
self.assertNotIn('KG =',self.ask('具体多少钱'))
def test_difference_uses_the_displayed_two_decimal_costs(self):
from logistics_chat.quote_comparison import speed_difference_lines
from logistics_chat.quote_data import load_book
from logistics_chat.quote_intent import parse_intent
base={'origin':'义乌','zone':'美东','kind':'parcel','unit':'kg','tax':'included'}
rates=[{**base,'service':'快线','price':'6.4','eta':'12天'},
{**base,'service':'慢线','price':'4.3','eta':'30天'}]
with self.app.app_context():
intent=parse_intent('美国12.555KG义乌美东海派报价',set())
text='\n'.join(speed_difference_lines(intent,load_book(),rates,None))
self.assertIn('差额为26.36元',text)
def test_difference_shows_both_speeds_for_each_origin_used_in_the_calculation(self):
with self.app.app_context():
c=db.connect()
c.execute("UPDATE quote_rates SET eta='船开后16天左右' WHERE service='美森正班海派' AND origin='华南'")
c.commit();c.close()
text=self.ask('美国1000KG美东海派最快最慢差价')
self.assertIn('美森正班海派 · 义乌',text)
self.assertIn('美森正班海派 · 华南',text)
self.assertEqual(text.count('运费差额为4000元'),2)
def test_volume_increments_keep_the_confirmed_total_and_units(self):
self.ask('美国2CBM义乌美东普船海派报价')
text=self.ask('再加1方')
self.assertIn('总体积为3CBM',text)
self.assertIn('3000元',text)
text=self.ask('总体积减少0.5CBM')
self.assertIn('总体积为2.5CBM',text)
self.assertIn('2500元',text)
def test_carton_changes_with_an_aggregate_volume_wait_for_the_updated_volume(self):
self.ask('美国2箱每箱20KG,1CBM,义乌美东普船海派报价')
self.assertIn('调整后的总体积',self.ask('再加1箱每箱20KG'))
text=self.ask('总重60KG')
self.assertIn('调整后的总体积',text)
self.assertNotIn('KG =',text)
text=self.ask('总体积1.5CBM')
self.assertIn('1500元',text)
def test_unrecognized_volume_increment_is_clarified_without_using_it_as_a_new_total(self):
self.ask('美国2CBM义乌美东普船海派报价')
text=self.ask('这批货后面增加1方')
self.assertIn('调整后的总体积',text)
self.assertNotIn('元/KG',text)
self.assertIn('3000元',self.ask('总体积3CBM'))