feat: Add online share functionality for secretaries

- Introduced `online_share_enabled` and `online_share_percent` fields in the `doctor_secretaries` table to manage secretary shares from online appointments.
- Added `bank_account` field in the `profiles` table to store user-level IBANs for settlements.
- Created `secretary_earnings` table to track earnings per secretary from online appointments, including a foreign key relationship with `financial_breakdowns`.
- Implemented `SecretaryEarning` entity and repository for managing secretary earnings.
- Developed `SecretaryShareResolver` service to determine which secretaries earn from online payments.
- Added `UserIbanResolver` service to handle user IBAN retrieval and management.
- Created `HasIbansTrait` for entities to manage IBANs in a JSON format.
- Implemented tests for secretary earnings and API endpoints for managing secretary shares and IBANs.
This commit is contained in:
hamed
2026-07-25 18:34:18 +03:30
parent 73a608c3dd
commit 8d2b0d908a
33 changed files with 2564 additions and 76 deletions
+81 -1
View File
@@ -940,7 +940,87 @@ List all secretaries.
| `search` | string | ❌ | Search by mobile |
### Response `200`
Paginated secretary list with linked doctor info.
Paginated secretary list with linked doctor info. هر ردیف علاوه بر مجوزها،
`online_share_enabled` و `online_share_percent` (سهم منشی از نوبت‌های آنلاین) را هم دارد.
---
### GET `/api/v1/admin/secretary/{uuid}`
جزئیات یک **رابطهٔ** منشی–پزشک/کلینیک (`uuid` = `DoctorSecretary.uuid`، همان uuid لیست بالا) به‌همراه تنظیمات سهم و خلاصهٔ درآمد.
**Permission:** `ROLE_ADMIN`
#### Response `200`
```json
{
"success": true,
"data": {
"data": {
"uuid": "rel-uuid-…",
"secretary_uuid": "user-uuid-…",
"user_name": "زهرا رضایی",
"mobile_number": "0912…",
"doctor_name": "دکتر احمدی",
"doctor_uuid": "doc-uuid-…",
"owner_type": "doctor",
"clinic_uuid": null,
"clinic_name": null,
"is_active": true,
"online_share_enabled": true,
"online_share_percent": 5,
"permissions": { "…": {} },
"created_at": 1700000000,
"earnings": {
"total_rials": 4500000,
"this_month_rials": 1500000,
"appointments_count": 9
}
}
}
}
```
`earnings` روی **کاربرِ منشی** جمع می‌شود (نه فقط این رابطه): مجموع همهٔ سهم‌های ثبت‌شده در `secretary_earnings`. `this_month_rials` = ۳۰ روز گذشته.
#### Errors
| Code | HTTP | Description |
|------|------|-------------|
| `ERR_AUTH_001` | 401 | Missing token |
| `ERR_AUTH_006` | 403 | Not admin |
| `ERR_NOT_FOUND_001` | 404 | منشی یافت نشد |
---
### PUT `/api/v1/admin/secretary/{uuid}/online-share`
فعال/غیرفعال‌کردن محاسبهٔ درآمد منشی از نوبت‌های آنلاین و تعیین درصد سهم. تنظیم
**per-relation** است: یک منشی می‌تواند برای یک پزشک سهم داشته باشد و برای دیگری نه.
**Permission:** `ROLE_ADMIN`
#### Request Body (`application/json`)
```json
{ "enabled": true, "percent": 5 }
```
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `enabled` | boolean | ✅ | محاسبهٔ سهم برای این رابطه فعال باشد؟ |
| `percent` | number | ✅ | درصد سهم از **مبلغ خالص** نوبت (۰ تا ۱۰۰) |
#### Response `200`
همان شکل رابطه (`DoctorSecretary::toArray()`) پس از ذخیره.
#### Errors
| Code | HTTP | Description |
|------|------|-------------|
| `ERR_AUTH_006` | 403 | Not admin |
| `ERR_NOT_FOUND_001` | 404 | منشی یافت نشد |
| `ERR_VALIDATION_001` | 422 | `percent` خارج از ۰–۱۰۰ (`field: percent`) |
| `ERR_VALIDATION_001` | 422 | `enabled=true` با `percent=0` (`field: percent`) |
> **مبنای محاسبه:** سهم منشی مثل پورسانت نماینده از «خالصِ پس از مالیات» گرفته می‌شود — ابتدا هزینهٔ پنل پیامک، بعد مالیات، بعد سهم‌ها. تنها نوبت‌هایی که **آنلاین** پرداخت می‌شوند سهم می‌سازند (نوبت ثبت‌شده در پنل از مسیر تقسیم مالی عبور نمی‌کند). جزئیات: [settlement.md](settlement.md) و [secretary.md](secretary.md).
---