feat: implement domain guard for commission calculation and enhance representation dashboard
- Added domain guard in CommissionService to ensure commission is calculated only when the appointment is booked under the same representation as the doctor. - Updated RepresentationController to filter statistics by representation, ensuring accurate data is shown for each representative. - Introduced new endpoints for the representation dashboard to provide summary statistics, doctor performance, and financial reports. - Created new pages for RepresentationFinance and RepresentationSettlement to display financial data and allow for settlement requests. - Added migration to include booking_representation_id in appointments for tracking the representative under which the appointment was booked.
This commit is contained in:
@@ -151,6 +151,7 @@ Book an appointment slot.
|
||||
| `patient_gender` | string | ✅ | جنسیت بیمار — **همیشه الزامی**. ورودی `man`/`male` یا `woman`/`female` پذیرفته میشود و به فرمِ متعارف `man`/`woman` ذخیره میگردد |
|
||||
| `patient_reason` | string | ❌ | Reason for visit |
|
||||
| `note` | string | ❌ | Patient note |
|
||||
| `city_id` | integer | ❌ | شناسهی شهرِ دامنهی جاری (از `city.json` سایت). برای گاردِ پورسانت نماینده: اگر شهر نمایندهی فعال داشته باشد، `booking_representation_id` نوبت ست میشود. پورسانت فقط وقتی واریز میشود که این نماینده با نمایندهی پزشک یکی باشد. خالی/ناموجود ⇒ بدون پورسانت |
|
||||
|
||||
> **آدرس نوبت:** آدرس (`address_id`) ارسالی نیست؛ سرور آن را از روی `location_id` همان session در برنامهی هفتگی که اسلات در آن قرار دارد، خودکار تعیین و ذخیره میکند. در پاسخ بهصورت `address_id` برمیگردد. همهی مسیرهای رزرو (آنلاین `POST /api/v1/appointment`، منشی `POST /api/v1/my/appointment`، ادمین) آدرس را به همین شکل ست میکنند.
|
||||
|
||||
|
||||
@@ -471,3 +471,76 @@ Get yearly earnings dashboard for a representation.
|
||||
| Code | HTTP | Description |
|
||||
|------|------|-------------|
|
||||
| `ERR_NOT_FOUND_001` | 404 | کاربر جاری نماینده نیست |
|
||||
|
||||
---
|
||||
|
||||
## داشبورد، عملکرد و مالیِ نمایندهی جاری
|
||||
|
||||
> همهی این endpointها `#[IsGranted('ROLE_REPRESENTATION')]` و scope بر اساس `#[CurrentUser]` (نه uuid مسیر). درآمد همیشه از `FinancialBreakdown.representation_share_rials` (پورسانت واقعیِ ثبتشده) محاسبه میشود، نه مبلغ کل نوبت. بازهها: امروز=`strtotime('today')`, هفته=۷ روز اخیر, ماه=۳۰ روز اخیر.
|
||||
|
||||
### GET `/api/v1/representation/dashboard/summary`
|
||||
|
||||
خلاصهی آمار نوبت و درآمد نمایندهی جاری.
|
||||
|
||||
**Response `200`:**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"data": {
|
||||
"appointments": { "today": 0, "week": 3, "month": 12, "total": 40 },
|
||||
"income": {
|
||||
"today": 0, "week": 270000, "month": 909090, "total": 3000000,
|
||||
"settlable_rials": 2090910, "settled_rials": 500000, "pending_rials": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
`settlable_rials` = موجودی کیفپول (`getWalletBalance`)؛ `settled_rials` = جمع Settlementهای `paid`؛ `pending_rials` = جمع `pending`+`approved`.
|
||||
|
||||
#### Errors
|
||||
| Code | HTTP | Description |
|
||||
|------|------|-------------|
|
||||
| `ERR_NOT_FOUND_001` | 404 | کاربر جاری نماینده نیست |
|
||||
|
||||
### GET `/api/v1/representation/doctors/performance`
|
||||
|
||||
عملکرد پزشکانِ نمایندهی جاری (paginated). **Query:** `page`, `limit`.
|
||||
|
||||
**Response `200` (paginated):**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"data": [
|
||||
{
|
||||
"uuid": "...", "name": "دکتر ...",
|
||||
"appointments": { "today": 0, "week": 1, "month": 4, "total": 18 },
|
||||
"representation_income_rials": 363636,
|
||||
"subscription_status": "active"
|
||||
}
|
||||
],
|
||||
"meta": { "totalRecords": 1, "totalPages": 1, "currentPage": 1 }
|
||||
}
|
||||
```
|
||||
`subscription_status`: `active` (اشتراک فعال دارد) یا `none`.
|
||||
|
||||
### GET `/api/v1/representation/finance/report`
|
||||
|
||||
گزارش مالی بازهای از ردیفهای `FinancialBreakdown` نمایندهی جاری (paginated). **Query:** `page`, `limit`, `from` (Unix ts), `to` (Unix ts).
|
||||
|
||||
**Response `200` (paginated):**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"data": [
|
||||
{
|
||||
"uuid": "...", "appointment_uuid": "...", "doctor_name": "دکتر ...",
|
||||
"gross_rials": 2000000, "tax_rials": 45455, "sms_fee_rials": 1500000,
|
||||
"commission_percent": 20, "representation_share_rials": 90909,
|
||||
"created_at": "2026-06-24T..."
|
||||
}
|
||||
],
|
||||
"meta": { "totalRecords": 1, "totalPages": 1, "currentPage": 1 }
|
||||
}
|
||||
```
|
||||
|
||||
> **اصلاح `buildStats`** (در `GET /api/v1/representation/{uuid}/dashboard/monthly|yearly`): قبلاً آمار را به نماینده فیلتر نمیکرد (کلِ پلتفرم). اکنون `total_appointments` فقط نوبتهای پزشکانِ همان نماینده، `commission_rials` از `FinancialBreakdown.representation_share_rials`، و `total_revenue_rials` از `FinancialBreakdown.gross_rials` (source=appointment) همان نماینده محاسبه میشود.
|
||||
|
||||
Reference in New Issue
Block a user