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

4.7 KiB
Raw Blame History

نکات پیاده‌سازی — تسک ۱۶: ماژول Representation (داشبورد دکتر)

مهم: این ماژول دو نقش دارد

۱. مدیریت نمایندگی (Multi-tenant) — هر نماینده یک دامنه دارد ۲. داشبورد دکتر — آمار نوبت‌ها، درآمد، بیماران

ساختار Representation در Drupal

// فیلدهای 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

// در زمان ثبت نوبت:
$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 برای تعیین ماه جاری شمسی استفاده می‌کند

// محاسبه بازه ماه جاری شمسی:
$persianMonthRange = $jalaliService->getCurrentPersianMonthRange($timestamp);
$startTimestamp = $persianMonthRange['start'];

// آمار پرداخت‌ها در این ماه:
// field_status = 'received' AND field_representation = $id AND created >= $startTimestamp

Response:

{
  "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 از تقویم شمسی (جلالی) استفاده می‌کند:

// محاسبه بازه سال شمسی:
$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:

{
  "year": 1403,
  "monthly_income": [
    { "month": 1, "income": 8500000 },
    { "month": 2, "income": 9200000 },
    ...
    { "month": 12, "income": 0 }
  ]
}

JalaliDateService پیاده‌سازی در Symfony

از کد custom_service/src/jalali/JalaliDateService.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 دقیقه):

$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