fix mandehesab, bazdid, sms
This commit is contained in:
1 parent
7e5c83bea2
commit
1fd27d0445
22 files changed
+16462
-5918
No files matched your search
+138
-24
@@ -18,6 +18,7 @@ from admin_panel.sms.recipients import resolve_recipients
|
||||
from admin_panel.sms.rules import is_sms_enabled
|
||||
from admin_panel.sms.scanner import run_all
|
||||
from admin_panel.sms.timing import apply_timing, current_timing_value, timing_for
|
||||
from admin_panel.sms.triggers import notify_welcome
|
||||
from integrations.sms.base import SMSProvider, SMSResult
|
||||
from integrations.sms.normalize import normalize_mobile, to_local
|
||||
|
||||
@@ -193,13 +194,13 @@ class ScannerTests(TestCase):
|
||||
customer=self.customer, phone_number='09120000001',
|
||||
)
|
||||
|
||||
def test_cheque_funding_fires_after_due_and_is_idempotent(self):
|
||||
"""یادآوری تأمین موجودی، چند روز پس از سررسید و فقط یکبار."""
|
||||
def test_cheque_funding_fires_before_due_and_is_idempotent(self):
|
||||
"""یادآوری تأمین موجودی، پیش از سررسید و فقط یکبار."""
|
||||
today = timezone.localdate()
|
||||
# سررسید ۳ روز پیش، offset پیشفرض = ۱ ⇒ واجد شرط.
|
||||
# سررسید فردا، offset پیشفرض = ۱ ⇒ همین امروز واجد شرط است.
|
||||
Sarresid.objects.create(
|
||||
customer=self.customer, price=5000, payStatus='false', type='check',
|
||||
sarresidDT=timezone.now() - timedelta(days=3),
|
||||
sarresidDT=timezone.now() + timedelta(days=1),
|
||||
)
|
||||
first = run_all(today)
|
||||
second = run_all(today)
|
||||
@@ -209,8 +210,8 @@ class ScannerTests(TestCase):
|
||||
SMSQueue.objects.filter(sms_type=SMSType.CHEQUE_REGISTRATION).count(), 1,
|
||||
)
|
||||
|
||||
def test_cheque_funding_waits_until_after_due(self):
|
||||
"""پیش از سررسید هیچ یادآوریای ساخته نمیشود."""
|
||||
def test_cheque_funding_waits_when_due_is_far_ahead(self):
|
||||
"""سررسیدِ دورتر از پنجرهٔ یادآوری هیچ پیامکی نمیسازد."""
|
||||
today = timezone.localdate()
|
||||
Sarresid.objects.create(
|
||||
customer=self.customer, price=5000, payStatus='false', type='check',
|
||||
@@ -223,29 +224,138 @@ class ScannerTests(TestCase):
|
||||
today = timezone.localdate()
|
||||
Sarresid.objects.create(
|
||||
customer=self.customer, price=5000, payStatus='true', type='check',
|
||||
sarresidDT=timezone.now() - timedelta(days=3),
|
||||
sarresidDT=timezone.now() + timedelta(days=1),
|
||||
)
|
||||
self.assertEqual(run_all(today)['cheque_registration'], 0)
|
||||
|
||||
def test_cheque_funding_offset_is_configurable(self):
|
||||
"""تعداد روز پس از سررسید از قالب (پنل) قابل تنظیم است."""
|
||||
"""تعداد روز پیش از سررسید از قالب (پنل) قابل تنظیم است."""
|
||||
template = SMSTemplate.objects.get(sms_type=SMSType.CHEQUE_REGISTRATION)
|
||||
apply_timing(template, 10)
|
||||
template.save()
|
||||
today = timezone.localdate()
|
||||
# سررسید ۳ روز پیش ولی offset=۱۰ ⇒ هنوز واجد شرط نیست.
|
||||
# سررسید فردا ولی offset=۱۰ ⇒ داخل پنجره ⇒ پیامک میرود.
|
||||
Sarresid.objects.create(
|
||||
customer=self.customer, price=5000, payStatus='false', type='check',
|
||||
sarresidDT=timezone.now() - timedelta(days=3),
|
||||
)
|
||||
self.assertEqual(run_all(today)['cheque_registration'], 0)
|
||||
# سررسید ۱۲ روز پیش ⇒ واجد شرط.
|
||||
Sarresid.objects.all().delete()
|
||||
Sarresid.objects.create(
|
||||
customer=self.customer, price=5000, payStatus='false', type='check',
|
||||
sarresidDT=timezone.now() - timedelta(days=12),
|
||||
sarresidDT=timezone.now() + timedelta(days=1),
|
||||
)
|
||||
self.assertEqual(run_all(today)['cheque_registration'], 1)
|
||||
# با offset کوچکتر (۱)، سررسید ۱۲ روز آینده بیرون پنجره است ⇒ ۰.
|
||||
Sarresid.objects.all().delete()
|
||||
SMSDedup.objects.all().delete()
|
||||
SMSQueue.objects.all().delete()
|
||||
apply_timing(template, 1)
|
||||
template.save()
|
||||
Sarresid.objects.create(
|
||||
customer=self.customer, price=5000, payStatus='false', type='check',
|
||||
sarresidDT=timezone.now() + timedelta(days=12),
|
||||
)
|
||||
self.assertEqual(run_all(today)['cheque_registration'], 0)
|
||||
# همان چک با offset=۱۲ داخل پنجره میشود ⇒ ۱.
|
||||
apply_timing(template, 12)
|
||||
template.save()
|
||||
self.assertEqual(run_all(today)['cheque_registration'], 1)
|
||||
|
||||
def test_cheque_funding_days_is_days_remaining(self):
|
||||
"""«{days}» تعداد روز باقیمانده تا سررسید است (مثبت = پیش از سررسید)."""
|
||||
today = timezone.localdate()
|
||||
Sarresid.objects.create(
|
||||
customer=self.customer, price=5000, payStatus='false', type='check',
|
||||
sarresidDT=timezone.now() + timedelta(days=1),
|
||||
)
|
||||
# قالبِ دیتابیس ممکن است {days} نداشته باشد؛ متن را برای این تست میگذاریم
|
||||
# تا معنای روزِ باقیمانده سنجیده شود (متنِ خودِ رکورد DB دستنخورده میماند).
|
||||
SMSTemplate.objects.filter(
|
||||
sms_type=SMSType.CHEQUE_REGISTRATION,
|
||||
).update(text='{days}')
|
||||
self.assertEqual(run_all(today)['cheque_registration'], 1)
|
||||
item = SMSQueue.objects.get(sms_type=SMSType.CHEQUE_REGISTRATION)
|
||||
# سررسید فردا ⇒ روز باقیمانده = ۱
|
||||
self.assertEqual(item.message, "1")
|
||||
|
||||
def test_cheque_funding_exposes_sayyad_id(self):
|
||||
"""«{sayyad_id}» شناسهٔ صیاد همان چک را نشان میدهد."""
|
||||
today = timezone.localdate()
|
||||
Sarresid.objects.create(
|
||||
customer=self.customer, price=5000, payStatus='false', type='check',
|
||||
sarresidDT=timezone.now() + timedelta(days=1),
|
||||
check_row_number='4321', check_sayyad_id='1234567890123456',
|
||||
)
|
||||
# متن با هر دو متغیر چک، برای سنجش مقدار واقعی (DB دستنخورده میماند).
|
||||
SMSTemplate.objects.filter(
|
||||
sms_type=SMSType.CHEQUE_REGISTRATION,
|
||||
).update(text='{check_row}|{sayyad_id}')
|
||||
self.assertEqual(run_all(today)['cheque_registration'], 1)
|
||||
item = SMSQueue.objects.get(sms_type=SMSType.CHEQUE_REGISTRATION)
|
||||
self.assertEqual(item.message, "4321|1234567890123456")
|
||||
|
||||
def test_cheque_funding_sayyad_id_empty_when_not_set(self):
|
||||
"""اگر شناسهٔ صیاد ثبت نشده باشد، متغیر خالی رندر میشود (نه خطا)."""
|
||||
today = timezone.localdate()
|
||||
Sarresid.objects.create(
|
||||
customer=self.customer, price=5000, payStatus='false', type='check',
|
||||
sarresidDT=timezone.now() + timedelta(days=1),
|
||||
check_row_number='9999',
|
||||
)
|
||||
SMSTemplate.objects.filter(
|
||||
sms_type=SMSType.CHEQUE_REGISTRATION,
|
||||
).update(text='[{sayyad_id}]')
|
||||
self.assertEqual(run_all(today)['cheque_registration'], 1)
|
||||
item = SMSQueue.objects.get(sms_type=SMSType.CHEQUE_REGISTRATION)
|
||||
self.assertEqual(item.message, "[]")
|
||||
|
||||
def test_balance_is_available_in_every_template(self):
|
||||
"""«{balance}» در همهٔ قالبها (نه فقط چک) قابل استفاده است."""
|
||||
from admin_panel.models import Article, SMSType as T
|
||||
|
||||
Article.objects.create(customer=self.customer, debit=500000, credit=0)
|
||||
Article.objects.create(customer=self.customer, debit=0, credit=125000)
|
||||
# ۵۰۰٬۰۰۰ − ۱۲۵٬۰۰۰ = ۳۷۵٬۰۰۰
|
||||
for sms_type in T.values:
|
||||
SMSTemplate.objects.filter(sms_type=sms_type).update(
|
||||
text='{balance}|{balance_sep}',
|
||||
)
|
||||
# رویدادی: خوشآمدگویی
|
||||
notify_welcome(self.customer)
|
||||
item = SMSQueue.objects.get(sms_type=T.WELCOME)
|
||||
self.assertEqual(item.message, "375000|375,000")
|
||||
|
||||
def test_balance_reflects_real_articles(self):
|
||||
"""مانده حساب = مجموع بدهکار − مجموع بستانکار اسناد مشتری."""
|
||||
from admin_panel.models import Article
|
||||
from admin_panel.sms.balance import customer_balance
|
||||
|
||||
self.assertEqual(customer_balance(self.customer), 0)
|
||||
Article.objects.create(customer=self.customer, debit=900000, credit=0)
|
||||
Article.objects.create(customer=self.customer, debit=0, credit=400000)
|
||||
self.assertEqual(customer_balance(self.customer), 500000)
|
||||
# مانده منفی هم باید درست برگردد (بستانکار بیشتر از بدهکار).
|
||||
Article.objects.create(customer=self.customer, debit=0, credit=750000)
|
||||
self.assertEqual(customer_balance(self.customer), -250000)
|
||||
|
||||
def test_balance_zero_when_customer_is_none(self):
|
||||
"""بدون مشتری، مانده صفر است و خطایی رخ نمیدهد."""
|
||||
from admin_panel.sms.balance import customer_balance
|
||||
|
||||
self.assertEqual(customer_balance(None), 0)
|
||||
|
||||
def test_balance_does_not_touch_due_amount(self):
|
||||
"""{balance} (مانده کل حساب) با {amount} (مبلغ چک) قاطی نمیشود."""
|
||||
from admin_panel.models import Article
|
||||
|
||||
today = timezone.localdate()
|
||||
Article.objects.create(customer=self.customer, debit=8000000, credit=0)
|
||||
Sarresid.objects.create(
|
||||
customer=self.customer, price=5000, payStatus='false', type='check',
|
||||
sarresidDT=timezone.now() + timedelta(days=1),
|
||||
)
|
||||
SMSTemplate.objects.filter(
|
||||
sms_type=SMSType.CHEQUE_REGISTRATION,
|
||||
).update(text='amount={amount_sep} balance={balance_sep}')
|
||||
self.assertEqual(run_all(today)['cheque_registration'], 1)
|
||||
item = SMSQueue.objects.get(sms_type=SMSType.CHEQUE_REGISTRATION)
|
||||
# مبلغ چک = ۵٬۰۰۰ (سررسیدشده) ولی مانده حساب = ۸٬۰۰۰٬۰۰۰
|
||||
self.assertEqual(item.message, "amount=5,000 balance=8,000,000")
|
||||
|
||||
def test_nesiye_due_fires_on_due_date_and_ignores_checks(self):
|
||||
"""یادآوری سررسید فقط برای نسیه است، نه چک."""
|
||||
@@ -356,7 +466,7 @@ class ScannerTests(TestCase):
|
||||
today = timezone.localdate()
|
||||
Sarresid.objects.create(
|
||||
customer=self.customer, price=5000, payStatus='false', type='check',
|
||||
sarresidDT=timezone.now() - timedelta(days=3),
|
||||
sarresidDT=timezone.now() + timedelta(days=1),
|
||||
)
|
||||
SMSTemplate.objects.filter(
|
||||
sms_type=SMSType.CHEQUE_REGISTRATION,
|
||||
@@ -374,16 +484,20 @@ class ColdStartTests(TestCase):
|
||||
)
|
||||
self.today = timezone.localdate()
|
||||
|
||||
def _make_due_cheque(self):
|
||||
# سررسید در گذشته تا یادآوری «تأمین موجودی» واجد شرط شود.
|
||||
def _make_cheque(self, days_from_today):
|
||||
"""چکِ پرداختنشده با سررسیدِ ``days_from_today`` نسبت به امروز."""
|
||||
return Sarresid.objects.create(
|
||||
customer=self.customer, price=5000, payStatus='false', type='check',
|
||||
sarresidDT=timezone.now() - timedelta(days=3),
|
||||
sarresidDT=timezone.now() + timedelta(days=days_from_today),
|
||||
)
|
||||
|
||||
def _make_due_cheque(self):
|
||||
# سررسید فردا تا یادآوری «تأمین موجودی» (offset=۱) واجد شرط شود.
|
||||
return self._make_cheque(1)
|
||||
|
||||
def test_first_run_sends_nothing_for_existing_records(self):
|
||||
# مورد پیش از فعالسازی وجود داشته است (خط شروع = همین حالا).
|
||||
self._make_due_cheque()
|
||||
# مورد قدیمی: لحظهٔ واجدشرطشدنش (سررسید − offset) پیش از «خط شروع» است.
|
||||
self._make_cheque(-3)
|
||||
activate_sms(since=timezone.now())
|
||||
self.assertEqual(run_all(self.today)['cheque_registration'], 0)
|
||||
self.assertEqual(SMSQueue.objects.count(), 0)
|
||||
@@ -1696,7 +1810,7 @@ class DeletedStaysDeletedTests(PanelTestCase):
|
||||
mark_primary(customer, '09120000000')
|
||||
Sarresid.objects.create(
|
||||
customer=customer, price=5000, payStatus='false', type='check',
|
||||
sarresidDT=timezone.now() - timedelta(days=3),
|
||||
sarresidDT=timezone.now() + timedelta(days=1),
|
||||
)
|
||||
activate_sms()
|
||||
template = SMSTemplate.objects.get(sms_type=SMSType.CHEQUE_REGISTRATION)
|
||||
|
||||
Reference in new issue
Block a user