feat: Implement SMS sending functionality with KavehNegar and Rangineh providers
- Add SendSmsMessage class for encapsulating SMS message data. - Create KavehNegarProvider and RanginehProvider classes implementing SmsProviderInterface for sending SMS. - Implement SmsLogRepository and SmsTemplateRepository for managing SMS logs and templates. - Develop SendSmsHandler for handling SMS sending messages. - Create SmsService to manage SMS dispatching and logging. - Add UserProfileController for managing user profiles with CRUD operations. - Implement UserProfile entity and repository for user profile data management. - Update symfony.lock and bootstrap.php for project dependencies and environment setup.
This commit is contained in:
@@ -0,0 +1,153 @@
|
||||
# تسک ۱۶: ماژول Representation (نمایندگی + داشبورد)
|
||||
|
||||
## توضیح
|
||||
این ماژول دو کارکرد دارد:
|
||||
۱. **مدیریت نمایندگیها (Multi-tenant)** — هر نماینده دامنهای دارد؛ نوبتها و دکترها به نماینده مرتبط میشوند
|
||||
۲. **داشبورد دکتر/نماینده** — آمار نوبتها، درآمد ماهانه/سالانه، بیماران
|
||||
|
||||
## Endpoint ها
|
||||
|
||||
| متد | مسیر | توضیح | نیاز به Auth |
|
||||
|-----|------|-------|-------------|
|
||||
| GET | `/api/v1/representation/{uuid}` | اطلاعات نمایندگی | بله (Admin) |
|
||||
| POST | `/api/v1/representations/{id}/bank-accounts` | اضافه کردن کارت بانکی | بله (Admin) |
|
||||
| GET | `/api/v1/representation/my-appointments/{representationId}` | نوبتهای نماینده | بله |
|
||||
| GET | `/api/v1/representation/my-doctor/{userId}` | دکترهای یک بیمار | بله |
|
||||
| GET | `/api/v1/representation/filter/{representationId}` | آمار ماه جاری شمسی | بله |
|
||||
| GET | `/api/v1/representation/yearly-income/{representationId}` | درآمد سالانه شمسی | بله |
|
||||
|
||||
## پیشنیازها
|
||||
- تسک ۰۱، ۰۲، ۰۵ (Doctor)، ۱۰ (Appointment)، ۱۵ (Payment)
|
||||
- پیادهسازی `JalaliDateService` (برای تبدیل تاریخ شمسی)
|
||||
|
||||
> **تسویه نماینده** در تسک ۱۸ پوشش داده میشود (کیف پول، درخواست برداشت، تأیید ادمین)
|
||||
|
||||
## زمان تخمینی
|
||||
۸ تا ۱۰ ساعت
|
||||
|
||||
## Query Params
|
||||
|
||||
### GET /api/v1/representation/filter/{representationId}
|
||||
```
|
||||
?timestamp=1704067200 (اختیاری — Unix timestamp — برای تعیین ماه شمسی)
|
||||
```
|
||||
اگر timestamp نداده شود، ماه جاری شمسی استفاده میشود.
|
||||
|
||||
### GET /api/v1/representation/yearly-income/{representationId}
|
||||
```
|
||||
?timestamp=1704067200 (اختیاری — Unix timestamp — برای تعیین سال شمسی)
|
||||
```
|
||||
|
||||
## نمونه Responseها
|
||||
|
||||
### GET /api/v1/representation/{uuid}
|
||||
```json
|
||||
{
|
||||
"id": 1,
|
||||
"uuid": "...",
|
||||
"domain_name": "http://yasuj-nobat.localhost:3000/",
|
||||
"city": { "id": 5, "uuid": "...", "label": "یاسوج" },
|
||||
"active": true,
|
||||
"commission_percent": 10.0,
|
||||
"created": 1704067200,
|
||||
"changed": 1716000000
|
||||
}
|
||||
```
|
||||
|
||||
### GET /api/v1/representation/filter/{id}
|
||||
```json
|
||||
{
|
||||
"payments_total": { "total_price": 12500000, "count": 25 },
|
||||
"total_patients": 142,
|
||||
"today_appointments": 8
|
||||
}
|
||||
```
|
||||
|
||||
### GET /api/v1/representation/yearly-income/{id}
|
||||
```json
|
||||
{
|
||||
"year": 1403,
|
||||
"monthly_income": [
|
||||
{ "month": 1, "income": 8500000 },
|
||||
{ "month": 2, "income": 9200000 },
|
||||
{ "month": 3, "income": 0 },
|
||||
...
|
||||
{ "month": 12, "income": 0 }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### GET /api/v1/representation/my-appointments/{id}
|
||||
```json
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"id": 10, "uuid": "...",
|
||||
"start_time": 1716000000, "end_time": 1716001800,
|
||||
"status": "confirmed",
|
||||
"slot": { "start": "09:00", "end": "09:30", "duration": 30, "location_id": 42 },
|
||||
"doctor": { "id": 5, "uuid": "...", "label": "دکتر محمدی" },
|
||||
"address": { "id": 42, "uuid": "...", "label": "مطب شیراز" },
|
||||
"representation": { "id": 1, "uuid": "...", "label": "نمایندگی یاسوج" },
|
||||
"owner": { "id": 20, "uuid": "...", "name": "علی رضایی" }
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## POST /api/v1/representations/{id}/bank-accounts
|
||||
|
||||
```
|
||||
ورودی:
|
||||
Authorization: Bearer <token>
|
||||
Content-Type: application/json
|
||||
|
||||
Body:
|
||||
{
|
||||
"card_number": "6037-9999-1234-5678",
|
||||
"bank_name": "ملت",
|
||||
"is_default": true
|
||||
}
|
||||
```
|
||||
|
||||
```json
|
||||
// خروجی HTTP 201:
|
||||
{
|
||||
"success": true,
|
||||
"bank_account": {
|
||||
"card_number": "6037-9999-1234-5678",
|
||||
"bank_name": "ملت",
|
||||
"is_default": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
> **⚠ نکات مهم:**
|
||||
> - فیلد `bank_account` در جدول Representation بهصورت JSON Array ذخیره میشود
|
||||
> - هر آیتم شامل: `card_number`, `bank_name`, `is_default`
|
||||
> - اگر `is_default=true` باشد، `is_default` سایر کارتها باید `false` شود
|
||||
> - حداقل یک کارت باید `is_default=true` داشته باشد
|
||||
|
||||
---
|
||||
|
||||
## نمونه `bank_account` در GET /api/v1/representation/{uuid}
|
||||
```json
|
||||
{
|
||||
"bank_account": [
|
||||
{ "card_number": "6037-9999-1234-5678", "bank_name": "ملت", "is_default": true },
|
||||
{ "card_number": "5859-3312-4455-6677", "bank_name": "صادرات", "is_default": false }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## فیلدهای Representation Entity
|
||||
```
|
||||
field_domain_name → دامنه (مثل: http://yasuj-nobat.localhost:3000/)
|
||||
field_city → entity reference → category (شهر)
|
||||
field_active → boolean
|
||||
field_commission_percent → درصد کمیسیون
|
||||
```
|
||||
Reference in New Issue
Block a user