feat(clinic): enhance clinic listing with additional details and address information
- Updated the clinic API response to include new fields: title, phone, logo, images_clinic, doctors_count, city, state, 24_7, and field_working_days. - Modified the ClinicController to fetch and include city and state information based on the clinic's address. - Refactored the toListArray method in the Clinic entity to accept city and state parameters. - Added a new method in the ClinicRepository to retrieve city and province names for each clinic based on their address.
This commit is contained in:
@@ -49,7 +49,7 @@
|
|||||||
### Backend
|
### Backend
|
||||||
|
|
||||||
| لایه | تکنولوژی |
|
| لایه | تکنولوژی |
|
||||||
|------|----------|
|
| ------------- | -------------------------------- |
|
||||||
| Framework | Symfony 7.x |
|
| Framework | Symfony 7.x |
|
||||||
| PHP | ≥ 8.2 |
|
| PHP | ≥ 8.2 |
|
||||||
| ORM | Doctrine ORM |
|
| ORM | Doctrine ORM |
|
||||||
@@ -63,7 +63,7 @@
|
|||||||
### Frontend (Admin SPA)
|
### Frontend (Admin SPA)
|
||||||
|
|
||||||
| لایه | تکنولوژی |
|
| لایه | تکنولوژی |
|
||||||
|------|----------|
|
| ------------- | --------------------- |
|
||||||
| Framework | React 19 + TypeScript |
|
| Framework | React 19 + TypeScript |
|
||||||
| Routing | React Router DOM v7 |
|
| Routing | React Router DOM v7 |
|
||||||
| Server State | TanStack Query v5 |
|
| Server State | TanStack Query v5 |
|
||||||
@@ -132,7 +132,7 @@ ddev exec php bin/console messenger:consume async
|
|||||||
## ۴. آدرسهای مهم
|
## ۴. آدرسهای مهم
|
||||||
|
|
||||||
| سرویس | آدرس |
|
| سرویس | آدرس |
|
||||||
|-------|------|
|
| ---------------- | ------------------------------------ |
|
||||||
| **وبسایت** | https://clinic-pro.ddev.site |
|
| **وبسایت** | https://clinic-pro.ddev.site |
|
||||||
| **پنل ادمین** | https://clinic-pro.ddev.site/admin |
|
| **پنل ادمین** | https://clinic-pro.ddev.site/admin |
|
||||||
| **Swagger UI** | https://clinic-pro.ddev.site/api/doc |
|
| **Swagger UI** | https://clinic-pro.ddev.site/api/doc |
|
||||||
@@ -143,7 +143,7 @@ ddev exec php bin/console messenger:consume async
|
|||||||
> آدرس: `https://clinic-pro.ddev.site/api/doc`
|
> آدرس: `https://clinic-pro.ddev.site/api/doc`
|
||||||
|
|
||||||
| فیلد | مقدار |
|
| فیلد | مقدار |
|
||||||
|------|-------|
|
| -------------- | ----------- |
|
||||||
| **نام کاربری** | `admin` |
|
| **نام کاربری** | `admin` |
|
||||||
| **رمز عبور** | `clinic123` |
|
| **رمز عبور** | `clinic123` |
|
||||||
|
|
||||||
@@ -201,7 +201,7 @@ SEP_TERMINAL_ID=<شناسه>
|
|||||||
|
|
||||||
# ── Swagger UI ───────────────────────────────────────────────────
|
# ── Swagger UI ───────────────────────────────────────────────────
|
||||||
API_DOC_USERNAME=admin
|
API_DOC_USERNAME=admin
|
||||||
API_DOC_PASSWORD=<bcrypt hash> # plain text: clinic123
|
API_DOC_PASSWORD=<bcrypt hash> # plain text: admin@admin
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -262,7 +262,7 @@ POST /api/v1/user/login
|
|||||||
### نقشهای کاربری
|
### نقشهای کاربری
|
||||||
|
|
||||||
| نقش | توضیح | دسترسی |
|
| نقش | توضیح | دسترسی |
|
||||||
|-----|--------|--------|
|
| ---------------- | ------------------ | ------------------------ |
|
||||||
| `ROLE_USER` | پایه — همه کاربران | نوبتگیری، پروفایل |
|
| `ROLE_USER` | پایه — همه کاربران | نوبتگیری، پروفایل |
|
||||||
| `ROLE_ADMIN` | مدیر کل | پنل ادمین کامل |
|
| `ROLE_ADMIN` | مدیر کل | پنل ادمین کامل |
|
||||||
| `ROLE_CLINIC` | صاحب کلینیک | مدیریت کلینیک خود |
|
| `ROLE_CLINIC` | صاحب کلینیک | مدیریت کلینیک خود |
|
||||||
@@ -275,10 +275,25 @@ POST /api/v1/user/login
|
|||||||
{
|
{
|
||||||
"version": 1,
|
"version": 1,
|
||||||
"resources": {
|
"resources": {
|
||||||
"appointments": { "view": true, "create": true, "cancel": false, "update_status": true },
|
"appointments": {
|
||||||
"addresses": { "view": true, "create": false, "update": false, "delete": false },
|
"view": true,
|
||||||
|
"create": true,
|
||||||
|
"cancel": false,
|
||||||
|
"update_status": true
|
||||||
|
},
|
||||||
|
"addresses": {
|
||||||
|
"view": true,
|
||||||
|
"create": false,
|
||||||
|
"update": false,
|
||||||
|
"delete": false
|
||||||
|
},
|
||||||
"clinic_info": { "view": true, "update": false },
|
"clinic_info": { "view": true, "update": false },
|
||||||
"insurances": { "view": true, "create": false, "update": false, "delete": false }
|
"insurances": {
|
||||||
|
"view": true,
|
||||||
|
"create": false,
|
||||||
|
"update": false,
|
||||||
|
"delete": false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -293,7 +308,7 @@ POST /api/v1/user/login
|
|||||||
### Firewall های security.yaml
|
### Firewall های security.yaml
|
||||||
|
|
||||||
| Firewall | Pattern | توضیح |
|
| Firewall | Pattern | توضیح |
|
||||||
|----------|---------|--------|
|
| ------------------ | ------------------------------ | ----------------------------------- |
|
||||||
| `api_doc` | `^/api/doc` | HTTP Basic Auth (admin / clinic123) |
|
| `api_doc` | `^/api/doc` | HTTP Basic Auth (admin / clinic123) |
|
||||||
| `public_endpoints` | OTP، OAuth، endpoint های عمومی | بدون احراز هویت |
|
| `public_endpoints` | OTP، OAuth، endpoint های عمومی | بدون احراز هویت |
|
||||||
| `payment_callback` | `/api/v1/payment/callback/` | بدون احراز هویت |
|
| `payment_callback` | `/api/v1/payment/callback/` | بدون احراز هویت |
|
||||||
@@ -306,7 +321,7 @@ POST /api/v1/user/login
|
|||||||
### جداول اصلی
|
### جداول اصلی
|
||||||
|
|
||||||
| جدول | موجودیت | توضیح |
|
| جدول | موجودیت | توضیح |
|
||||||
|------|---------|--------|
|
| --------------------------- | ---------------------- | ------------------------------------------------------------------------------------ |
|
||||||
| `users` | User | uuid، mobile_number (unique)، roles (JSON)، status |
|
| `users` | User | uuid، mobile_number (unique)، roles (JSON)، status |
|
||||||
| `doctors` | Doctor | user_id (OneToOne)، degree، doctor_rate، active_doctor_appointment |
|
| `doctors` | Doctor | user_id (OneToOne)، degree، doctor_rate، active_doctor_appointment |
|
||||||
| `doctor_addresses` | DoctorAddress | doctor_id، name، latitude، longitude |
|
| `doctor_addresses` | DoctorAddress | doctor_id، name، latitude، longitude |
|
||||||
@@ -338,7 +353,7 @@ POST /api/v1/user/login
|
|||||||
### جداول رابطهای (ManyToMany)
|
### جداول رابطهای (ManyToMany)
|
||||||
|
|
||||||
| جدول | رابطه |
|
| جدول | رابطه |
|
||||||
|------|-------|
|
| -------------------- | ---------------------- |
|
||||||
| `clinic_doctors` | Clinic ↔ Doctor |
|
| `clinic_doctors` | Clinic ↔ Doctor |
|
||||||
| `clinic_specialties` | Clinic ↔ Specialty |
|
| `clinic_specialties` | Clinic ↔ Specialty |
|
||||||
| `clinic_services` | Clinic ↔ DoctorService |
|
| `clinic_services` | Clinic ↔ DoctorService |
|
||||||
@@ -375,7 +390,7 @@ Clinic ──ManyToOne──► User (owner)
|
|||||||
### احراز هویت
|
### احراز هویت
|
||||||
|
|
||||||
| متد | آدرس | توضیح | دسترسی |
|
| متد | آدرس | توضیح | دسترسی |
|
||||||
|-----|------|--------|--------|
|
| ---- | -------------------------- | ------------------ | ---------- |
|
||||||
| POST | `/api/v1/user/send-code` | ارسال OTP | عمومی |
|
| POST | `/api/v1/user/send-code` | ارسال OTP | عمومی |
|
||||||
| POST | `/api/v1/user/verify-code` | تأیید OTP | عمومی |
|
| POST | `/api/v1/user/verify-code` | تأیید OTP | عمومی |
|
||||||
| POST | `/api/v1/user/register` | ثبتنام | عمومی |
|
| POST | `/api/v1/user/register` | ثبتنام | عمومی |
|
||||||
@@ -388,7 +403,7 @@ Clinic ──ManyToOne──► User (owner)
|
|||||||
### پزشکان
|
### پزشکان
|
||||||
|
|
||||||
| متد | آدرس | توضیح | دسترسی |
|
| متد | آدرس | توضیح | دسترسی |
|
||||||
|-----|------|--------|--------|
|
| ------ | ------------------------------------------------------------ | --------------- | ---------- |
|
||||||
| GET | `/api/v1/doctors` | لیست پزشکان | عمومی |
|
| GET | `/api/v1/doctors` | لیست پزشکان | عمومی |
|
||||||
| GET | `/api/v1/doctor/{uuid}` | جزئیات پزشک | عمومی |
|
| GET | `/api/v1/doctor/{uuid}` | جزئیات پزشک | عمومی |
|
||||||
| POST | `/api/v1/doctor` | ایجاد پروفایل | احراز هویت |
|
| POST | `/api/v1/doctor` | ایجاد پروفایل | احراز هویت |
|
||||||
@@ -404,7 +419,7 @@ Clinic ──ManyToOne──► User (owner)
|
|||||||
### کلینیکها
|
### کلینیکها
|
||||||
|
|
||||||
| متد | آدرس | توضیح | دسترسی |
|
| متد | آدرس | توضیح | دسترسی |
|
||||||
|-----|------|--------|--------|
|
| ----- | --------------------------------------------------- | -------------- | ---------- |
|
||||||
| GET | `/api/v1/clinics` | لیست کلینیکها | عمومی |
|
| GET | `/api/v1/clinics` | لیست کلینیکها | عمومی |
|
||||||
| GET | `/api/v1/clinic/{uuid}` | جزئیات کلینیک | عمومی |
|
| GET | `/api/v1/clinic/{uuid}` | جزئیات کلینیک | عمومی |
|
||||||
| POST | `/api/v1/clinic` | ایجاد کلینیک | احراز هویت |
|
| POST | `/api/v1/clinic` | ایجاد کلینیک | احراز هویت |
|
||||||
@@ -416,7 +431,7 @@ Clinic ──ManyToOne──► User (owner)
|
|||||||
### دعوتنامه پزشک به کلینیک
|
### دعوتنامه پزشک به کلینیک
|
||||||
|
|
||||||
| متد | آدرس | توضیح | دسترسی |
|
| متد | آدرس | توضیح | دسترسی |
|
||||||
|-----|------|--------|--------|
|
| ------ | -------------------------------------------------- | ----------------- | ---------- |
|
||||||
| POST | `/api/v1/admin/clinic/{uuid}/invite-doctor` | ارسال دعوتنامه | ROLE_ADMIN |
|
| POST | `/api/v1/admin/clinic/{uuid}/invite-doctor` | ارسال دعوتنامه | ROLE_ADMIN |
|
||||||
| GET | `/api/v1/admin/clinic/{uuid}/invitations` | لیست دعوتنامهها | ROLE_ADMIN |
|
| GET | `/api/v1/admin/clinic/{uuid}/invitations` | لیست دعوتنامهها | ROLE_ADMIN |
|
||||||
| POST | `/api/v1/admin/clinic/invitation/{invUuid}/resend` | ارسال مجدد پیامک | ROLE_ADMIN |
|
| POST | `/api/v1/admin/clinic/invitation/{invUuid}/resend` | ارسال مجدد پیامک | ROLE_ADMIN |
|
||||||
@@ -431,7 +446,7 @@ Clinic ──ManyToOne──► User (owner)
|
|||||||
### نوبتدهی
|
### نوبتدهی
|
||||||
|
|
||||||
| متد | آدرس | توضیح | دسترسی |
|
| متد | آدرس | توضیح | دسترسی |
|
||||||
|-----|------|--------|--------|
|
| ----- | ------------------------------------------ | -------------- | ---------- |
|
||||||
| GET | `/api/v1/appointment-slots` | اسلاتهای خالی | عمومی |
|
| GET | `/api/v1/appointment-slots` | اسلاتهای خالی | عمومی |
|
||||||
| POST | `/api/v1/appointment` | رزرو نوبت | احراز هویت |
|
| POST | `/api/v1/appointment` | رزرو نوبت | احراز هویت |
|
||||||
| GET | `/api/v1/appointment/{uuid}` | جزئیات نوبت | احراز هویت |
|
| GET | `/api/v1/appointment/{uuid}` | جزئیات نوبت | احراز هویت |
|
||||||
@@ -442,7 +457,7 @@ Clinic ──ManyToOne──► User (owner)
|
|||||||
### تنظیمات نوبتدهی
|
### تنظیمات نوبتدهی
|
||||||
|
|
||||||
| متد | آدرس | توضیح |
|
| متد | آدرس | توضیح |
|
||||||
|-----|------|--------|
|
| --------------------- | ---------------------------------------------- | ------------ |
|
||||||
| POST/PATCH/GET | `/api/v1/appointment-settings/weekly-schedule` | برنامه هفتگی |
|
| POST/PATCH/GET | `/api/v1/appointment-settings/weekly-schedule` | برنامه هفتگی |
|
||||||
| POST/PATCH/DELETE/GET | `/api/v1/appointment-settings/date-override` | روز استثناء |
|
| POST/PATCH/DELETE/GET | `/api/v1/appointment-settings/date-override` | روز استثناء |
|
||||||
| POST/PATCH/DELETE/GET | `/api/v1/appointment-settings/holidays` | تعطیلات |
|
| POST/PATCH/DELETE/GET | `/api/v1/appointment-settings/holidays` | تعطیلات |
|
||||||
@@ -450,7 +465,7 @@ Clinic ──ManyToOne──► User (owner)
|
|||||||
### پرداخت
|
### پرداخت
|
||||||
|
|
||||||
| متد | آدرس | توضیح | دسترسی |
|
| متد | آدرس | توضیح | دسترسی |
|
||||||
|-----|------|--------|--------|
|
| -------- | ------------------------------------ | ---------------------- | ---------- |
|
||||||
| POST | `/api/v1/payment/appointment` | شروع پرداخت نوبت | احراز هویت |
|
| POST | `/api/v1/payment/appointment` | شروع پرداخت نوبت | احراز هویت |
|
||||||
| POST/GET | `/api/v1/payment/callback/{gateway}` | callback (mellat\|sep) | عمومی |
|
| POST/GET | `/api/v1/payment/callback/{gateway}` | callback (mellat\|sep) | عمومی |
|
||||||
| GET | `/api/v1/payment/{uuid}` | وضعیت پرداخت | احراز هویت |
|
| GET | `/api/v1/payment/{uuid}` | وضعیت پرداخت | احراز هویت |
|
||||||
@@ -459,7 +474,7 @@ Clinic ──ManyToOne──► User (owner)
|
|||||||
### کیف پول و تسویهحساب
|
### کیف پول و تسویهحساب
|
||||||
|
|
||||||
| متد | آدرس | توضیح | دسترسی |
|
| متد | آدرس | توضیح | دسترسی |
|
||||||
|-----|------|--------|--------|
|
| ---- | ----------------------------------- | ------------------- | ---------- |
|
||||||
| GET | `/api/v1/wallet/balance` | موجودی کیف پول | احراز هویت |
|
| GET | `/api/v1/wallet/balance` | موجودی کیف پول | احراز هویت |
|
||||||
| GET | `/api/v1/wallet/transactions` | تاریخچه تراکنشها | احراز هویت |
|
| GET | `/api/v1/wallet/transactions` | تاریخچه تراکنشها | احراز هویت |
|
||||||
| POST | `/api/v1/settlement` | درخواست تسویه | احراز هویت |
|
| POST | `/api/v1/settlement` | درخواست تسویه | احراز هویت |
|
||||||
@@ -470,7 +485,7 @@ Clinic ──ManyToOne──► User (owner)
|
|||||||
### امتیاز و نظرات
|
### امتیاز و نظرات
|
||||||
|
|
||||||
| متد | آدرس | توضیح | دسترسی |
|
| متد | آدرس | توضیح | دسترسی |
|
||||||
|-----|------|--------|--------|
|
| ------ | ------------------------------- | -------------- | ---------- |
|
||||||
| POST | `/api/v1/rate` | ثبت امتیاز | احراز هویت |
|
| POST | `/api/v1/rate` | ثبت امتیاز | احراز هویت |
|
||||||
| GET | `/api/v1/rate/{doctorUuid}` | میانگین امتیاز | عمومی |
|
| GET | `/api/v1/rate/{doctorUuid}` | میانگین امتیاز | عمومی |
|
||||||
| POST | `/api/v1/comment` | ثبت نظر | احراز هویت |
|
| POST | `/api/v1/comment` | ثبت نظر | احراز هویت |
|
||||||
@@ -481,7 +496,7 @@ Clinic ──ManyToOne──► User (owner)
|
|||||||
### منشی
|
### منشی
|
||||||
|
|
||||||
| متد | آدرس | توضیح | دسترسی |
|
| متد | آدرس | توضیح | دسترسی |
|
||||||
|-----|------|--------|--------|
|
| ------ | ---------------------------------- | ------------------ | ----------- |
|
||||||
| POST | `/api/v1/secretary` | ایجاد منشی | ROLE_DOCTOR |
|
| POST | `/api/v1/secretary` | ایجاد منشی | ROLE_DOCTOR |
|
||||||
| GET | `/api/v1/secretary/{uuid}` | جزئیات | احراز هویت |
|
| GET | `/api/v1/secretary/{uuid}` | جزئیات | احراز هویت |
|
||||||
| PATCH | `/api/v1/secretary/{uuid}` | ویرایش permissions | ROLE_DOCTOR |
|
| PATCH | `/api/v1/secretary/{uuid}` | ویرایش permissions | ROLE_DOCTOR |
|
||||||
@@ -491,7 +506,7 @@ Clinic ──ManyToOne──► User (owner)
|
|||||||
### نمایندگان
|
### نمایندگان
|
||||||
|
|
||||||
| متد | آدرس | توضیح | دسترسی |
|
| متد | آدرس | توضیح | دسترسی |
|
||||||
|-----|------|--------|--------|
|
| --------------------- | ------------------------------------------------- | -------------- | ---------- |
|
||||||
| POST/GET/PATCH/DELETE | `/api/v1/representation/{uuid?}` | مدیریت نماینده | احراز هویت |
|
| POST/GET/PATCH/DELETE | `/api/v1/representation/{uuid?}` | مدیریت نماینده | احراز هویت |
|
||||||
| GET | `/api/v1/representation/{uuid}/dashboard/monthly` | آمار ماهانه | احراز هویت |
|
| GET | `/api/v1/representation/{uuid}/dashboard/monthly` | آمار ماهانه | احراز هویت |
|
||||||
| GET | `/api/v1/representation/{uuid}/dashboard/yearly` | آمار سالانه | احراز هویت |
|
| GET | `/api/v1/representation/{uuid}/dashboard/yearly` | آمار سالانه | احراز هویت |
|
||||||
@@ -499,7 +514,7 @@ Clinic ──ManyToOne──► User (owner)
|
|||||||
### پیامک
|
### پیامک
|
||||||
|
|
||||||
| متد | آدرس | توضیح | دسترسی |
|
| متد | آدرس | توضیح | دسترسی |
|
||||||
|-----|------|--------|--------|
|
| --------------------- | ------------------------------------------- | ---------------- | ---------- |
|
||||||
| POST | `/api/v1/sms/send` | ارسال مستقیم | احراز هویت |
|
| POST | `/api/v1/sms/send` | ارسال مستقیم | احراز هویت |
|
||||||
| POST | `/api/v1/sms/send-template` | ارسال با قالب | احراز هویت |
|
| POST | `/api/v1/sms/send-template` | ارسال با قالب | احراز هویت |
|
||||||
| POST/PATCH/GET/DELETE | `/api/v1/sms/template/{uuid?}` | مدیریت قالب | احراز هویت |
|
| POST/PATCH/GET/DELETE | `/api/v1/sms/template/{uuid?}` | مدیریت قالب | احراز هویت |
|
||||||
@@ -528,7 +543,7 @@ POST/PATCH/DELETE /api/v1/admin/city/{id?} ROLE_ADMIN
|
|||||||
### بلاگ
|
### بلاگ
|
||||||
|
|
||||||
| متد | آدرس | توضیح | دسترسی |
|
| متد | آدرس | توضیح | دسترسی |
|
||||||
|-----|------|--------|--------|
|
| ------ | ------------------------------------------ | ---------------------- | ---------- |
|
||||||
| GET | `/api/v1/blogs` | لیست بلاگهای منتشرشده | عمومی |
|
| GET | `/api/v1/blogs` | لیست بلاگهای منتشرشده | عمومی |
|
||||||
| GET | `/api/v1/blog/{slug}` | جزئیات بلاگ | عمومی |
|
| GET | `/api/v1/blog/{slug}` | جزئیات بلاگ | عمومی |
|
||||||
| POST | `/api/v1/blog` | نوشتن بلاگ | احراز هویت |
|
| POST | `/api/v1/blog` | نوشتن بلاگ | احراز هویت |
|
||||||
@@ -541,7 +556,7 @@ POST/PATCH/DELETE /api/v1/admin/city/{id?} ROLE_ADMIN
|
|||||||
> همه endpoint های زیر نیاز به `ROLE_ADMIN` دارند.
|
> همه endpoint های زیر نیاز به `ROLE_ADMIN` دارند.
|
||||||
|
|
||||||
| آدرس | توضیح |
|
| آدرس | توضیح |
|
||||||
|------|--------|
|
| ------------------------------------------ | ------------------------------------------ |
|
||||||
| `GET /api/v1/admin/dashboard/stats` | ۱۲ KPI (کاربران، پزشکان، نوبت، درآمد، ...) |
|
| `GET /api/v1/admin/dashboard/stats` | ۱۲ KPI (کاربران، پزشکان، نوبت، درآمد، ...) |
|
||||||
| `GET /api/v1/admin/dashboard/charts` | نمودار ۳۰ روزه نوبت و درآمد |
|
| `GET /api/v1/admin/dashboard/charts` | نمودار ۳۰ روزه نوبت و درآمد |
|
||||||
| `GET /api/v1/admin/dashboard/recent` | آخرین نوبتها، پرداختها، کاربران |
|
| `GET /api/v1/admin/dashboard/recent` | آخرین نوبتها، پرداختها، کاربران |
|
||||||
@@ -587,7 +602,7 @@ POST/PATCH/DELETE /api/v1/admin/city/{id?} ROLE_ADMIN
|
|||||||
### Route های پنل
|
### Route های پنل
|
||||||
|
|
||||||
| مسیر | صفحه | توضیح |
|
| مسیر | صفحه | توضیح |
|
||||||
|------|------|--------|
|
| ------------------------------ | ------------------------ | ------------------------------------ |
|
||||||
| `/admin/login` | LoginPage | ورود با موبایل + رمز |
|
| `/admin/login` | LoginPage | ورود با موبایل + رمز |
|
||||||
| `/admin/dashboard` | DashboardPage | آمار KPI، نمودار، فعالیتهای اخیر |
|
| `/admin/dashboard` | DashboardPage | آمار KPI، نمودار، فعالیتهای اخیر |
|
||||||
| `/admin/users` | UsersPage | لیست + جستجو + فیلتر نقش |
|
| `/admin/users` | UsersPage | لیست + جستجو + فیلتر نقش |
|
||||||
@@ -616,8 +631,9 @@ POST/PATCH/DELETE /api/v1/admin/city/{id?} ROLE_ADMIN
|
|||||||
```typescript
|
```typescript
|
||||||
// لیست paginated
|
// لیست paginated
|
||||||
const { data } = useQuery({
|
const { data } = useQuery({
|
||||||
queryKey: ['resource', page, filters],
|
queryKey: ["resource", page, filters],
|
||||||
queryFn: () => api.get<PaginatedResponse<T>>(`/api/v1/admin/...?page=${page}`),
|
queryFn: () =>
|
||||||
|
api.get<PaginatedResponse<T>>(`/api/v1/admin/...?page=${page}`),
|
||||||
});
|
});
|
||||||
const items = data?.data ?? []; // آرایه آیتمها
|
const items = data?.data ?? []; // آرایه آیتمها
|
||||||
const total = data?.meta?.totalRecords ?? 0;
|
const total = data?.meta?.totalRecords ?? 0;
|
||||||
@@ -655,7 +671,7 @@ ddev exec php bin/console doctrine:migrations:status
|
|||||||
### لیست migration های موجود
|
### لیست migration های موجود
|
||||||
|
|
||||||
| فایل | توضیح |
|
| فایل | توضیح |
|
||||||
|------|--------|
|
| ------------------------- | ---------------------------------------------- |
|
||||||
| Version20260609130407 | جداول پایه: users, doctors, appointments |
|
| Version20260609130407 | جداول پایه: users, doctors, appointments |
|
||||||
| Version20260609131304 | پرداخت، کیف پول |
|
| Version20260609131304 | پرداخت، کیف پول |
|
||||||
| Version20260609131553 | امتیاز، نظرات |
|
| Version20260609131553 | امتیاز، نظرات |
|
||||||
@@ -683,14 +699,17 @@ ddev exec php bin/console doctrine:migrations:status
|
|||||||
### پیامک
|
### پیامک
|
||||||
|
|
||||||
**KaveNegar** (پیشفرض)
|
**KaveNegar** (پیشفرض)
|
||||||
|
|
||||||
- API: `https://api.kavenegar.com/v1/{KEY}/sms/send.json`
|
- API: `https://api.kavenegar.com/v1/{KEY}/sms/send.json`
|
||||||
- پشتیبانی از: send (متن آزاد) + sendTemplate (قالب)
|
- پشتیبانی از: send (متن آزاد) + sendTemplate (قالب)
|
||||||
|
|
||||||
**Rangineh**
|
**Rangineh**
|
||||||
|
|
||||||
- API: `https://rest.payamresan.com/api/v1/send`
|
- API: `https://rest.payamresan.com/api/v1/send`
|
||||||
- پشتیبانی از: send + sendTemplate
|
- پشتیبانی از: send + sendTemplate
|
||||||
|
|
||||||
**ارسال async:**
|
**ارسال async:**
|
||||||
|
|
||||||
```php
|
```php
|
||||||
$this->smsService->dispatchAsync($mobile, $message);
|
$this->smsService->dispatchAsync($mobile, $message);
|
||||||
// → Symfony Messenger → Redis → SendSmsHandler
|
// → Symfony Messenger → Redis → SendSmsHandler
|
||||||
@@ -699,13 +718,16 @@ $this->smsService->dispatchAsync($mobile, $message);
|
|||||||
### درگاه پرداخت
|
### درگاه پرداخت
|
||||||
|
|
||||||
**بانک ملت (Mellat)**
|
**بانک ملت (Mellat)**
|
||||||
|
|
||||||
- SOAP WebService: `https://bpm.shaparak.ir/pgwchannel/services/pgw?wsdl`
|
- SOAP WebService: `https://bpm.shaparak.ir/pgwchannel/services/pgw?wsdl`
|
||||||
- تأیید: ResCode=0 + SettlePayment
|
- تأیید: ResCode=0 + SettlePayment
|
||||||
|
|
||||||
**سپ (SEP)**
|
**سپ (SEP)**
|
||||||
|
|
||||||
- REST API با ترمینال ID
|
- REST API با ترمینال ID
|
||||||
|
|
||||||
### Redis
|
### Redis
|
||||||
|
|
||||||
- صف پیام: `redis://redis:6379/messages`
|
- صف پیام: `redis://redis:6379/messages`
|
||||||
- Cache: `redis://redis:6379`
|
- Cache: `redis://redis:6379`
|
||||||
- Refresh Token: کلید `refresh_<sha256>`
|
- Refresh Token: کلید `refresh_<sha256>`
|
||||||
|
|||||||
+23
-2
@@ -192,11 +192,23 @@ List clinics with pagination.
|
|||||||
"success": true,
|
"success": true,
|
||||||
"data": [
|
"data": [
|
||||||
{
|
{
|
||||||
|
"id": "3426",
|
||||||
"uuid": "...",
|
"uuid": "...",
|
||||||
"name": "کلینیک الوند",
|
"name": "کلینیک الوند",
|
||||||
|
"title": "کلینیک الوند",
|
||||||
|
"phone": "02112345678",
|
||||||
|
"phone_number": "02112345678",
|
||||||
|
"logo": "/uploads/clinics/logo/...",
|
||||||
|
"clinic_logo": "/uploads/clinics/logo/...",
|
||||||
|
"images_clinic": [{ "url": "/uploads/clinics/gallery/..." }],
|
||||||
|
"doctors_count": 4,
|
||||||
|
"is_active": true,
|
||||||
|
"created_at": 1781762386,
|
||||||
"city": "تهران",
|
"city": "تهران",
|
||||||
"clinic_logo": "https://...",
|
"state": "تهران",
|
||||||
"is_active": true
|
"specialties": [{ "uuid": "...", "id": "7", "name": "..." }],
|
||||||
|
"24_7": false,
|
||||||
|
"field_working_days": "شنبه تا پنجشنبه ۸ تا ۲۰"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"meta": {
|
"meta": {
|
||||||
@@ -207,6 +219,15 @@ List clinics with pagination.
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
| Field | Type | Description |
|
||||||
|
|-------|------|-------------|
|
||||||
|
| `clinic_logo` / `logo` | string\|null | Logo path (relative `/uploads/...` or absolute URL) |
|
||||||
|
| `doctors_count` | integer | Number of doctors linked to the clinic |
|
||||||
|
| `city` | string\|null | City name, resolved from the clinic's address (`DoctorAddress`) |
|
||||||
|
| `state` | string\|null | Province name, resolved from the clinic's address (`DoctorAddress`) |
|
||||||
|
| `24_7` | boolean | Open 24/7 flag |
|
||||||
|
| `field_working_days` | string\|null | Working days/hours description |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## GET `/api/v1/clinic/doctor-list/{clinicUuid}`
|
## GET `/api/v1/clinic/doctor-list/{clinicUuid}`
|
||||||
|
|||||||
@@ -252,8 +252,14 @@ class ClinicController extends BaseController
|
|||||||
$filters = $request->query->all();
|
$filters = $request->query->all();
|
||||||
$result = $this->clinicRepo->findWithFilters($filters);
|
$result = $this->clinicRepo->findWithFilters($filters);
|
||||||
|
|
||||||
|
$clinicIds = array_map(fn(Clinic $c) => $c->getId(), $result['items']);
|
||||||
|
$locations = $this->clinicRepo->findAddressLocations($clinicIds);
|
||||||
|
|
||||||
return $this->paginated(
|
return $this->paginated(
|
||||||
array_map(fn(Clinic $c) => $c->toListArray(), $result['items']),
|
array_map(function (Clinic $c) use ($locations) {
|
||||||
|
$loc = $locations[$c->getId()] ?? ['city' => null, 'state' => null];
|
||||||
|
return $c->toListArray($loc['city'], $loc['state']);
|
||||||
|
}, $result['items']),
|
||||||
$result['total'],
|
$result['total'],
|
||||||
$result['page'],
|
$result['page'],
|
||||||
$result['limit']
|
$result['limit']
|
||||||
|
|||||||
@@ -211,7 +211,7 @@ class Clinic
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function toListArray(): array
|
public function toListArray(?string $city = null, ?string $state = null): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'id' => (string) $this->id,
|
'id' => (string) $this->id,
|
||||||
@@ -226,10 +226,13 @@ class Clinic
|
|||||||
'doctors_count' => $this->doctors->count(),
|
'doctors_count' => $this->doctors->count(),
|
||||||
'is_active' => $this->isActive,
|
'is_active' => $this->isActive,
|
||||||
'created_at' => $this->createdAt,
|
'created_at' => $this->createdAt,
|
||||||
|
'city' => $city,
|
||||||
|
'state' => $state,
|
||||||
'specialties' => array_map(fn(Specialty $s) => [
|
'specialties' => array_map(fn(Specialty $s) => [
|
||||||
'uuid' => $s->getUuid(), 'id' => (string) $s->getId(), 'name' => $s->getName(),
|
'uuid' => $s->getUuid(), 'id' => (string) $s->getId(), 'name' => $s->getName(),
|
||||||
], $this->specialties->toArray()),
|
], $this->specialties->toArray()),
|
||||||
'24_7' => $this->is247,
|
'24_7' => $this->is247,
|
||||||
|
'field_working_days' => $this->workingDays,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -83,6 +83,40 @@ class ClinicRepository extends ServiceEntityRepository
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* City/province names for each clinic, taken from the clinic's address
|
||||||
|
* (DoctorAddress.clinicId). Returns [clinicId => ['city' => ?string, 'state' => ?string]].
|
||||||
|
*
|
||||||
|
* @param int[] $clinicIds
|
||||||
|
* @return array<int, array{city: ?string, state: ?string}>
|
||||||
|
*/
|
||||||
|
public function findAddressLocations(array $clinicIds): array
|
||||||
|
{
|
||||||
|
if ($clinicIds === []) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$rows = $this->getEntityManager()->createQueryBuilder()
|
||||||
|
->select('addr.clinicId AS clinic_id', 'cityCat.name AS city', 'provinceCat.name AS state')
|
||||||
|
->from(DoctorAddress::class, 'addr')
|
||||||
|
->leftJoin('addr.city', 'cityCat')
|
||||||
|
->leftJoin('addr.province', 'provinceCat')
|
||||||
|
->where('addr.clinicId IN (:ids)')
|
||||||
|
->setParameter('ids', $clinicIds)
|
||||||
|
->getQuery()
|
||||||
|
->getResult();
|
||||||
|
|
||||||
|
$map = [];
|
||||||
|
foreach ($rows as $row) {
|
||||||
|
$id = (int) $row['clinic_id'];
|
||||||
|
if (!isset($map[$id])) {
|
||||||
|
$map[$id] = ['city' => $row['city'], 'state' => $row['state']];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $map;
|
||||||
|
}
|
||||||
|
|
||||||
public function save(Clinic $clinic, bool $flush = true): void
|
public function save(Clinic $clinic, bool $flush = true): void
|
||||||
{
|
{
|
||||||
$this->getEntityManager()->persist($clinic);
|
$this->getEntityManager()->persist($clinic);
|
||||||
|
|||||||
Reference in New Issue
Block a user