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:
hamed
2026-06-09 22:00:34 +03:30
commit de1a78a235
222 changed files with 36388 additions and 0 deletions
@@ -0,0 +1,121 @@
# پایگاه داده — تسک ۰۹: ماژول تنظیمات نوبت‌دهی
## مهم: ساختار واقعی field_setting از DB backup
**تفاوت اساسی با طراحی اولیه:**
- یک فیلد JSON به نام `field_setting` کل برنامه هفتگی را ذخیره می‌کند
- ساختار: **آرایه ۷ المان** (ایندکس 0=شنبه تا 6=جمعه)
- هر روز دو نوبت **صبح** و **عصر** دارد (نه slot‌های آرایه‌ای)
## جدول: weekly_schedules
_(entity_type=appointment_settings, bundle=weekly_schedule)_
| ستون | نوع | توضیح |
|------|-----|-------|
| id | INT UNSIGNED AUTO_INCREMENT PK | |
| uuid | CHAR(36) UNIQUE NOT NULL | |
| doctor_id | INT FK → doctors.id UNIQUE | یک رکورد به‌ازای هر دکتر |
| setting | LONGTEXT NOT NULL | JSON برنامه کامل هفتگی |
| created_at | INT NOT NULL | Unix timestamp |
| updated_at | INT NOT NULL | Unix timestamp |
## ساختار واقعی JSON فیلد `setting` (از DB backup)
```json
[
{
"morning": {
"active": 1,
"location_id": 48,
"start_time": "08:00",
"end_time": "12:00",
"patient_limit": 10,
"duration_per_patient": 15,
"has_rest": true,
"rest_interval": 60,
"time_to_rest": 10
},
"evening": {
"active": 0
}
},
{
"morning": { "active": 0 },
"evening": {
"active": 1,
"location_id": 49,
"start_time": "15:00",
"end_time": "18:00",
"patient_limit": 8,
"duration_per_patient": 20,
"has_rest": false
}
},
...
]
```
ایندکس روزها:
| ایندکس | روز |
|--------|-----|
| 0 | شنبه |
| 1 | یکشنبه |
| 2 | دوشنبه |
| 3 | سه‌شنبه |
| 4 | چهارشنبه |
| 5 | پنجشنبه |
| 6 | جمعه |
فیلدهای هر session (morning/evening):
| فیلد | نوع | توضیح |
|------|-----|-------|
| active | 0/1 | آیا این نوبت فعال است |
| location_id | int | ID آدرس مطب (→ doctor_addresses) |
| start_time | "HH:MM" | ساعت شروع |
| end_time | "HH:MM" | ساعت پایان |
| patient_limit | int | حداکثر تعداد بیمار |
| duration_per_patient | int (دقیقه) | مدت هر ویزیت |
| has_rest | boolean | آیا استراحت دارد |
| rest_interval | int (دقیقه) | فاصله استراحت |
| time_to_rest | int (دقیقه) | مدت استراحت |
## جدول: date_overrides
_(entity_type=appointment_settings, bundle=date_override)_
| ستون | نوع | توضیح |
|------|-----|-------|
| id | INT UNSIGNED AUTO_INCREMENT PK | |
| uuid | CHAR(36) UNIQUE NOT NULL | |
| doctor_id | INT FK → doctors.id | دکتر |
| date | INT NOT NULL | تاریخ (Unix timestamp) — field_date |
| active | TINYINT(1) DEFAULT 0 | آیا کار می‌کند — field_active |
| setting | LONGTEXT NULL | JSON اسلات‌های سفارشی (همان ساختار field_setting) |
| created_at | INT NOT NULL | |
| updated_at | INT NOT NULL | |
## جدول: holidays
_(entity_type=appointment_settings, bundle=holidays)_
| ستون | نوع | توضیح |
|------|-----|-------|
| id | INT UNSIGNED AUTO_INCREMENT PK | |
| uuid | CHAR(36) UNIQUE NOT NULL | |
| doctor_id | INT FK → doctors.id | دکتر |
| start_date | INT NOT NULL | تاریخ شروع (Unix timestamp) |
| end_date | INT NOT NULL | تاریخ پایان (Unix timestamp) |
| active | TINYINT(1) DEFAULT 1 | field_active |
| created_at | INT NOT NULL | |
| updated_at | INT NOT NULL | |
## ایندکس‌ها
```sql
CREATE UNIQUE INDEX idx_weekly_schedules_doctor ON weekly_schedules(doctor_id);
CREATE INDEX idx_date_overrides_doctor_date ON date_overrides(doctor_id, date);
CREATE INDEX idx_holidays_doctor_range ON holidays(doctor_id, start_date, end_date);
```
## نکات مهم
- **GET /appointment-settings/{uuid}** — uuid دکتر است، نه uuid schedule
- `setting[0]` ایندکس 0=شنبه تا 6=جمعه (هفته ایرانی)
- هر روز دقیقاً ۲ نوبت (morning و evening) دارد
- session غیرفعال فقط `{"active": 0}` است، بقیه فیلدها ندارد