Files

71 lines
3.6 KiB
Python
Raw Permalink Normal View History

2026-08-24 15:54:08 +03:30
from django.conf import settings
from django.db import models
from django.utils.translation import gettext_lazy as _
from apps.banker.models import Contact, ContactGroup, MessageTemplate
# این اپ فقط از مسیرهای رسمی هر پلتفرم برای ارسال استفاده می‌کند: پیامک از
# طریق درگاه بالک کاوه‌نگار (سمت سرور، خودکار)، واتساپ از طریق WhatsApp
# Business Cloud API رسمی، تلگرام/بله/ایتا از طریق Bot API رسمی هرکدام —
# فقط برای مخاطبینی که قبلا چت با بات را شروع کرده‌اند (opt-in). برای بقیه‌ی
# موارد، MessageRecipient با status=needs_manual برمی‌گردد تا اپ یک صف
# deep-link یک‌لمسی به کاربر نشان دهد؛ هیچ اتوماسیون/شبیه‌سازی رفتار انسانی
# برای دور زدن ضدهرزنامه‌ی این پلتفرم‌ها در این اپ وجود ندارد.
class Channel(models.TextChoices):
SMS = "sms", _("پیامک")
WHATSAPP = "whatsapp", _("واتساپ")
TELEGRAM = "telegram", _("تلگرام")
BALE = "bale", _("بله")
EITAA = "eitaa", _("ایتا")
class BulkMessage(models.Model):
class Status(models.TextChoices):
DISPATCHED = "dispatched", _("ارسال‌شده")
PARTIALLY_MANUAL = "partially_manual", _("بخشی نیاز به تایید دستی")
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="bulk_messages")
# null = همه‌ی مخاطبین کاربر
group = models.ForeignKey(ContactGroup, on_delete=models.SET_NULL, null=True, blank=True, related_name="+")
template = models.ForeignKey(
MessageTemplate, on_delete=models.SET_NULL, null=True, blank=True, related_name="+"
)
body_override = models.TextField(blank=True, verbose_name=_("متن آزاد (اگر قالب انتخاب نشده)"))
channels = models.JSONField(default=list, verbose_name=_("کانال‌های انتخاب‌شده"))
status = models.CharField(max_length=20, choices=Status.choices, default=Status.DISPATCHED)
created_at = models.DateTimeField(auto_now_add=True)
class Meta:
verbose_name = _("ارسال گروهی")
verbose_name_plural = _("ارسال‌های گروهی")
ordering = ["-created_at"]
def __str__(self):
return f"#{self.pk} — {self.user.phone} — {', '.join(self.channels)}"
class MessageRecipient(models.Model):
class Status(models.TextChoices):
SENT = "sent", _("ارسال‌شده")
FAILED = "failed", _("ناموفق")
NEEDS_MANUAL = "needs_manual", _("نیاز به تایید دستی")
MANUAL_CONFIRMED = "manual_confirmed", _("تایید دستی شد")
bulk_message = models.ForeignKey(BulkMessage, on_delete=models.CASCADE, related_name="recipients")
contact = models.ForeignKey(Contact, on_delete=models.CASCADE, related_name="+")
channel = models.CharField(max_length=10, choices=Channel.choices)
status = models.CharField(max_length=20, choices=Status.choices)
rendered_body = models.TextField()
error = models.CharField(max_length=255, blank=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
verbose_name = _("گیرنده‌ی پیام")
verbose_name_plural = _("گیرنده‌های پیام")
indexes = [models.Index(fields=["bulk_message", "status"])]
def __str__(self):
return f"{self.contact.name} — {self.channel} — {self.status}"