feat(bot): centralize defaults, refine ambiguity lifecycle, improve entity resolution and auto-create new projects
This commit is contained in:
@@ -9,7 +9,7 @@ from app import drafts as draft_store
|
||||
from app.runtime import LinkedUser
|
||||
from app.texts import CANCELLED, UNLINKED, esc
|
||||
|
||||
from . import quote, supplier, material, decisions
|
||||
from . import quote, supplier, material, project, decisions
|
||||
|
||||
logger = logging.getLogger("bot.callbacks")
|
||||
|
||||
@@ -57,6 +57,45 @@ async def _dispatch(ctx, chat_id: int, data: str, cq: dict) -> None:
|
||||
await decisions.handle_arrive_callback(ctx, chat_id, user, parts)
|
||||
return
|
||||
|
||||
# ---- ambiguity sub-messages (Requirement 2.a) -------------------------
|
||||
if parts[0] == "amb" and len(parts) >= 4:
|
||||
action, prefix, amb_id = parts[1], parts[2], parts[3]
|
||||
draft = await draft_store.get_by_prefix(prefix, chat_id)
|
||||
if draft is None:
|
||||
await ctx.send(chat_id, "این پیشنویس دیگر معتبر نیست.")
|
||||
return
|
||||
|
||||
payload = draft.payload or {}
|
||||
ambiguities = payload.get("ambiguities") or []
|
||||
target_amb = next((a for a in ambiguities if a.get("id") == amb_id), None)
|
||||
if not target_amb:
|
||||
return
|
||||
|
||||
if action == "ok":
|
||||
proposed = target_amb.get("proposed_patch") or {}
|
||||
draft_store.merge_quote_patch(payload, proposed)
|
||||
target_amb["status"] = "applied"
|
||||
await quote.resolve_payload(ctx, payload)
|
||||
await draft_store.save_payload(draft, mark_bale_synced=True)
|
||||
# In-place edit main review card
|
||||
await quote.render(ctx, chat_id, draft, fresh=False)
|
||||
# Delete ONLY this ambiguity message
|
||||
if target_amb.get("message_id"):
|
||||
try:
|
||||
await ctx.delete(chat_id, target_amb["message_id"])
|
||||
except Exception:
|
||||
pass
|
||||
elif action == "no":
|
||||
target_amb["status"] = "rejected"
|
||||
await draft_store.save_payload(draft, mark_bale_synced=True)
|
||||
# Delete ONLY this ambiguity message
|
||||
if target_amb.get("message_id"):
|
||||
try:
|
||||
await ctx.delete(chat_id, target_amb["message_id"])
|
||||
except Exception:
|
||||
pass
|
||||
return
|
||||
|
||||
# ---- pick a candidate for a draft field -------------------------------
|
||||
if parts[0] == "pk" and len(parts) == 4:
|
||||
draft = await draft_store.get_by_prefix(parts[1], chat_id)
|
||||
@@ -68,8 +107,13 @@ async def _dispatch(ctx, chat_id: int, data: str, cq: dict) -> None:
|
||||
|
||||
# ---- draft commit / cancel --------------------------------------------
|
||||
op, arg, prefix = parts[0], parts[1], parts[2] if len(parts) > 2 else ""
|
||||
if op in ("q", "s", "m") and arg in ("ok", "ok2", "no"):
|
||||
kind = {"q": draft_store.KIND_QUOTE, "s": draft_store.KIND_SUPPLIER, "m": draft_store.KIND_MATERIAL}[op]
|
||||
if op in ("q", "s", "m", "p") and arg in ("ok", "ok2", "no"):
|
||||
kind = {
|
||||
"q": draft_store.KIND_QUOTE,
|
||||
"s": draft_store.KIND_SUPPLIER,
|
||||
"m": draft_store.KIND_MATERIAL,
|
||||
"p": draft_store.KIND_PROJECT,
|
||||
}[op]
|
||||
draft = await draft_store.get_by_prefix(prefix, chat_id)
|
||||
if draft is None or draft.kind != kind:
|
||||
await ctx.send(chat_id, "این پیشنویس دیگر معتبر نیست.")
|
||||
@@ -89,8 +133,10 @@ async def _dispatch(ctx, chat_id: int, data: str, cq: dict) -> None:
|
||||
await quote.commit(ctx, chat_id, user, draft, only_resolved=(arg == "ok2"))
|
||||
elif kind == draft_store.KIND_SUPPLIER:
|
||||
await supplier.commit(ctx, chat_id, user, draft)
|
||||
else:
|
||||
elif kind == draft_store.KIND_MATERIAL:
|
||||
await material.commit(ctx, chat_id, user, draft)
|
||||
elif kind == draft_store.KIND_PROJECT:
|
||||
await project.commit(ctx, chat_id, user, draft)
|
||||
|
||||
|
||||
async def _apply_pick(ctx, chat_id: int, user: LinkedUser, draft, field: str, idx: int) -> None:
|
||||
|
||||
Reference in New Issue
Block a user