diff --git a/.claude/prompt/appointment-detail-enrich.md b/.claude/prompt/appointment-detail-enrich.md new file mode 100644 index 00000000..01032a75 --- /dev/null +++ b/.claude/prompt/appointment-detail-enrich.md @@ -0,0 +1,81 @@ +# غنی‌سازی پاسخ نوبت با تخصص و آدرس مطب پزشک + +## پروژه + +`clinicpro` (Backend — منبع حقیقت). + +> **Cross-repo:** صفحه‌ی «جزئیات نوبت» در `nobat724_front` (داشبورد → نوبت‌های من → مشاهده جزئیات) این فیلدها را مصرف می‌کند (پرامپت همتا: `nobat724_front/.claude/prompt/appointment-detail-fields-fix.md`). این پرامپت **اول** اجرا شود. + +## زمینه + +`Appointment::toArray()` فقط `doctor:{uuid,name}`, `slot_start/slot_end`, `status`, `note`, `patient_*` را برمی‌گرداند. اما صفحه‌ی جزئیات نوبت در فرانت می‌خواهد **تخصص پزشک، آدرس مطب، تلفن و مختصات نقشه** را هم نشان دهد. چون این داده‌ها در پاسخ نیستند، آن بخش‌ها خالی می‌مانند. + +`Doctor` این روابط را دارد: `getSpecialties()` (ManyToMany به `Specialty`)، `getAddresses()` (OneToMany به `DoctorAddress`). `DoctorAddress::toArray()` شکل `{address, telephone, map:{latitude,longitude}, name, ...}` می‌دهد. نوبت آدرس مشخصی ذخیره نمی‌کند، پس **اولین آدرس پزشک** به‌عنوان آدرس مطب استفاده می‌شود. + +## مشکل / هدف + +`Appointment::toArray()` گسترش یابد تا `doctor` شامل `specialties` و `address` (اولین آدرس پزشک با `address/telephone/map`) باشد — بدون شکستن مصرف‌کننده‌های فعلی. + +## فایل‌های مرتبط + +| فایل | نقش | +|------|-----| +| `src/Appointment/Entity/Appointment.php` | `toArray()` — افزودن specialties + address زیر `doctor` | +| `src/Doctor/Entity/Doctor.php` | `getSpecialties()`, `getAddresses()` (موجود) | +| `src/Doctor/Entity/DoctorAddress.php` | `toArray()` → `{address, telephone, map, ...}` (موجود) | +| `src/Specialty/Entity/Specialty.php` | `getUuid()/getName()` (موجود) | + +## وضعیت فعلی (کد واقعی) + +```php +// Appointment::toArray() +'doctor' => [ + 'uuid' => $this->doctor->getUuid(), + 'name' => $this->doctor->getName(), +], +'slot_start' => $this->slotStart, +'slot_end' => $this->slotEnd, +// ... بدون specialties / address +``` + +`DoctorAddress::toArray()` (مرجع شکل): +```php +'map' => ['latitude' => (string)…, 'longitude' => (string)…], +'address' => $this->address, +'telephone' => $this->telephone, +'name' => $this->name, +``` + +## وظایف + +### ۱. افزودن specialties و address به `doctor` در `Appointment::toArray()` +```php +$doctor = $this->doctor; +$firstAddress = $doctor->getAddresses()->first() ?: null; + +// ... +'doctor' => [ + 'uuid' => $doctor->getUuid(), + 'name' => $doctor->getName(), + 'specialties' => array_map( + fn($s) => ['uuid' => $s->getUuid(), 'name' => $s->getName()], + $doctor->getSpecialties()->toArray() + ), +], +'address' => $firstAddress ? $firstAddress->toArray() : null, +``` +- `address` را در سطح بالای آرایه‌ی نوبت بگذار (نه داخل doctor) تا فرانت `appointmentData.address.{address,telephone,map}` را مستقیم بخواند. +- `getAddresses()->first()` ممکن است `false` برگرداند (Doctrine Collection) → با `?: null` ایمن کن. +- بقیه‌ی کلیدهای موجود (`slot_start`, `status`, ...) بدون تغییر بمانند. + +### ۲. مستندسازی `docs/api/appointment.md` +شکل جدید `doctor.specialties` و `address` را در response نمونه‌ی `GET /api/v1/appointments/user` (و `GET /api/v1/appointment/{uuid}`) اضافه کن. + +## نکات مهم + +- **بدون شکستن مصرف‌کننده‌ها:** فقط کلید اضافه می‌شود؛ کلیدهای فعلی دست‌نخورده. (پنل ادمین/جاهای دیگری که `toArray` نوبت را می‌خوانند نباید بشکنند.) +- تخصص ممکن است خالی باشد (آرایه‌ی خالی) و آدرس ممکن است `null` باشد (پزشک بدون آدرس) — فرانت باید این‌ها را تحمل کند (در پرامپت فرانت لحاظ شده). +- نوبت آدرس اختصاصی ذخیره نمی‌کند؛ «اولین آدرس پزشک» یک تقریب منطقی است. اگر بعداً نوبت به آدرس مشخص گره خورد، اینجا باید آن را ترجیح داد. +- `slot_start`/`slot_end` Unix‌اند (فرانت تاریخ و ساعت را از `slot_start` می‌سازد). +- پاسخ‌ها از `BaseController`؛ migration لازم نیست. +- تست: `GET /api/v1/appointments/user` برای کاربری با نوبت → آیتم باید `doctor.specialties[]` و `address.{address,telephone,map}` داشته باشد. diff --git a/docs/api/appointment.md b/docs/api/appointment.md index 83d6e85d..11947a30 100644 --- a/docs/api/appointment.md +++ b/docs/api/appointment.md @@ -216,24 +216,32 @@ Get appointment detail. "uuid": "appt-uuid-...", "doctor": { "uuid": "...", - "title": "دکتر علی احمدی", - "image": "https://..." + "name": "دکتر علی احمدی", + "specialties": [ + { "uuid": "...", "name": "اورولوژی عمومی" } + ] }, - "user": { + "address": { "uuid": "...", - "real_name": "کاربر", - "mobile_number": "09..." + "name": "مطب دکتر علی احمدی", + "address": "یزد، خیابان ...", + "telephone": "035...", + "map": { "latitude": "31.8", "longitude": "54.3" }, + "city": { "id": "132", "name": "یزد" }, + "province": { "id": "100", "name": "یزد" } }, + "user": { "uuid": "...", "mobile": "09..." }, "slot_start": 1718438400, "slot_end": 1718439600, "status": "confirmed", "note": "...", - "price": 500000, - "payment_uuid": "pay-uuid-...", + "patient_name": "...", + "patient_mobile": "...", "created_at": 1717000000 } } ``` +> `doctor.specialties` آرایه (ممکن است خالی)؛ `address` اولین آدرس پزشک است (ممکن است `null` اگر پزشک آدرسی ندارد). `address.map.latitude/longitude` رشته یا `null`. تاریخ‌ها Unix. ### Errors | Code | HTTP | Description | diff --git a/src/Appointment/Entity/Appointment.php b/src/Appointment/Entity/Appointment.php index e28317fb..b3773798 100644 --- a/src/Appointment/Entity/Appointment.php +++ b/src/Appointment/Entity/Appointment.php @@ -153,12 +153,19 @@ class Appointment public function toArray(): array { + $firstAddress = $this->doctor->getAddresses()->first() ?: null; + return [ 'uuid' => $this->uuid, 'doctor' => [ - 'uuid' => $this->doctor->getUuid(), - 'name' => $this->doctor->getName(), + 'uuid' => $this->doctor->getUuid(), + 'name' => $this->doctor->getName(), + 'specialties' => array_map( + fn($s) => ['uuid' => $s->getUuid(), 'name' => $s->getName()], + $this->doctor->getSpecialties()->toArray() + ), ], + 'address' => $firstAddress?->toArray(), 'user' => [ 'uuid' => $this->user->getUuid(), 'mobile' => $this->user->getMobileNumber(),