diff --git a/docs/api/doctor.md b/docs/api/doctor.md index 04cb2983..92b51f24 100644 --- a/docs/api/doctor.md +++ b/docs/api/doctor.md @@ -162,7 +162,9 @@ Get doctor detail for clinic owner — only doctors who are members of the authe |-------|---------------------|-----------------| | `free_turn` | نزدیک‌ترین روز/ساعت کاری از امروز (مثلاً «دوشنبه ۹:۰۰–۱۳:۰۰») | «نوبت آزادی موجود نیست» | | `hours_of_work` | خلاصه ساعت‌های روزهای فعال با `\|` جداشده | «برنامه کاری تنظیم نشده» | -| `active` | `activeDoctorAppointment && has_active_sessions` | `false` — نوبت‌دهی غیرفعال | +| `active` | `online_booking_enabled && has_active_sessions` | `false` — نوبت‌دهی غیرفعال | + +> **نوبت‌دهی آنلاین غیرفعال:** منبعِ فعال/غیرفعال بودن نوبت‌دهی آنلاین، فیلد `meta.online_booking_enabled` در `WeeklySchedule` پزشک است. اگر `false` باشد، صرف‌نظر از سشن‌های برنامه‌ی هفتگی، `free_turn` همیشه `"نوبت‌دهی آنلاین غیرفعال است"` و `active` برابر `false` برمی‌گردد؛ `hours_of_work` در صورت وجود برنامه حفظ می‌شود. چنین پزشکی در لیست عمومی `GET /api/v1/doctors` (پیش‌فرض `active=true`) نمایش داده نمی‌شود، ولی صفحه‌ی تکی `GET /api/v1/doctor/{slug}` همچنان قابل دسترسی است. --- diff --git a/src/Doctor/Entity/Doctor.php b/src/Doctor/Entity/Doctor.php index 163dd718..ab6ff34a 100644 --- a/src/Doctor/Entity/Doctor.php +++ b/src/Doctor/Entity/Doctor.php @@ -131,51 +131,214 @@ class Doctor $this->addresses = new ArrayCollection(); } - public function getId(): ?int { return $this->id; } - public function getUuid(): string { return $this->uuid; } - public function getUser(): User { return $this->user; } - public function getName(): string { return $this->name; } - public function getGender(): ?string { return $this->gender; } - public function getMedicalSystemCode(): ?string { return $this->medicalSystemCode; } - public function getMobileNumber(): ?string { return $this->mobileNumber; } - public function getActivityTime(): ?int { return $this->activityTime; } - public function getDegree(): ?string { return $this->degree; } - public function getInfo(): ?string { return $this->info; } - public function getImages(): ?array { return $this->images; } - public function getSocialMedia(): ?array { return $this->socialMedia; } - public function getDoctorRate(): float { return $this->doctorRate; } - public function getDoctorRatePercentage(): float { return $this->doctorRatePercentage; } - public function isActiveDoctorAppointment(): bool { return $this->activeDoctorAppointment; } - public function getRepresentationId(): ?int { return $this->representationId; } - public function getNotificationMobile(): ?string { return $this->notificationMobile; } - public function getCreatedAt(): int { return $this->createdAt; } - public function getUpdatedAt(): int { return $this->updatedAt; } - public function getSpecialties(): Collection { return $this->specialties; } - public function getServices(): Collection { return $this->services; } - public function getProvinces(): Collection { return $this->provinces; } - public function getCities(): Collection { return $this->cities; } - public function getAddresses(): Collection { return $this->addresses; } + public function getId(): ?int + { + return $this->id; + } + public function getUuid(): string + { + return $this->uuid; + } + public function getUser(): User + { + return $this->user; + } + public function getName(): string + { + return $this->name; + } + public function getGender(): ?string + { + return $this->gender; + } + public function getMedicalSystemCode(): ?string + { + return $this->medicalSystemCode; + } + public function getMobileNumber(): ?string + { + return $this->mobileNumber; + } + public function getActivityTime(): ?int + { + return $this->activityTime; + } + public function getDegree(): ?string + { + return $this->degree; + } + public function getInfo(): ?string + { + return $this->info; + } + public function getImages(): ?array + { + return $this->images; + } + public function getSocialMedia(): ?array + { + return $this->socialMedia; + } + public function getDoctorRate(): float + { + return $this->doctorRate; + } + public function getDoctorRatePercentage(): float + { + return $this->doctorRatePercentage; + } + public function isActiveDoctorAppointment(): bool + { + return $this->activeDoctorAppointment; + } + public function getRepresentationId(): ?int + { + return $this->representationId; + } + public function getNotificationMobile(): ?string + { + return $this->notificationMobile; + } + public function getCreatedAt(): int + { + return $this->createdAt; + } + public function getUpdatedAt(): int + { + return $this->updatedAt; + } + public function getSpecialties(): Collection + { + return $this->specialties; + } + public function getServices(): Collection + { + return $this->services; + } + public function getProvinces(): Collection + { + return $this->provinces; + } + public function getCities(): Collection + { + return $this->cities; + } + public function getAddresses(): Collection + { + return $this->addresses; + } - public function setName(string $v): self { $this->name = $v; return $this; } - public function setGender(?string $v): self { $this->gender = $v; $this->touch(); return $this; } - public function setMedicalSystemCode(?string $v): self { $this->medicalSystemCode = $v; $this->touch(); return $this; } - public function setMobileNumber(?string $v): self { $this->mobileNumber = $v; $this->touch(); return $this; } - public function setActivityTime(?int $v): self { $this->activityTime = $v; $this->touch(); return $this; } - public function setDegree(?string $v): self { $this->degree = $v; $this->touch(); return $this; } - public function setInfo(?string $v): self { $this->info = $v; $this->touch(); return $this; } - public function setImages(?array $v): self { $this->images = $v; $this->touch(); return $this; } - public function setSocialMedia(?array $v): self { $this->socialMedia = $v; $this->touch(); return $this; } - public function setDoctorRate(float $v): self { $this->doctorRate = $v; $this->touch(); return $this; } - public function setDoctorRatePercentage(float $v): self { $this->doctorRatePercentage = $v; $this->touch(); return $this; } - public function setActiveDoctorAppointment(bool $v): self { $this->activeDoctorAppointment = $v; $this->touch(); return $this; } - public function setRepresentationId(?int $v): self { $this->representationId = $v; $this->touch(); return $this; } - public function setNotificationMobile(?string $v): self { $this->notificationMobile = $v; $this->touch(); return $this; } + public function setName(string $v): self + { + $this->name = $v; + return $this; + } + public function setGender(?string $v): self + { + $this->gender = $v; + $this->touch(); + return $this; + } + public function setMedicalSystemCode(?string $v): self + { + $this->medicalSystemCode = $v; + $this->touch(); + return $this; + } + public function setMobileNumber(?string $v): self + { + $this->mobileNumber = $v; + $this->touch(); + return $this; + } + public function setActivityTime(?int $v): self + { + $this->activityTime = $v; + $this->touch(); + return $this; + } + public function setDegree(?string $v): self + { + $this->degree = $v; + $this->touch(); + return $this; + } + public function setInfo(?string $v): self + { + $this->info = $v; + $this->touch(); + return $this; + } + public function setImages(?array $v): self + { + $this->images = $v; + $this->touch(); + return $this; + } + public function setSocialMedia(?array $v): self + { + $this->socialMedia = $v; + $this->touch(); + return $this; + } + public function setDoctorRate(float $v): self + { + $this->doctorRate = $v; + $this->touch(); + return $this; + } + public function setDoctorRatePercentage(float $v): self + { + $this->doctorRatePercentage = $v; + $this->touch(); + return $this; + } + public function setActiveDoctorAppointment(bool $v): self + { + $this->activeDoctorAppointment = $v; + $this->touch(); + return $this; + } + public function setRepresentationId(?int $v): self + { + $this->representationId = $v; + $this->touch(); + return $this; + } + public function setNotificationMobile(?string $v): self + { + $this->notificationMobile = $v; + $this->touch(); + return $this; + } - private function touch(): void { $this->updatedAt = time(); } + private function touch(): void + { + $this->updatedAt = time(); + } private const DAY_NAMES = ['شنبه', 'یکشنبه', 'دوشنبه', 'سه‌شنبه', 'چهارشنبه', 'پنجشنبه', 'جمعه']; + private const APPOINTMENT_DISABLED_LABEL = 'نوبت‌دهی آنلاین غیرفعال است'; + private function computeScheduleFields(?WeeklySchedule $schedule): array + { + $parts = $this->computeScheduleParts($schedule); + + // Online booking enabled flag lives in the weekly schedule meta. + // When disabled, free_turn reflects that while hours_of_work is kept. + if ($schedule !== null && !$schedule->getMeta()['online_booking_enabled']) { + return [ + 'free_turn' => self::APPOINTMENT_DISABLED_LABEL, + 'hours_of_work' => $parts['hours_of_work'], + 'has_schedule' => false, + ]; + } + + return $parts; + } + + private function computeScheduleParts(?WeeklySchedule $schedule): array { if ($schedule === null) { return ['free_turn' => 'نوبت آزادی موجود نیست', 'hours_of_work' => 'برنامه کاری تنظیم نشده', 'has_schedule' => false]; @@ -264,7 +427,9 @@ class Doctor 'degree' => $this->degree, 'img' => $this->images ?? [], '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()), 'satisfaction' => (string) $this->doctorRatePercentage, 'point' => (string) $this->doctorRate, @@ -288,14 +453,18 @@ class Doctor 'detail' => $this->info, 'degree' => $this->degree, '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(), 'parent_id' => $s->getParent()?->getId() !== null ? (string) $s->getParent()->getId() : null, ], $this->specialties->toArray()), 'active' => $this->activeDoctorAppointment && $sf['has_schedule'], 'img' => $this->images ?? [], 'social_media' => $this->socialMedia, 'expertise' => array_map(fn(DoctorService $ds) => [ - 'uuid' => $ds->getUuid(), 'id' => (string) $ds->getId(), 'name' => $ds->getName(), + 'uuid' => $ds->getUuid(), + 'id' => (string) $ds->getId(), + 'name' => $ds->getName(), ], $this->services->toArray()), 'satisfaction' => (string) $this->doctorRatePercentage, 'point' => (string) $this->doctorRate, @@ -304,10 +473,14 @@ class Doctor 'address' => array_map(fn(DoctorAddress $a) => $a->toArray(), $this->addresses->toArray()), 'average_rate' => ['total_rates' => null], 'state' => array_map(fn(Province $p) => [ - 'uuid' => $p->getUuid(), 'id' => (string) $p->getId(), 'name' => $p->getName(), + 'uuid' => $p->getUuid(), + 'id' => (string) $p->getId(), + 'name' => $p->getName(), ], $this->provinces->toArray()), 'city' => array_map(fn(City $c) => [ - 'uuid' => $c->getUuid(), 'id' => (string) $c->getId(), 'name' => $c->getName(), + 'uuid' => $c->getUuid(), + 'id' => (string) $c->getId(), + 'name' => $c->getName(), 'parent' => $c->getProvince() !== null ? (string) $c->getProvince()->getId() : null, ], $this->cities->toArray()), ];