Fix OTP/SMS, ledger accounting, order tracking, and add reviews app

- Add MessageTemplate.runtime_field_labels so mobile's per-field
  execution-time labels are actually persisted (were silently dropped)
- Fix AdvanceOrderStageView reading the wrong extra-input key, and be
  honest about SMS send failures instead of always claiming success
- Add admin gift-gem SMS notification via Kavenegar
- Post real double-entry Transactions for plain (non-invoice) ledger
  entries so trial balance, the معین screen, and CSV/XLSX exports
  actually include everyday income/expense entries; backfill existing
  historical entries via data migration
- Rewrite CSV ledger export to produce an actual دفتر معین structure
  (per-account running balance) instead of a flat row dump
- Add invoice percent/promotional discounts, tax presets, ledger
  discount-percent handling, product SKU/category/expiry fields, and
  manual ledger-book archiving (replacing auto-archive on new book)
- Add reviews app (models, API, admin) for the comments/reviews feature
- Update tests for the above; fix two stale assertions left over from
  earlier work in this branch (معین sheet name, book auto-close)
This commit is contained in:
2026-09-15 23:18:05 +03:30
parent 61b7c91b02
commit 831e656fa3
32 changed files with 1036 additions and 77 deletions
+1 -1
View File
@@ -47,7 +47,7 @@ class ContactCrudSerializer(serializers.ModelSerializer):
class MessageTemplateCrudSerializer(serializers.ModelSerializer):
class Meta:
model = MessageTemplate
fields = ["id", "group", "name", "body", "mode"]
fields = ["id", "group", "name", "body", "mode", "runtime_field_labels"]
def validate_group(self, group: ContactGroup | None) -> ContactGroup | None:
if group is None:
+1 -1
View File
@@ -34,7 +34,7 @@ class ContactSerializer(serializers.ModelSerializer):
class MessageTemplateSerializer(serializers.ModelSerializer):
class Meta:
model = MessageTemplate
fields = ["id", "group_id", "name", "body", "mode"]
fields = ["id", "group_id", "name", "body", "mode", "runtime_field_labels"]
extra_kwargs = _ID_NO_UNIQUE_CHECK
@@ -0,0 +1,18 @@
# Generated by Django 5.1.15 on 2026-09-14 23:07
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('banker', '0001_initial'),
]
operations = [
migrations.AddField(
model_name='messagetemplate',
name='runtime_field_labels',
field=models.JSONField(blank=True, default=list, verbose_name='فیلدهای زمان اجرا'),
),
]
+5
View File
@@ -100,6 +100,11 @@ class MessageTemplate(models.Model):
name = models.CharField(max_length=150, verbose_name=_("نام قالب"))
body = models.TextField(verbose_name=_("متن قالب"))
mode = models.CharField(max_length=10, choices=Mode.choices)
# فیلدهای «زمان اجرا» — مقدارشان از دیتای مخاطب خوانده نمی‌شود، هر بار
# موقع ارسال (یا رسیدن سفارش به مرحله‌ای که این قالب رویش است) از کاربر
# پرسیده می‌شود. لیست است چون یک قالب می‌تواند چند فیلدِ این‌چنینی
# داشته باشد (مثلا هم «کد رهگیری» هم «مبلغ نهایی»).
runtime_field_labels = models.JSONField(default=list, blank=True, verbose_name=_("فیلدهای زمان اجرا"))
updated_at = models.DateTimeField(auto_now=True)
class Meta: