@@ -246,7 +246,7 @@ def extract_collab_fields(
|
|||||||
"""
|
"""
|
||||||
群里协同字段:标签(冒号可省)+ 口语含油/含电/含磁/危险品、货好时间。
|
群里协同字段:标签(冒号可省)+ 口语含油/含电/含磁/危险品、货好时间。
|
||||||
|
|
||||||
allowed_keys 传入则只返回本单该有的项。不传则海运六项 ∪ 陆运协同键,给意图分类。
|
allowed_keys 传入则只返回本单该有的项。不传则海运协同五项 ∪ 贸易条款(陆运跨境仍要)∪ 陆运协同键,给意图分类。
|
||||||
闲聊、只说「纸箱」不进这里。商品海关编码 / HS 折成 HS编码。
|
闲聊、只说「纸箱」不进这里。商品海关编码 / HS 折成 HS编码。
|
||||||
"""
|
"""
|
||||||
from agent.schema.field_validate import (
|
from agent.schema.field_validate import (
|
||||||
|
|||||||
@@ -2091,12 +2091,12 @@ def group_fields_not_recognized(
|
|||||||
keys: tuple[str, ...] | None = None,
|
keys: tuple[str, ...] | None = None,
|
||||||
business_line: str = "",
|
business_line: str = "",
|
||||||
) -> str:
|
) -> str:
|
||||||
"""没认出协同字段。陆运列出本单可补项;海运保持原六项口。"""
|
"""没认出协同字段。陆运列出本单可补项;海运列出协同五项(不含贸易条款)。"""
|
||||||
if keys:
|
if keys:
|
||||||
line = (business_line or "").strip().upper() or "SEA"
|
line = (business_line or "").strip().upper() or "SEA"
|
||||||
names = [collab_display_name(k, line) for k in keys]
|
names = [collab_display_name(k, line) for k in keys]
|
||||||
return "听到了。请直接说" + "、".join(names) + "。"
|
return "听到了。请直接说" + "、".join(names) + "。"
|
||||||
return "听到了。请直接说贸易条款、货好时间、商品海关编码、是否含油/含电/含磁。"
|
return "听到了。请直接说货好时间、商品海关编码、是否含油/含电/含磁。"
|
||||||
|
|
||||||
|
|
||||||
def group_deal_stale(*, work_order_no: str) -> str:
|
def group_deal_stale(*, work_order_no: str) -> str:
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
海运协同群业务:填表进群、补字段重发、产品报价、附件、解散、成交跟进。
|
海运协同群业务:填表进群、补字段重发、产品报价、附件、解散、成交跟进。
|
||||||
|
|
||||||
本文件职责:群里副作用(主账+企微群)。私聊按钮仍走 sea_text_flow.on_button。
|
本文件职责:群里副作用(主账+企微群)。私聊按钮仍走 sea_text_flow.on_button。
|
||||||
禁止:改询价七项;终态默默忽略;把销售附件当报价。
|
禁止:改询价十项;终态默默忽略;把销售附件当报价。
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|||||||
@@ -231,7 +231,7 @@ def _classify_with_model(text: str, settings) -> str:
|
|||||||
client = LlmHttpClient.from_settings(settings)
|
client = LlmHttpClient.from_settings(settings)
|
||||||
system = (
|
system = (
|
||||||
"你是海运协同群意图分类。只回复一个英文词,不要解释。"
|
"你是海运协同群意图分类。只回复一个英文词,不要解释。"
|
||||||
"collab_fields=在补贸易条款/货好时间/商品海关编码/含油含电含磁;"
|
"collab_fields=在补货好时间/商品海关编码/含油含电含磁;"
|
||||||
"quote_adjust=销售在调已有费用,口令不写死(上升、上浮、往上抬、加一成、减、改到某金额都算),不是新产品报价;"
|
"quote_adjust=销售在调已有费用,口令不写死(上升、上浮、往上抬、加一成、减、改到某金额都算),不是新产品报价;"
|
||||||
"product_quote=产品在报价格或费用(含具体金额);"
|
"product_quote=产品在报价格或费用(含具体金额);"
|
||||||
"quote_confirm_tms=产品确认沿用当前TMS报价,没有报新金额;"
|
"quote_confirm_tms=产品确认沿用当前TMS报价,没有报新金额;"
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ LAND_DISPLAY = {
|
|||||||
|
|
||||||
# 协同补充字段:拉群后可静默写入,不挡首次查价。内部键仍是 HS编码。
|
# 协同补充字段:拉群后可静默写入,不挡首次查价。内部键仍是 HS编码。
|
||||||
SEA_COLLAB_FIELDS = ("货好时间", "HS编码", "是否含油", "是否含电", "是否含磁")
|
SEA_COLLAB_FIELDS = ("货好时间", "HS编码", "是否含油", "是否含电", "是否含磁")
|
||||||
# 空运群只补含电/含磁,摘要不要把海运六项搬过去。
|
# 空运群只补含电/含磁,摘要不要把海运协同五项搬过去。
|
||||||
AIR_COLLAB_FIELDS = ("是否含电", "是否含磁")
|
AIR_COLLAB_FIELDS = ("是否含电", "是否含磁")
|
||||||
# 群摘要对外展示名。内部继续用 HS编码,避免改合同键。
|
# 群摘要对外展示名。内部继续用 HS编码,避免改合同键。
|
||||||
SEA_COLLAB_DISPLAY = {
|
SEA_COLLAB_DISPLAY = {
|
||||||
@@ -143,11 +143,11 @@ _LAND_COLLAB_BY_PAIR: dict[tuple[str, str], tuple[str, ...]] = {
|
|||||||
"是否为危险品",
|
"是否为危险品",
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
# 意图分类用:海运六项 ∪ 陆运全部协同键。
|
# 意图分类用:海运协同五项 ∪ 贸易条款(陆运跨境仍要)∪ 陆运协同键。
|
||||||
ALL_COLLAB_KEYS = tuple(
|
ALL_COLLAB_KEYS = tuple(
|
||||||
dict.fromkeys(
|
dict.fromkeys(
|
||||||
list(SEA_COLLAB_FIELDS)
|
list(SEA_COLLAB_FIELDS)
|
||||||
+ ["客户名称", "包装方式", "货值", "是否为危险品", "车型/数量"]
|
+ ["贸易条款", "客户名称", "包装方式", "货值", "是否为危险品", "车型/数量"]
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -319,7 +319,7 @@ def land_collab_fields(land_type: str, route: str) -> tuple[str, ...]:
|
|||||||
"""
|
"""
|
||||||
本单陆运协同内部键,顺序与规格一致。
|
本单陆运协同内部键,顺序与规格一致。
|
||||||
|
|
||||||
对不上填写样例返回空元组,调用方不得按海运六项去列。
|
对不上填写样例返回空元组,调用方不得按海运协同五项去列。
|
||||||
海关编码内部仍是 HS编码。副作用:无。
|
海关编码内部仍是 HS编码。副作用:无。
|
||||||
"""
|
"""
|
||||||
from agent.schema.land_options import canonicalize_route, canonicalize_transport_type
|
from agent.schema.land_options import canonicalize_route, canonicalize_transport_type
|
||||||
|
|||||||
@@ -631,6 +631,9 @@ class SeaSkipAndPullTests(unittest.TestCase):
|
|||||||
self.assertIn(wo, group_text)
|
self.assertIn(wo, group_text)
|
||||||
self.assertIn("起运港", group_text)
|
self.assertIn("起运港", group_text)
|
||||||
self.assertIn("贸易条款", group_text)
|
self.assertIn("贸易条款", group_text)
|
||||||
|
collab_block = group_text.split("协同补充字段:", 1)[-1].split("TMS报价:", 1)[0]
|
||||||
|
self.assertNotIn("贸易条款", collab_block)
|
||||||
|
self.assertIn("货好时间", collab_block)
|
||||||
self.assertIn("商品海关编码", group_text)
|
self.assertIn("商品海关编码", group_text)
|
||||||
self.assertNotIn("HS编码", group_text)
|
self.assertNotIn("HS编码", group_text)
|
||||||
self.assertIn("TMS", group_text)
|
self.assertIn("TMS", group_text)
|
||||||
@@ -842,7 +845,7 @@ class SeaGroupCollabFieldTests(unittest.TestCase):
|
|||||||
def _reply(self, text: str, extra=None) -> None:
|
def _reply(self, text: str, extra=None) -> None:
|
||||||
self.replies.append(text)
|
self.replies.append(text)
|
||||||
|
|
||||||
def test_group_text_writes_incoterm_silently(self) -> None:
|
def test_group_text_ignores_trade_terms_saves_ready_date(self) -> None:
|
||||||
self.ledger.set_sea_staff(
|
self.ledger.set_sea_staff(
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
@@ -870,11 +873,24 @@ class SeaGroupCollabFieldTests(unittest.TestCase):
|
|||||||
ticket = self.ledger.get_ticket(work_order_no=wo)
|
ticket = self.ledger.get_ticket(work_order_no=wo)
|
||||||
chat_id = ticket.collab_chat_id
|
chat_id = ticket.collab_chat_id
|
||||||
n = len(self.replies)
|
n = len(self.replies)
|
||||||
phase = handle_group_collab(
|
ignored = handle_group_collab(
|
||||||
InboundMessage(
|
InboundMessage(
|
||||||
sender_id="prod4",
|
sender_id="prod4",
|
||||||
message_id="g1",
|
message_id="g1",
|
||||||
content="贸易条款:FOB",
|
content="贸易条款:CIF",
|
||||||
|
chat_id=chat_id,
|
||||||
|
chat_type="group",
|
||||||
|
),
|
||||||
|
flow=self.flow,
|
||||||
|
ledger=self.ledger,
|
||||||
|
)
|
||||||
|
self.assertEqual(ignored, "collab_not_recognized")
|
||||||
|
self.assertFalse(ticket.collab_facts.get("贸易条款"))
|
||||||
|
phase = handle_group_collab(
|
||||||
|
InboundMessage(
|
||||||
|
sender_id="prod4",
|
||||||
|
message_id="g2",
|
||||||
|
content="货好时间:下周",
|
||||||
chat_id=chat_id,
|
chat_id=chat_id,
|
||||||
chat_type="group",
|
chat_type="group",
|
||||||
),
|
),
|
||||||
@@ -883,7 +899,7 @@ class SeaGroupCollabFieldTests(unittest.TestCase):
|
|||||||
)
|
)
|
||||||
self.assertEqual(phase, "collab_field_saved")
|
self.assertEqual(phase, "collab_field_saved")
|
||||||
self.assertEqual(len(self.replies), n)
|
self.assertEqual(len(self.replies), n)
|
||||||
self.assertEqual(ticket.collab_facts.get("贸易条款"), "FOB")
|
self.assertEqual(ticket.collab_facts.get("货好时间"), "下周")
|
||||||
|
|
||||||
def test_group_price_chat_is_ignored(self) -> None:
|
def test_group_price_chat_is_ignored(self) -> None:
|
||||||
self.ledger.set_sea_staff(
|
self.ledger.set_sea_staff(
|
||||||
@@ -1241,6 +1257,9 @@ class SeaGroupCopyTests(unittest.TestCase):
|
|||||||
self.assertIn("询价字段:\n运输方式:海运", text)
|
self.assertIn("询价字段:\n运输方式:海运", text)
|
||||||
self.assertIn("\n\n协同补充字段:\n", text)
|
self.assertIn("\n\n协同补充字段:\n", text)
|
||||||
self.assertIn("商品海关编码:-", text)
|
self.assertIn("商品海关编码:-", text)
|
||||||
|
self.assertIn("货好时间:-", text)
|
||||||
|
collab_block = text.split("协同补充字段:", 1)[-1].split("TMS报价:", 1)[0]
|
||||||
|
self.assertNotIn("贸易条款", collab_block)
|
||||||
self.assertNotIn("HS编码", text)
|
self.assertNotIn("HS编码", text)
|
||||||
self.assertIn("\n\nTMS报价:\nTMS 暂无匹配报价", text)
|
self.assertIn("\n\nTMS报价:\nTMS 暂无匹配报价", text)
|
||||||
self.assertNotIn("未查到合适报价", text)
|
self.assertNotIn("未查到合适报价", text)
|
||||||
|
|||||||
Reference in New Issue
Block a user