fix mandehesab, bazdid, sms
This commit is contained in:
1 parent
7e5c83bea2
commit
1fd27d0445
22 files changed
+16462
-5918
No files matched your search
+29
-4
@@ -1,11 +1,11 @@
|
||||
Project Root: khatibi
|
||||
Generated At: 2026-10-15T06:59:41+00:00
|
||||
Python Files: 175
|
||||
Generated At: 2026-10-16T12:37:31+00:00
|
||||
Python Files: 179
|
||||
Django Files: 12
|
||||
JavaScript/TypeScript Files: 14
|
||||
HTML Files: 58
|
||||
Total Files: 689
|
||||
Total Directories: 76
|
||||
Total Files: 713
|
||||
Total Directories: 77
|
||||
|
||||
khatibi
|
||||
├── .cursor
|
||||
@@ -41,6 +41,7 @@ khatibi
|
||||
│ │ │ ├── fix_customer_names.py
|
||||
│ │ │ ├── fix_customer_phones.py
|
||||
│ │ │ ├── gt_esh.py
|
||||
│ │ │ ├── normalize_customer_sms_phones.py
|
||||
│ │ │ ├── recalc_last_bazdid.py
|
||||
│ │ │ ├── send_daily_report.py
|
||||
│ │ │ ├── sms_delivery.py
|
||||
@@ -121,6 +122,8 @@ khatibi
|
||||
│ │ ├── 0070_sms_types_seven.py
|
||||
│ │ ├── 0071_sms_settings_permission.py
|
||||
│ │ ├── 0072_customernamefixjob.py
|
||||
│ │ ├── 0073_alter_action_actiontype_choices.py
|
||||
│ │ ├── 0074_alter_action_status_choices.py
|
||||
│ │ └── __init__.py
|
||||
│ ├── models
|
||||
│ │ ├── __init__.py
|
||||
@@ -338,6 +341,13 @@ khatibi
|
||||
│ │ ├── graph.json
|
||||
│ │ ├── GRAPH_REPORT.md
|
||||
│ │ └── manifest.json
|
||||
│ ├── 2026-10-16
|
||||
│ │ ├── .graphify_analysis.json
|
||||
│ │ ├── .graphify_labels.json
|
||||
│ │ ├── .graphify_semantic_marker
|
||||
│ │ ├── graph.json
|
||||
│ │ ├── GRAPH_REPORT.md
|
||||
│ │ └── manifest.json
|
||||
│ ├── cache
|
||||
│ │ ├── ast
|
||||
│ │ │ └── v0.9.82-s7
|
||||
@@ -368,8 +378,10 @@ khatibi
|
||||
│ │ │ ├── 183467d5c1ee7daac78dfb428bd335c17e17272bd4510358f38fc5924140c816.json
|
||||
│ │ │ ├── 1893253c5245ae073f9de9168d537384ab764b79d7b1631c785cd7335aab791b.json
|
||||
│ │ │ ├── 1d5a29a9dabb365c079039c788988636b66c3a4bd2dbe66b249df001c2b5396f.json
|
||||
│ │ │ ├── 1d7a28f73bb52bbc018674a0c01405b7f395bcc5f340ecabe332e2fe440bcae8.json
|
||||
│ │ │ ├── 1d9f15f04104af07c60349f21bcd9f6f2c0e65c915e3e9c69040a10197b0fa6f.json
|
||||
│ │ │ ├── 1dd0c6958a307a1e4e59c24f20225292277585dd8652b35537ede94fc04807ee.json
|
||||
│ │ │ ├── 1f7001563689c4ba77d24f98418fd10725419d45385094fd18d89f20573d6453.json
|
||||
│ │ │ ├── 20652a8d348bf514ac266f30a6400f923674dae819d18046d008066943377804.json
|
||||
│ │ │ ├── 21af53aa7322868a25b47458e59f339a8f6e58b7914fbe8e3389ab86e0b0b643.json
|
||||
│ │ │ ├── 22310d4d49f2beee611c83915933ea06e80ec562fd92c170345c556cd3772561.json
|
||||
@@ -399,10 +411,12 @@ khatibi
|
||||
│ │ │ ├── 4162977f2c2251e7a8b331d7229bd43dff56df31356191b19886b5bf5d56377d.json
|
||||
│ │ │ ├── 41952e7c846da15fe658603ff001dafdb0e12d3372a7f0306adfa3a71de8bee7.json
|
||||
│ │ │ ├── 4204828f3cbb3465c469e28345e0fc4d7ff9a84e30e3dd9f00ab4dbe27014e0d.json
|
||||
│ │ │ ├── 435b8e433cd2f09f7b81717214592f9bfadd8edd8177adcabd4338ce803855d2.json
|
||||
│ │ │ ├── 458c1b9a3ce257e789f75305939ab2e79029c557657102eebf2082e50a47a0e5.json
|
||||
│ │ │ ├── 45f7e59ef3f291171180b6763e8da408d8b7579bb7cb96dd4ca859e48aa5ce14.json
|
||||
│ │ │ ├── 46616763804b2b938d73c75f7651158e94803e0b86b3a759ecdd59375759eea3.json
|
||||
│ │ │ ├── 46bde576f6f1e69457e4ad33238fdbd602d2a7f027644a84cb81068215fbd5e1.json
|
||||
│ │ │ ├── 477b0c06bcadb94314490ac76899f499d45a942aadef1e65623d303342157463.json
|
||||
│ │ │ ├── 4da7df08a0ef803551d404438fe24d6c8cc11d9a2c3cc8d85e37d5228ba3a166.json
|
||||
│ │ │ ├── 4e24d52f79dfa76aa2406de05583fa49ce966a28fb653fa284fb8e8204797385.json
|
||||
│ │ │ ├── 4e604dd03a70463ae25f6615ea3ce4fe8e98fab15d6b11ddafd51d601062e84d.json
|
||||
@@ -440,6 +454,7 @@ khatibi
|
||||
│ │ │ ├── 6603c5eb7403f7426c429341d43018fdffcb3430f22972c426ac43956d229b33.json
|
||||
│ │ │ ├── 6648bc2b25d0bd25846d48f406d3e9a6f89677542600e9f3f57533747ed9b08c.json
|
||||
│ │ │ ├── 6691dea01045e5561ac1c72f902f96ba84564c221498829443f793fee8784021.json
|
||||
│ │ │ ├── 67b4e119f02b3ed94553e526bbd33cddff90053edb27438e472409b2ca5ad9a0.json
|
||||
│ │ │ ├── 6805914035b171d32a1b80948179da15f78c5741e5a80b216d51a6586185c0c3.json
|
||||
│ │ │ ├── 6876f75a9cb4a5f5857c47e3b0d6b38e51941aff76bc6d92cb1b4eef1c51071e.json
|
||||
│ │ │ ├── 6a88f82e5b9f9da12b50f8531eac30c10e1c2a0cf39601d275fd90ee3e28da55.json
|
||||
@@ -451,6 +466,7 @@ khatibi
|
||||
│ │ │ ├── 6e262456570c174e207055c7c964fe85431addb0f59298b1e4d912500dfb23a3.json
|
||||
│ │ │ ├── 6e2ed39911a83c75e432ffd0dab22fd095ce8c5bb186d6ab22d594375f3b32bc.json
|
||||
│ │ │ ├── 6ed362dbf43e46eeb440246d52fdc4e0783c895114249ea33f3de7ddf6898a3a.json
|
||||
│ │ │ ├── 6ee8ac22fd8b7d0152fe85c630c98fd9c7f1f74312b5f923dbebb3ff5367a71e.json
|
||||
│ │ │ ├── 71a07328d56403d55714d76cefc05db3e68c6498719e629e4e76889a1940efc2.json
|
||||
│ │ │ ├── 72577fde1eae8cf079aff518cecce910ac310cefcc038fbbcb0a5d11f20fa20d.json
|
||||
│ │ │ ├── 73a129efd08cc38274f3c56503c234eef17f58faf74dadbdbbe475efcbfc2777.json
|
||||
@@ -505,9 +521,11 @@ khatibi
|
||||
│ │ │ ├── a823c9c28027c8d525714e6571bc3f3ca38f3bd0420aaf4f4921067cf0672475.json
|
||||
│ │ │ ├── a8311f6e51027ea4606e35bf14d50edc1795e71b2d63cddeae8c7bb7ece215b8.json
|
||||
│ │ │ ├── aabf6dbb2202699bb1b06fd582c88465b9cf2b8cc060bda2e2bc0c67fc493bed.json
|
||||
│ │ │ ├── ab5d0682afc0714c24b9ac5fda36b243c638d272ea973f46a5c18e783132c861.json
|
||||
│ │ │ ├── add004e78a62164d7565c102eb825debea20811f7fe76afa0567a1b6b289f264.json
|
||||
│ │ │ ├── aeaae7b60339b1283cab517b4ab42806c64933c272d007a68431988ba8e0edb5.json
|
||||
│ │ │ ├── af128ca7fc8d02ae40fff36925a5b96034862ce0d581e22a8a0c88f41040e526.json
|
||||
│ │ │ ├── b24556e20d540fd63de3dc04501ffd021836b930c4ebc3ff309f7950ef17a335.json
|
||||
│ │ │ ├── b26c22033963df1727407c1fa6c79d8241bfc16056e7a8d3c4383fb2d050d3cd.json
|
||||
│ │ │ ├── b26e251bde84a040dbb2d1a4f700ebcd761f51a124a98a104704e82537e320eb.json
|
||||
│ │ │ ├── b34cb0a1a28e753a900b3d23f01d3810f9c06635b0650d34be4ec9d98daa8fbb.json
|
||||
@@ -526,11 +544,13 @@ khatibi
|
||||
│ │ │ ├── be72e639c12e860a2120c3ecf96b94c86e5c69b2f1f0715cd2804d0475409cd6.json
|
||||
│ │ │ ├── c12baf851ec40542280cb62d2f878d5e7383357365281938cfb55a64c08a9a10.json
|
||||
│ │ │ ├── c36b696b57c1deb51e47a057b32d1dd75e3f1560e83931aab1f8ba86abcc1543.json
|
||||
│ │ │ ├── c3c6651e6b7dd802c31efb56ac20c1f1ba3c4c0108599f1480c6a143b2e688ef.json
|
||||
│ │ │ ├── c46ad3fc8fd3db1315ab2e40add760b44e8f98c24c79e334c342c6a411fc671c.json
|
||||
│ │ │ ├── c52300dce4cf464158f8db56df5030359a501a81bbe4a5f36e50c8c38a5ac48c.json
|
||||
│ │ │ ├── c535c8a7523b768d28903b84f4cfbce7d62181a2a05f3db08ec3a7c8cbf86ce8.json
|
||||
│ │ │ ├── c56beb43cf063fd1cc92950ca14695b543b3971bf7e7dbd4a676242057258533.json
|
||||
│ │ │ ├── c5c93ccc7715c31fc7538bcd9327c8fb7c1e495bd17d6444b384ec426b7a231f.json
|
||||
│ │ │ ├── c718a8f0cdfb66217ab4484dca103c7029d43976f7f0889bfb11f6cab3bb2510.json
|
||||
│ │ │ ├── c72226544540cc75217ba02f1d09d989eb810d879409ac086c76245f27220cfa.json
|
||||
│ │ │ ├── c795f43bd1f10cf666ff987d18af538b2164c1683629ac689f0a54cb875118be.json
|
||||
│ │ │ ├── c7eb97fa16701c6d9ee531fa032479a7c771292f3e9d8921d3ea12a4897fd43a.json
|
||||
@@ -545,6 +565,7 @@ khatibi
|
||||
│ │ │ ├── d1289d5406d360e3ff617e213db4e262cd43a32711a61aba97bdcd0a906cbcb5.json
|
||||
│ │ │ ├── d12cd2b31145213be1b4d89e7be64f3aecc122841cdeac7660eceae3dd871f01.json
|
||||
│ │ │ ├── d12dccf07d58d7c0a2b5ea5b6aa821aa419fdc8b34a48939ebf9c565bc439551.json
|
||||
│ │ │ ├── d1392fc7270aa978a815d8dbe99ea56de021ee699664635d53b8df5b2988c835.json
|
||||
│ │ │ ├── d1f2090208e1aab3b0e377278b02e9fc1007e5e1724c9000fb69d050365c8660.json
|
||||
│ │ │ ├── d3456cd690135f9630e6b0bb79fef5d205804c7acabffc61cbd5ac4032b17bc7.json
|
||||
│ │ │ ├── d51b2eb414ee4ea432987cd45d6b623013e994a6080c89cde57b69004b576e9d.json
|
||||
@@ -565,6 +586,7 @@ khatibi
|
||||
│ │ │ ├── e2c62f6012dcae176d19340f6db8db3e94547ebbc4a21577b63caf35cc72ecfb.json
|
||||
│ │ │ ├── e3ee8d9942c74a74be83ca00d5438e4a1e1cb5b23f55d95d308a42954e4757f0.json
|
||||
│ │ │ ├── e86dc6bb7703d4329623bd33ccbc5e5e6c6daebf8d36d84fd415d6f868c779b0.json
|
||||
│ │ │ ├── e8738fdd0a67e92abd0ce636990ee001a2fc7586e9eda224915f33cb80d3b2c6.json
|
||||
│ │ │ ├── e8e380264b41f789dddd25b7af5d0e3c517b957a14fe8ba2ce7bb8a529e005cf.json
|
||||
│ │ │ ├── e9589ded446a5befb285a0a2e93a182ca9431c76661e68c9210ed252580dd7f0.json
|
||||
│ │ │ ├── e9e14d581ed59799b2d83c67402e8555b5b59e7d49425950ec490422bd0307d9.json
|
||||
@@ -577,6 +599,7 @@ khatibi
|
||||
│ │ │ ├── efd113025c3fb3c0becaecd8090e8494b13d92ff3c49220d54665b3a8af586af.json
|
||||
│ │ │ ├── f081ba494afddbf02c2599aedee9fc9d38ccdb159ade7f07ce3bdad3323a001e.json
|
||||
│ │ │ ├── f1af209a02f2ec5c5a344e3fa7dd8ad7d443e0479e55f5465449c0a2eed314a1.json
|
||||
│ │ │ ├── f2eacc54ffb4b9802045711c0fb0ac7210c95f21ed6ae78011fe0496951aa086.json
|
||||
│ │ │ ├── f3a6285dcf9eb39df500bc0b76b03b5941103e8b90c06ffaeab1b3129f18fedc.json
|
||||
│ │ │ ├── f3fe81220df98d0410b1505fa995df65427035dd552c85f1d80e35bb75a9aba1.json
|
||||
│ │ │ ├── f48decaf1220666fbda1a5328b963dbd999caab9ebbb1d84459d4c556a6e6ba7.json
|
||||
@@ -740,6 +763,7 @@ khatibi
|
||||
│ ├── test_inventory.py
|
||||
│ ├── test_models_contract.py
|
||||
│ ├── test_sms.py
|
||||
│ ├── test_sms_phone_normalize.py
|
||||
│ ├── test_urls_contract.py
|
||||
│ └── test_view_smoke.py
|
||||
├── .clinerules
|
||||
@@ -763,6 +787,7 @@ khatibi
|
||||
├── khatibi.zip
|
||||
├── local.env
|
||||
├── manage.py
|
||||
├── normalize_customer_sms_phones.md
|
||||
├── production.env
|
||||
├── project_tree.py
|
||||
├── recalc_last_bazdid.md
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
# Generated by Django 3.2.25 on 2026-10-16 10:49
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
"""افزودن ``choices`` به ``Action.actionType``.
|
||||
|
||||
این migration فقط وضعیت مدل را بهروز میکند: Django ``choices`` را در
|
||||
``deconstruct()`` فیلد نگه میدارد، پس بدون این migration دستور
|
||||
``makemigrations --check`` شکست میخورد. تعریف ستون در SQLite هیچ تغییری
|
||||
نمیکند (``choices`` در DDL بازتاب نمییابد) و هیچ دادهای بازنویسی نمیشود.
|
||||
"""
|
||||
|
||||
dependencies = [
|
||||
('admin_panel', '0072_customernamefixjob'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='action',
|
||||
name='actionType',
|
||||
field=models.CharField(
|
||||
blank=True,
|
||||
choices=[
|
||||
('bazdid', 'بازدید'),
|
||||
('nasb', 'نصب'),
|
||||
('vosol', 'وصول مطالبات'),
|
||||
('hamahangi', 'هماهنگی'),
|
||||
('inCall', 'تماس ورودی'),
|
||||
('outCall', 'تماس خروجی'),
|
||||
],
|
||||
max_length=50,
|
||||
null=True,
|
||||
),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,37 @@
|
||||
# Generated by Django 3.2.25 on 2026-10-16 10:49
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
"""افزودن ``choices`` به ``Action.status``.
|
||||
|
||||
این migration فقط وضعیت مدل را بهروز میکند: Django ``choices`` را در
|
||||
``deconstruct()`` فیلد نگه میدارد، پس بدون این migration دستور
|
||||
``makemigrations --check`` شکست میخورد. تعریف ستون در SQLite هیچ تغییری
|
||||
نمیکند (``choices`` در DDL بازتاب نمییابد) و هیچ دادهای بازنویسی نمیشود.
|
||||
|
||||
املای مقادیر عیناً همان چیزی است که در دیتابیس و کد موجود بهکار رفته:
|
||||
``'waite'`` (نه ``'wait'``)، ``'finish'`` و ``'cancell'``.
|
||||
"""
|
||||
|
||||
dependencies = [
|
||||
('admin_panel', '0073_alter_action_actiontype_choices'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='action',
|
||||
name='status',
|
||||
field=models.CharField(
|
||||
blank=True,
|
||||
choices=[
|
||||
('waite', 'در انتظار (باز)'),
|
||||
('finish', 'انجام شده'),
|
||||
('cancell', 'لغو شده'),
|
||||
],
|
||||
max_length=50,
|
||||
null=True,
|
||||
),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,49 @@
|
||||
"""یادآوری تأمین موجودی چک: تغییر جهت از «پس از سررسید» به «پیش از سررسید».
|
||||
|
||||
هدف این migration **فقط** همراستاکردن مقدار عددی ``offset_days`` قالب
|
||||
``cheque_registration`` با معنای جدید است (تعداد روز **قبل** از سررسید).
|
||||
|
||||
آنچه این migration عمداً **نمیکند**:
|
||||
|
||||
* ``text`` (متن پیامک) را تغییر نمیدهد — متنی که مدیر در پنل تنظیم کرده دستنخورده
|
||||
میماند. اگر متن فعلی از زمان گذشته حرف میزند («سررسید شده است»)، مدیر میتواند
|
||||
خودش از صفحهٔ «قالبهای پیامک» ویرایشش کند.
|
||||
* ``title``، ``is_enabled`` و ``auto_send`` را تغییر نمیدهد.
|
||||
* هیچ نوع/قالب دیگری را لمس نمیکند.
|
||||
|
||||
مقدار ``offset_days`` روی پیشفرض معنای جدید (۱ روز قبل از سررسید) تنظیم میشود تا
|
||||
نصبهای تازه و نصبهای موجود یکسان رفتار کنند؛ اما اگر مدیر قبلاً عددی غیر از مقدار
|
||||
قدیمی (``1``) گذاشته باشد، به آن دست نمیزنیم تا انتخابش از بین نرود.
|
||||
|
||||
idempotent است؛ اجرای دوباره بیخطر است.
|
||||
"""
|
||||
from django.db import migrations
|
||||
|
||||
SMS_TYPE = "cheque_registration"
|
||||
# مقدار پیشفرضِ منطق قدیم («۱ روز پس از سررسید») که با معنای جدید همعددی است؛
|
||||
# فقط رکوردهایی که هنوز روی همین مقدار هستند همراستا میشوند.
|
||||
OLD_DEFAULT = 1
|
||||
NEW_DEFAULT = 1
|
||||
|
||||
|
||||
def align_cheque_offset(apps, schema_editor):
|
||||
"""``offset_days`` قالب چک را روی پیشفرض جدید بگذارد (بدون لمس متن)."""
|
||||
SMSTemplate = apps.get_model("admin_panel", "SMSTemplate")
|
||||
SMSTemplate.objects.filter(
|
||||
sms_type=SMS_TYPE, offset_days=OLD_DEFAULT,
|
||||
).update(offset_days=NEW_DEFAULT)
|
||||
|
||||
|
||||
def noop(apps, schema_editor):
|
||||
pass
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("admin_panel", "0074_alter_action_status_choices"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(align_cheque_offset, noop),
|
||||
]
|
||||
@@ -0,0 +1,36 @@
|
||||
"""افزودن متغیر ``{sayyad_id}`` به راهنمای ``help_text`` متن قالب پیامک.
|
||||
|
||||
هدف: راهنمای متغیرها در پنل، «شناسهٔ صیاد چک» را هم نشان دهد.
|
||||
|
||||
آنچه این migration عمداً **نمیکند**:
|
||||
|
||||
* ``text`` (متن واقعی قالبها) را تغییر نمیدهد — فقط ``help_text`` فیلد عوض شده
|
||||
است که در ``deconstruct()`` میآید و state مدل را جلو میبرد.
|
||||
* هیچ رکورد ``SMSTemplate`` را لمس نمیکند.
|
||||
|
||||
idempotent است؛ اجرای دوباره بیخطر است.
|
||||
"""
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("admin_panel", "0075_cheque_funding_before_due"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name="smstemplate",
|
||||
name="text",
|
||||
field=models.TextField(
|
||||
help_text=(
|
||||
"متغیرهای قابل استفاده: {name} نام مشتری، {amount} مبلغ، "
|
||||
"{amount_sep} مبلغ با جداکننده، {date} تاریخ جلالی، "
|
||||
"{days} تعداد روز، {check_row} شماره ردیف چک، "
|
||||
"{sayyad_id} شناسه صیاد چک، {owner_name} نام مالک چک."
|
||||
),
|
||||
verbose_name="متن پیامک",
|
||||
),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,39 @@
|
||||
"""افزودن متغیرهای ``{balance}`` / ``{balance_sep}`` به راهنمای متن قالب پیامک.
|
||||
|
||||
هدف: راهنمای متغیرها در پنل، «مانده حساب مشتری» را هم نشان دهد و تفاوتش را با
|
||||
مبلغ سررسیدشده روشن کند.
|
||||
|
||||
آنچه این migration عمداً **نمیکند**:
|
||||
|
||||
* ``text`` (متن واقعی قالبها) را تغییر نمیدهد — فقط ``help_text`` فیلد عوض شده
|
||||
است که در ``deconstruct()`` میآید و state مدل را جلو میبرد.
|
||||
* هیچ رکورد ``SMSTemplate`` را لمس نمیکند.
|
||||
|
||||
idempotent است؛ اجرای دوباره بیخطر است.
|
||||
"""
|
||||
from django.db import migrations, models
|
||||
|
||||
HELP_TEXT = (
|
||||
"متغیرهای قابل استفاده: {name} نام مشتری، {amount} مبلغ، "
|
||||
"{amount_sep} مبلغ با جداکننده، {date} تاریخ جلالی، {days} تعداد روز، "
|
||||
"{check_row} شماره ردیف چک، {sayyad_id} شناسه صیاد چک، "
|
||||
"{owner_name} نام مالک چک، {balance} مانده حساب مشتری، "
|
||||
"{balance_sep} مانده حساب با جداکننده. "
|
||||
"(توجه: {balance} مانده کل حساب است و با مبلغ سررسیدشدهٔ چک/نسیه "
|
||||
"که در {amount} میآید تفاوت دارد.)"
|
||||
)
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("admin_panel", "0076_alter_smstemplate_text_help"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name="smstemplate",
|
||||
name="text",
|
||||
field=models.TextField(help_text=HELP_TEXT, verbose_name="متن پیامک"),
|
||||
),
|
||||
]
|
||||
@@ -22,7 +22,35 @@ class VisitQueue(models.Model):
|
||||
|
||||
|
||||
class Action(models.Model):
|
||||
actionType = models.CharField(max_length=50, null=True, blank=True)
|
||||
"""اقدام/وظیفهٔ CRM مرتبط با مشتری.
|
||||
|
||||
``actionType`` فقط این شش مقدار را میپذیرد؛ همین شش مقدار در فرمهای پنل
|
||||
(``customerActionInc.html``) و در تمام مقایسههای کد (``== 'bazdid'``،
|
||||
``exclude(actionType='vosol')`` و …) استفاده میشوند.
|
||||
|
||||
``status`` نیز همان سه مقدارِ بهکاررفته در کد و قالبها را میپذیرد.
|
||||
املای ``'waite'`` عمداً حفظ شده است: ۲٫۷۱۹ رکورد موجودِ دیتابیس و تمام
|
||||
مقایسههای کد/قالب (``== 'waite'``، ``if filter_status == 'waite'``) با
|
||||
همین املا کار میکنند و تغییرش داده را از موتور جستوجو جدا میکند.
|
||||
"""
|
||||
|
||||
class ActionType(models.TextChoices):
|
||||
BAZDID = 'bazdid', 'بازدید'
|
||||
NASB = 'nasb', 'نصب'
|
||||
VOSOL = 'vosol', 'وصول مطالبات'
|
||||
HAMAHANGI = 'hamahangi', 'هماهنگی'
|
||||
IN_CALL = 'inCall', 'تماس ورودی'
|
||||
OUT_CALL = 'outCall', 'تماس خروجی'
|
||||
|
||||
class Status(models.TextChoices):
|
||||
# املا عیناً مطابق داده و کد فعلی است (نه 'wait').
|
||||
WAITE = 'waite', 'در انتظار (باز)'
|
||||
FINISH = 'finish', 'انجام شده'
|
||||
CANCELL = 'cancell', 'لغو شده'
|
||||
|
||||
actionType = models.CharField(
|
||||
max_length=50, null=True, blank=True, choices=ActionType.choices,
|
||||
)
|
||||
forUser = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True)
|
||||
customer = models.ForeignKey('Customer', related_name='actionrlt', on_delete=models.CASCADE, null=True, blank=True)
|
||||
createdDT = models.DateTimeField(auto_now_add=True)
|
||||
@@ -31,7 +59,9 @@ class Action(models.Model):
|
||||
finishDateTime = models.DateTimeField(null=True, blank=True)
|
||||
desc = models.CharField(max_length=500, null=True, blank=True)
|
||||
result = models.CharField(max_length=500, null=True, blank=True)
|
||||
status = models.CharField(max_length=50, null=True, blank=True)
|
||||
status = models.CharField(
|
||||
max_length=50, null=True, blank=True, choices=Status.choices,
|
||||
)
|
||||
nazar = models.CharField(max_length=50, null=True, blank=True, default=None)
|
||||
nextNazarDT = models.DateTimeField(null=True, blank=True, default=None)
|
||||
nazarDT = models.DateTimeField(null=True, blank=True, default=None)
|
||||
|
||||
@@ -154,7 +154,11 @@ class SMSTemplate(models.Model):
|
||||
verbose_name="متن پیامک",
|
||||
help_text="متغیرهای قابل استفاده: {name} نام مشتری، {amount} مبلغ، "
|
||||
"{amount_sep} مبلغ با جداکننده، {date} تاریخ جلالی، {days} تعداد روز، "
|
||||
"{check_row} شماره ردیف چک، {owner_name} نام مالک چک.",
|
||||
"{check_row} شماره ردیف چک، {sayyad_id} شناسه صیاد چک، "
|
||||
"{owner_name} نام مالک چک، {balance} مانده حساب مشتری، "
|
||||
"{balance_sep} مانده حساب با جداکننده. "
|
||||
"(توجه: {balance} مانده کل حساب است و با مبلغ سررسیدشدهٔ چک/نسیه "
|
||||
"که در {amount} میآید تفاوت دارد.)",
|
||||
)
|
||||
is_enabled = models.BooleanField(default=True, verbose_name="فعال")
|
||||
auto_send = models.BooleanField(
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
"""مانده حساب مشتری برای استفاده در قالبهای پیامک.
|
||||
|
||||
تعریف (همان قاعدهٔ صفحهٔ حسابداری مشتری و گزارش مالی)::
|
||||
|
||||
مانده حساب = مجموع بدهکار (debit) − مجموع بستانکار (credit)
|
||||
|
||||
نکتهٔ مهم — تفاوت با «مانده سررسیدشده»:
|
||||
|
||||
* **مانده حساب** (این ماژول): تراز کل همهٔ اسناد حسابداری مشتری (``Article``).
|
||||
منبع: ``admin_panel/models/finance.py::Article``.
|
||||
* **مانده/مبلغ سررسیدشده**: مبلغ چکها و نسیههای پرداختنشده در جدول
|
||||
``Sarresid`` (``payStatus='false'``). بسیار متفاوت از مانده حساب است و
|
||||
جای دیگری (``views/finance.py``) محاسبه میشود.
|
||||
|
||||
به همین دلیل این مقدار با کلید مستقل ``{balance}`` در قالبها منتشر میشود و
|
||||
هرگز با مبلغ سررسید (``{amount}`` در پیامک چک/نسیه) قاطی نمیشود.
|
||||
"""
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def customer_balance(customer):
|
||||
"""مانده حساب مشتری (``debit − credit``) بهصورت عدد صحیح.
|
||||
|
||||
اگر مشتری یا اسنادش وجود نداشته باشد ``0`` برمیگردد. هیچ استثنایی پرتاب
|
||||
نمیکند تا مسیر ساخت پیامک هرگز مختل نشود.
|
||||
"""
|
||||
if customer is None or getattr(customer, "pk", None) is None:
|
||||
return 0
|
||||
try:
|
||||
from django.db.models import Sum
|
||||
|
||||
from ..models import Article
|
||||
|
||||
agg = Article.objects.filter(customer=customer).aggregate(
|
||||
d=Sum("debit"), c=Sum("credit"),
|
||||
)
|
||||
debit = agg["d"] or 0
|
||||
credit = agg["c"] or 0
|
||||
return debit - credit
|
||||
except Exception:
|
||||
logger.exception("محاسبهٔ مانده حساب مشتری %s شکست خورد", customer.pk)
|
||||
return 0
|
||||
@@ -5,6 +5,7 @@ from uuid import uuid4
|
||||
from django.db import IntegrityError
|
||||
|
||||
from ..models import SMSDedup, SMSQueue, SMSTemplate, SMSType
|
||||
from .balance import customer_balance
|
||||
from .recipients import resolve_recipients
|
||||
from .render import render_template
|
||||
from .rules import is_sms_enabled
|
||||
@@ -22,6 +23,11 @@ def enqueue_sms(*, customer=None, sms_type, context=None, dedup_key=None,
|
||||
یا آزمایشی)، و ``SMSTemplate.auto_send`` که مدیر در صفحهٔ قالبها برای هر نوع
|
||||
پیامک روشن میکند تا پیامکهای خودکارِ اسکنر بدون صف تأیید ارسال شوند.
|
||||
|
||||
متغیرهای مشترکِ همهٔ قالبها (مثل ``{balance}`` = مانده حساب مشتری) همینجا و
|
||||
یکبار به ``context`` افزوده میشوند تا هر قالبی بتواند از آنها استفاده کند؛
|
||||
فراخوانها لازم نیست هر بار آنها را بسازند. اگر فراخوان خودش مقداری داده باشد
|
||||
(``context``) همان اولویت دارد.
|
||||
|
||||
هیچ استثنایی به فراخوان پرتاب نمیشود؛ خطاها فقط لاگ میشوند تا مسیر اصلی
|
||||
(مثلاً ایجاد مشتری یا اسکنر) هرگز بهخاطر پیامک مختل نشود.
|
||||
"""
|
||||
@@ -30,7 +36,10 @@ def enqueue_sms(*, customer=None, sms_type, context=None, dedup_key=None,
|
||||
template = SMSTemplate.objects.filter(sms_type=sms_type, is_enabled=True).first()
|
||||
if template is None:
|
||||
return 0
|
||||
message = render_template(template.text, context)
|
||||
ctx = dict(context or {})
|
||||
# متغیرهای سراسری قالبها؛ هرگز مقدار فراخوان را بازنویسی نمیکنند.
|
||||
ctx.setdefault("balance", customer_balance(customer))
|
||||
message = render_template(template.text, ctx)
|
||||
# «ارسال خودکار» هر نوع پیامک در صفحهٔ قالبها تعیین میشود؛ خاموش = بازبینی مدیر.
|
||||
approved = approved or template.auto_send
|
||||
|
||||
|
||||
@@ -3,11 +3,21 @@ from persiantools.jdatetime import JalaliDate, JalaliDateTime
|
||||
|
||||
|
||||
class _SafeDict(dict):
|
||||
"""دیکشنری که برای کلیدهای ناشناخته رشته خالی برمیگرداند (بدون خطا)."""
|
||||
"""دیکشنری امن برای ``str.format_map``.
|
||||
|
||||
* کلیدِ ناشناخته ⇒ رشتهٔ خالی (بدون ``KeyError``).
|
||||
* کلیدِ شناختهشده با مقدار ``None`` ⇒ رشتهٔ خالی. فیلدهای اختیاری مدل
|
||||
(مثل ``Sarresid.check_sayyad_id`` یا ``check_row_number``) ممکن است ``NULL``
|
||||
باشند؛ بدون این تبدیل، ``None`` عیناً در متن پیامک چاپ میشد.
|
||||
"""
|
||||
|
||||
def __missing__(self, key):
|
||||
return ""
|
||||
|
||||
def __getitem__(self, key):
|
||||
value = super().__getitem__(key) if key in self else ""
|
||||
return "" if value is None else value
|
||||
|
||||
|
||||
def format_amount(value):
|
||||
try:
|
||||
@@ -35,6 +45,10 @@ def render_template(text, context=None):
|
||||
ctx = dict(context or {})
|
||||
if "amount" in ctx:
|
||||
ctx.setdefault("amount_sep", format_amount(ctx["amount"]))
|
||||
if "balance" in ctx:
|
||||
# مثل «مبلغ»، نسخهٔ جداکنندهدار هم آماده میشود تا در قالبها
|
||||
# ``{balance_sep}`` در دسترس باشد (۳٬۵۰۰٬۰۰۰ → "3,500,000").
|
||||
ctx.setdefault("balance_sep", format_amount(ctx["balance"]))
|
||||
if "date" in ctx:
|
||||
ctx.setdefault("date_raw", ctx["date"])
|
||||
ctx["date"] = format_jalali(ctx["date"])
|
||||
|
||||
+23
-10
@@ -81,36 +81,49 @@ class _Budget:
|
||||
|
||||
|
||||
def scan_cheque_funding(today):
|
||||
"""یادآوری «تأمین موجودی چک» چند روز پس از سررسید چکِ پرداختنشده.
|
||||
"""یادآوری «تأمین موجودی چک» چند روز **پیش از** سررسید چکِ پرداختنشده.
|
||||
|
||||
چند روزِ پس از سررسید از قالب همین نوع (قابل تنظیم از پنل) خوانده میشود و مبلغ
|
||||
چک در متن قرار میگیرد. اگر چک پرداخت شود (``payStatus=true``) دیگر یادآوری
|
||||
نمیگیرد؛ ``dedup_key`` نیز مانع ارسال تکراری در اجراهای بعدی میشود. اگر اسکنر
|
||||
چند روز از دست برود، چکهای «معوقتر» هم واجد شرط میشوند تا یادآوری از دست نرود.
|
||||
تعداد روزِ *قبل* از سررسید از قالب همین نوع (``offset_days`` در دیتابیس،
|
||||
قابل ویرایش از پنل) خوانده میشود؛ مثلاً ``offset_days = 1`` یعنی یک روز پیش
|
||||
از سررسید پیامک میرود تا مشتری فرصت تأمین موجودی داشته باشد.
|
||||
|
||||
پنجرهٔ یادآوری از «سررسید − offset روز» باز میشود و تا خودِ سررسید ادامه
|
||||
دارد؛ پس اگر اسکنر چند روز از دست برود، یادآوری از دست نمیرود (چکهایی که
|
||||
سررسیدشان رسیده هم واجد شرط میمانند). اگر چک پرداخت شود
|
||||
(``payStatus=true``) دیگر یادآوری نمیگیرد؛ ``dedup_key`` نیز مانع ارسال
|
||||
تکراری در اجراهای بعدی میشود.
|
||||
"""
|
||||
template = _template(SMSType.CHEQUE_REGISTRATION)
|
||||
if template is None:
|
||||
return 0
|
||||
budget = _Budget(SMSProviderConfig.load())
|
||||
offset = template.offset_days or 0
|
||||
target = today - timedelta(days=offset)
|
||||
# پنجرهٔ یادآوری: از «سررسید − offset» تا «سررسید». یعنی فقط سررسیدهای
|
||||
# امروز تا offset روز آینده واجد شرطاند و مقادیر دورتر هنوز پیامکی نمیگیرند.
|
||||
# (سررسیدهای گذشته هم داخل شرط میمانند تا یک یادآوری از دست نرود.)
|
||||
window_end = today + timedelta(days=max(offset, 0))
|
||||
qs = Sarresid.objects.filter(
|
||||
type="check", payStatus="false", sarresidDT__date__lte=target,
|
||||
type="check", payStatus="false", sarresidDT__date__lte=window_end,
|
||||
).select_related("customer").order_by("sarresidDT")
|
||||
count = 0
|
||||
for s in qs:
|
||||
if not s.customer or not s.sarresidDT:
|
||||
continue
|
||||
# لحظهٔ باز شدن پنجرهٔ یادآوری = سررسید + offset روز.
|
||||
trigger = _aware(s.sarresidDT) + timedelta(days=offset)
|
||||
due = s.sarresidDT.date()
|
||||
# لحظهٔ باز شدن پنجرهٔ یادآوری = سررسید − offset روز.
|
||||
trigger = _aware(s.sarresidDT) - timedelta(days=offset)
|
||||
if not budget.can_send(trigger):
|
||||
continue
|
||||
days = (today - s.sarresidDT.date()).days
|
||||
# روزهای باقیمانده تا سررسید؛ اگر سررسید دورتر از پنجره باشد پیامک نمیرود.
|
||||
days = (due - today).days
|
||||
if days > offset:
|
||||
continue
|
||||
made = enqueue_sms(
|
||||
customer=s.customer, sms_type=SMSType.CHEQUE_REGISTRATION,
|
||||
context={
|
||||
"name": s.customer.name_family, "amount": s.price,
|
||||
"date": s.sarresidDT, "days": days, "check_row": s.check_row_number,
|
||||
"sayyad_id": s.check_sayyad_id, "owner_name": s.check_owner_name,
|
||||
},
|
||||
dedup_key=f"cheque_fund:{s.id}",
|
||||
)
|
||||
|
||||
@@ -27,11 +27,11 @@ TIMING = {
|
||||
"note": "بیدرنگ پس از ثبت فاکتور ارسال میشود؛ تنظیم زمانی ندارد.",
|
||||
},
|
||||
SMSType.CHEQUE_REGISTRATION: {
|
||||
"kind": AFTER_DUE,
|
||||
"kind": BEFORE_DUE,
|
||||
"field": "offset_days",
|
||||
"label": "چند روز پس از سررسید چک",
|
||||
"label": "چند روز قبل از سررسید چک",
|
||||
"default": 1,
|
||||
"note": "این تعداد روز پس از سررسید چکِ پرداختنشده، پیامک یادآوری "
|
||||
"note": "این تعداد روز پیش از سررسید چکِ پرداختنشده، پیامک یادآوری "
|
||||
"تأمین موجودی با مبلغ چک ارسال میشود.",
|
||||
},
|
||||
SMSType.VISIT: {
|
||||
|
||||
@@ -12,6 +12,7 @@ from persiantools.jdatetime import JalaliDate
|
||||
|
||||
from ..models import (Customer, PhoneNumber, ProductCategory, Product, Factor,
|
||||
FactorIteam, Article, Sarresid, Action, CacheTable)
|
||||
from ..sms.balance import customer_balance
|
||||
from ..sms.phones import (normalize_primary_values,
|
||||
save_primary_normalized)
|
||||
from ..sms.triggers import notify_payment_thanks, notify_welcome
|
||||
@@ -437,14 +438,13 @@ def customerDel(request, c_id):
|
||||
@login_required(login_url='/panel/p_login/')
|
||||
def customerHesabdari(request ,c_id):
|
||||
customer = Customer.objects.get(id=c_id)
|
||||
# مانده حساب از همان تابع مشترکی میآید که قالبهای پیامک استفاده میکنند تا
|
||||
# عددِ این صفحه و پیامک هرگز واگرا نشوند (منبع حقیقت: sms/balance.py).
|
||||
mandehesabCs = customer_balance(customer)
|
||||
try:
|
||||
debit = Article.objects.filter(customer=customer).aggregate(Sum('debit'))['debit__sum']
|
||||
credit = Article.objects.filter(customer=customer).aggregate(Sum('credit'))['credit__sum']
|
||||
mandehesabCs = debit - credit
|
||||
articls = Article.objects.filter(customer=customer).order_by('-createdDT')
|
||||
except:
|
||||
articls =None
|
||||
mandehesabCs = 0
|
||||
articls = None
|
||||
|
||||
dateNow = datetime.datetime.now().date
|
||||
data = {'customer': customer, 'mandehesabCs': mandehesabCs, 'articls': articls}
|
||||
|
||||
@@ -64,14 +64,17 @@ TEMPLATE_VARIABLES = [
|
||||
("{date}", "تاریخ جلالی"),
|
||||
("{days}", "تعداد روز"),
|
||||
("{check_row}", "شمارهٔ ردیف چک"),
|
||||
("{sayyad_id}", "شناسهٔ چک صیاد (۱۶ رقم)"),
|
||||
("{owner_name}", "نام مالک چک"),
|
||||
("{balance}", "مانده حساب مشتری (بدهکار − بستانکار)"),
|
||||
("{balance_sep}", "مانده حساب با جداکنندهٔ هزارگان"),
|
||||
]
|
||||
|
||||
# فقط برای نمایش: آیکن و توضیح کوتاه «چه زمانی ارسال میشود» هر نوع (لایهٔ UI، نه دامنه).
|
||||
SMS_TYPE_UI = {
|
||||
SMSType.WELCOME: {"icon": "👋", "when": "بیدرنگ پس از ثبت مشتری"},
|
||||
SMSType.SURVEY: {"icon": "⭐", "when": "بیدرنگ پس از ثبت فاکتور"},
|
||||
SMSType.CHEQUE_REGISTRATION: {"icon": "🧾", "when": "چند روز پس از سررسید چک"},
|
||||
SMSType.CHEQUE_REGISTRATION: {"icon": "🧾", "when": "چند روز پیش از سررسید چک"},
|
||||
SMSType.VISIT: {"icon": "🔧", "when": "پس از گذشت دورهٔ بازدید دستگاه"},
|
||||
SMSType.VISIT_CREATED: {"icon": "📅", "when": "پس از ثبت اقدام بازدید"},
|
||||
SMSType.PAYMENT_THANKS: {"icon": "🙏", "when": "پس از ثبت پرداخت"},
|
||||
@@ -86,7 +89,10 @@ SAMPLE_CONTEXT = {
|
||||
"date": None, # در زمان ساخت ویو با تاریخ امروز پر میشود
|
||||
"days": 2,
|
||||
"check_row": "1234",
|
||||
"sayyad_id": "1234567890123456",
|
||||
"owner_name": "نام مالک",
|
||||
"balance": 3500000,
|
||||
"balance_sep": "3,500,000",
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -2,117 +2,117 @@
|
||||
"0": "views/sms.py",
|
||||
"1": "run_all",
|
||||
"2": "django_db",
|
||||
"3": "views/store.py",
|
||||
"3": "create_transfer_request",
|
||||
"4": "ModelsPackageContractTests",
|
||||
"5": "PhoneCleanupTests",
|
||||
"6": ".load",
|
||||
"7": "models/sms.py",
|
||||
"8": "logging",
|
||||
"8": "models/__init__.py",
|
||||
"9": "views/customers.py",
|
||||
"10": "django_db_models_deletion",
|
||||
"10": "django_conf",
|
||||
"11": "make_customer",
|
||||
"12": "customer_phone_entries",
|
||||
"12": "resolve_recipients",
|
||||
"13": "EventTriggerTests",
|
||||
"14": "views/finance.py",
|
||||
"15": "SMSResult",
|
||||
"15": "views/store.py",
|
||||
"16": "sms0098ws.py",
|
||||
"17": "Admin Panel Customization",
|
||||
"18": "User",
|
||||
"19": "django_conf",
|
||||
"20": "test_customers.py",
|
||||
"19": "timing_for",
|
||||
"20": "Customer",
|
||||
"21": "phones.py",
|
||||
"22": "Login Template Forms",
|
||||
"23": "cheque_inquiry.py",
|
||||
"24": "factories.py",
|
||||
"25": "Rip'n Fast. Fewer Tokens. Better Code.",
|
||||
"26": "views/factors.py",
|
||||
"27": "to_local",
|
||||
"27": "sms0098.py",
|
||||
"28": "make_user",
|
||||
"29": "QueueReviewTests",
|
||||
"30": "NoticeMechanismTests",
|
||||
"31": "enqueue.py",
|
||||
"32": "enqueue_sms",
|
||||
"33": "PanelTestCase",
|
||||
"31": "SmsReportTests",
|
||||
"32": "scanner.py",
|
||||
"33": "ZeroZeroNinetyEightWebServiceTests",
|
||||
"34": "ProductInStore",
|
||||
"35": "admin_panel/templates/admin_panel/baseHesabdari.html",
|
||||
"36": "Reference guide",
|
||||
"37": "Factor Creation UI",
|
||||
"38": "admin_panel/templates/admin_panel/bedehi.html",
|
||||
"39": "project_tree.py",
|
||||
"38": "hesabdariResidNashode.html",
|
||||
"39": "requests",
|
||||
"40": "CustomerSmsHistoryTests",
|
||||
"41": "TemplatesPageUITests",
|
||||
"42": "SMS Integration Docs",
|
||||
"43": "timing_for",
|
||||
"43": "enqueue.py",
|
||||
"44": "django_shortcuts",
|
||||
"45": "stock_in",
|
||||
"46": "admin_panel/templates/admin_panel/customerAction.html",
|
||||
"47": "parts_count",
|
||||
"48": "write_tree",
|
||||
"49": "CustomerInfoCardUITests",
|
||||
"50": "Customer",
|
||||
"50": "test_sms.py",
|
||||
"51": "Phone Cleanup Guide",
|
||||
"52": "SmsReportTests",
|
||||
"53": "manage.py",
|
||||
"52": ".run_command",
|
||||
"53": "project_tree.py",
|
||||
"54": "Agent Operating Guidelines",
|
||||
"55": "SMSDeliveryCommandTests",
|
||||
"55": "Command",
|
||||
"56": "BehinSMSProvider",
|
||||
"57": "test_sms.py",
|
||||
"57": "normalize_mobile",
|
||||
"58": "Financial Data Objects",
|
||||
"59": "Hybrid Migration Command",
|
||||
"60": "بازمحاسبهٔ «آخرین بازدید» مشتریان",
|
||||
"60": ".run_cmd",
|
||||
"61": "Resource Cleanup Handler",
|
||||
"62": "SMS Timing Migration",
|
||||
"63": "Articl Model",
|
||||
"63": "admin_panel/templates/admin_panel/bedehi.html",
|
||||
"64": "customerIDFactorBackup.html",
|
||||
"65": "test_factors.py",
|
||||
"66": "os",
|
||||
"65": "bale/providers.py",
|
||||
"66": "asgi.py",
|
||||
"67": "Graphify Tooling Docs",
|
||||
"68": "django_urls",
|
||||
"69": "0063_alter_smsqueue_status.py",
|
||||
"68": "Command",
|
||||
"69": "ZeroZeroNinetyEightLinkTests",
|
||||
"70": "SMS Template Seeding",
|
||||
"71": "admin_panel/entezar.html",
|
||||
"72": "customerNewBackup.html",
|
||||
"73": "hesabdariResidNashode.html",
|
||||
"73": "SMSResult",
|
||||
"74": "0070_sms_types_seven.py",
|
||||
"75": "Endpoint Smoke Tests",
|
||||
"76": "Timezone Migration History",
|
||||
"77": "models/__init__.py",
|
||||
"78": "UrlContractTests",
|
||||
"77": "Command",
|
||||
"78": "django_urls",
|
||||
"79": "Brand Scrubbing Migration",
|
||||
"80": "SMS Dedup Migration",
|
||||
"81": "Installation Guide",
|
||||
"82": "Project Honesty Contract",
|
||||
"83": "Flow Control Migration",
|
||||
"84": "Permission Label Migration",
|
||||
"85": "stop.sh",
|
||||
"85": "IntegrationAndEfficiencyTests",
|
||||
"86": "Output Format Specs",
|
||||
"87": "Performance Benchmarks",
|
||||
"88": "SMS Integration Overview",
|
||||
"89": "System Cache Table",
|
||||
"89": "CustomerNameFixJob",
|
||||
"90": "Customer Modal UI",
|
||||
"91": "SentQueueProtectionTests",
|
||||
"91": "PanelTestCase",
|
||||
"92": "Infrastructure Services",
|
||||
"93": "Agent Setup Guide",
|
||||
"94": "First Use Guide",
|
||||
"95": "0056_auto_20260731_1824.py",
|
||||
"96": "0009_remove_storeroom_user.py",
|
||||
"97": "PhoneEntry",
|
||||
"98": "reconciliation_tool.py",
|
||||
"99": "announcements.py",
|
||||
"100": "pathlib",
|
||||
"95": "ConsoleSMSProvider",
|
||||
"96": "PhoneNumber",
|
||||
"97": "تجمیع شمارههای پیامک مشتریان",
|
||||
"98": "Command",
|
||||
"99": "Base Template",
|
||||
"100": "test_customer_name_fix.py",
|
||||
"101": "Command",
|
||||
"102": "0064_sms_webservice_delivery.py",
|
||||
"103": "0040_customer_laghv_bazdid.py",
|
||||
"104": "0068_auto_20261010_1305.py",
|
||||
"105": "0069_smstemplate_auto_send.py",
|
||||
"106": "0047_alter_productinstore_movement_type.py",
|
||||
"107": "Command",
|
||||
"102": "customer_phone_entries",
|
||||
"103": "manage.py",
|
||||
"104": "افزودن پیشوند «آقای/خانم» به نام مشتریان",
|
||||
"105": "بازمحاسبهٔ «آخرین بازدید» مشتریان",
|
||||
"106": "QueueStatsTests",
|
||||
"107": "admin_panel/apps.py",
|
||||
"108": "SMS Domain Logic",
|
||||
"109": "Customer Communication Partials",
|
||||
"110": "SMS Template Management",
|
||||
"111": "Documentation and Graphing",
|
||||
"112": "Admin Migration Package",
|
||||
"113": "bale/providers.py",
|
||||
"113": "primary_phones",
|
||||
"114": "Customer Action Templates",
|
||||
"115": "Customer Feedback Components",
|
||||
"116": "Customer Invoice Details",
|
||||
@@ -152,6 +152,7 @@
|
||||
"150": "Transfer Processing Endpoint",
|
||||
"151": "Satisfaction Edit Endpoint",
|
||||
"152": "Customer Deletion Endpoint",
|
||||
"153": "HttpProviderRobustnessTests",
|
||||
"154": "Django Permissions System",
|
||||
"155": "Static Asset Management",
|
||||
"156": "Data Cleanup Documentation",
|
||||
@@ -161,13 +162,25 @@
|
||||
"160": "Khatibi Custom Module",
|
||||
"161": "Project Dependencies",
|
||||
"162": "Test Suite Package",
|
||||
"164": "QueueStatsTests",
|
||||
"166": "sms_settings",
|
||||
"163": "Customer",
|
||||
"164": "SMSQueue",
|
||||
"165": "signals.py",
|
||||
"166": "توقف و ادامه (Resume / Checkpoint)",
|
||||
"167": "Command",
|
||||
"168": "0071_sms_settings_permission.py",
|
||||
"169": "index",
|
||||
"172": "0017_factoriteam_garantyesh.py",
|
||||
"173": "0028_action_grade.py",
|
||||
"174": "0034_alter_article_sarresid.py",
|
||||
"175": "0039_customer_last_bazdid_dt.py"
|
||||
"170": "الگوریتم تصمیم (به همین ترتیب)",
|
||||
"171": "سریعترین مسیر روی Production (خلاصهٔ اجرایی)",
|
||||
"172": "models/customers.py",
|
||||
"173": "stop.sh",
|
||||
"174": "SMSDedup",
|
||||
"175": "rules.py",
|
||||
"176": "اجرای محلی (توسعه)",
|
||||
"177": "Factor",
|
||||
"178": "اجرا روی سرور Production",
|
||||
"179": "اجرای محلی (توسعه)",
|
||||
"180": "ادامهٔ job پس از crash / قطع برق",
|
||||
"181": "اجرا روی سرور Production",
|
||||
"182": "wsgi.py",
|
||||
"189": "django_contrib_auth_models"
|
||||
}
|
||||
@@ -1 +1 @@
|
||||
{"0": "41d4c54b2ed9be31", "1": "b3e9db47e46c8950", "2": "c23f6f22b3532a57", "3": "44c42f7cbafe0d72", "4": "a480b4d6afdb4d1b", "5": "a8d6a179fdf0eb6f", "6": "3bd1354c22863397", "7": "88c19438cd72b3dd", "8": "15ca8060fedfc22d", "9": "274a49fd42c1a00e", "10": "58991daa10bb40c9", "11": "892dbef1deee47a9", "12": "f30060e6c2359aa4", "13": "96ec15fbcfe2d27a", "14": "05fc19ac0daa7b6c", "15": "7fe7625f0e064fdb", "16": "60b1fcd46cba604e", "17": "9eec9953ee3ca67f", "18": "dd5464972fce7e01", "19": "1f155e80fa7aa135", "20": "5c5477821216359a", "21": "13d087c92ddf57ef", "22": "9701f1591d8fda6e", "23": "7cd46ce4c8fb3ca4", "24": "d0b49ec6ae8ee7a4", "25": "75866dc8db907971", "26": "c578cf70cb6202fa", "27": "5c3fd3713dd960e8", "28": "1f2e16b5709d3936", "29": "1e9c1fa6fabde0d3", "30": "627dae19704f40f5", "31": "a5bd616f03cdbec3", "32": "ba49af147f38b69e", "33": "509eeabd8a23e031", "34": "f5248661c2005b5a", "35": "e091859c108d6145", "36": "4e9567703b727de7", "37": "d36df3c85181f806", "38": "b9fa892721272dc1", "39": "219b01f43ec5f76d", "40": "89444f5d51189c99", "41": "8c2e4ed6cd161bf3", "42": "bbd8a9066e48dada", "43": "781d0380d9314204", "44": "159d7e82897e35fc", "45": "0827f8a8bc343f88", "46": "a2f2be073f6f5bb9", "47": "8fd5a6f3cd5970b9", "48": "9d46bbe4641a8543", "49": "7bc001888a685a2a", "50": "dc8e4b85d8dd63ea", "51": "afc6d855b9fc1b76", "52": "11d769da5f6dd93e", "53": "3ec6277e63307488", "54": "34401beb9f60ebfd", "55": "054037b18f80b80c", "56": "330644cc56a0e06c", "57": "a3022e2d8c68315c", "58": "90146abe85d9419f", "59": "88f880da5a61f9dc", "60": "69bb788e4cabbf39", "61": "dbfbf8557361f5ea", "62": "6e90b41fbd82c265", "63": "bf2566d91998d2e4", "64": "8ff365aee1c1a767", "65": "120dc3cc659bbc4a", "66": "41c8f6c33d904f01", "67": "0f632fc57e9feeb0", "68": "2db67510f080898c", "69": "84208a7b8507da66", "70": "df7ea8ce3fa52be3", "71": "7db54a3d7ae0017c", "72": "aea8fc3ff351253f", "73": "af89b22ae0662d6d", "74": "a534e43d03671a7c", "75": "5290f7a7558a9c3e", "76": "a19c211702401a5b", "77": "7f4cbca34cc36f61", "78": "0f4a56d55e3925dc", "79": "da683f642f8c61ac", "80": "40313433c93b7054", "81": "81af0a28b68936d9", "82": "25287261c3d1c44b", "83": "bda9be183e0f933e", "84": "63526d01888c4f22", "85": "827420b645a55301", "86": "694a38d63caf7217", "87": "f220eaa4fac26e3e", "88": "d78c8e21a45613e9", "89": "c5743041b2101132", "90": "03f8896e9b60ca96", "91": "a06651e191a4aa22", "92": "4bfa64a1cd8c6a47", "93": "057eae5a523d2004", "94": "5de74655cbc56e06", "95": "cfbcf8cef78c5757", "96": "a1a1f3c1cdff72cf", "97": "72fca8ce97e3eeee", "98": "2ae07d5b9790c230", "99": "4793efd518dcb021", "100": "1b94d53a14e88aa3", "101": "35aa0fc2a0626f70", "102": "cb48fd8d430ac66e", "103": "ef8221c5fdeee7f8", "104": "9144923ab31b52a3", "105": "a2eea51406c7d4fc", "106": "b5ce3fce9192f8b8", "107": "7508d3e84c588617", "108": "b738c5aefe939cff", "109": "d2001d7d283134ac", "110": "6b8e6100893a6b6a", "111": "66ed76491a412a72", "112": "e67668b62ee6c62c", "113": "7b932cfef527d130", "114": "68aee39cd24db354", "115": "054401d27ffaa4b2", "116": "dace81c1995fb321", "117": "19e301aeace95bb2", "118": "d6fd0cec4634a0b0", "119": "0230d355a6dabb54", "120": "5cebbb5528321795", "121": "536fe28d24c361f5", "122": "b08bdc2712cb0f12", "123": "6ce8444f504022cc", "124": "8021f52559633383", "125": "d8e34a3b3eb43ee0", "126": "171c34c74a95481b", "127": "73e9eca6f2ca1c9b", "128": "dcc2230ae751c29a", "129": "2a617b932f5d92b2", "130": "d55cb638532fdfeb", "131": "06cae4389208269f", "132": "e9c0a7be255e9b26", "133": "455b4ca39e55ecb0", "134": "8105c55538c34081", "135": "74304670b54c018f", "136": "a27f876eabb044b2", "137": "73f74dd7a40776d6", "138": "29d433d164b99f89", "139": "3f44aa48aa05d597", "140": "ca8a7efba0a3e579", "141": "5cc770af9d184d77", "142": "2d31fa723128b164", "143": "be720fc0071f0c3d", "144": "9d814c2520329846", "145": "f97d1a5c3a066598", "146": "14f84a6e4cd311d6", "147": "3a592d27b1f4ccc9", "148": "0bf6f9d0aeab4fd8", "149": "8b491bb3ff0649dd", "150": "638812cee15d1b9b", "151": "3dd16d68928a479c", "152": "03a0ee43e18f7934", "154": "435331945d6aad17", "155": "968e1a135dc062b7", "156": "d1a987a548e55a76", "157": "a9bf69b3d550abef", "158": "b039e1c69c8fb7b9", "159": "60029bf0948fc02a", "160": "72dad91d66d471ce", "161": "353a9d09eaae47ea", "162": "43bbf35b96423d46", "164": "825ba1cf2cfa5500", "166": "9fee6d982ee873a6", "167": "ce80aac5f4c439da", "168": "1abe2e7b0bcbeca9", "169": "ce5f237abed01c9e", "172": "a800ecffc01fc9d5", "173": "edb619bf5ac0fc49", "174": "c02bc9595eaedd36", "175": "52502a4c1ef75ce6"}
|
||||
{"0": "038518c7d9194bab", "1": "06dae62b458fc666", "2": "f61ab1111a89fc50", "3": "e61c3927bdba862c", "4": "11012e19786f67ca", "5": "22b97ba625f8378b", "6": "65060bb181af0bf2", "7": "3ce7acc47ea68c9f", "8": "fabc1e3307709f1a", "9": "123d258529fa9882", "10": "237c411f20dd22bb", "11": "fee454d62d24fd21", "12": "a62dcf8197187c85", "13": "96ec15fbcfe2d27a", "14": "9547a4a3dbac41ac", "15": "499026e81d8e6a05", "16": "1b80b390c6d35082", "17": "9eec9953ee3ca67f", "18": "f04ceeae6fdfe7c6", "19": "781d0380d9314204", "20": "895beea340408433", "21": "1e32348234be9dd4", "22": "9701f1591d8fda6e", "23": "8f0f51ff611eb425", "24": "102a0c450b7cb6b3", "25": "75866dc8db907971", "26": "b6a24d75ed17d59c", "27": "9b6b55a8d8dcb4c4", "28": "1f2e16b5709d3936", "29": "1e9c1fa6fabde0d3", "30": "627dae19704f40f5", "31": "11d769da5f6dd93e", "32": "9f3159f2dae4ab4f", "33": "8794530c7ccb06cb", "34": "4864a4651499f51b", "35": "0928f3aa4e597117", "36": "4e9567703b727de7", "37": "d36df3c85181f806", "38": "bc695fcee2050806", "39": "3557c20b0ad29e99", "40": "89444f5d51189c99", "41": "8c2e4ed6cd161bf3", "42": "bbd8a9066e48dada", "43": "6378ca56250cfe26", "44": "00d4d9fc79267971", "45": "a7e9b25451da94c4", "46": "f38c1f1dc0ead50f", "47": "8fd5a6f3cd5970b9", "48": "9d46bbe4641a8543", "49": "7bc001888a685a2a", "50": "4c34de7757ef1e08", "51": "afc6d855b9fc1b76", "52": "e9a7c031e64eeadb", "53": "afa933e731f6344a", "54": "34401beb9f60ebfd", "55": "05213eed8eed2d6f", "56": "330644cc56a0e06c", "57": "20956521d16ce674", "58": "90146abe85d9419f", "59": "88f880da5a61f9dc", "60": "f723d0b8f5c4997b", "61": "dbfbf8557361f5ea", "62": "6e90b41fbd82c265", "63": "6af26e59b0e8c354", "64": "8ae1cb991df55ba5", "65": "7b932cfef527d130", "66": "e0d0013fbf063aa4", "67": "0f632fc57e9feeb0", "68": "92d7e4efe25770db", "69": "7650c66736fc59da", "70": "df7ea8ce3fa52be3", "71": "fd47ef3914adf11e", "72": "9b3249f4a4e6fbfe", "73": "e00f9e12dd9fb95f", "74": "a534e43d03671a7c", "75": "5290f7a7558a9c3e", "76": "a19c211702401a5b", "77": "35aa0fc2a0626f70", "78": "3100956d3076c59f", "79": "da683f642f8c61ac", "80": "40313433c93b7054", "81": "81af0a28b68936d9", "82": "25287261c3d1c44b", "83": "bda9be183e0f933e", "84": "63526d01888c4f22", "85": "e5577b2d90500462", "86": "694a38d63caf7217", "87": "f220eaa4fac26e3e", "88": "d78c8e21a45613e9", "89": "8cb58c63b0d606b1", "90": "03f8896e9b60ca96", "91": "50363e32255931f4", "92": "4bfa64a1cd8c6a47", "93": "057eae5a523d2004", "94": "5de74655cbc56e06", "95": "b8ea4a512b424113", "96": "e0d3010c0e1a9d7a", "97": "de6816239e70e6e8", "98": "7508d3e84c588617", "99": "15f6a40009e539bb", "100": "ed5eb60fa9b1adb6", "101": "4b7f81f0e7e4c044", "102": "24252b994a79d741", "103": "85ecb40ed558ed43", "104": "756a405f723988ce", "105": "e618d1b582eac9a5", "106": "825ba1cf2cfa5500", "107": "6c05d0c0a89d1816", "108": "b738c5aefe939cff", "109": "d2001d7d283134ac", "110": "6b8e6100893a6b6a", "111": "66ed76491a412a72", "112": "e67668b62ee6c62c", "113": "800f5b95a2eac8d1", "114": "68aee39cd24db354", "115": "054401d27ffaa4b2", "116": "dace81c1995fb321", "117": "19e301aeace95bb2", "118": "d6fd0cec4634a0b0", "119": "0230d355a6dabb54", "120": "5cebbb5528321795", "121": "536fe28d24c361f5", "122": "b08bdc2712cb0f12", "123": "6ce8444f504022cc", "124": "8021f52559633383", "125": "d8e34a3b3eb43ee0", "126": "171c34c74a95481b", "127": "73e9eca6f2ca1c9b", "128": "dcc2230ae751c29a", "129": "2a617b932f5d92b2", "130": "d55cb638532fdfeb", "131": "06cae4389208269f", "132": "e9c0a7be255e9b26", "133": "455b4ca39e55ecb0", "134": "8105c55538c34081", "135": "74304670b54c018f", "136": "a27f876eabb044b2", "137": "73f74dd7a40776d6", "138": "29d433d164b99f89", "139": "3f44aa48aa05d597", "140": "ca8a7efba0a3e579", "141": "5cc770af9d184d77", "142": "2d31fa723128b164", "143": "be720fc0071f0c3d", "144": "9d814c2520329846", "145": "f97d1a5c3a066598", "146": "14f84a6e4cd311d6", "147": "3a592d27b1f4ccc9", "148": "0bf6f9d0aeab4fd8", "149": "8b491bb3ff0649dd", "150": "638812cee15d1b9b", "151": "3dd16d68928a479c", "152": "03a0ee43e18f7934", "153": "60e9520e0a9facae", "154": "435331945d6aad17", "155": "968e1a135dc062b7", "156": "d1a987a548e55a76", "157": "a9bf69b3d550abef", "158": "b039e1c69c8fb7b9", "159": "60029bf0948fc02a", "160": "72dad91d66d471ce", "161": "353a9d09eaae47ea", "162": "43bbf35b96423d46", "163": "742c12886e57d4fa", "164": "6b4bf464232edaa0", "165": "d0c2310f7d93caf6", "166": "bca6f6760a942d10", "167": "ce80aac5f4c439da", "168": "1abe2e7b0bcbeca9", "169": "ce5f237abed01c9e", "170": "c9f25e20d3a7d5d8", "171": "7e818e8715c414bd", "172": "22f3057d405a4f06", "173": "827420b645a55301", "174": "adfc2fda7e4fc28a", "175": "59ba9ce54759cbf2", "176": "adac855b05ea55ee", "177": "6ba88c862239632d", "178": "c67bd11d1973d6ac", "179": "63c999649e523e73", "180": "56f7f3573c34f651", "181": "f8f5346df7d0a239", "182": "9c5614d4fee3efc0", "189": "36b8b06281e0571e"}
|
||||
+298
-201
@@ -1,17 +1,17 @@
|
||||
# Graph Report - khatibi (2026-10-11)
|
||||
# Graph Report - khatibi (2026-10-16)
|
||||
|
||||
## Corpus Check
|
||||
- 182 files · ~145,325 words
|
||||
- 193 files · ~286,477 words
|
||||
- Verdict: corpus is large enough that graph structure adds value.
|
||||
- Unclassified: 8 file(s) not represented in the graph (top: (none) 5, .env 2, .csv 1)
|
||||
|
||||
## Summary
|
||||
- 1684 nodes · 3008 edges · 171 communities (74 shown, 97 thin omitted)
|
||||
- Extraction: 95% EXTRACTED · 5% INFERRED · 0% AMBIGUOUS · INFERRED: 151 edges (avg confidence: 0.89)
|
||||
- 1960 nodes · 3584 edges · 184 communities (95 shown, 89 thin omitted)
|
||||
- Extraction: 95% EXTRACTED · 5% INFERRED · 0% AMBIGUOUS · INFERRED: 188 edges (avg confidence: 0.89)
|
||||
- Token cost: 0 input · 0 output
|
||||
|
||||
## Graph Freshness
|
||||
- Built from commit: `1dea3509`
|
||||
- Built from commit: `7e5c83be`
|
||||
- Run `git rev-parse HEAD` and compare to check if the graph is stale.
|
||||
- Run `graphify update .` after code changes (no API cost).
|
||||
|
||||
@@ -19,113 +19,114 @@
|
||||
- views/sms.py
|
||||
- run_all
|
||||
- django_db
|
||||
- views/store.py
|
||||
- create_transfer_request
|
||||
- ModelsPackageContractTests
|
||||
- PhoneCleanupTests
|
||||
- .load
|
||||
- models/sms.py
|
||||
- logging
|
||||
- models/__init__.py
|
||||
- views/customers.py
|
||||
- django_db_models_deletion
|
||||
- django_conf
|
||||
- make_customer
|
||||
- customer_phone_entries
|
||||
- resolve_recipients
|
||||
- EventTriggerTests
|
||||
- views/finance.py
|
||||
- SMSResult
|
||||
- views/store.py
|
||||
- sms0098ws.py
|
||||
- Admin Panel Customization
|
||||
- User
|
||||
- django_conf
|
||||
- test_customers.py
|
||||
- timing_for
|
||||
- Customer
|
||||
- phones.py
|
||||
- Login Template Forms
|
||||
- cheque_inquiry.py
|
||||
- factories.py
|
||||
- Rip'n Fast. Fewer Tokens. Better Code.
|
||||
- views/factors.py
|
||||
- to_local
|
||||
- sms0098.py
|
||||
- make_user
|
||||
- QueueReviewTests
|
||||
- NoticeMechanismTests
|
||||
- enqueue.py
|
||||
- enqueue_sms
|
||||
- PanelTestCase
|
||||
- SmsReportTests
|
||||
- scanner.py
|
||||
- ZeroZeroNinetyEightWebServiceTests
|
||||
- ProductInStore
|
||||
- admin_panel/templates/admin_panel/baseHesabdari.html
|
||||
- Reference guide
|
||||
- Factor Creation UI
|
||||
- admin_panel/templates/admin_panel/bedehi.html
|
||||
- project_tree.py
|
||||
- hesabdariResidNashode.html
|
||||
- requests
|
||||
- CustomerSmsHistoryTests
|
||||
- TemplatesPageUITests
|
||||
- SMS Integration Docs
|
||||
- timing_for
|
||||
- enqueue.py
|
||||
- django_shortcuts
|
||||
- stock_in
|
||||
- admin_panel/templates/admin_panel/customerAction.html
|
||||
- parts_count
|
||||
- write_tree
|
||||
- CustomerInfoCardUITests
|
||||
- Customer
|
||||
- Phone Cleanup Guide
|
||||
- SmsReportTests
|
||||
- manage.py
|
||||
- Agent Operating Guidelines
|
||||
- SMSDeliveryCommandTests
|
||||
- BehinSMSProvider
|
||||
- test_sms.py
|
||||
- Phone Cleanup Guide
|
||||
- .run_command
|
||||
- project_tree.py
|
||||
- Agent Operating Guidelines
|
||||
- Command
|
||||
- BehinSMSProvider
|
||||
- normalize_mobile
|
||||
- Financial Data Objects
|
||||
- Hybrid Migration Command
|
||||
- بازمحاسبهٔ «آخرین بازدید» مشتریان
|
||||
- .run_cmd
|
||||
- Resource Cleanup Handler
|
||||
- SMS Timing Migration
|
||||
- Articl Model
|
||||
- admin_panel/templates/admin_panel/bedehi.html
|
||||
- customerIDFactorBackup.html
|
||||
- test_factors.py
|
||||
- os
|
||||
- bale/providers.py
|
||||
- Graphify Tooling Docs
|
||||
- 0063_alter_smsqueue_status.py
|
||||
- Command
|
||||
- ZeroZeroNinetyEightLinkTests
|
||||
- SMS Template Seeding
|
||||
- admin_panel/entezar.html
|
||||
- customerNewBackup.html
|
||||
- hesabdariResidNashode.html
|
||||
- SMSResult
|
||||
- 0070_sms_types_seven.py
|
||||
- Endpoint Smoke Tests
|
||||
- Timezone Migration History
|
||||
- models/__init__.py
|
||||
- UrlContractTests
|
||||
- Command
|
||||
- django_urls
|
||||
- Brand Scrubbing Migration
|
||||
- SMS Dedup Migration
|
||||
- Installation Guide
|
||||
- Project Honesty Contract
|
||||
- Flow Control Migration
|
||||
- Permission Label Migration
|
||||
- stop.sh
|
||||
- IntegrationAndEfficiencyTests
|
||||
- Output Format Specs
|
||||
- Performance Benchmarks
|
||||
- SMS Integration Overview
|
||||
- System Cache Table
|
||||
- CustomerNameFixJob
|
||||
- Customer Modal UI
|
||||
- SentQueueProtectionTests
|
||||
- PanelTestCase
|
||||
- Infrastructure Services
|
||||
- Agent Setup Guide
|
||||
- First Use Guide
|
||||
- 0056_auto_20260731_1824.py
|
||||
- 0009_remove_storeroom_user.py
|
||||
- PhoneEntry
|
||||
- reconciliation_tool.py
|
||||
- announcements.py
|
||||
- ConsoleSMSProvider
|
||||
- PhoneNumber
|
||||
- تجمیع شمارههای پیامک مشتریان
|
||||
- Command
|
||||
- 0064_sms_webservice_delivery.py
|
||||
- 0040_customer_laghv_bazdid.py
|
||||
- 0068_auto_20261010_1305.py
|
||||
- 0069_smstemplate_auto_send.py
|
||||
- 0047_alter_productinstore_movement_type.py
|
||||
- Base Template
|
||||
- test_customer_name_fix.py
|
||||
- Command
|
||||
- customer_phone_entries
|
||||
- manage.py
|
||||
- افزودن پیشوند «آقای/خانم» به نام مشتریان
|
||||
- بازمحاسبهٔ «آخرین بازدید» مشتریان
|
||||
- QueueStatsTests
|
||||
- admin_panel/apps.py
|
||||
- Customer Communication Partials
|
||||
- SMS Template Management
|
||||
- Documentation and Graphing
|
||||
- bale/providers.py
|
||||
- primary_phones
|
||||
- Customer Action Templates
|
||||
- Customer Feedback Components
|
||||
- Customer Invoice Details
|
||||
@@ -155,41 +156,53 @@
|
||||
- Store Transfer Interface
|
||||
- Store Directory Template
|
||||
- Currency Formatting Utility
|
||||
- HttpProviderRobustnessTests
|
||||
- Data Cleanup Documentation
|
||||
- Project Dependencies
|
||||
- QueueStatsTests
|
||||
- sms_settings
|
||||
- Customer
|
||||
- SMSQueue
|
||||
- signals.py
|
||||
- توقف و ادامه (Resume / Checkpoint)
|
||||
- Command
|
||||
- 0071_sms_settings_permission.py
|
||||
- index
|
||||
- 0017_factoriteam_garantyesh.py
|
||||
- 0028_action_grade.py
|
||||
- 0034_alter_article_sarresid.py
|
||||
- 0039_customer_last_bazdid_dt.py
|
||||
- الگوریتم تصمیم (به همین ترتیب)
|
||||
- سریعترین مسیر روی Production (خلاصهٔ اجرایی)
|
||||
- models/customers.py
|
||||
- stop.sh
|
||||
- SMSDedup
|
||||
- rules.py
|
||||
- اجرای محلی (توسعه)
|
||||
- Factor
|
||||
- اجرا روی سرور Production
|
||||
- اجرای محلی (توسعه)
|
||||
- ادامهٔ job پس از crash / قطع برق
|
||||
- اجرا روی سرور Production
|
||||
- django_contrib_auth_models
|
||||
|
||||
## God Nodes (most connected - your core abstractions)
|
||||
1. `make_customer()` - 70 edges
|
||||
1. `make_customer()` - 89 edges
|
||||
2. `make_user()` - 28 edges
|
||||
3. `run_all()` - 24 edges
|
||||
4. `enqueue_sms()` - 23 edges
|
||||
5. `SMSResult` - 23 edges
|
||||
6. `Rip'n Fast. Fewer Tokens. Better Code.` - 23 edges
|
||||
7. `User` - 22 edges
|
||||
8. `create_transfer_request()` - 22 edges
|
||||
9. `normalize_mobile()` - 22 edges
|
||||
10. `SMSProvider` - 21 edges
|
||||
3. `normalize_mobile()` - 27 edges
|
||||
4. `Customer` - 24 edges
|
||||
5. `PhoneNumber` - 24 edges
|
||||
6. `Command` - 24 edges
|
||||
7. `run_all()` - 24 edges
|
||||
8. `enqueue_sms()` - 23 edges
|
||||
9. `SMSResult` - 23 edges
|
||||
10. `Rip'n Fast. Fewer Tokens. Better Code.` - 23 edges
|
||||
|
||||
## Surprising Connections (you probably didn't know these)
|
||||
- `نکتههای مهم` --references--> `Action` [INFERRED]
|
||||
recalc_last_bazdid.md → admin_panel/models/actions.py
|
||||
- `SMS Templates UI` --semantically_similar_to--> `SMS Templates UI Screenshot` [EXTRACTED] [semantically similar]
|
||||
admin_panel/templates/admin_panel/sms_templates.html → screencapture-localhost-8000-panel-sms-templates-2026-10-09-23_01_18.png
|
||||
- `check_financial_discrepancy()` --uses--> `Customer` [INFERRED]
|
||||
check_finance.py → admin/models.py
|
||||
- `run_360_audit()` --uses--> `Customer` [INFERRED]
|
||||
ghost_hunter.py → admin/models.py
|
||||
- ``nest=` is a max, so it cannot tell a long function from a tangled one` --references--> `index()` [INFERRED]
|
||||
ripwire - README.md → admin/views.py
|
||||
- `مدل وضعیت job` --references--> `CustomerNameFixJob` [INFERRED]
|
||||
fix_customer_names.md → admin_panel/models/system.py
|
||||
- `چرا؟` --references--> `CustomerNameFixJob` [INFERRED]
|
||||
fix_customer_names.md → admin_panel/models/system.py
|
||||
- `سریعترین مسیر روی Production (اگر همین یک دستور را میخواهی)` --references--> `CustomerNameFixJob` [INFERRED]
|
||||
normalize_customer_sms_phones.md → admin_panel/models/system.py
|
||||
- `تستها` --references--> `resolve_recipients()` [INFERRED]
|
||||
normalize_customer_sms_phones.md → admin_panel/sms/recipients.py
|
||||
|
||||
## Import Cycles
|
||||
- None detected.
|
||||
@@ -222,102 +235,98 @@
|
||||
- **New Factor Creation Flow** — admin_panel_templates_admin_panel_customeridbackup_html, django_url_admin_panel_productsjson, api_endpoint_panel_productmojodi, admin_panel_templates_admin_panel_customeridbackup_html_orderlist, admin_panel_templates_admin_panel_customeridbackup_html_buildorderlist, django_url_admin_panel_newfactor [INFERRED]
|
||||
- **Store and Inventory Management Flow** — admin_panel_templates_admin_panel_basestore, concept_url_admin_panel_stores, concept_url_admin_panel_productadd, concept_url_admin_panel_operations, concept_url_admin_panel_store_transfers [INFERRED]
|
||||
|
||||
## Communities (171 total, 97 thin omitted)
|
||||
## Communities (184 total, 89 thin omitted)
|
||||
|
||||
### Community 0 - "views/sms.py"
|
||||
Cohesion: 0.14
|
||||
Nodes (14): _approve(), customer_sms_history(), _customer_url(), _notice(), sms_customer_toggle(), sms_primary_toggle(), sms_queue(), sms_queue_approve() (+6 more)
|
||||
Cohesion: 0.12
|
||||
Nodes (18): _approve(), customer_sms_history(), _customer_url(), _notice(), parse_jalali_date(), parse_scan_since(), resolve_recipients_test(), sms_customer_toggle() (+10 more)
|
||||
|
||||
### Community 1 - "run_all"
|
||||
Cohesion: 0.06
|
||||
Nodes (9): Command, run_all(), apply_timing(), activate_sms(), AutoSendTests, ColdStartTests, ConsoleEncodingTests, ScannerTests (+1 more)
|
||||
Cohesion: 0.05
|
||||
Nodes (9): Command, run_all(), apply_timing(), activate_sms(), AutoSendTests, ColdStartTests, ScannerTests, keys() (+1 more)
|
||||
|
||||
### Community 2 - "django_db"
|
||||
Cohesion: 0.04
|
||||
Nodes (24): Migration, Migration, Migration, Migration, Migration, Migration, Migration, Migration (+16 more)
|
||||
Cohesion: 0.03
|
||||
Nodes (38): Migration, Migration, Migration, Migration, Migration, Migration, Migration, Migration (+30 more)
|
||||
|
||||
### Community 3 - "views/store.py"
|
||||
Cohesion: 0.07
|
||||
Nodes (26): Product, Meta, StoreTransferRequest, Meta, Status, approve_transfer_request(), cancel_transfer_request(), _check_source_store_permission() (+18 more)
|
||||
|
||||
### Community 4 - "ModelsPackageContractTests"
|
||||
Cohesion: 0.07
|
||||
Nodes (5): AdminConfig, AdminPanelConfig, make_std_streams_unicode_safe(), configure_sqlite_connection(), ModelsPackageContractTests
|
||||
### Community 3 - "create_transfer_request"
|
||||
Cohesion: 0.10
|
||||
Nodes (12): StoreTransferRequest, Meta, Status, approve_transfer_request(), cancel_transfer_request(), _check_source_store_permission(), _check_target_store_permission(), create_transfer_request() (+4 more)
|
||||
|
||||
### Community 5 - "PhoneCleanupTests"
|
||||
Cohesion: 0.09
|
||||
Cohesion: 0.08
|
||||
Nodes (9): Command, Migration, scrub_legacy_phones(), _append_note(), clean_all(), clean_customer(), clean_legacy_cell(), _numeric_tokens() (+1 more)
|
||||
|
||||
### Community 6 - ".load"
|
||||
Cohesion: 0.06
|
||||
Nodes (9): 12. Supported languages and formats, Languages, HttpProviderRobustnessTests, RuleTests, SettingsPanelTests, TestMessageSettingsTests, WorkerTests, ZeroZeroNinetyEightLinkTests (+1 more)
|
||||
Cohesion: 0.12
|
||||
Nodes (6): SMSProviderConfig, Meta, 12. Supported languages and formats, Languages, SettingsPanelTests, TestMessageSettingsTests
|
||||
|
||||
### Community 7 - "models/sms.py"
|
||||
Cohesion: 0.06
|
||||
Nodes (15): CustomerSMSSetting, Meta, SMSDedup, Meta, SMSLog, Meta, SMSProviderConfig, Meta (+7 more)
|
||||
Cohesion: 0.12
|
||||
Nodes (7): CustomerSMSSetting, Meta, SMSLog, Meta, SMSTemplate, Meta, SMSType
|
||||
|
||||
### Community 8 - "logging"
|
||||
Cohesion: 0.09
|
||||
Nodes (3): get_provider_class(), get_sms_provider(), reset_sms_provider()
|
||||
### Community 8 - "models/__init__.py"
|
||||
Cohesion: 0.10
|
||||
Nodes (4): remove_query_param(), check_financial_discrepancy(), run_360_audit(), run_audit()
|
||||
|
||||
### Community 9 - "views/customers.py"
|
||||
Cohesion: 0.09
|
||||
Nodes (18): normalize_primary_values(), customer_toggle_map(), notify_welcome(), customer(), customerDel(), customerEdit(), customerFactor(), customerFactors() (+10 more)
|
||||
Cohesion: 0.16
|
||||
Nodes (11): customer(), customerDel(), customerFactor(), customerFactors(), customerHesabdari(), customerNew(), customerNew2(), customers() (+3 more)
|
||||
|
||||
### Community 10 - "django_db_models_deletion"
|
||||
Cohesion: 0.08
|
||||
Nodes (12): Migration, Migration, Migration, Migration, Migration, Migration, Migration, Migration (+4 more)
|
||||
### Community 10 - "django_conf"
|
||||
Cohesion: 0.05
|
||||
Nodes (23): Migration, Migration, Migration, Migration, Migration, Migration, Migration, Migration (+15 more)
|
||||
|
||||
### Community 11 - "make_customer"
|
||||
Cohesion: 0.14
|
||||
Cohesion: 0.15
|
||||
Nodes (3): make_customer(), EmptyQueueTests, PrimaryNumberPanelTests
|
||||
|
||||
### Community 12 - "customer_phone_entries"
|
||||
Cohesion: 0.13
|
||||
Nodes (5): customer_phone_entries(), _iter_sources(), resolve_recipients(), mark_primary(), RecipientTests
|
||||
### Community 12 - "resolve_recipients"
|
||||
Cohesion: 0.15
|
||||
Nodes (4): resolve_recipients(), تستها, mark_primary(), RecipientTests
|
||||
|
||||
### Community 14 - "views/finance.py"
|
||||
Cohesion: 0.18
|
||||
Nodes (19): Article, Meta, notify_payment_thanks(), addSarresid(), bedehi(), bedehiKhadamat(), bedehiNasb(), financial_dashboard() (+11 more)
|
||||
Cohesion: 0.17
|
||||
Nodes (20): Article, Meta, notify_payment_thanks(), customerHesabdariAdd(), addSarresid(), bedehi(), bedehiKhadamat(), bedehiNasb() (+12 more)
|
||||
|
||||
### Community 15 - "SMSResult"
|
||||
Cohesion: 0.13
|
||||
Nodes (7): SMSProvider, SMSResult, webotp_message(), console_write(), ConsoleSMSProvider, HTTPSMSProvider, _FailingProvider
|
||||
### Community 15 - "views/store.py"
|
||||
Cohesion: 0.14
|
||||
Nodes (16): Product, Meta, StoreRoom, Meta, newOperation(), newStore(), operation(), operationProduct() (+8 more)
|
||||
|
||||
### Community 16 - "sms0098ws.py"
|
||||
Cohesion: 0.10
|
||||
Nodes (7): classify_delivery(), DeliveryCode, describe_send_code(), _as_text(), ZeroZeroNinetyEightWebServiceProvider, place_voip_call(), VoipCallResult
|
||||
Cohesion: 0.27
|
||||
Nodes (3): classify_delivery(), DeliveryCode, describe_send_code()
|
||||
|
||||
### Community 17 - "Admin Panel Customization"
|
||||
Cohesion: 0.12
|
||||
Nodes (10): CustomerSMSSettingAdmin, SMSLogAdmin, SMSProviderConfigAdmin, SMSProviderConfigForm, Meta, SMSQueueAdmin, SMSTemplateAdmin, StoreRoomAdmin (+2 more)
|
||||
|
||||
### Community 18 - "User"
|
||||
Cohesion: 0.16
|
||||
Nodes (17): User, Action, VisitQueue, UserProfile, notify_visit_scheduled(), ActionList(), ActionListAll(), ActionListToday() (+9 more)
|
||||
Cohesion: 0.17
|
||||
Nodes (18): User, Action, ActionType, Status, notify_visit_scheduled(), ActionList(), ActionListAll(), ActionListToday() (+10 more)
|
||||
|
||||
### Community 19 - "django_conf"
|
||||
Cohesion: 0.09
|
||||
Nodes (11): Migration, Migration, Migration, Migration, Migration, Migration, Migration, Migration (+3 more)
|
||||
### Community 19 - "timing_for"
|
||||
Cohesion: 0.12
|
||||
Nodes (6): current_timing_value(), timing_for(), sms_template_edit(), sms_templates(), _templates_redirect(), TimingsTests
|
||||
|
||||
### Community 20 - "test_customers.py"
|
||||
Cohesion: 0.11
|
||||
Nodes (4): login_superuser(), CustomerCrudTests, CustomerDeleteGuardTests, InactiveCustomerHiddenTests
|
||||
### Community 20 - "Customer"
|
||||
Cohesion: 0.12
|
||||
Nodes (5): Customer, login_superuser(), CustomerCrudTests, CustomerDeleteGuardTests, InactiveCustomerHiddenTests
|
||||
|
||||
### Community 21 - "phones.py"
|
||||
Cohesion: 0.18
|
||||
Nodes (6): primary_phones(), resolved_recipients(), save_primary_normalized(), stored_primary_normalized(), usable_entries(), primary_phones()
|
||||
Cohesion: 0.19
|
||||
Nodes (7): normalize_primary_values(), resolved_recipients(), save_primary_normalized(), stored_primary_normalized(), usable_entries(), قالبِ ذخیرهشده: `+989xxxxxxxxx`, قواعد اعتبارسنجی و قالب شماره
|
||||
|
||||
### Community 22 - "Login Template Forms"
|
||||
Cohesion: 0.11
|
||||
Nodes (17): Django CSRF Token, Django Custom Tags, Django Static Files, Django URL: admin_panel:newStore, Django URL: admin_panel:operations, Django URL: admin_panel:p_login, Django URL: admin_panel:store, Form Field: password (+9 more)
|
||||
|
||||
### Community 23 - "cheque_inquiry.py"
|
||||
Cohesion: 0.19
|
||||
Cohesion: 0.17
|
||||
Nodes (6): api_check_sabt_inquiry(), api_check_status_inquiry(), parse_cheque_result_html(), run_bpi_cheque_inquiry_logic(), run_cbi_sayad_inquiry_logic(), solve_base64_captcha()
|
||||
|
||||
### Community 24 - "factories.py"
|
||||
Cohesion: 0.27
|
||||
Cohesion: 0.18
|
||||
Nodes (5): ProductCategory, make_category(), make_product(), make_store(), _next()
|
||||
|
||||
### Community 25 - "Rip'n Fast. Fewer Tokens. Better Code."
|
||||
@@ -325,36 +334,32 @@ Cohesion: 0.11
|
||||
Nodes (18): Against the leading graph-database code-context MCP server, Better Code: It automates the review judgments nobody has time to make — every lens from published research, Documentation, Graph-Ranked Retrieval: It finds the right files more often than the alternatives, If it works on your codebase, tell us what it got wrong, Improve it with your agent, Licence, Quickstart (+10 more)
|
||||
|
||||
### Community 26 - "views/factors.py"
|
||||
Cohesion: 0.19
|
||||
Nodes (6): notify_factor_survey(), newFactor2(), InventoryException, _parse_jalali_date(), _parse_timestamp(), _safe_int()
|
||||
Cohesion: 0.14
|
||||
Nodes (9): FactorIteam, notify_factor_survey(), FactorDel(), newFactor(), newFactor2(), InventoryException, _parse_jalali_date(), _parse_timestamp() (+1 more)
|
||||
|
||||
### Community 27 - "to_local"
|
||||
Cohesion: 0.17
|
||||
Nodes (4): to_local(), _configured_codes(), _response_code(), ZeroZeroNinetyEightSMSProvider
|
||||
### Community 27 - "sms0098.py"
|
||||
Cohesion: 0.20
|
||||
Nodes (3): _configured_codes(), _response_code(), ZeroZeroNinetyEightSMSProvider
|
||||
|
||||
### Community 30 - "NoticeMechanismTests"
|
||||
Cohesion: 0.17
|
||||
Nodes (3): dashBoxData(), resolve(), NoticeMechanismTests
|
||||
|
||||
### Community 31 - "enqueue.py"
|
||||
Cohesion: 0.15
|
||||
Nodes (6): format_amount(), format_jalali(), render_template(), _SafeDict, is_sms_enabled(), _sample_context()
|
||||
### Community 32 - "scanner.py"
|
||||
Cohesion: 0.23
|
||||
Nodes (6): _aware(), _Budget, scan_cheque_funding(), scan_nesiye_due(), scan_visit(), _template()
|
||||
|
||||
### Community 32 - "enqueue_sms"
|
||||
Cohesion: 0.21
|
||||
Nodes (7): enqueue_sms(), _aware(), _Budget, scan_cheque_funding(), scan_nesiye_due(), scan_visit(), _template()
|
||||
|
||||
### Community 33 - "PanelTestCase"
|
||||
Cohesion: 0.17
|
||||
Nodes (5): PhoneNumber, DeletedStaysDeletedTests, EnqueueIdempotencyTests, PanelTestCase, WelcomeTriggerTests
|
||||
### Community 33 - "ZeroZeroNinetyEightWebServiceTests"
|
||||
Cohesion: 0.11
|
||||
Nodes (5): SMSDeliveryResult, _as_text(), ZeroZeroNinetyEightWebServiceProvider, SMSDeliveryCommandTests, ZeroZeroNinetyEightWebServiceTests
|
||||
|
||||
### Community 34 - "ProductInStore"
|
||||
Cohesion: 0.14
|
||||
Nodes (8): Factor, Meta, FactorIteam, ProductInStore, Meta, MovementType, FactorDel(), newFactor()
|
||||
Cohesion: 0.33
|
||||
Nodes (3): ProductInStore, Meta, MovementType
|
||||
|
||||
### Community 35 - "admin_panel/templates/admin_panel/baseHesabdari.html"
|
||||
Cohesion: 0.07
|
||||
Nodes (27): Base Template, Customer Base Template, New Customer Base Template, Create Factor View, Customer List View, Django Custom Tags: custom_tags, URL: admin_panel:ActionListUserToday, URL: admin_panel:bedehi (+19 more)
|
||||
Cohesion: 0.13
|
||||
Nodes (14): URL: admin_panel:ActionListUserToday, URL: admin_panel:bedehi, URL: admin_panel:entezar, URL: admin_panel:hesabdari, URL: admin_panel:hesabdari_residnashone, URL: admin_panel:index, URL: admin_panel:p_logout, URL: admin_panel:rezayat (+6 more)
|
||||
|
||||
### Community 36 - "Reference guide"
|
||||
Cohesion: 0.14
|
||||
@@ -364,13 +369,13 @@ Nodes (14): 10. Quality evaluation, 11. Agent integration, 13. Performance, 14.
|
||||
Cohesion: 0.15
|
||||
Nodes (4): Customer ID Backup/New Factor Template, all_products (JS variable), buildOrderList (JS function), orderList (JS variable)
|
||||
|
||||
### Community 38 - "admin_panel/templates/admin_panel/bedehi.html"
|
||||
Cohesion: 0.16
|
||||
Nodes (10): admin_panel:pardakhtNesiye, /panel/passCheck/, all_sarresid, mandehesabKP, admin_panel.ViewReportMali, toJalali, admin_panel:bedehi, admin_panel:bedehiKhadamat (+2 more)
|
||||
### Community 38 - "hesabdariResidNashode.html"
|
||||
Cohesion: 0.19
|
||||
Nodes (11): admin_panel:customerNew, admin_panel:pardakhtNesiye, /panel/passCheck/, all_sarresid, mandehesabKP, admin_panel.ViewReportMali, jQuery, pDatepicker JS Library (+3 more)
|
||||
|
||||
### Community 39 - "project_tree.py"
|
||||
### Community 39 - "requests"
|
||||
Cohesion: 0.21
|
||||
Nodes (6): is_excluded_file(), main(), non_negative_integer(), parse_args(), sorted_entries(), warn()
|
||||
Nodes (4): AnnouncementRejected, place_announcement_call(), place_voip_call(), VoipCallResult
|
||||
|
||||
### Community 40 - "CustomerSmsHistoryTests"
|
||||
Cohesion: 0.15
|
||||
@@ -380,17 +385,21 @@ Nodes (3): customer_phones(), toJalaliDT(), CustomerSmsHistoryTests
|
||||
Cohesion: 0.15
|
||||
Nodes (12): **جدول کدهای خطای لینک ارتباطی**, **جدول کدهای خطای وبسرویس و وضعیتهای دلیوری**, **راهنمای استفاده از Web Service**, **راهنمای استفاده از لینک ارتباطی (URL GET)**, **راهنمای استفاده از لینک ارتباطی و وبسرویس سامانه پیامک (0098vip.com و 0098sms.com)**, **فهرست مطالب**, **مقدمات اتصال**, **نمونه کدهای پیادهسازی** (+4 more)
|
||||
|
||||
### Community 43 - "timing_for"
|
||||
Cohesion: 0.12
|
||||
Nodes (6): current_timing_value(), timing_for(), sms_template_edit(), sms_templates(), _templates_redirect(), TimingsTests
|
||||
### Community 43 - "enqueue.py"
|
||||
Cohesion: 0.19
|
||||
Nodes (5): format_amount(), format_jalali(), render_template(), _SafeDict, _sample_context()
|
||||
|
||||
### Community 44 - "django_shortcuts"
|
||||
Cohesion: 0.13
|
||||
Nodes (3): Migration, ArticleType, Sarresid
|
||||
|
||||
### Community 45 - "stock_in"
|
||||
Cohesion: 0.25
|
||||
Nodes (6): Product, ProductInStore, StoreRoom, current_stock(), stock_in(), ProductInStoreMathTests
|
||||
Cohesion: 0.12
|
||||
Nodes (11): Factor, FactorIteam, Product, ProductInStore, StoreRoom, VisitQueue, current_stock(), stock_in() (+3 more)
|
||||
|
||||
### Community 46 - "admin_panel/templates/admin_panel/customerAction.html"
|
||||
Cohesion: 0.16
|
||||
Nodes (10): admin_panel/templates/admin_panel/customerActionInc.html, admin_panel:customerNew, admin_panel:customerNewAction URL, Action Data Model, DataTables Library, jQuery, Django 'url' template tag, Bulma CSS (+2 more)
|
||||
Cohesion: 0.18
|
||||
Nodes (9): admin_panel/templates/admin_panel/customerActionInc.html, admin_panel:customerNewAction URL, Action Data Model, DataTables Library, jQuery, Django 'url' template tag, Bulma CSS, DataTables.js (+1 more)
|
||||
|
||||
### Community 47 - "parts_count"
|
||||
Cohesion: 0.16
|
||||
@@ -400,70 +409,78 @@ Nodes (6): describe(), detect_encoding(), encoded_length(), is_gsm7(), parts_cou
|
||||
Cohesion: 0.21
|
||||
Nodes (6): Counts, format_header(), generate_snapshot(), normalized_path(), write_tree(), visit()
|
||||
|
||||
### Community 50 - "Customer"
|
||||
Cohesion: 0.16
|
||||
Nodes (6): Customer, Factor, FactorIteam, VisitQueue, Command, NewFactor2ViewTests
|
||||
### Community 50 - "test_sms.py"
|
||||
Cohesion: 0.21
|
||||
Nodes (4): enqueue_sms(), is_sms_enabled(), EnqueueIdempotencyTests, RuleTests
|
||||
|
||||
### Community 51 - "Phone Cleanup Guide"
|
||||
Cohesion: 0.17
|
||||
Nodes (11): اجرا روی سرور اصلی (production), اجرای دستور, اصلاح دستی شمارههای قدیمی مشتریان, راه جایگزین: مهاجرت (migration), قاعدهٔ پاکسازی, مشاهدهٔ نتیجه, نکتهها, چرا؟ (+3 more)
|
||||
|
||||
### Community 53 - "manage.py"
|
||||
Cohesion: 0.22
|
||||
Nodes (5): entrypoint.sh script, main(), run.sh script, start_service(), usage()
|
||||
### Community 52 - ".run_command"
|
||||
Cohesion: 0.13
|
||||
Nodes (6): ApplyTests, CommandTestMixin, DryRunTests, ResilienceTests, flaky(), sha256_of()
|
||||
|
||||
### Community 53 - "project_tree.py"
|
||||
Cohesion: 0.23
|
||||
Nodes (6): is_excluded_file(), main(), non_negative_integer(), parse_args(), sorted_entries(), warn()
|
||||
|
||||
### Community 54 - "Agent Operating Guidelines"
|
||||
Cohesion: 0.18
|
||||
Nodes (8): 1. Codebase Navigation & Analysis (Ripwire vs. Graphify), 2. Dynamic Help, Self-Correction & Staleness, 3. Git Operations & Safety, 4. Development Server Lifecycle, 5. Environment, Frontend & PWA Safety, 6. End-to-End Browser Tests (Playwright), Project Operating & Agent Guidelines, Routing Gate & Pipeline
|
||||
|
||||
### Community 57 - "test_sms.py"
|
||||
Cohesion: 0.17
|
||||
Nodes (4): to_display(), _clean(), normalize_mobile(), NormalizeTests
|
||||
### Community 55 - "Command"
|
||||
Cohesion: 0.05
|
||||
Nodes (12): Command, build_name_index(), DatasetError, decide_prefix(), Decision, load_name_index(), NameIndex, normalize_name_key() (+4 more)
|
||||
|
||||
### Community 57 - "normalize_mobile"
|
||||
Cohesion: 0.18
|
||||
Nodes (5): to_display(), _clean(), normalize_mobile(), to_local(), NormalizeTests
|
||||
|
||||
### Community 58 - "Financial Data Objects"
|
||||
Cohesion: 0.20
|
||||
Nodes (9): Customer Data Object, Factor Data Object, Sarresid Data Object, admin_panel:customerNew URL, admin_panel:pardakhtNesiye URL, /panel/passCheck/ URL, admin_panel.ViewReportMali Permission, jQuery JS Library (+1 more)
|
||||
|
||||
### Community 60 - "بازمحاسبهٔ «آخرین بازدید» مشتریان"
|
||||
Cohesion: 0.18
|
||||
Nodes (10): اجرا روی production, بازمحاسبهٔ «آخرین بازدید» مشتریان, بررسی صحت داده (SQL، پیش از اجرا), دستور, دقیقاً چه میکند؟, نمونهٔ خروجی, نکتههای مهم, گزینهها (+2 more)
|
||||
### Community 60 - ".run_cmd"
|
||||
Cohesion: 0.11
|
||||
Nodes (5): ApplyTests, BatchAndCheckpointTests, flaky(), CommandTestCase, OverflowTests
|
||||
|
||||
### Community 62 - "SMS Timing Migration"
|
||||
Cohesion: 0.22
|
||||
Nodes (4): backfill_primary_phones(), Migration, _normalize(), normalize_template_timing()
|
||||
|
||||
### Community 63 - "Articl Model"
|
||||
Cohesion: 0.67
|
||||
Nodes (3): Articl Model, Customer Model, articls
|
||||
### Community 63 - "admin_panel/templates/admin_panel/bedehi.html"
|
||||
Cohesion: 0.20
|
||||
Nodes (8): Articl Model, Customer Model, articls, toJalali, admin_panel:bedehi, admin_panel:bedehiKhadamat, admin_panel:bedehiNasb, admin_panel:customer
|
||||
|
||||
### Community 64 - "customerIDFactorBackup.html"
|
||||
Cohesion: 0.18
|
||||
Nodes (8): Client-side script in customerIDFactorBackup.html, URL: admin_panel:customerEdit, Customer Data, Factor Data Model, Product Data Model, Product Category Data Model, User Data Model, URL: /panel/productMojodi/
|
||||
Cohesion: 0.20
|
||||
Nodes (7): Client-side script in customerIDFactorBackup.html, URL: admin_panel:customerEdit, Factor Data Model, Product Data Model, Product Category Data Model, User Data Model, URL: /panel/productMojodi/
|
||||
|
||||
### Community 65 - "bale/providers.py"
|
||||
Cohesion: 0.36
|
||||
Nodes (4): BaleBotProvider, ConsoleBaleProvider, get_bale_provider(), NotificationResult
|
||||
|
||||
### Community 67 - "Graphify Tooling Docs"
|
||||
Cohesion: 0.22
|
||||
Nodes (8): Copilot Chat, graphify, graphify-out/graph.json, graphify-out/GRAPH_REPORT.md, graphify-out/wiki/index.md, graphify explain, graphify path, graphify query
|
||||
|
||||
### Community 71 - "admin_panel/entezar.html"
|
||||
Cohesion: 0.40
|
||||
Nodes (4): Customer Data Structure, kamaDatepicker Library, custom_tags, toJalali filter
|
||||
Cohesion: 0.25
|
||||
Nodes (6): Customer Data Structure, kamaDatepicker Library, URL: admin_panel:customers, URL: /panel/customer/{id}/factor/{id}/del, custom_tags, toJalali filter
|
||||
|
||||
### Community 72 - "customerNewBackup.html"
|
||||
Cohesion: 0.29
|
||||
Nodes (6): admin_panel:newFactor URL, Category Data, Client-side Form Logic, CSRF Token, custom_tags, static
|
||||
Cohesion: 0.25
|
||||
Nodes (7): admin_panel:newFactor URL, Category Data, Client-side Form Logic, Customer Data, CSRF Token, custom_tags, static
|
||||
|
||||
### Community 73 - "hesabdariResidNashode.html"
|
||||
Cohesion: 0.47
|
||||
Nodes (5): jQuery, pDatepicker JS Library, custom_tags, toCurrency, toJalali
|
||||
### Community 73 - "SMSResult"
|
||||
Cohesion: 0.11
|
||||
Nodes (8): SMSProvider, SMSResult, webotp_message(), get_provider_class(), get_sms_provider(), reset_sms_provider(), HTTPSMSProvider, _FailingProvider
|
||||
|
||||
### Community 76 - "Timezone Migration History"
|
||||
Cohesion: 0.29
|
||||
Nodes (3): Migration, Migration, Migration
|
||||
|
||||
### Community 77 - "models/__init__.py"
|
||||
Cohesion: 0.08
|
||||
Nodes (9): Customer, Meta, PhoneNumber, ProductCategory, ProductStockHistory, Meta, StoreRoom, Meta (+1 more)
|
||||
|
||||
### Community 81 - "Installation Guide"
|
||||
Cohesion: 0.40
|
||||
Nodes (5): 3.1 Install a prebuilt binary, 3.2 Build from source, 3.3 Install the agent skills, 3.4 Register the MCP server (optional), 3. Installation
|
||||
@@ -472,10 +489,6 @@ Nodes (5): 3.1 Install a prebuilt binary, 3.2 Build from source, 3.3 Install the
|
||||
Cohesion: 0.40
|
||||
Nodes (5): In the numbers, In the output, In the tests, The honesty contract, What it misses, and what to run next
|
||||
|
||||
### Community 85 - "stop.sh"
|
||||
Cohesion: 0.73
|
||||
Nodes (5): is_our_process(), say(), stop.sh script, stop_pid(), windows_cleanup()
|
||||
|
||||
### Community 86 - "Output Format Specs"
|
||||
Cohesion: 0.50
|
||||
Nodes (4): 6.1 Output example, 6.2 Exit codes, 6.3 JSON output, 6. Output format
|
||||
@@ -488,10 +501,18 @@ Nodes (4): Against other tools, Measured, What it saves you, in tokens, Where it
|
||||
Cohesion: 0.67
|
||||
Nodes (3): SMS Gateway Integration Guide, SMS Settings UI, Python Dependencies
|
||||
|
||||
### Community 89 - "CustomerNameFixJob"
|
||||
Cohesion: 0.25
|
||||
Nodes (6): CustomerNameFixJob, Meta, Status, مدل وضعیت job, چرا؟, سریعترین مسیر روی Production (اگر همین یک دستور را میخواهی)
|
||||
|
||||
### Community 90 - "Customer Modal UI"
|
||||
Cohesion: 0.67
|
||||
Nodes (3): createCS click handler, openRow click handler, Customer Modals UI
|
||||
|
||||
### Community 91 - "PanelTestCase"
|
||||
Cohesion: 0.24
|
||||
Nodes (3): DeletedStaysDeletedTests, PanelTestCase, SentQueueProtectionTests
|
||||
|
||||
### Community 92 - "Infrastructure Services"
|
||||
Cohesion: 0.67
|
||||
Nodes (3): Docker Infrastructure, SMS Delivery Tracker, SMS Worker Service
|
||||
@@ -504,46 +525,122 @@ Nodes (3): 1. (Optional) Register the MCP server, 2. Install the skills, Set it
|
||||
Cohesion: 0.67
|
||||
Nodes (3): 4.1 Make the first map, 4.2 Use the common commands, 4. First use
|
||||
|
||||
### Community 98 - "reconciliation_tool.py"
|
||||
### Community 95 - "ConsoleSMSProvider"
|
||||
Cohesion: 0.21
|
||||
Nodes (3): console_write(), ConsoleSMSProvider, ConsoleEncodingTests
|
||||
|
||||
### Community 96 - "PhoneNumber"
|
||||
Cohesion: 0.22
|
||||
Nodes (4): PhoneNumber, DryRunTests, make_phone(), WelcomeTriggerTests
|
||||
|
||||
### Community 97 - "تجمیع شمارههای پیامک مشتریان"
|
||||
Cohesion: 0.14
|
||||
Nodes (13): الگوریتم (برای هر مشتری), بازگردانی (اگر نتیجه را نخواستی), بررسی صحت داده (SQL), تجمیع شمارههای پیامک مشتریان, تعریف کلیدهای گزارش, خطاها و اقدام درست, عملکرد و بار روی دیتابیس, نمونهها (+5 more)
|
||||
|
||||
### Community 99 - "Base Template"
|
||||
Cohesion: 0.15
|
||||
Nodes (11): Base Template, Customer Base Template, New Customer Base Template, Create Factor View, Customer List View, Django Custom Tags: custom_tags, URL: admin_panel:newFactor, URL: admin_panel:operations (+3 more)
|
||||
|
||||
### Community 100 - "test_customer_name_fix.py"
|
||||
Cohesion: 0.09
|
||||
Nodes (3): digit_string(), is_landline(), PureHelperTests
|
||||
|
||||
### Community 102 - "customer_phone_entries"
|
||||
Cohesion: 0.20
|
||||
Nodes (3): customer_phone_entries(), _iter_sources(), PhoneEntry
|
||||
|
||||
### Community 103 - "manage.py"
|
||||
Cohesion: 0.24
|
||||
Nodes (3): remove_query_param(), run_360_audit(), run_audit()
|
||||
Nodes (5): entrypoint.sh script, main(), run.sh script, start_service(), usage()
|
||||
|
||||
### Community 113 - "bale/providers.py"
|
||||
Cohesion: 0.36
|
||||
Nodes (4): BaleBotProvider, ConsoleBaleProvider, get_bale_provider(), NotificationResult
|
||||
### Community 104 - "افزودن پیشوند «آقای/خانم» به نام مشتریان"
|
||||
Cohesion: 0.15
|
||||
Nodes (12): SQLite، قفل دیتابیس و بار روی سایت, افزودن پیشوند «آقای/خانم» به نام مشتریان, بررسی صحت داده (SQL، پیش از/پس از اجرا), بکاپ/بازیابی خودکار نیست, بکاپ پیش از اجرای واقعی, تستها, تعریف کلیدهای آماری, خطاهای رایج و اقدام درست (+4 more)
|
||||
|
||||
### Community 166 - "sms_settings"
|
||||
Cohesion: 0.33
|
||||
Nodes (4): parse_jalali_date(), parse_scan_since(), resolve_recipients_test(), sms_settings()
|
||||
### Community 105 - "بازمحاسبهٔ «آخرین بازدید» مشتریان"
|
||||
Cohesion: 0.20
|
||||
Nodes (9): اجرا روی production, بازمحاسبهٔ «آخرین بازدید» مشتریان, بررسی صحت داده (SQL، پیش از اجرا), دستور, دقیقاً چه میکند؟, نمونهٔ خروجی, گزینهها, ۱) اول «شبیهسازی» — بدون هیچ تغییری (+1 more)
|
||||
|
||||
### Community 113 - "primary_phones"
|
||||
Cohesion: 0.25
|
||||
Nodes (5): primary_phones(), primary_phones(), customerEdit(), _parse_phone_rows(), ⚠️ هشدار معنای داده (مهمترین نکتهٔ این سند)
|
||||
|
||||
### Community 163 - "Customer"
|
||||
Cohesion: 0.29
|
||||
Nodes (4): Customer, Meta, notify_welcome(), customersAdd()
|
||||
|
||||
### Community 164 - "SMSQueue"
|
||||
Cohesion: 0.29
|
||||
Nodes (4): SMSQueue, DeliveryStatus, Meta, Status
|
||||
|
||||
### Community 166 - "توقف و ادامه (Resume / Checkpoint)"
|
||||
Cohesion: 0.40
|
||||
Nodes (5): اتمیک بودن, توقف و ادامه (Resume / Checkpoint), سلسلهمراتب تصمیم نقطهٔ شروع, فایل وضعیت, گزینههای ادامه
|
||||
|
||||
### Community 169 - "index"
|
||||
Cohesion: 0.67
|
||||
Nodes (3): index(), `nest=` is a max, so it cannot tell a long function from a tangled one, The quality panel
|
||||
|
||||
### Community 170 - "الگوریتم تصمیم (به همین ترتیب)"
|
||||
Cohesion: 0.50
|
||||
Nodes (4): الگوریتم تصمیم (به همین ترتیب), برخورد با نامهای تکراری و متناقض, نرمالسازی (فقط برای کلید جستوجو), نمونههای رفتاری
|
||||
|
||||
### Community 171 - "سریعترین مسیر روی Production (خلاصهٔ اجرایی)"
|
||||
Cohesion: 0.50
|
||||
Nodes (4): اگر وسط کار قطع شد, بررسی نتیجه, سریعترین مسیر روی Production (خلاصهٔ اجرایی), ✅ فایل JSON داخل ایمیج کپی میشود (تضمینشده)
|
||||
|
||||
### Community 173 - "stop.sh"
|
||||
Cohesion: 0.73
|
||||
Nodes (5): is_our_process(), say(), stop.sh script, stop_pid(), windows_cleanup()
|
||||
|
||||
### Community 176 - "اجرای محلی (توسعه)"
|
||||
Cohesion: 0.50
|
||||
Nodes (4): اجرای محلی (توسعه), ۱) شبیهسازی — همیشه قدم اول, ۲) تنظیم سرعت batch, ۳) اجرای واقعی
|
||||
|
||||
### Community 178 - "اجرا روی سرور Production"
|
||||
Cohesion: 0.67
|
||||
Nodes (3): اجرا روی سرور Production, اطمینان از انتخاب دیتابیس درست, ترتیب دقیق اجرا
|
||||
|
||||
### Community 179 - "اجرای محلی (توسعه)"
|
||||
Cohesion: 0.67
|
||||
Nodes (3): اجرای محلی (توسعه), ۱) اول همیشه شبیهسازی, ۲) اجرای واقعی (فقط روی مقصد دلخواه)
|
||||
|
||||
### Community 180 - "ادامهٔ job پس از crash / قطع برق"
|
||||
Cohesion: 0.67
|
||||
Nodes (3): ادامهٔ job پس از crash / قطع برق, دستورهای دقیق ادامه / شروع مجدد, گزینههای ادامه
|
||||
|
||||
### Community 181 - "اجرا روی سرور Production"
|
||||
Cohesion: 0.67
|
||||
Nodes (3): اجرا روی سرور Production, ترتیب دقیق, نکتهها برای Production
|
||||
|
||||
### Community 189 - "django_contrib_auth_models"
|
||||
Cohesion: 0.12
|
||||
Nodes (6): VisitQueue, ProductCategory, ProductStockHistory, Meta, StoreRoomOwner, UserProfile
|
||||
|
||||
## Ambiguous Edges - Review These
|
||||
- `admin_panel/templates/admin_panel/baseHesabdari.html` → `Base Template` [AMBIGUOUS]
|
||||
admin_panel/templates/admin_panel/baseHesabdari.html · relation: conceptually_related_to
|
||||
|
||||
## Knowledge Gaps
|
||||
- **118 isolated node(s):** `base.html`, `toCurrency`, `DataTables Library`, `Customer Data Object`, `Factor Data Object` (+113 more)
|
||||
These have ≤1 connection - possible missing edges or undocumented components. (Counts symbols only; 738 node(s) total have ≤1 connection when file, concept and rationale nodes are included.)
|
||||
- **97 thin communities (<3 nodes) omitted from report** — run `graphify query` to explore isolated nodes.
|
||||
These have ≤1 connection - possible missing edges or undocumented components. (Counts symbols only; 841 node(s) total have ≤1 connection when file, concept and rationale nodes are included.)
|
||||
- **89 thin communities (<3 nodes) omitted from report** — run `graphify query` to explore isolated nodes.
|
||||
|
||||
## Suggested Questions
|
||||
_Questions this graph is uniquely positioned to answer:_
|
||||
|
||||
- **Why does `Rip'n Fast. Fewer Tokens. Better Code.` connect `Rip'n Fast. Fewer Tokens. Better Code.` to `Reference guide`, `.load`, `index`, `Project Honesty Contract`, `Agent Operating Guidelines`, `Performance Benchmarks`, `Agent Setup Guide`?**
|
||||
_High betweenness centrality (0.046) - this node is a cross-community bridge._
|
||||
- **Why does `make_customer()` connect `make_customer` to `run_all`, `PhoneCleanupTests`, `resolve_recipients`, `EventTriggerTests`, `Customer`, `factories.py`, `make_user`, `QueueReviewTests`, `NoticeMechanismTests`, `CustomerSmsHistoryTests`, `stock_in`, `CustomerInfoCardUITests`, `test_sms.py`, `Command`, `.run_cmd`, `IntegrationAndEfficiencyTests`, `PanelTestCase`, `ConsoleSMSProvider`, `PhoneNumber`, `test_customer_name_fix.py`, `customer_phone_entries`, `QueueStatsTests`?**
|
||||
_High betweenness centrality (0.075) - this node is a cross-community bridge._
|
||||
- **Are the 2 inferred relationships involving `make_customer()` (e.g. with `Customer` and `PhoneNumber`) actually correct?**
|
||||
_`make_customer()` has 2 INFERRED edges - model-reasoned connections that need verification._
|
||||
- **What connects `base.html`, `toCurrency`, `DataTables Library` to the rest of the system?**
|
||||
_118 weakly-connected nodes found - possible documentation gaps or missing edges._
|
||||
- **Should `views/sms.py` be split into smaller, more focused modules?**
|
||||
_Cohesion score 0.1425287356321839 - nodes in this community are weakly interconnected._
|
||||
- **Why does `Languages` connect `.load` to `Rip'n Fast. Fewer Tokens. Better Code.`?**
|
||||
_High betweenness centrality (0.044) - this node is a cross-community bridge._
|
||||
- **Should `run_all` be split into smaller, more focused modules?**
|
||||
_Cohesion score 0.05552617662612375 - nodes in this community are weakly interconnected._
|
||||
_Cohesion score 0.1226890756302521 - nodes in this community are weakly interconnected._
|
||||
- **Why does `Reference guide` connect `Reference guide` to `.load`, `Installation Guide`, `Output Format Specs`, `Rip'n Fast. Fewer Tokens. Better Code.`, `First Use Guide`?**
|
||||
_High betweenness centrality (0.038) - this node is a cross-community bridge._
|
||||
- **Are the 2 inferred relationships involving `normalize_mobile()` (e.g. with `الگوریتم (برای هر مشتری)` and `قالبِ ذخیرهشده: `+989xxxxxxxxx``) actually correct?**
|
||||
_`normalize_mobile()` has 2 INFERRED edges - model-reasoned connections that need verification._
|
||||
|
||||
### Low-confidence Hints
|
||||
_AMBIGUOUS edges — the extractor was unsure. Verify before acting on these._
|
||||
|
||||
@@ -63,12 +63,12 @@
|
||||
</div>
|
||||
<div id="legend"></div>
|
||||
</div>
|
||||
<div id="stats">1684 nodes · 3008 edges · 171 communities</div>
|
||||
<div id="stats">1960 nodes · 3584 edges · 184 communities</div>
|
||||
</div>
|
||||
<script>
|
||||
const RAW_NODES = [{"id": "admin_panel_management_commands_sms_scan_command", "label": "Command", "color": {"background": "#F28E2B", "border": "#F28E2B", "highlight": {"background": "#ffffff", "border": "#F28E2B"}}, "size": 12.4, "font": {"size": 0, "color": "#ffffff"}, "title": "Command", "community": 1, "community_name": "run_all", "source_file": "admin_panel/management/commands/sms_scan.py", "file_type": "code", "degree": 7}, {"id": "tests_test_sms_autosendtests", "label": "AutoSendTests", "color": {"background": "#F28E2B", "border": "#F28E2B", "highlight": {"background": "#ffffff", "border": "#F28E2B"}}, "size": 14.0, "font": {"size": 0, "color": "#ffffff"}, "title": "AutoSendTests", "community": 1, "community_name": "run_all", "source_file": "tests/test_sms.py", "file_type": "code", "degree": 12}, {"id": "tests_test_sms_coldstarttests", "label": "ColdStartTests", "color": {"background": "#F28E2B", "border": "#F28E2B", "highlight": {"background": "#ffffff", "border": "#F28E2B"}}, "size": 14.0, "font": {"size": 0, "color": "#ffffff"}, "title": "ColdStartTests", "community": 1, "community_name": "run_all", "source_file": "tests/test_sms.py", "file_type": "code", "degree": 12}, {"id": "tests_test_sms_consoleencodingtests", "label": "ConsoleEncodingTests", "color": {"background": "#F28E2B", "border": "#F28E2B", "highlight": {"background": "#ffffff", "border": "#F28E2B"}}, "size": 13.4, "font": {"size": 0, "color": "#ffffff"}, "title": "ConsoleEncodingTests", "community": 1, "community_name": "run_all", "source_file": "tests/test_sms.py", "file_type": "code", "degree": 10}, {"id": "tests_test_sms_scannertests", "label": "ScannerTests", "color": {"background": "#F28E2B", "border": "#F28E2B", "highlight": {"background": "#ffffff", "border": "#F28E2B"}}, "size": 15.1, "font": {"size": 12, "color": "#ffffff"}, "title": "ScannerTests", "community": 1, "community_name": "run_all", "source_file": "tests/test_sms.py", "file_type": "code", "degree": 15}, {"id": "admin_panel_migrations_0001_initial_migration", "label": "Migration", "color": {"background": "#4E79A7", "border": "#4E79A7", "highlight": {"background": "#ffffff", "border": "#4E79A7"}}, "size": 10.3, "font": {"size": 0, "color": "#ffffff"}, "title": "Migration", "community": 10, "community_name": "django_db_models_deletion", "source_file": "admin_panel/migrations/0001_initial.py", "file_type": "code", "degree": 1}, {"id": "admin_panel_migrations_0007_productinstore_factor_migration", "label": "Migration", "color": {"background": "#4E79A7", "border": "#4E79A7", "highlight": {"background": "#ffffff", "border": "#4E79A7"}}, "size": 10.3, "font": {"size": 0, "color": "#ffffff"}, "title": "Migration", "community": 10, "community_name": "django_db_models_deletion", "source_file": "admin_panel/migrations/0007_productinstore_factor.py", "file_type": "code", "degree": 1}, {"id": "admin_panel_migrations_0008_storeroom_user_migration", "label": "Migration", "color": {"background": "#4E79A7", "border": "#4E79A7", "highlight": {"background": "#ffffff", "border": "#4E79A7"}}, "size": 10.3, "font": {"size": 0, "color": "#ffffff"}, "title": "Migration", "community": 10, "community_name": "django_db_models_deletion", "source_file": "admin_panel/migrations/0008_storeroom_user.py", "file_type": "code", "degree": 1}, {"id": "admin_panel_migrations_0018_alter_factoriteam_product_migration", "label": "Migration", "color": {"background": "#4E79A7", "border": "#4E79A7", "highlight": {"background": "#ffffff", "border": "#4E79A7"}}, "size": 10.3, "font": {"size": 0, "color": "#ffffff"}, "title": "Migration", "community": 10, "community_name": "django_db_models_deletion", "source_file": "admin_panel/migrations/0018_alter_factoriteam_product.py", "file_type": "code", "degree": 1}, {"id": "admin_panel_migrations_0019_article_articletype_migration", "label": "Migration", "color": {"background": "#4E79A7", "border": "#4E79A7", "highlight": {"background": "#ffffff", "border": "#4E79A7"}}, "size": 10.3, "font": {"size": 0, "color": "#ffffff"}, "title": "Migration", "community": 10, "community_name": "django_db_models_deletion", "source_file": "admin_panel/migrations/0019_article_articletype.py", "file_type": "code", "degree": 1}, {"id": "admin_panel_migrations_0036_sarresid_migration", "label": "Migration", "color": {"background": "#4E79A7", "border": "#4E79A7", "highlight": {"background": "#ffffff", "border": "#4E79A7"}}, "size": 10.3, "font": {"size": 0, "color": "#ffffff"}, "title": "Migration", "community": 10, "community_name": "django_db_models_deletion", "source_file": "admin_panel/migrations/0036_sarresid.py", "file_type": "code", "degree": 1}, {"id": "admin_panel_migrations_0038_auto_20240213_1735_migration", "label": "Migration", "color": {"background": "#4E79A7", "border": "#4E79A7", "highlight": {"background": "#ffffff", "border": "#4E79A7"}}, "size": 10.3, "font": {"size": 0, "color": "#ffffff"}, "title": "Migration", "community": 10, "community_name": "django_db_models_deletLine truncated
|
||||
const RAW_EDGES = [{"from": "admin_panel_management_commands_sms_scan", "to": "admin_panel_management_commands_sms_scan_command", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "admin_panel_management_commands_sms_scan_command", "to": "admin_panel_management_commands_sms_scan_py_basecommand", "label": "inherits", "title": "inherits [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "admin_panel_management_commands_sms_scan_command", "to": "admin_panel_management_commands_sms_scan_command_init", "label": "method", "title": "method [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "admin_panel_management_commands_sms_scan_command", "to": "admin_panel_management_commands_sms_scan_command_add_arguments", "label": "method", "title": "method [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "admin_panel_management_commands_sms_scan_command", "to": "admin_panel_management_commands_sms_scan_command_handle", "label": "method", "title": "method [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "admin_panel_management_commands_sms_scan_command", "to": "admin_panel_management_commands_sms_scan_command_handle_signal", "label": "method", "title": "method [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "admin_panel_management_commands_sms_scan_command", "to": "admin_panel_management_commands_sms_scan_command_emit", "label": "method", "title": "method [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "tests_test_sms", "to": "tests_test_sms_autosendtests", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "tests_test_sms_autosendtests", "to": "tests_test_sms_paneltestcase", "label": "inherits", "title": "inherits [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "tests_test_sms_autosendtests", "to": "tests_test_sms_autosendtests_overdue_visit_customer", "label": "method", "title": "method [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "tests_test_sms_autosendtests", "to": "tests_test_sms_autosendtests_test_default_is_pending_so_manager_must_approve", "label": "method", "title": "method [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "tests_test_sms_autosendtests", "to": "tests_test_sms_autosendtests_test_auto_send_enqueues_approved_without_manager", "label": "method", "title": "method [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "tests_test_sms_autosendtests", "to": "tests_test_sms_autosendtests_test_auto_send_does_not_bypass_opt_out_or_disabled", "label": "method", "title": "method [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "tests_test_sms_autosendtests", "to": "tests_test_sms_autosendtests_test_welcome_auto_send_skips_approval_on_customer_creation", "label": "method", "title": "method [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "tests_test_sms_autosendtests", "to": "tests_test_sms_autosendtests_test_template_edit_persists_auto_send", "label": "method", "title": "method [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "tests_test_sms_autosendtests", "to": "tests_test_sms_autosendtests_test_templates_page_shows_auto_send_switch", "label": "method", "title": "method [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "tests_test_sms_rationale_1069", "to": "tests_test_sms_autosendtests", "label": "rationale_for", "title": "rationale_for [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "tests_test_sms_autosendtests", "to": "admin_models_phonenumber", "label": "uses", "title": "uses [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "tests_test_sms_autosendtests", "to": "admin_models_customer", "label": "uses", "title": "uses [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "tests_test_sms", "to": "tests_test_sms_coldstarttests", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "tests_test_sms_coldstarttests", "to": "tests_test_sms_py_testcase", "label": "inherits", "Line truncated
|
||||
const LEGEND = [{"cid": 0, "color": "#4E79A7", "label": "views/sms.py", "count": 30}, {"cid": 1, "color": "#F28E2B", "label": "run_all", "count": 62}, {"cid": 2, "color": "#E15759", "label": "django_db", "count": 49}, {"cid": 3, "color": "#76B7B2", "label": "views/store.py", "count": 63}, {"cid": 4, "color": "#59A14F", "label": "ModelsPackageContractTests", "count": 28}, {"cid": 5, "color": "#EDC948", "label": "PhoneCleanupTests", "count": 33}, {"cid": 6, "color": "#B07AA1", "label": ".load", "count": 61}, {"cid": 7, "color": "#FF9DA7", "label": "models/sms.py", "count": 32}, {"cid": 8, "color": "#9C755F", "label": "logging", "count": 34}, {"cid": 9, "color": "#BAB0AC", "label": "views/customers.py", "count": 34}, {"cid": 10, "color": "#4E79A7", "label": "django_db_models_deletion", "count": 25}, {"cid": 11, "color": "#F28E2B", "label": "make_customer", "count": 20}, {"cid": 12, "color": "#E15759", "label": "customer_phone_entries", "count": 23}, {"cid": 13, "color": "#76B7B2", "label": "EventTriggerTests", "count": 22}, {"cid": 14, "color": "#59A14F", "label": "views/finance.py", "count": 26}, {"cid": 15, "color": "#EDC948", "label": "SMSResult", "count": 31}, {"cid": 16, "color": "#B07AA1", "label": "sms0098ws.py", "count": 29}, {"cid": 17, "color": "#FF9DA7", "label": "Admin Panel Customization", "count": 22}, {"cid": 18, "color": "#9C755F", "label": "User", "count": 25}, {"cid": 19, "color": "#BAB0AC", "label": "django_conf", "count": 23}, {"cid": 20, "color": "#4E79A7", "label": "test_customers.py", "count": 21}, {"cid": 21, "color": "#F28E2B", "label": "phones.py", "count": 14}, {"cid": 22, "color": "#E15759", "label": "Login Template Forms", "count": 19}, {"cid": 23, "color": "#76B7B2", "label": "cheque_inquiry.py", "count": 19}, {"cid": 24, "color": "#59A14F", "label": "factories.py", "count": 14}, {"cid": 25, "color": "#EDC948", "label": "Rip'n Fast. Fewer Tokens. Better Code.", "count": 18}, {"cid": 26, "color": "#B07AA1", "label": "views/factors.py", "count": 20}, {"cid": 27, "color": "#FF9DA7", "label": "to_local", "count": 16}, {"cid": 28, "color": "#9C755F", "label": "make_user", "count": 23}, {"cid": 29, "color": "#BAB0AC", "label": "QueueReviewTests", "count": 9}, {"cid": 30, "color": "#4E79A7", "label": "NoticeMechanismTests", "count": 16}, {"cid": 31, "color": "#F28E2B", "label": "enqueue.py", "count": 17}, {"cid": 32, "color": "#E15759", "label": "enqueue_sms", "count": 18}, {"cid": 33, "color": "#76B7B2", "label": "PanelTestCase", "count": 13}, {"cid": 34, "color": "#59A14F", "label": "ProductInStore", "count": 16}, {"cid": 35, "color": "#EDC948", "label": "admin_panel/templates/admin_panel/baseHesabdari.html", "count": 31}, {"cid": 36, "color": "#B07AA1", "label": "Reference guide", "count": 14}, {"cid": 37, "color": "#FF9DA7", "label": "Factor Creation UI", "count": 14}, {"cid": 38, "color": "#9C755F", "label": "admin_panel/templates/admin_panel/bedehi.html", "count": 14}, {"cid": 39, "color": "#BAB0AC", "label": "project_tree.py", "count": 14}, {"cid": 40, "color": "#4E79A7", "label": "CustomerSmsHistoryTests", "count": 24}, {"cid": 41, "color": "#F28E2B", "label": "TemplatesPageUITests", "count": 14}, {"cid": 42, "color": "#E15759", "label": "SMS Integration Docs", "count": 13}, {"cid": 43, "color": "#76B7B2", "label": "timing_for", "count": 20}, {"cid": 44, "color": "#59A14F", "label": "django_shortcuts", "count": 12}, {"cid": 45, "color": "#EDC948", "label": "stock_in", "count": 14}, {"cid": 46, "color": "#B07AA1", "label": "admin_panel/templates/admin_panel/customerAction.html", "count": 14}, {"cid": 47, "color": "#FF9DA7", "label": "parts_count", "count": 22}, {"cid": 48, "color": "#9C755F", "label": "write_tree", "count": 14}, {"cid": 49, "color": "#BAB0AC", "label": "CustomerInfoCardUITests", "count": 12}, {"cid": 50, "color": "#4E79A7", "label": "Customer", "count": 14}, {"cid": 51, "color": "#F28E2B", "label": "Phone Cleanup Guide", "count": 12}, {"cid": 52, "color": "#E15759", "label": "SmsReportTests", "count": 17}, {"cid": 53, "color": "#76B7B2", "label": "manage.py", "count": 11}, {"cid": 54, "color": "#59A14F", "label": "Agent Operating Guidelines", "count": 11}, {"cid": 55, "color": "#EDC948", "label": "SMSDeliveryCommandTests", "count": 10}, {"cid": 56, "color": "#B07AA1", "label": "BehinSMSProvider", "count": 8}, {"cid": 57, "color": "#FF9DA7", "label": "test_sms.py", "count": 16}, {"cid": 58, "color": "#9C755F", "label": "Financial Data Objects", "count": 10}, {"cid": 59, "color": "#BAB0AC", "label": "Hybrid Migration Command", "count": 10}, {"cid": 60, "color": "#4E79A7", "label": "\u0628\u0627\u0632\u0645\u062d\u0627\u0633\u0628\u0647\u0654 \u00ab\u0622\u062e\u0631\u06cc\u0646 \u0628\u0627\u0632\u062f\u06cc\u062f\u00bb \u0645\u0634\u062a\u0631\u06cc\u0627\u0646", "count": 11}, {"cid": 61, "color": "#F28E2B", "label": "Resource Cleanup Handler", "count": 10}, {"cid": 62, "color": "#E15759", "label": "SMS Timing Migration", "count": 10}, {"cid": 63, "color": "#Line truncated
|
||||
const RAW_NODES = [{"id": "admin_panel_management_commands_sms_scan_command", "label": "Command", "color": {"background": "#F28E2B", "border": "#F28E2B", "highlight": {"background": "#ffffff", "border": "#F28E2B"}}, "size": 12.2, "font": {"size": 0, "color": "#ffffff"}, "title": "Command", "community": 1, "community_name": "run_all", "source_file": "admin_panel/management/commands/sms_scan.py", "file_type": "code", "degree": 7}, {"id": "tests_test_sms_autosendtests", "label": "AutoSendTests", "color": {"background": "#F28E2B", "border": "#F28E2B", "highlight": {"background": "#ffffff", "border": "#F28E2B"}}, "size": 13.8, "font": {"size": 0, "color": "#ffffff"}, "title": "AutoSendTests", "community": 1, "community_name": "run_all", "source_file": "tests/test_sms.py", "file_type": "code", "degree": 12}, {"id": "tests_test_sms_coldstarttests", "label": "ColdStartTests", "color": {"background": "#F28E2B", "border": "#F28E2B", "highlight": {"background": "#ffffff", "border": "#F28E2B"}}, "size": 13.8, "font": {"size": 0, "color": "#ffffff"}, "title": "ColdStartTests", "community": 1, "community_name": "run_all", "source_file": "tests/test_sms.py", "file_type": "code", "degree": 12}, {"id": "tests_test_sms_scannertests", "label": "ScannerTests", "color": {"background": "#F28E2B", "border": "#F28E2B", "highlight": {"background": "#ffffff", "border": "#F28E2B"}}, "size": 14.7, "font": {"size": 12, "color": "#ffffff"}, "title": "ScannerTests", "community": 1, "community_name": "run_all", "source_file": "tests/test_sms.py", "file_type": "code", "degree": 15}, {"id": "tests_test_sms_workertests", "label": "WorkerTests", "color": {"background": "#F28E2B", "border": "#F28E2B", "highlight": {"background": "#ffffff", "border": "#F28E2B"}}, "size": 12.8, "font": {"size": 0, "color": "#ffffff"}, "title": "WorkerTests", "community": 1, "community_name": "run_all", "source_file": "tests/test_sms.py", "file_type": "code", "degree": 9}, {"id": "admin_panel_migrations_0001_initial_migration", "label": "Migration", "color": {"background": "#4E79A7", "border": "#4E79A7", "highlight": {"background": "#ffffff", "border": "#4E79A7"}}, "size": 10.3, "font": {"size": 0, "color": "#ffffff"}, "title": "Migration", "community": 10, "community_name": "django_conf", "source_file": "admin_panel/migrations/0001_initial.py", "file_type": "code", "degree": 1}, {"id": "admin_panel_migrations_0007_productinstore_factor_migration", "label": "Migration", "color": {"background": "#4E79A7", "border": "#4E79A7", "highlight": {"background": "#ffffff", "border": "#4E79A7"}}, "size": 10.3, "font": {"size": 0, "color": "#ffffff"}, "title": "Migration", "community": 10, "community_name": "django_conf", "source_file": "admin_panel/migrations/0007_productinstore_factor.py", "file_type": "code", "degree": 1}, {"id": "admin_panel_migrations_0008_storeroom_user_migration", "label": "Migration", "color": {"background": "#4E79A7", "border": "#4E79A7", "highlight": {"background": "#ffffff", "border": "#4E79A7"}}, "size": 10.3, "font": {"size": 0, "color": "#ffffff"}, "title": "Migration", "community": 10, "community_name": "django_conf", "source_file": "admin_panel/migrations/0008_storeroom_user.py", "file_type": "code", "degree": 1}, {"id": "admin_panel_migrations_0011_storeroom_user_migration", "label": "Migration", "color": {"background": "#4E79A7", "border": "#4E79A7", "highlight": {"background": "#ffffff", "border": "#4E79A7"}}, "size": 10.3, "font": {"size": 0, "color": "#ffffff"}, "title": "Migration", "community": 10, "community_name": "django_conf", "source_file": "admin_panel/migrations/0011_storeroom_user.py", "file_type": "code", "degree": 1}, {"id": "admin_panel_migrations_0012_visitqueue_user_migration", "label": "Migration", "color": {"background": "#4E79A7", "border": "#4E79A7", "highlight": {"background": "#ffffff", "border": "#4E79A7"}}, "size": 10.3, "font": {"size": 0, "color": "#ffffff"}, "title": "Migration", "community": 10, "community_name": "django_conf", "source_file": "admin_panel/migrations/0012_visitqueue_user.py", "file_type": "code", "degree": 1}, {"id": "admin_panel_migrations_0015_auto_20220124_0858_migration", "label": "Migration", "color": {"background": "#4E79A7", "border": "#4E79A7", "highlight": {"background": "#ffffff", "border": "#4E79A7"}}, "size": 10.3, "font": {"size": 0, "color": "#ffffff"}, "title": "Migration", "community": 10, "community_name": "django_conf", "source_file": "admin_panel/migrations/0015_auto_20220124_0858.py", "file_type": "code", "degree": 1}, {"id": "admin_panel_migrations_0016_factor_user_migration", "label": "Migration", "color": {"background": "#4E79A7", "border": "#4E79A7", "highlight": {"background": "#ffffff", "border": "#4E79A7"}}, "size": 10.3, "font": {"size": 0, "color": "#ffffff"}, "title": "Migration", "community": 10, "community_name": "django_conf", "source_file": "admin_panel/migrations/0016_factor_user.py", "file_type": "code", "degree": 1}, {"id": "admin_panel_migrations_0018_alterLine truncated
|
||||
const RAW_EDGES = [{"from": "admin_panel_management_commands_sms_scan", "to": "admin_panel_management_commands_sms_scan_command", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "admin_panel_management_commands_sms_scan_command", "to": "admin_panel_management_commands_sms_scan_py_basecommand", "label": "inherits", "title": "inherits [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "admin_panel_management_commands_sms_scan_command", "to": "admin_panel_management_commands_sms_scan_command_init", "label": "method", "title": "method [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "admin_panel_management_commands_sms_scan_command", "to": "admin_panel_management_commands_sms_scan_command_add_arguments", "label": "method", "title": "method [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "admin_panel_management_commands_sms_scan_command", "to": "admin_panel_management_commands_sms_scan_command_handle", "label": "method", "title": "method [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "admin_panel_management_commands_sms_scan_command", "to": "admin_panel_management_commands_sms_scan_command_handle_signal", "label": "method", "title": "method [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "admin_panel_management_commands_sms_scan_command", "to": "admin_panel_management_commands_sms_scan_command_emit", "label": "method", "title": "method [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "tests_test_sms", "to": "tests_test_sms_autosendtests", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "tests_test_sms_autosendtests", "to": "tests_test_sms_paneltestcase", "label": "inherits", "title": "inherits [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "tests_test_sms_autosendtests", "to": "tests_test_sms_autosendtests_overdue_visit_customer", "label": "method", "title": "method [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "tests_test_sms_autosendtests", "to": "tests_test_sms_autosendtests_test_default_is_pending_so_manager_must_approve", "label": "method", "title": "method [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "tests_test_sms_autosendtests", "to": "tests_test_sms_autosendtests_test_auto_send_enqueues_approved_without_manager", "label": "method", "title": "method [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "tests_test_sms_autosendtests", "to": "tests_test_sms_autosendtests_test_auto_send_does_not_bypass_opt_out_or_disabled", "label": "method", "title": "method [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "tests_test_sms_autosendtests", "to": "tests_test_sms_autosendtests_test_welcome_auto_send_skips_approval_on_customer_creation", "label": "method", "title": "method [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "tests_test_sms_autosendtests", "to": "tests_test_sms_autosendtests_test_template_edit_persists_auto_send", "label": "method", "title": "method [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "tests_test_sms_autosendtests", "to": "tests_test_sms_autosendtests_test_templates_page_shows_auto_send_switch", "label": "method", "title": "method [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "tests_test_sms_rationale_1069", "to": "tests_test_sms_autosendtests", "label": "rationale_for", "title": "rationale_for [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "tests_test_sms_autosendtests", "to": "admin_models_phonenumber", "label": "uses", "title": "uses [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "tests_test_sms_autosendtests", "to": "admin_models_customer", "label": "uses", "title": "uses [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "tests_test_sms", "to": "tests_test_sms_coldstarttests", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "tests_test_sms_coldstarttests", "to": "tests_test_sms_py_testcase", "label": "inherits", "Line truncated
|
||||
const LEGEND = [{"cid": 0, "color": "#4E79A7", "label": "views/sms.py", "count": 35}, {"cid": 1, "color": "#F28E2B", "label": "run_all", "count": 65}, {"cid": 2, "color": "#E15759", "label": "django_db", "count": 79}, {"cid": 3, "color": "#76B7B2", "label": "create_transfer_request", "count": 42}, {"cid": 4, "color": "#59A14F", "label": "ModelsPackageContractTests", "count": 14}, {"cid": 5, "color": "#EDC948", "label": "PhoneCleanupTests", "count": 33}, {"cid": 6, "color": "#B07AA1", "label": ".load", "count": 19}, {"cid": 7, "color": "#FF9DA7", "label": "models/sms.py", "count": 16}, {"cid": 8, "color": "#9C755F", "label": "models/__init__.py", "count": 39}, {"cid": 9, "color": "#BAB0AC", "label": "views/customers.py", "count": 19}, {"cid": 10, "color": "#4E79A7", "label": "django_conf", "count": 50}, {"cid": 11, "color": "#F28E2B", "label": "make_customer", "count": 20}, {"cid": 12, "color": "#E15759", "label": "resolve_recipients", "count": 19}, {"cid": 13, "color": "#76B7B2", "label": "EventTriggerTests", "count": 22}, {"cid": 14, "color": "#59A14F", "label": "views/finance.py", "count": 27}, {"cid": 15, "color": "#EDC948", "label": "views/store.py", "count": 26}, {"cid": 16, "color": "#B07AA1", "label": "sms0098ws.py", "count": 10}, {"cid": 17, "color": "#FF9DA7", "label": "Admin Panel Customization", "count": 22}, {"cid": 18, "color": "#9C755F", "label": "User", "count": 24}, {"cid": 19, "color": "#BAB0AC", "label": "timing_for", "count": 20}, {"cid": 20, "color": "#4E79A7", "label": "Customer", "count": 22}, {"cid": 21, "color": "#F28E2B", "label": "phones.py", "count": 14}, {"cid": 22, "color": "#E15759", "label": "Login Template Forms", "count": 19}, {"cid": 23, "color": "#76B7B2", "label": "cheque_inquiry.py", "count": 20}, {"cid": 24, "color": "#59A14F", "label": "factories.py", "count": 21}, {"cid": 25, "color": "#EDC948", "label": "Rip'n Fast. Fewer Tokens. Better Code.", "count": 18}, {"cid": 26, "color": "#B07AA1", "label": "views/factors.py", "count": 25}, {"cid": 27, "color": "#FF9DA7", "label": "sms0098.py", "count": 14}, {"cid": 28, "color": "#9C755F", "label": "make_user", "count": 23}, {"cid": 29, "color": "#BAB0AC", "label": "QueueReviewTests", "count": 9}, {"cid": 30, "color": "#4E79A7", "label": "NoticeMechanismTests", "count": 16}, {"cid": 31, "color": "#F28E2B", "label": "SmsReportTests", "count": 17}, {"cid": 32, "color": "#E15759", "label": "scanner.py", "count": 16}, {"cid": 33, "color": "#76B7B2", "label": "ZeroZeroNinetyEightWebServiceTests", "count": 38}, {"cid": 34, "color": "#59A14F", "label": "ProductInStore", "count": 6}, {"cid": 35, "color": "#EDC948", "label": "admin_panel/templates/admin_panel/baseHesabdari.html", "count": 15}, {"cid": 36, "color": "#B07AA1", "label": "Reference guide", "count": 14}, {"cid": 37, "color": "#FF9DA7", "label": "Factor Creation UI", "count": 14}, {"cid": 38, "color": "#9C755F", "label": "hesabdariResidNashode.html", "count": 14}, {"cid": 39, "color": "#BAB0AC", "label": "requests", "count": 13}, {"cid": 40, "color": "#4E79A7", "label": "CustomerSmsHistoryTests", "count": 24}, {"cid": 41, "color": "#F28E2B", "label": "TemplatesPageUITests", "count": 14}, {"cid": 42, "color": "#E15759", "label": "SMS Integration Docs", "count": 13}, {"cid": 43, "color": "#76B7B2", "label": "enqueue.py", "count": 14}, {"cid": 44, "color": "#59A14F", "label": "django_shortcuts", "count": 15}, {"cid": 45, "color": "#EDC948", "label": "stock_in", "count": 27}, {"cid": 46, "color": "#B07AA1", "label": "admin_panel/templates/admin_panel/customerAction.html", "count": 13}, {"cid": 47, "color": "#FF9DA7", "label": "parts_count", "count": 22}, {"cid": 48, "color": "#9C755F", "label": "write_tree", "count": 14}, {"cid": 49, "color": "#BAB0AC", "label": "CustomerInfoCardUITests", "count": 12}, {"cid": 50, "color": "#4E79A7", "label": "test_sms.py", "count": 14}, {"cid": 51, "color": "#F28E2B", "label": "Phone Cleanup Guide", "count": 12}, {"cid": 52, "color": "#E15759", "label": ".run_command", "count": 40}, {"cid": 53, "color": "#76B7B2", "label": "project_tree.py", "count": 14}, {"cid": 54, "color": "#59A14F", "label": "Agent Operating Guidelines", "count": 11}, {"cid": 55, "color": "#EDC948", "label": "Command", "count": 72}, {"cid": 56, "color": "#B07AA1", "label": "BehinSMSProvider", "count": 8}, {"cid": 57, "color": "#FF9DA7", "label": "normalize_mobile", "count": 17}, {"cid": 58, "color": "#9C755F", "label": "Financial Data Objects", "count": 10}, {"cid": 59, "color": "#BAB0AC", "label": "Hybrid Migration Command", "count": 10}, {"cid": 60, "color": "#4E79A7", "label": ".run_cmd", "count": 34}, {"cid": 61, "color": "#F28E2B", "label": "Resource Cleanup Handler", "count": 10}, {"cid": 62, "color": "#E15759", "label": "SMS Timing Migration", "count": 10}, {"cid": 63, "color": "#76B7B2", "label": "admin_panel/templates/admin_panel/bedehi.html", "count": 10}, {"cid": 64, "color": "#59A14F", "label": "customerIDFactorBackup.html", "count": 10}, {"cid": 65, "colLine truncated
|
||||
|
||||
// HTML-escape helper — prevents XSS when injecting graph data into innerHTML
|
||||
function esc(s) {
|
||||
|
||||
+15519
-5602
File diff suppressed because it is too large.
Load diff
@@ -882,10 +882,10 @@
|
||||
"semantic_hash": "7cd6b8258d07f9d1a4f668a95b1c9c58"
|
||||
},
|
||||
"admin_panel/models/actions.py": {
|
||||
"mtime": 1791557666.0745652,
|
||||
"seen": 1791560671.8564537,
|
||||
"ast_hash": "8213389e796cad243cdb758fc78076a5",
|
||||
"semantic_hash": "8213389e796cad243cdb758fc78076a5"
|
||||
"mtime": 1792153042.089988,
|
||||
"seen": 1792154233.652624,
|
||||
"ast_hash": "5b305ef4bef23a1e8b518282ef1b318e",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"admin_panel/models/customers.py": {
|
||||
"mtime": 1791621708.4566169,
|
||||
@@ -918,10 +918,10 @@
|
||||
"semantic_hash": "eb5af656ba8114816e5ccabf297fe73c"
|
||||
},
|
||||
"admin_panel/models/system.py": {
|
||||
"mtime": 1791557640.9975393,
|
||||
"seen": 1791560671.8564537,
|
||||
"ast_hash": "519f162ee90768141c9d3a8bc66f899b",
|
||||
"semantic_hash": "519f162ee90768141c9d3a8bc66f899b"
|
||||
"mtime": 1792044277.0221417,
|
||||
"seen": 1792143069.509325,
|
||||
"ast_hash": "c10d997d1e07f8068c6fc1058f175272",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"admin_panel/models/users.py": {
|
||||
"mtime": 1791557633.8912268,
|
||||
@@ -1456,5 +1456,65 @@
|
||||
"seen": 1791720362.5829337,
|
||||
"ast_hash": "29e04949da66478a11268a7672440f2b",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"admin_panel/management/commands/fix_customer_names.py": {
|
||||
"mtime": 1792044603.4607384,
|
||||
"seen": 1792143069.4936357,
|
||||
"ast_hash": "5a49fa8cbc87b9f6a953d057fa57d99a",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"admin_panel/management/commands/normalize_customer_sms_phones.py": {
|
||||
"mtime": 1792047955.413919,
|
||||
"seen": 1792143069.4936357,
|
||||
"ast_hash": "133a138ccdd4893c1f143ae1c02624fc",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"admin_panel/migrations/0072_customernamefixjob.py": {
|
||||
"mtime": 1792044430.7213922,
|
||||
"seen": 1792143069.5073185,
|
||||
"ast_hash": "bb36754a8212524a8139a1902c5d7342",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"admin_panel/name_fix.py": {
|
||||
"mtime": 1792044299.406774,
|
||||
"seen": 1792143069.509325,
|
||||
"ast_hash": "dcd494dfe70787d8f08fc7931cb672e1",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"tests/test_customer_name_fix.py": {
|
||||
"mtime": 1792044607.9337437,
|
||||
"seen": 1792143069.5209367,
|
||||
"ast_hash": "9be8b6950f0393905fece6a5ec39d3fe",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"tests/test_sms_phone_normalize.py": {
|
||||
"mtime": 1792047960.6255968,
|
||||
"seen": 1792143069.5209367,
|
||||
"ast_hash": "136471d0abdbcf7954655a016227debe",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"fix_customer_names.md": {
|
||||
"mtime": 1792050620.3585155,
|
||||
"seen": 1792143069.5341449,
|
||||
"ast_hash": "219b8dae11524c783147745a3dcf95b2",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"normalize_customer_sms_phones.md": {
|
||||
"mtime": 1792050085.597962,
|
||||
"seen": 1792143069.5341449,
|
||||
"ast_hash": "eb58b7f94cbb566de62503c61f011ac9",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"admin_panel/migrations/0073_alter_action_actiontype_choices.py": {
|
||||
"mtime": 1792147840.0279932,
|
||||
"seen": 1792152215.2757294,
|
||||
"ast_hash": "c7edfada8a3fc49fc89515b8d6e38aab",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"admin_panel/migrations/0074_alter_action_status_choices.py": {
|
||||
"mtime": 1792153129.8287945,
|
||||
"seen": 1792154233.652624,
|
||||
"ast_hash": "315d8f435e2837683f3c4b797f7928b9",
|
||||
"semantic_hash": ""
|
||||
}
|
||||
}
|
||||
+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