"""Persian message templates (the ERP's user-facing layer is Persian).""" import html from datetime import date STATUS_FA = { "offered": "🔵 در انتظار بررسی", "accepted": "🟢 پذیرفته‌شده", "arrived": "✅ رسیده", "rejected": "🔴 ردشده", "expired": "⚪️ منقضی", } MISSING_MARKS = {True: "✅", False: "❌"} WARNING_MARK = "⚠️" def esc(value) -> str: return html.escape(str(value if value is not None else "—")) def fa_date(value: str | None) -> str: if not value: return "—" return str(value)[:10] WELCOME = ( "سلام! 👋 من دستیار تدارکات هستم.\n\n" "می‌توانی با پیام متنی یا صوتی فعالیتی تعریف کنی — مثلاً:\n" "«سازان نو برای پروژه برج آسمان، ۵۰۰ کیلو میلگرد A3، هر کیلو ۴۵ تومن، پرداخت ۳ فاز»\n\n" "من هر چه را فهمیدم به‌صورت پیش‌نویس آماده می‌کنم، چیزی که فهمیدم و چیزهای خالی را نشان " "می‌دهم و فقط با تأیید تو در سیستم ثبت می‌کنم.\n\n" "دستورها:\n" "/drafts — پیش‌نویس‌های باز\n" "/cancel — لغو پیش‌نویس/عملیات جاری\n" "/whoami — اتصال من\n" "/unlink — قطع اتصال\n" "/help — راهنما" ) HELP = ( "چه کارهایی می‌توانم بکنم؟\n\n" "🧾 ثبت استعلام — تأمین‌کننده، پروژه، اقلام (کالا/مقدار/واحد)، قیمت و شرایط پرداخت را از گفتگو درمی‌آورم.\n" "🏢 افزودن تأمین‌کننده — «تأمین‌کننده جدید فلانی، دسته لوله و اتصالات، تلفن ...»\n" "📦 افزودن کالا — «کالای جدید میلگرد A3 با واحد کیلوگرم»\n" "📊 پرس‌وجو — «استعلام‌های در انتظار؟»، «کدام‌ها به‌زودی منقضی می‌شوند؟»\n" "✔️ پذیرش استعلام — «استعلام سازان نو را قبول کن»\n" "🚚 اعلام رسیدن — «اقلام سازان نو رسید، ۵۰۰ کیلو»\n\n" "هر ثبت فقط با دکمه ✅ انجام می‌شود. با /cancel هر چیز نیمه‌کاره را لغو کن." ) LINK_START = ( "برای اتصال حساب Bale به حساب ERP، نام کاربری Casdoor خود را بفرست " "(یا اگر رمز جدا داری همان نام کاربری سامانه). برای لغو: /cancel" ) LINK_ASK_PASSWORD = "ممنون. حالا رمز عبور را بفرست (فقط برای یک بار ورود؛ ذخیره نمی‌شود). /cancel برای لغو" LINK_OK = "✅ اتصال انجام شد: {name} ({role})\nحالا می‌توانی فعالیت‌ها را بفرستی. /help را ببین." LINK_FAIL = "ورود ناموفق بود: {detail}\nدوباره /start بزن یا نام کاربری را بفرست." ADMIN_NO_LINK = "حالت ادمین (بدون اتصال) فعال است؛ ثبت‌ها بدون انتساب کاربر انجام می‌شود." DRAFTS_LIST_HEADER = "📋 پیش‌نویس‌های باز:" DRAFTS_EMPTY = "پیش‌نویس بازی نداری. یک فعالیت را با متن یا وویس بفرست." NOTHING_TO_COMMIT = "پیش‌نویس بازی برای ثبت نیست؛ اول یک فعالیت بفرست." CANCELLED = "لغو شد. ✔️" UNKNOWN_HINT = ( "متوجه منظورت نشد 🤔\n" "می‌توانی مثلاً بگویی: «ثبت استعلام از سازان نو برای ۲۰۰ عدد شیر فلکه» یا /help را ببینی." ) UNLINKED = "ابتدا حساب خود را متصل کن: /start" AI_NOT_CONFIGURED = ( "پردازش هوشمند تنظیم نشده است (متغیرهای PROCUREMENT_BOT_AI_*). " "با مدیر سیستم تماس بگیر." ) STT_FAILED = "نتوانستم پیام صوتی را تبدیل کنم: {detail}" VOICE_EMPTY = "از پیام صوتی متنی شنیده نشد؛ دوباره بگو یا با متن بفرست." ERR_GENERIC = "خطا: {detail}" PICK_QUOTE = "چند استعلام پیدا شد؛ کدام را می‌خواهی؟" QUOTE_NOT_FOUND = "استعلامی برای «{q}» پیدا نکردم." ACCEPT_REPORT = ( "✅ پذیرش انجام شد\n" "استعلام #{id}\n" "وضعیت: {status}\n" "اقلام تصمیم‌گیری‌شده: {count}" ) ARRIVE_REPORT = ( "🚚 ثبت رسید انجام شد\n" "استعلام #{id} — وضعیت: {status}\n{lines}" ) ACCEPT_DONE_TS = "شرایط انتخاب‌شده: {label}" def missing_block(missing: list[dict]) -> str: """✅/❌ list of what's captured vs. still empty (⚠️ = nice-to-have).""" if not missing: return "همه فیلدها کامل است ✅" lines = [] for m in missing: mark = MISSING_MARKS[m["ok"]] if m["blocking"] else (MISSING_MARKS.get(m["ok"], WARNING_MARK)) if not m["blocking"] and not m["ok"]: mark = WARNING_MARK lines.append(f"{mark} {m['label']}") return "\n".join(lines) def quote_review_text(payload: dict, missing: list[dict], status_note: str | None = None) -> str: lines = ["🧾 پیش‌نویس استعلام:"] if status_note: lines.append(status_note) sup = payload.get("supplier_name") or "—" if payload.get("supplier_id"): sup_label = f"{esc(sup)} ✅" elif payload.get("supplier_name"): sup_label = f"{esc(sup)} ✨ (تأمین‌کننده جدید)" else: sup_label = "—" lines.append(f"تأمین‌کننده: {sup_label}") proj_names = payload.get("project_names") or ([payload["project_name"]] if payload.get("project_name") else []) if proj_names: lines.append(f"پروژه(ها): {esc('، '.join(proj_names))}") lines.append(f"نوع: {'رسمی' if payload.get('is_official', True) else 'برآوردی'}") if payload.get("expiry_date"): lines.append(f"اعتبار تا: {fa_date(payload['expiry_date'])}") items = payload.get("items") or [] if items: lines.append("\n📦 اقلام:") for i, it in enumerate(items, start=1): name = it.get('material_name') or '?' if it.get('brand_name'): name += f" ({it['brand_name']})" parts = [f"{i}. {esc(name)}"] if it.get('specs'): parts.append(esc("، ".join(it['specs']))) if it.get("quantity"): parts.append(f"مقدار {esc(it['quantity'])}") unit = it.get("unit_name") or ("(واحد کالا)" if it.get("unit_id") else None) if unit: parts.append(str(unit)) if it.get("unit_price"): parts.append(f"قیمت {esc(it['unit_price'])}") if not it.get("material_id"): parts.append("✨ کالای جدید") lines.append(" — ".join(str(p) for p in parts)) else: lines.append("\nاقلام: هنوز چیزی ثبت نشده ❌") sheets = payload.get("termsheets") or [] if sheets: ts_parts = [] for t in sheets: lbl = esc(t.get('label')) if t.get("milestones"): steps_txt = " + ".join(f"{fa_date(m.get('due_date'))}: {esc(m.get('amount'))}" for m in t["milestones"] if m.get("amount")) if steps_txt: lbl += f" [{steps_txt}]" elif t.get("discount_value"): lbl += f" (تخفیف {esc(t.get('discount_value'))})" ts_parts.append(lbl) lines.append("\n💳 شرایط پرداخت: " + "؛ ".join(ts_parts)) if payload.get("notes"): lines.append(f"یادداشت: {esc(payload['notes'])}") lines.append("\n📋 وضعیت فیلدها:") lines.append(missing_block(missing)) lines.append("\nبا پیام بعدی می‌توانی چیزهای خالی را تکمیل کنی، یا با دکمه‌ها ثبت/لغو کنی.") return "\n".join(lines) def supplier_review_text(payload: dict, missing: list[dict]) -> str: lines = ["🏢 پیش‌نویس تأمین‌کننده جدید", f"نام: {esc(payload.get('name'))}"] lines.append(f"دسته: {esc(payload.get('category_name'))}") if payload.get("phone"): lines.append(f"تلفن: {esc(payload['phone'])}") if payload.get("location"): lines.append(f"موقعیت: {esc(payload['location'])}") if payload.get("contact_person"): lines.append(f"رابط: {esc(payload['contact_person'])}") lines.append("\nوضعیت فیلدها:") lines.append(missing_block(missing)) return "\n".join(lines) def material_review_text(payload: dict, missing: list[dict]) -> str: lines = ["📦 پیش‌نویس کالای جدید", f"نام: {esc(payload.get('name'))}"] lines.append(f"واحد اصلی: {esc(payload.get('unit_name'))}") if payload.get("topic"): lines.append(f"تاپیک: {esc(payload['topic'])}") lines.append("\nوضعیت فیلدها:") lines.append(missing_block(missing)) return "\n".join(lines) def quote_committed_report(created: dict, payload: dict, remaining: list[str]) -> str: lines = [f"✅ ثبت شد — استعلام #{esc(created.get('id'))}"] sup = (created.get("supplier") or {}).get("name") or payload.get("supplier_name") if sup: lines.append(f"تأمین‌کننده: {esc(sup)}") items = created.get("line_items") or [] if items: lines.append(f"اقلام: {len(items)}") sheets = created.get("termsheets") or [] if sheets: lines.append(f"شرایط پرداخت: {len(sheets)}") if payload.get("project_id"): lines.append("پروژه: پیوست شد") if remaining: lines.append("\nخالی مانده‌ها (بعداً می‌توانی در برنامه تکمیل کنی):") lines += [f"⚠️ {esc(r)}" for r in remaining] lines.append("\nمرحله بعد: وقتی تصمیم گرفتی، بگو «استعلام را قبول کن» تا پذیرش را با هم انجام دهیم.") return "\n".join(lines) def supplier_committed_report(created: dict) -> str: return ( f"✅ تأمین‌کننده ثبت شد — {esc(created.get('name'))}\n" f"دسته: {esc((created.get('category') or {}).get('name'))}" ) def material_committed_report(created: dict) -> str: return f"✅ کالا ثبت شد — {esc(created.get('name'))}" def quote_line(quote: dict) -> str: sup = (quote.get("supplier") or {}).get("name") or quote.get("supplier_id") or "—" items = quote.get("line_items") or [] item_names = [] for it in items: mat = (it.get("material") or {}).get("name") if mat: qty = it.get("quantity") item_names.append(f"{mat} ({qty})" if qty else mat) tail = f" — {'، '.join(item_names[:3])}" + ("…" if len(item_names) > 3 else "") if item_names else "" return ( f"#{str(quote.get('id'))[:8]} — {esc(sup)} — {STATUS_FA.get(quote.get('status'), quote.get('status'))} — " f"{fa_date(quote.get('quote_date'))}{tail}" ) def status_report(kind: str, quotes: list[dict], extra_note: str | None = None) -> str: titles = { "pending": "🔵 استعلام‌های در انتظار بررسی", "accepted": "🟢 پذیرفته‌شده (در انتظار تحویل)", "arrived": "✅ رسیده", "expiring": "⏳ به‌زودی منقضی می‌شوند (۷ روز آینده)", "recent": "🕘 آخرین استعلام‌ها", } if not quotes: return f"{titles.get(kind, 'نتیجه‌ای')}\nموردی نیست." lines = [titles.get(kind, "استعلام‌ها")] if extra_note: lines.append(extra_note) lines += [f"• {quote_line(q)}" for q in quotes[:10]] return "\n".join(lines)