some improve

This commit is contained in:
javad committed 2026-10-27 11:49:09 +03:30
1 parent fa73a734a0
commit 2e5d0bcdd3
17 files changed
+1512 -226

No files matched your search

+34 -6
View File
@@ -158,7 +158,8 @@ customerActionInc.html
| نوع | زمان ارسال | تصمیم‌گیر | داده‌های دخیل |
|---|---|---|---|
| `visit` (دوره‌ای) | اسکنر (`scan_visit`) وقتی موعدِ «آخرین بازدید + ۹ ماه» رسیده باشد | `cycle_anchor_map` + `next_appointment_map` | **هر دو فیلد** (فیلد اول به‌واسطهٔ لنگر، فیلد دوم به‌واسطهٔ قرار) |
| `visit_created` (رویدادی) | بلافاصله پس از ثبت اقدام **بازدید** | `notify_visit_scheduled` | فقط `actionDateTime` (برای متن `{date}`) |
| `visit_created` (رویدادی) | بلافاصله پس از ثبت اقدام **بازدید** — هم در «ایجاد» و هم وقتی نوع اقدام در «ویرایش» **به** بازدید تغییر کند | `notify_visit_scheduled` | فقط `actionDateTime` (برای متن `{date}`) |
| `install_created` (رویدادی) | بلافاصله پس از ثبت اقدام **نصب** — همان دو مسیر (ایجاد و تغییر نوع در ویرایش) | `notify_install_scheduled` | فقط `actionDateTime` (برای متن `{date}`) |
### ۴.۲ ماتریس اثر (نتیجهٔ شبیه‌سازی، همه با `scan_visit`)
@@ -171,6 +172,7 @@ customerActionInc.html
| هماهنگی با تاریخ +۵ روز (بدون تعویق) | ⛔ | — |
| هماهنگی «انجام‌شده» با تاریخ گذشته و بدون تعویق | ✅ ارسال | — |
| ثبت اقدام بازدید (هر وضعیتی) | — | ✅ با `{date}` = `actionDateTime` |
| ثبت اقدام نصب (هر وضعیتی) | — | ✅ `install_created`، مستقل از `visit_created` |
| ثبت اقدام هماهنگی | — | ❌ |
| قرار دستی فعال + ثبت بازدید | — | ✅ (فیلد دوم مانع نیست) |
@@ -181,11 +183,13 @@ customerActionInc.html
### ۴.۳ چرا «تعویق» روی `visit_created` اثر ندارد؟
چون این پیامک در `views/actions.py:170-171` فقط برای `actionType == bazdid` صدا زده
می‌شود، و اصلاً از `next_appointment_map` عبور نمی‌کند. یعنی اگر هماهنگی بگذارید و بعد
بازدیدی ثبت کنید، پیامکِ «بازدید شما برای تاریخ … ثبت شد» می‌رود حتی اگر «تا تاریخ
پیگیری نشود» فعال باشد. (اگر رفتار مطلوب چیز دیگری است، باید در `notify_visit_scheduled`
یا در شرط فراخوانی آن تغییر کند.)
چون این پیامک در ویوهای اقدام (`views/actions.py`، تابع `_sync_action_event_sms`) فقط
برای `actionType == bazdid` صدا زده می‌شود، و اصلاً از `next_appointment_map` عبور
نمی‌کند. یعنی اگر هماهنگی بگذارید و بعد بازدیدی ثبت کنید، پیامکِ «بازدید شما برای
تاریخ … ثبت شد» می‌رود حتی اگر «تا تاریخ پیگیری نشود» فعال باشد. همین قاعده برای
`install_created` (اقدام از نوع نصب) هم برقرار است. (اگر رفتار مطلوب چیز دیگری است،
باید در `notify_visit_scheduled`/`notify_install_scheduled` یا در شرط فراخوانی آن‌ها
تغییر کند.)
### ۴.۴ جزئیات مهم `scan_visit`
@@ -525,6 +529,30 @@ for customer_id in manual_holds_map(now=now):
| B6 | فنی | مرز «وظایف امروز» با رشتهٔ naive ساخته می‌شد (وابسته به تایم‌زون/DST) | `strftime('%Y-%m-%d 00:00:00')` در `ActionListToday`/`ActionListUserToday` | `_local_day_range()` صریح و aware با پوشش DST |
| B7 | فنی | هر GET صفحهٔ انتظار، `CacheTable` را می‌نوشت (حتی بدون تغییر) | `save()` بی‌قید در ویو | فقط در صورت تغییر + `update_fields` |
| B8 | فنی (تست) | تست `test_overdue_column_hidden_only_in_followup_view` به ساعت اجرا وابسته بود | هماهنگی «امروز ساعت ۱۲» می‌توانست «آینده» شمرده شود | تست با مشتری بدون قرار، مستقل از ساعت |
| B9 | کسب‌وکار | اقدام **«نصب»** ردیف را از فهرست‌های کار (`?view=today` و `?view=today&missed=1`) حذف نمی‌کرد؛ فقط «بازدید» حذف می‌کرد | `followups_on_date`/`overdue_followups` در دو مرحلهٔ «قرار در انتظار» و «انجام‌شده» فقط `bazdid` را می‌دیدند (`_pending_visit_customer_ids` و `last_visit_map`) | آن دو مرحله به `_pending_appointment_ids` (با `_CYCLE_RESET_TYPES` = `bazdid`/`nasb`) و `cycle_anchor_map` منتقل شدند؛ `last_visit_map` دست‌نخورده ماند |
| B10 | رویداد | تغییر نوع یک اقدام از «هماهنگی» به «بازدید» در فرم **ویرایش**، پیامک `visit_created` نمی‌فرستاد | تریگر `notify_visit_scheduled` فقط در `customerNewAction` صدا زده می‌شد (یک فراخوان در کل کد) | در `customerEditAction` گذار نوع بررسی می‌شود: غیربازدید → بازدید ⇒ تریگر؛ بازدید → غیربازدید ⇒ `cancel_pending_sms_for_action(action_id=…)`. تکرار با `dedup_key=visit_created:{action.pk}` مهار می‌شود |
| F1 | قابلیت | نوع پیامک «ثبت نصب» (اقدام از نوع نصب) وجود نداشت | فرم‌های اقدام از نوع نصب هیچ تریگر پیامکی نداشتند | `SMSType.INSTALL_CREATED` + `notify_install_scheduled` + قالب قابل ویرایش در `/panel/sms/templates` + تریگر در هر دو ویوی ایجاد/ویرایش (مهاجرت ۰۰۸۱) |
> **F1 — قیدهای ایمنی مهاجرت ۰۰۸۱:** مهاجرت فقط `choices` را گسترش می‌دهد
> (`AlterField` = متادیتا، بدون تغییر داده) و **یک** ردیف تازه با
> `get_or_create` می‌سازد. هیچ `update`/`save` روی قالب‌های موجود ندارد؛ اگر قالب
> `install_created` از قبل باشد هم دست نمی‌خورد. قالب تازه:
> `is_enabled=True` (در پنل دیده شود) و **`auto_send=False`** ⇒ پیامک‌ها در صف
> «در انتظار تأیید» می‌مانند تا مدیر خودش تأیید کند. تست‌های نگهبان:
> `InstallTemplateMigrationTests` و `test_install_template_is_seeded_with_auto_send_off`
> در `tests/test_sms.py`.
> **B9 — جزئیات (۲۰۲۶-۱۰-۲۷):** «نصب» از قبل در `_SUPERSEDING_TYPES` (ابطال قرار
> دستی) و `_CYCLE_RESET_TYPES` (ریست چرخهٔ ۹ ماهه در اسکنر پیامک) بود، ولی فهرست
> کار روزانه آن را نمی‌دید. حالا:
>
> * `nasb + waite` با تاریخ از آغاز روز مورد نظر به بعد ⇒ ردیف پنهان می‌شود
> (همان قاعدهٔ `bazdid + waite`؛ «قرار امروز» تا پایان امروز معتبر است).
> نصبِ در انتظارِ **قدیمی‌تر** از آن روز، قرار فعال نیست و ردیف را باز نمی‌گذارد.
> * `nasb + finish` با تاریخ مؤثر از موعد به بعد ⇒ ردیف بسته می‌شود (همان قاعدهٔ
> `bazdid + finish`).
> * `last_visit_map` (تاریخ آخرین **بازدید**، ستون جدول، `last_bazdid_dt` و پیامک)
> عمداً تغییر نکرد؛ «نصب» فقط لنگر چرخه است، نه بازدید.
### ۹.۳ اثر روی دادهٔ واقعی (همان نسخهٔ پشتیبان)
+8 -1
View File
@@ -64,9 +64,16 @@
| حذف اقدام هماهنگی | قرار **خودکار بی‌اثر** می‌شود |
| لغو هماهنگی (`cancell`) | بی‌اثر می‌شود |
| ویرایش تاریخ هماهنگی | قرار با تاریخ جدید هم‌راستا می‌شود |
| **ثبت بازدید (یا هر اقدام دیگر) پس از هماهنگی** | قرار **خودکار بی‌اثر** می‌شود |
| **ثبت بازدید یا نصب پس از هماهنگی** | قرار **خودکار بی‌اثر** می‌شود |
| ثبت سایر اقدام‌ها (وصول، تماس…) | قرار دست‌نخورده می‌ماند |
| کهنه ماندن ستون | **هیچ اثر مخربی ندارد** |
> **تکمیل ۲۰۲۶-۱۰-۲۷:** «نصب» در فهرست‌های کار هم مثل «بازدید» عمل می‌کند:
> `nasb + waite` با تاریخ از امروز به بعد و `nasb + finish` از موعد به بعد، ردیف را
> از `?view=today` و `?view=today&missed=1` خارج می‌کند
> (`visit_policy._pending_appointment_ids` و `cycle_anchor_map`). این دو نوع همان
> `_CYCLE_RESET_TYPES` هستند که چرخهٔ ۹ ماهه و قرار دستی را هم بازنشانی می‌کنند.
به همین دلیل دیگر خطر «کش کهنه» وجود ندارد: منبع حقیقت همیشه جدول `Action` است.
---