improve bazdid 2
This commit is contained in:
1 parent
534a84f977
commit
f8d768a724
6 files changed
+374
-92
No files matched your search
+136
-7
@@ -927,6 +927,80 @@ class VisitHoldTests(TestCase):
|
||||
)
|
||||
self.assertNotIn(customer.pk, self._ids())
|
||||
|
||||
# ---------- ثبت بازدید پس از هماهنگی ⇒ قرار هماهنگی منتفی میشود ----------
|
||||
def test_visit_created_after_coordination_clears_manual_hold(self):
|
||||
"""سناریوی گزارششده: هماهنگی + قرار، سپس ثبت «بازدید».
|
||||
|
||||
انتظار: مشتری از `view=manual` خارج شود و در `view=scheduled` دیده شود.
|
||||
"""
|
||||
customer = self._customer('بازدید بعد از هماهنگی')
|
||||
Action.objects.create(
|
||||
customer=customer, actionType='hamahangi', status='finish',
|
||||
# «چند دقیقه پیش تماس گرفتم» — از مرز لحظهای فاصله دارد.
|
||||
actionDateTime=timezone.now() - timedelta(minutes=5),
|
||||
finishDateTime=timezone.now() - timedelta(minutes=5),
|
||||
)
|
||||
set_visit_hold(customer, timezone.now() + timedelta(days=2))
|
||||
self.assertIn(customer.pk, self._ids('manual'))
|
||||
|
||||
# بازدید برنامهریزیشده (بدون تیک «انجام شد»).
|
||||
self._post_action(
|
||||
customer, actionType='bazdid',
|
||||
dateTimeAnjam=self._ms(timezone.now() + timedelta(hours=2)),
|
||||
desc='بازدید برنامهریزی شد',
|
||||
)
|
||||
|
||||
customer.refresh_from_db()
|
||||
self.assertIsNone(customer.visit_hold_until, 'قرار دستی باید پاک شود')
|
||||
self.assertNotIn(customer.pk, self._ids('manual'))
|
||||
self.assertIn(customer.pk, self._ids('scheduled'))
|
||||
|
||||
def test_visit_created_after_coordination_without_hold_still_schedules(self):
|
||||
customer = self._customer('بدون قرار قبلی')
|
||||
self._post_action(
|
||||
customer, actionType='bazdid',
|
||||
dateTimeAnjam=self._ms(timezone.now() + timedelta(days=3)),
|
||||
desc='بازدید',
|
||||
)
|
||||
self.assertIn(customer.pk, self._ids('scheduled'))
|
||||
|
||||
def test_old_visit_does_not_void_newer_coordination(self):
|
||||
"""بازدید قدیمیتر نباید قرار هماهنگیِ جدیدتر را باطل کند."""
|
||||
customer = self._customer('هماهنگی جدیدتر')
|
||||
Action.objects.create(
|
||||
customer=customer, actionType='bazdid', status='finish',
|
||||
actionDateTime=timezone.now() - timedelta(days=400),
|
||||
finishDateTime=timezone.now() - timedelta(days=400),
|
||||
)
|
||||
Action.objects.create(
|
||||
customer=customer, actionType='hamahangi', status='finish',
|
||||
actionDateTime=timezone.now() - timedelta(minutes=5),
|
||||
finishDateTime=timezone.now() - timedelta(minutes=5),
|
||||
)
|
||||
set_visit_hold(customer, timezone.now() + timedelta(days=20))
|
||||
self.assertIn(customer.pk, self._ids('manual'))
|
||||
|
||||
def test_scheduled_visit_earlier_today_still_counts(self):
|
||||
"""بازدیدِ برنامهریزیشده برای «امروز» تا پایان امروز معتبر است.
|
||||
|
||||
رگرسیون: فیلتر قبلی لحظهای بود و بازدیدی که ساعتش چند دقیقه پیش گذشته
|
||||
بود از فهرست ناپدید میشد.
|
||||
"""
|
||||
customer = self._customer('بازدید امروز')
|
||||
Action.objects.create(
|
||||
customer=customer, actionType='bazdid', status='waite',
|
||||
actionDateTime=timezone.now() - timedelta(minutes=30),
|
||||
)
|
||||
self.assertIn(customer.pk, self._ids('scheduled'))
|
||||
|
||||
def test_scheduled_visit_yesterday_is_not_upcoming(self):
|
||||
customer = self._customer('بازدید دیروز')
|
||||
Action.objects.create(
|
||||
customer=customer, actionType='bazdid', status='waite',
|
||||
actionDateTime=timezone.now() - timedelta(days=1),
|
||||
)
|
||||
self.assertNotIn(customer.pk, self._ids('scheduled'))
|
||||
|
||||
|
||||
# ---------- تفکیک چهارگروهی و فیلترها ----------
|
||||
def test_groups_and_filters(self):
|
||||
@@ -937,23 +1011,31 @@ class VisitHoldTests(TestCase):
|
||||
|
||||
# b: قرار دستی (هماهنگی با تاریخ تماس «همین حالا» + ستون قرار ۲۰ روز بعد).
|
||||
Action.objects.create(customer=b, actionType='hamahangi', status='finish',
|
||||
actionDateTime=timezone.now(), finishDateTime=timezone.now())
|
||||
actionDateTime=timezone.now() - timedelta(minutes=5),
|
||||
finishDateTime=timezone.now() - timedelta(minutes=5))
|
||||
set_visit_hold(b, timezone.now() + timedelta(days=20))
|
||||
|
||||
Action.objects.create(customer=c, actionType='bazdid', status='waite',
|
||||
actionDateTime=timezone.now() + timedelta(days=7))
|
||||
|
||||
# d: هم قرار دستی و هم بازدید برنامهریزیشده.
|
||||
Action.objects.create(customer=d, actionType='hamahangi', status='finish',
|
||||
actionDateTime=timezone.now(), finishDateTime=timezone.now())
|
||||
set_visit_hold(d, timezone.now() + timedelta(days=25))
|
||||
# d: بازدید برنامهریزیشده (قدیمیتر) + قرار دستی (جدیدتر).
|
||||
# ترتیب مهم است: اگر بازدید *پس از* هماهنگی ثبت شود، هماهنگی منتفی
|
||||
# محسوب میشود (تست جداگانهٔ زیر). اینجا برعکس است تا گروه D پوشش داده شود.
|
||||
Action.objects.create(customer=d, actionType='bazdid', status='waite',
|
||||
actionDateTime=timezone.now() + timedelta(days=9))
|
||||
Action.objects.create(customer=d, actionType='hamahangi', status='finish',
|
||||
actionDateTime=timezone.now() - timedelta(minutes=5),
|
||||
finishDateTime=timezone.now() - timedelta(minutes=5))
|
||||
set_visit_hold(d, timezone.now() + timedelta(days=25))
|
||||
|
||||
counts = self._entezar().context['counts']
|
||||
self.assertEqual(counts['uncoordinated'], 1) # a
|
||||
self.assertEqual(counts['manual'], 1) # b
|
||||
self.assertEqual(counts['scheduled'], 1) # c
|
||||
# عددِ کارت باید با فهرستی که با کلیک باز میشود بخواند:
|
||||
# view=manual گروههای B و D را نشان میدهد.
|
||||
self.assertEqual(counts['manual'], 2) # b + d
|
||||
self.assertEqual(counts['scheduled'], 2) # c + d
|
||||
self.assertEqual(counts['manual_only'], 1) # b
|
||||
self.assertEqual(counts['scheduled_only'], 1) # c
|
||||
self.assertEqual(counts['both'], 1) # d
|
||||
self.assertEqual(counts['total'], 4)
|
||||
self.assertEqual(counts['coordinated'], 3)
|
||||
@@ -969,6 +1051,53 @@ class VisitHoldTests(TestCase):
|
||||
self.assertEqual(self._ids('nonsense'), {a.pk})
|
||||
self.assertEqual(self._entezar('nonsense').context['view'], 'uncoordinated')
|
||||
|
||||
def test_card_number_matches_filtered_list(self):
|
||||
"""عدد هر کارت باید با تعداد ردیفهای همان فیلتر یکی باشد.
|
||||
|
||||
رگرسیون: کارت «قرار هماهنگی» فقط گروه B را میشمرد، ولی فیلتر
|
||||
``view=manual`` گروه D را هم نشان میداد؛ کاربر عدد ۰ میدید و با کلیک
|
||||
ردیف پیدا میکرد.
|
||||
"""
|
||||
b = self._customer('قرار دستی تنها')
|
||||
Action.objects.create(customer=b, actionType='hamahangi', status='finish',
|
||||
actionDateTime=timezone.now() - timedelta(minutes=5),
|
||||
finishDateTime=timezone.now() - timedelta(minutes=5))
|
||||
set_visit_hold(b, timezone.now() + timedelta(days=20))
|
||||
|
||||
d = self._customer('هم قرار و هم بازدید')
|
||||
Action.objects.create(customer=d, actionType='bazdid', status='waite',
|
||||
actionDateTime=timezone.now() + timedelta(days=9))
|
||||
Action.objects.create(customer=d, actionType='hamahangi', status='finish',
|
||||
actionDateTime=timezone.now() - timedelta(minutes=5),
|
||||
finishDateTime=timezone.now() - timedelta(minutes=5))
|
||||
set_visit_hold(d, timezone.now() + timedelta(days=25))
|
||||
|
||||
counts = self._entezar().context['counts']
|
||||
self.assertEqual(counts['manual'], len(self._ids('manual')))
|
||||
self.assertEqual(counts['scheduled'], len(self._ids('scheduled')))
|
||||
self.assertEqual(counts['coordinated'], len(self._ids('coordinated')))
|
||||
self.assertEqual(counts['uncoordinated'], len(self._ids('uncoordinated')))
|
||||
self.assertEqual(counts['total'], len(self._ids('all')))
|
||||
|
||||
# وقتی مشتریای هر دو نوع قرار را دارد، راهنمای بالای صفحه باید
|
||||
# توضیح بدهد که چرا جمع دو کارت با «با قرار» برابر نیست.
|
||||
self.assertGreaterEqual(counts['both'], 1)
|
||||
self.assertIn('پس در هر دو کارت شمرده میشوند', self._entezar().content.decode())
|
||||
|
||||
def test_stats_cards_have_minimal_descriptions(self):
|
||||
"""هر کارت آمار باید یک توضیح کوتاه داشته باشد تا معنیاش روشن باشد."""
|
||||
html = self._entezar().content.decode()
|
||||
# سرِ نوار آمار + توضیح «عقبافتاده»
|
||||
self.assertIn('ez-stats-title', html)
|
||||
self.assertIn('ez-stats-hint', html)
|
||||
# پنج توضیح، یکی برای هر کارت
|
||||
self.assertEqual(html.count('class="ez-desc"'), 5)
|
||||
for phrase in ('هنوز وقت بازدید تعیین نشده',
|
||||
'وقت بازدیدشان مشخص است',
|
||||
'تعویق دستی از فرم هماهنگی',
|
||||
'اقدام «بازدید» با تاریخ آینده'):
|
||||
self.assertIn(phrase, html, f'توضیح «{phrase}» روی کارتها نیست')
|
||||
|
||||
# ---------- اسکنر پیامک هم قرار دستی را میبیند ----------
|
||||
def test_scanner_skips_customer_with_manual_hold(self):
|
||||
from admin_panel.models import PhoneNumber, SMSProviderConfig, SMSQueue
|
||||
|
||||
Reference in new issue
Block a user