"""معنای «زمان‌بندی» برای هر نوع پیامک. هر نوع پیامک زمان‌بندی متفاوتی دارد و نمی‌شود همه را زیر یک برچسب «روز قبل از سررسید» جمع کرد. این ماژول تنها مرجع این معناست: هم پنل قالب‌ها بر اساسش فیلد درست را نشان می‌دهد، هم اسکنر بر اساسش تصمیم می‌گیرد. هر نوع دقیقاً به یک فیلد زمانی نگاشت می‌شود (``field``) تا داده هرگز ناهمخوان نشود؛ بقیهٔ فیلدهای زمانی صفر/خالی می‌مانند. """ from ..models import SMSType NONE = "none" BEFORE_DUE = "before_due" AFTER_DUE = "after_due" PERIOD_MONTHS = "period_months" # پیش‌فرض دورهٔ بازدید (ماه) وقتی مدیر مقداری در قالب نگذاشته باشد. DEFAULT_VISIT_MONTHS = 9 TIMING = { SMSType.WELCOME: { "kind": NONE, "field": None, "note": "به‌محض ثبت مشتری و بدون تأخیر ارسال می‌شود؛ تنظیم زمانی ندارد.", }, SMSType.SURVEY: { "kind": NONE, "field": None, "note": "بی‌درنگ پس از ثبت فاکتور ارسال می‌شود؛ تنظیم زمانی ندارد.", }, SMSType.CHEQUE_REGISTRATION: { "kind": AFTER_DUE, "field": "offset_days", "label": "چند روز پس از سررسید چک", "default": 1, "note": "این تعداد روز پس از سررسید چکِ پرداخت‌نشده، پیامک یادآوری " "تأمین موجودی با مبلغ چک ارسال می‌شود.", }, SMSType.VISIT: { "kind": PERIOD_MONTHS, "field": "repeat_interval_months", "label": "هر چند ماه یک‌بار", "default": DEFAULT_VISIT_MONTHS, "note": "برای مشتریانی که از این مدت بازدید نشده‌اند ارسال می‌شود.", }, SMSType.VISIT_CREATED: { "kind": NONE, "field": None, "note": "به‌محض ثبت «اقدام از نوع بازدید» ارسال می‌شود؛ تنظیم زمانی ندارد.", }, SMSType.PAYMENT_THANKS: { "kind": NONE, "field": None, "note": "بی‌درنگ پس از ثبت پرداخت (سند وصول/بستانکار) ارسال می‌شود؛ تنظیم زمانی ندارد.", }, SMSType.NESIYE_DUE: { "kind": BEFORE_DUE, "field": "offset_days", "label": "چند روز قبل از سررسید نسیه", "default": 0, "note": "پنجرهٔ یادآوری از «سررسید − این تعداد روز» باز می‌شود و تا سررسید ادامه دارد.", }, } def timing_for(sms_type): """اطلاعات زمان‌بندی یک نوع پیامک (با پیش‌فرض بی‌خطر برای انواع ناشناخته).""" return TIMING.get(sms_type, {"kind": NONE, "field": None, "note": ""}) def apply_timing(template, value): """فیلد زمانیِ متناسب با نوع قالب را می‌نشاند و بقیه را صفر/خالی می‌کند. ``value`` عدد صحیحِ واردشده از فرم است (یا ``None``). این کار تضمین می‌کند صرف‌نظر از اینکه فرم چه بفرستد، فقط یک فیلد زمانی برای هر قالب معنا داشته باشد. """ info = timing_for(template.sms_type) field = info["field"] template.offset_days = 0 template.repeat_interval_days = None template.repeat_interval_months = None if field == "offset_days": template.offset_days = value if value is not None else info["default"] elif field == "repeat_interval_days": template.repeat_interval_days = value if value else info["default"] elif field == "repeat_interval_months": template.repeat_interval_months = value if value else None return template def current_timing_value(template): """مقدار فعلی فیلد زمانیِ متناسب (برای نمایش در فرم). اگر مقدار خالی باشد، پیش‌فرض همان نوع برگردانده می‌شود تا فیلدِ تنظیم‌نشده هم در فرم دیده شود و مدیر بتواند مقدارش را تغییر دهد. """ info = timing_for(template.sms_type) field = info["field"] if field is None: return None value = getattr(template, field) if value is None: value = info.get("default") return value