Files
clinicpro/docs/tasks/task-16-representation/implementation_notes.md
T
hamed de1a78a235 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.
2026-06-09 22:00:34 +03:30

134 lines
4.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# نکات پیاده‌سازی — تسک ۱۶: ماژول Representation (داشبورد دکتر)
## مهم: این ماژول دو نقش دارد
۱. **مدیریت نمایندگی (Multi-tenant)** — هر نماینده یک دامنه دارد
۲. **داشبورد دکتر** — آمار نوبت‌ها، درآمد، بیماران
## ساختار Representation در Drupal
```php
// فیلدهای entity (clinic_pro, bundle=representation):
field_domain_name // دامنه سایت نماینده (مثل: http://yasuj-nobat.localhost:3000/)
field_city // entity reference به category (شهر)
field_active // boolean
field_commission_percent // درصد کمیسیون
// دکتر به نماینده از طریق field_representation لینک می‌شود
// نوبت هم با field_representation لینک می‌شود (از HTTP Host)
```
## شناسایی نماینده از Host
```php
// در زمان ثبت نوبت:
$host = 'http://yasuj-nobat.localhost:3000/';
$representation = $this->representationRepo->findByDomainName($host);
// در Symfony: $request->getSchemeAndHttpHost() . '/'
```
## endpoint: my-doctor (برای بیمار)
```
GET /api/v1/representation/my-doctor/{userId}
```
→ لیست دکترهایی که این کاربر نوبت گرفته را برمی‌گرداند.
فیلد search: `field_representation = $representationId`
## endpoint: my-appointments (برای نماینده)
```
GET /api/v1/representation/my-appointments/{representationId}
```
→ تمام نوبت‌های مرتبط با این نماینده
کوئری روی `appointment.field_representation = $id`
## endpoint: filter (داشبورد ماهانه)
```
GET /api/v1/representation/filter/{representationId}?timestamp=...
```
→ از `timestamp` برای تعیین ماه جاری شمسی استفاده می‌کند
```php
// محاسبه بازه ماه جاری شمسی:
$persianMonthRange = $jalaliService->getCurrentPersianMonthRange($timestamp);
$startTimestamp = $persianMonthRange['start'];
// آمار پرداخت‌ها در این ماه:
// field_status = 'received' AND field_representation = $id AND created >= $startTimestamp
```
Response:
```json
{
"payments_total": { "total_price": 12500000, "count": 25 },
"total_patients": 142,
"today_appointments": 8
}
```
## endpoint: yearly-income (درآمد سالانه)
```
GET /api/v1/representation/yearly-income/{id}?timestamp=...
```
این endpoint از تقویم **شمسی (جلالی)** استفاده می‌کند:
```php
// محاسبه بازه سال شمسی:
$persianYearRange = $jalaliService->getPersianYearRange($timestamp);
$jalaliYear = $persianYearRange['year'];
// Loop از ماه ۱ تا ۱۲ شمسی:
for ($month = 1; $month <= 12; $month++) {
$monthRange = $this->getMonthRangeByYearAndMonth($jalaliYear, $month);
$income = $this->getMonthIncome($representationId, $monthRange['start'], $monthRange['end']);
// income = SUM(payment.amount) WHERE status='received' AND representation=$id AND created BETWEEN start AND end
}
```
Response:
```json
{
"year": 1403,
"monthly_income": [
{ "month": 1, "income": 8500000 },
{ "month": 2, "income": 9200000 },
...
{ "month": 12, "income": 0 }
]
}
```
## JalaliDateService پیاده‌سازی در Symfony
از کد `custom_service/src/jalali/JalaliDateService.php` برای پیاده‌سازی استفاده کن.
توابع مورد نیاز:
```php
class JalaliDateService {
public function getCurrentPersianMonthRange(?int $timestamp): array;
// return: ['start' => timestamp, 'end' => timestamp]
public function getPersianYearRange(?int $timestamp): array;
// return: ['year' => int, 'start' => timestamp, 'end' => timestamp]
public function getMonthRangeByYearAndMonth(int $year, int $month): array;
// return: ['start' => timestamp, 'end' => timestamp]
public function gregorianToPersian(int $gy, int $gm, int $gd): array;
// return: [$jy, $jm, $jd]
public function persianToGregorian(int $jy, int $jm, int $jd): array;
// return: [$gy, $gm, $gd]
}
```
## کشینگ آمار داشبورد
آمار داشبورد را با Redis کش کن (TTL = 5 دقیقه):
```php
$cacheKey = "dashboard_representation_{$representation->getId()}";
// بعد از هر payment جدید → cache invalidate
```
## مجوزها
```
GET /representation/{uuid} → دکتر مرتبط یا ROLE_ADMIN
GET /representation/my-appointments/{id} → دکتر/نماینده یا ROLE_ADMIN
GET /representation/my-doctor/{userId} → کاربر خودش
GET /representation/filter/{id} → دکتر/نماینده یا ROLE_ADMIN
GET /representation/yearly-income/{id} → دکتر/نماینده یا ROLE_ADMIN
```