add payment_link and banks

This commit is contained in:
javad committed 2026-10-06 10:03:22 +03:30
1 parent 2ae79b1ca4
commit de3135b588
100 files changed
+6167 -47

No files matched your search

+6 -1
View File
@@ -16,7 +16,12 @@ class AnnouncementJobAdmin(admin.ModelAdmin):
class SMSTemplateAdmin(admin.ModelAdmin):
list_display=("event_type","unit","title","is_active","updated_at")
list_filter=("unit","is_active","event_type")
readonly_fields=("allowed_tags",)
readonly_fields=("allowed_tags_display",)
exclude=("allowed_tags",)
@admin.display(description='Allowed tags / تگ‌های مجاز')
def allowed_tags_display(self, obj):
return obj.supported_tags
@admin.register(NotificationPolicy)
class NotificationPolicyAdmin(admin.ModelAdmin):
list_display=("key","quiet_period_seconds","is_active","updated_at")
@@ -73,6 +73,9 @@ def _bale_ticket_text(ticket, message=None, *, is_reply=False, message_count=1,
return "\n".join(lines)
def _send_sms(job):
if job.event_type in {"PAYMENT_NOTICE_CREATED", "PAYMENT_RECEIPT_APPROVED"}:
from apps.payments.notifications import send_payment_sms
return send_payment_sms(job, provider_factory=get_sms_provider)
issued = None
if job.event_type == "UNIT_SUPERVISOR_NEW_TICKET":
recipient = job.payload.get("recipient_mobile", "")
@@ -0,0 +1,18 @@
# Generated by Django 5.1.1 on 2026-10-05 10:44
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('notifications', '0016_announcementjob_requested_by_announcementjob_source_and_more'),
]
operations = [
migrations.AlterField(
model_name='smstemplate',
name='event_type',
field=models.CharField(choices=[('CUSTOMER_TICKET_CREATED', 'ثبت تیکت توسط مشتری'), ('STAFF_TICKET_CREATED', 'ثبت تیکت توسط کارشناس'), ('STAFF_REPLY', 'پاسخ کارشناس'), ('PAYMENT_NOTICE_CREATED', 'صدور اعلامیه واریز'), ('PAYMENT_RECEIPT_APPROVED', 'تأیید نهایی فیش واریز'), ('UNIT_SUPERVISOR_NEW_TICKET', 'اطلاع تیکت جدید به سرپرستان واحد')], max_length=50),
),
]
@@ -0,0 +1,31 @@
# Generated by Django 5.1.1 on 2026-10-06 05:38
from django.db import migrations, models
def align_template_tags(apps, schema_editor):
template = apps.get_model('notifications', 'SMSTemplate')
ticket_tags = ['magic_link', 'first_name', 'last_name', 'recipient_name', 'unit_name', 'company_name',
'ticket_number', 'subject', 'province', 'city', 'expert_name', 'customer_mobile', 'category_name']
payment_tags = ['recipient_name', 'company_name', 'notice_number', 'receipt_number', 'amount_rial', 'invoice_number', 'payment_link']
for item in template.objects.all():
tags = payment_tags if item.event_type in {'PAYMENT_NOTICE_CREATED', 'PAYMENT_RECEIPT_APPROVED'} else ticket_tags
if item.event_type == 'UNIT_SUPERVISOR_NEW_TICKET':
tags = [tag for tag in tags if tag != 'magic_link']
template.objects.filter(pk=item.pk).update(allowed_tags=tags)
class Migration(migrations.Migration):
dependencies = [
('notifications', '0017_alter_smstemplate_event_type'),
]
operations = [
migrations.AlterField(
model_name='smstemplate',
name='body',
field=models.TextField(help_text='تگ\u200cها بر اساس رویداد مشخص\u200cاند: {magic_link} برای تیکت و {payment_link} برای پرداخت.'),
),
migrations.RunPython(align_template_tags, migrations.RunPython.noop),
]
+26 -2
View File
@@ -13,20 +13,44 @@ class SMSTemplate(PersianTextNormalizationMixin, models.Model):
CUSTOMER_TICKET_CREATED="CUSTOMER_TICKET_CREATED","ثبت تیکت توسط مشتری"
STAFF_TICKET_CREATED="STAFF_TICKET_CREATED","ثبت تیکت توسط کارشناس"
STAFF_REPLY="STAFF_REPLY","پاسخ کارشناس"
PAYMENT_NOTICE_CREATED="PAYMENT_NOTICE_CREATED","صدور اعلامیه واریز"
PAYMENT_RECEIPT_APPROVED="PAYMENT_RECEIPT_APPROVED","تأیید نهایی فیش واریز"
UNIT_SUPERVISOR_NEW_TICKET="UNIT_SUPERVISOR_NEW_TICKET","اطلاع تیکت جدید به سرپرستان واحد"
unit=models.ForeignKey("staff.OrganizationalUnit",on_delete=models.CASCADE,null=True,blank=True,related_name="sms_templates",help_text="خالی یعنی الگوی عمومی و fallback.")
event_type=models.CharField(max_length=50,choices=Event.choices)
title=models.CharField(max_length=120)
body=models.TextField(help_text="تگ‌ها را مانند {magic_link} در متن قرار دهید.")
body=models.TextField(help_text="تگ‌ها بر اساس رویداد مشخص‌اند: {magic_link} برای تیکت و {payment_link} برای پرداخت.")
allowed_tags=models.JSONField(default=sms_template_tags,blank=True)
is_active=models.BooleanField(default=True)
updated_at=models.DateTimeField(auto_now=True)
class Meta:
constraints=[models.UniqueConstraint(fields=["unit","event_type"],name="unique_sms_template_per_unit"),models.UniqueConstraint(fields=["event_type"],condition=models.Q(unit__isnull=True),name="unique_global_sms_template_event")]
def __str__(self): return self.get_event_type_display()
@classmethod
def tags_for_event(cls, event_type):
if event_type in {'PAYMENT_NOTICE_CREATED', 'PAYMENT_RECEIPT_APPROVED'}:
from apps.payments.notifications import TAGS
return list(TAGS)
tags = sms_template_tags()
return [tag for tag in tags if tag != 'magic_link'] if event_type == 'UNIT_SUPERVISOR_NEW_TICKET' else tags
@property
def supported_tags(self):
return ', '.join('{' + tag + '}' for tag in self.tags_for_event(self.event_type))
def save(self, *args, **kwargs):
self.allowed_tags = self.tags_for_event(self.event_type)
if kwargs.get('update_fields') is not None:
kwargs['update_fields'] = set(kwargs['update_fields']) | {'allowed_tags'}
return super().save(*args, **kwargs)
def clean(self):
self.allowed_tags = self.tags_for_event(self.event_type)
from string import Formatter
tags={field for _,field,_,_ in Formatter().parse(self.body) if field}
try:
tags={field for _,field,_,_ in Formatter().parse(self.body) if field}
except ValueError:
raise ValidationError({'body': 'ساختار تگ معتبر نیست؛ هر تگ باید بین { و } قرار بگیرد.'})
invalid=tags-set(self.allowed_tags)
if invalid: raise ValidationError({"body":f"تگ‌های غیرمجاز: {', '.join(sorted(invalid))}"})