Files
khatibi/admin_panel/sms/triggers.py
T
2026-10-27 11:49:09 +03:30

101 lines
4.7 KiB
Python

"""تریگرهای رویدادی پیامک (لایهٔ سرویس، بدون signal).
چهار نوع پیامک «رویدادی» هستند و لحظهٔ وقوع‌شان یک اکشن پنل است، نه یک سررسید
تاریخی؛ پس به‌جای اسکنر دوره‌ای، ویوها بعد از انجام کارِ اصلی این توابع را صدا
می‌زنند:
* :func:`notify_welcome` — ایجاد مشتری.
* :func:`notify_factor_survey` — ثبت فاکتور (نظرسنجی).
* :func:`notify_visit_scheduled` — ثبت «اقدام از نوع بازدید».
* :func:`notify_install_scheduled` — ثبت «اقدام از نوع نصب».
* :func:`notify_payment_thanks` — ثبت پرداخت (سند بستانکار / وصول).
قرارداد پروژه: استفاده از signal ممنوع است؛ همه‌چیز صریح از دلِ ویو صدا زده می‌شود.
این توابع هیچ استثنایی به فراخوان پرتاب نمی‌کنند (``enqueue_sms`` خودش مقاوم است) تا
مسیر اصلی هرگز به‌خاطر پیامک مختل نشود.
"""
import logging
from ..models import SMSType
from .enqueue import enqueue_sms
logger = logging.getLogger(__name__)
# روش‌های «غیرپرداخت»: سند بستانکاری که به‌خاطر تخفیف صادر شده، پرداختِ واقعی نیست
# و نباید پیامک «تشکر از پرداخت» بگیرد.
NON_PAYMENT_METHODS = {"تخفیف"}
def notify_welcome(customer, *, created_by=None):
"""پیامک خوش‌آمدگویی در لحظهٔ ساخت مشتری."""
if customer is None or customer.pk is None:
return 0
return enqueue_sms(
customer=customer, sms_type=SMSType.WELCOME,
context={"name": customer.name_family},
dedup_key=f"welcome:{customer.pk}",
created_by=created_by,
)
def notify_factor_survey(customer, factor, *, created_by=None):
"""پیامک نظرسنجی، بی‌درنگ پس از ثبت فاکتور."""
if customer is None or factor is None or factor.pk is None:
return 0
return enqueue_sms(
customer=customer, sms_type=SMSType.SURVEY,
context={"name": customer.name_family, "amount": factor.amount},
dedup_key=f"survey:{factor.pk}",
created_by=created_by,
)
def notify_visit_scheduled(customer, action, *, created_by=None):
"""پیامک «بازدید شما برای تاریخ … ثبت شد» پس از ایجاد اقدام بازدید."""
if customer is None or action is None or action.pk is None:
return 0
return enqueue_sms(
customer=customer, sms_type=SMSType.VISIT_CREATED,
context={"name": customer.name_family, "date": action.actionDateTime},
dedup_key=f"visit_created:{action.pk}",
created_by=created_by,
)
def notify_install_scheduled(customer, action, *, created_by=None):
"""پیامک «نصب شما برای تاریخ … ثبت شد» پس از ایجاد اقدام نصب.
قرینهٔ :func:`notify_visit_scheduled` است و همان قرارداد را دارد: فقط برای
اقدام ``nasb`` صدا زده می‌شود، متن از قالب ``install_created`` می‌آید و
یکتاسازی با شناسهٔ همان رکورد اقدام انجام می‌شود (ویرایش دوباره = بدون تکرار).
"""
if customer is None or action is None or action.pk is None:
return 0
return enqueue_sms(
customer=customer, sms_type=SMSType.INSTALL_CREATED,
context={"name": customer.name_family, "date": action.actionDateTime},
dedup_key=f"install_created:{action.pk}",
created_by=created_by,
)
def notify_payment_thanks(customer, amount, *, article_id=None, method=None,
created_by=None):
"""پیامک تشکر از پرداخت؛ پس از ثبت سند پرداخت (بستانکار/وصول).
``article_id`` برای یکتاسازی استفاده می‌شود تا یک پرداخت هرگز دو پیامک نگیرد.
``method`` نحوهٔ پرداخت است؛ اگر «تخفیف» باشد (که پرداختِ واقعی نیست) هیچ پیامکی
ساخته نمی‌شود.
"""
if customer is None:
return 0
if method and str(method).strip() in NON_PAYMENT_METHODS:
return 0
dedup_key = f"payment_thanks:{article_id}" if article_id is not None else None
return enqueue_sms(
customer=customer, sms_type=SMSType.PAYMENT_THANKS,
context={"name": customer.name_family, "amount": amount},
dedup_key=dedup_key,
created_by=created_by,
)