Add dental module phase 4 and phase 5 documentation, including treatment estimates, clinical operations, and preset content
- Introduced phase 4 documentation detailing treatment estimates, data models, state machines, API endpoints, and new dashboard metrics. - Added phase 5 documentation covering consumables, lab operations, periodontal charts, sterilization cycles, clinical images, and a checklist for professional review. - Created a preset content document outlining default dental service packages and protocols for clinics.
This commit is contained in:
@@ -0,0 +1,218 @@
|
||||
# فاز ۴ — برآورد درمان و نرخ پذیرش
|
||||
|
||||
> پیشنیاز: فاز ۱ تا ۳.
|
||||
> خروجی قابل تست: دندانپزشک برآورد چندخدمتی میسازد، بیمار تصمیم میگیرد، و نرخ پذیرش در داشبورد دیده میشود.
|
||||
|
||||
---
|
||||
|
||||
## ۱. چرا این فاز جدا افتاد
|
||||
|
||||
در جلسهٔ تصمیمگیری قرار شد فاز ۱ بدون برآورد جلو برود تا زودتر به خروجی برسیم.
|
||||
هزینهاش این است که تا این فاز، چهار شاخص وجود ندارند:
|
||||
نرخ پذیرش، درمان زمانبندینشده، درمان مجدد، و ارزش معوق طرح.
|
||||
|
||||
---
|
||||
|
||||
## ۲. نامگذاری
|
||||
|
||||
واژهٔ انگلیسی `Treatment Plan` در `CONTEXT.md` ممنوع است، چون بین `TreatmentProtocol` و `TreatmentCase` ابهام میساخت.
|
||||
|
||||
واژهٔ این مفهوم:
|
||||
|
||||
**Treatment Estimate** — فهرست پیشنهادی خدمات روی دندانهای مشخص، با قیمت، که به بیمار ارائه میشود و بیمار کل یا بخشی از آن را میپذیرد.
|
||||
در فارسی همان «طرح درمان» است، چون زبان روزمرهٔ دندانپزشک همین است.
|
||||
جدایی نام انگلیسی و فارسی عمدی است: کد باید بدون ابهام باشد، رابط کاربری باید آشنا باشد.
|
||||
|
||||
---
|
||||
|
||||
## ۳. مدل داده
|
||||
|
||||
### `TreatmentEstimate` — جدول `dental_treatment_estimates`
|
||||
|
||||
| ستون | نوع | توضیح |
|
||||
|---|---|---|
|
||||
| `id`, `uuid` | | |
|
||||
| `entity_type`, `entity_id` | | جفت محیط |
|
||||
| `patient_record_id` | int | |
|
||||
| `doctor_id` | int, nullable | پزشک ارائهدهنده |
|
||||
| `title` | string 150 | |
|
||||
| `status` | string 20 | |
|
||||
| `total_rials` | int | جمع همهٔ ردیفها |
|
||||
| `accepted_rials` | int | جمع ردیفهای پذیرفتهشده |
|
||||
| `presented_at` | int, nullable | لحظهٔ ارائه به بیمار |
|
||||
| `decided_at` | int, nullable | لحظهٔ تصمیم بیمار |
|
||||
| `expires_at` | int, nullable | |
|
||||
| `created_at`, `updated_at` | int | |
|
||||
|
||||
### `TreatmentEstimateItem` — جدول `dental_treatment_estimate_items`
|
||||
|
||||
| ستون | نوع | توضیح |
|
||||
|---|---|---|
|
||||
| `id`, `uuid` | | |
|
||||
| `estimate_id` | int | `ON DELETE CASCADE` |
|
||||
| `service_item_id` | int | `ON DELETE RESTRICT` |
|
||||
| `name_snapshot` | string 200 | نام خدمت در لحظهٔ ارائه |
|
||||
| `tooth_number` | smallint, nullable | |
|
||||
| `surfaces` | json, nullable | |
|
||||
| `target_code` | string 10, nullable | |
|
||||
| `quantity` | smallint | |
|
||||
| `unit_price_rials` | int | |
|
||||
| `amount_rials` | int | |
|
||||
| `status` | string 20 | |
|
||||
| `phase` | smallint | فاز درمان، برای اولویتبندی |
|
||||
| `sort_order` | smallint | |
|
||||
| `payer_type` | string 20 | پیشفرض `self_pay` |
|
||||
| `insurance_ref_id` | int, nullable | فقط رزرو شده، بدون منطق |
|
||||
| `session_service_id` | int, nullable | وقتی انجام شد به ردیف فاکتور وصل میشود |
|
||||
|
||||
`name_snapshot` و `unit_price_rials` عمدیاند.
|
||||
همان دلیلی که `TreatmentCaseArea` اسنپشات میگیرد و در `docs/adr/0002` ثبت شده:
|
||||
برآوردی که به بیمار داده شده، سند است و با تغییر تعرفهٔ فردا نباید بازنویسی شود.
|
||||
|
||||
دو ستون `payer_type` و `insurance_ref_id` تنها نقطهٔ اتصال بیمهاند.
|
||||
در این فاز هیچ محاسبهای رویشان نوشته نمیشود.
|
||||
|
||||
---
|
||||
|
||||
## ۴. ماشین حالت
|
||||
|
||||
### برآورد
|
||||
|
||||
```
|
||||
draft ──▶ presented ──▶ accepted ──▶ in_progress ──▶ completed
|
||||
│ │ │
|
||||
├──▶ partially_accepted ─────┤
|
||||
├──▶ rejected └──▶ cancelled
|
||||
└──▶ expired
|
||||
```
|
||||
|
||||
قواعد گذار:
|
||||
|
||||
- `draft → presented`: حداقل یک ردیف و جمع بزرگتر از صفر. `presented_at` ثبت میشود.
|
||||
- `presented → accepted | partially_accepted | rejected`: با تصمیم بیمار. `decided_at` ثبت میشود و `accepted_rials` از جمع ردیفهای پذیرفتهشده حساب میشود.
|
||||
- `presented → expired`: با یک job زمانبندیشده بعد از N روز. پیشفرض پیشنهادی ۹۰ روز، قابل تنظیم در `Config`.
|
||||
- `accepted → in_progress`: با اولین ردیفی که انجام میشود.
|
||||
- `→ completed`: وقتی همهٔ ردیفهای پذیرفتهشده انجام یا لغو شدهاند. توسط پروجکتور، نه دستی.
|
||||
|
||||
### ردیف
|
||||
|
||||
```
|
||||
proposed ──▶ accepted ──▶ scheduled ──▶ done
|
||||
│ │ │ │
|
||||
└▶ rejected └▶ cancelled └▶ cancelled └▶ redo ──▶ scheduled
|
||||
```
|
||||
|
||||
`redo` حالت مستقل است، نه حذف رکورد.
|
||||
دلیل: ورودی شاخص کیفیت است.
|
||||
اگر درمان مجدد با ویرایش رکورد قبلی جایگزین شود، آن شاخص برای همیشه از بین میرود.
|
||||
|
||||
---
|
||||
|
||||
## ۵. چرا `expired` لازم است
|
||||
|
||||
نرخ پذیرش باید مخرجش برآوردهایی باشد که در آن بازه **ارائه** شدهاند، نه برآوردهایی که در آن بازه **تصمیمگیری** شدهاند.
|
||||
|
||||
اگر مخرج بر اساس تصمیم باشد، برآوردهایی که هنوز جواب نگرفتهاند از مخرج بیرون میمانند و نرخ بهصورت مصنوعی بالا میرود.
|
||||
`expired` همان چیزی است که برآورد بیجواب قدیمی را از حالت معلق در میآورد.
|
||||
|
||||
---
|
||||
|
||||
## ۶. اتصال به موتور موجود
|
||||
|
||||
ردیف پذیرفتهشده وقتی زمانبندی میشود:
|
||||
|
||||
- اگر خدمتش پروتکل فعال دارد، همان مسیر موجود `TreatmentCaseStarter` یک `TreatmentCase` باز میکند.
|
||||
- اگر ندارد، فقط یک نوبت ساخته میشود.
|
||||
|
||||
هیچ مسیر رزرو تازهای نوشته نمیشود.
|
||||
|
||||
وقتی ردیف انجام شد و در ویزیت فاکتور شد، `session_service_id` پر میشود و وضعیت ردیف `done` میگیرد.
|
||||
از همانجا پروجکتور فاز ۲ چارت را بهروز میکند.
|
||||
|
||||
هیچ ستون پولی از برآورد به `TreatmentSession` نمیرود.
|
||||
قاعدهٔ `docs/adr/0006` سر جایش میماند.
|
||||
|
||||
---
|
||||
|
||||
## ۷. API
|
||||
|
||||
```
|
||||
GET /api/v1/dental/estimates?patientRecordUuid=&status=
|
||||
POST /api/v1/dental/estimate
|
||||
GET /api/v1/dental/estimate/{uuid}
|
||||
PATCH /api/v1/dental/estimate/{uuid}
|
||||
POST /api/v1/dental/estimate/{uuid}/present
|
||||
POST /api/v1/dental/estimate/{uuid}/decision
|
||||
DELETE /api/v1/dental/estimate/{uuid}
|
||||
|
||||
POST /api/v1/dental/estimate/{uuid}/items
|
||||
PATCH /api/v1/dental/estimate-item/{uuid}
|
||||
DELETE /api/v1/dental/estimate-item/{uuid}
|
||||
POST /api/v1/dental/estimate-item/{uuid}/schedule
|
||||
```
|
||||
|
||||
دسترسی:
|
||||
|
||||
| عملیات | clinic | doctor | secretary |
|
||||
|---|---|---|---|
|
||||
| ساخت و ویرایش برآورد | نه | بله | نه |
|
||||
| ارائه به بیمار | نه | بله | بله |
|
||||
| ثبت تصمیم بیمار | بله | بله | بله |
|
||||
| زمانبندی ردیف پذیرفتهشده | بله | بله | بله |
|
||||
|
||||
دلیل اینکه ثبت تصمیم را منشی هم دارد: تصمیم بیمار معمولاً پشت میز پذیرش گفته میشود.
|
||||
|
||||
`docs/api/dental.md` گسترش پیدا میکند.
|
||||
|
||||
---
|
||||
|
||||
## ۸. شاخصهای تازه در داشبورد
|
||||
|
||||
| کلید | تعریف |
|
||||
|---|---|
|
||||
| `case_acceptance_rate` | جمع پذیرفتهشده تقسیم بر جمع ارائهشده، در بازهٔ ارائه |
|
||||
| `unscheduled_treatment` | جمع مبلغ ردیفهای پذیرفتهشده بدون نوبت |
|
||||
| `redo_rate` | ردیفهای درمان مجدد تقسیم بر ردیفهای انجامشده |
|
||||
| `estimate_backlog` | جمع مبلغ برآوردهای ارائهشدهٔ بیجواب |
|
||||
|
||||
اضافهشدنشان به `DentalMetricProvider` است، بدون تغییر اینترفیس.
|
||||
|
||||
---
|
||||
|
||||
## ۹. پنل ادمین
|
||||
|
||||
- تب تازه در پروندهٔ بیمار: «طرح درمان».
|
||||
- ساخت ردیف با انتخاب خدمت و انتخاب دندان از روی همان `ToothChart` فاز ۲.
|
||||
- نمای چاپی برای دادن به بیمار.
|
||||
- ثبت تصمیم بهصورت ردیفبهردیف با `Switch`، نه یک دکمهٔ کلی. دلیل: پذیرش جزئی حالت رایج است.
|
||||
- کارتهای تازه در بخش دندانی داشبورد.
|
||||
|
||||
---
|
||||
|
||||
## ۱۰. تسکها
|
||||
|
||||
| کد | تسک | معیار پذیرش |
|
||||
|---|---|---|
|
||||
| DM4-01 | موجودیتهای برآورد و ردیف | `TenantSchemaCoverageTest` سبز |
|
||||
| DM4-02 | ماشین حالت برآورد در یک کلاس جدا | گذار غیرمجاز `AppException` میدهد |
|
||||
| DM4-03 | ماشین حالت ردیف | همان |
|
||||
| DM4-04 | محاسبهٔ جمع و جمع پذیرفتهشده در پروجکتور | ویرایش ردیف، جمع را همگام نگه میدارد |
|
||||
| DM4-05 | job انقضا با مهلت قابل تنظیم | برآورد قدیمی `expired` میشود، برآورد پذیرفتهشده نه |
|
||||
| DM4-06 | اندپوینتهای برآورد | همهٔ حالتهای دسترسی تست میشوند |
|
||||
| DM4-07 | زمانبندی ردیف و اتصال به `TreatmentCaseStarter` | خدمت پروتکلدار دوره باز میکند، بقیه فقط نوبت |
|
||||
| DM4-08 | اتصال ردیف به `SessionService` هنگام انجام | وضعیت `done` و بهروزرسانی چارت |
|
||||
| DM4-09 | چهار شاخص تازه | مخرج صفر، `null` میدهد |
|
||||
| DM4-10 | تب طرح درمان در پنل | پذیرش جزئی درست ثبت میشود |
|
||||
| DM4-11 | نمای چاپی | در تم تیره هم درست چاپ میشود |
|
||||
| DM4-12 | مستندات API | مسیرها با کد یکی است |
|
||||
|
||||
---
|
||||
|
||||
## ۱۱. تصمیمهای باز
|
||||
|
||||
اینها قبل از شروع فاز ۴ باید جواب بگیرند:
|
||||
|
||||
۱. مهلت انقضای برآورد چند روز باشد؟ پیشنهاد ۹۰ روز.
|
||||
۲. درمان مجدد هزینهدار است یا صفر؟ روی شاخص تولید اثر مستقیم دارد.
|
||||
۳. قیمت ردیف برآورد از تعرفهٔ لحظهٔ ارائه میآید یا قابل ویرایش دستی است؟ پیشنهاد: پیشفرض از تعرفه، قابل ویرایش با ثبت لاگ.
|
||||
۴. آیا یک بیمار میتواند همزمان دو برآورد ارائهشده داشته باشد؟ پیشنهاد: بله، ولی داشبورد باید هشدار بدهد.
|
||||
Reference in New Issue
Block a user