fix(clinic): send each contracted insurer's logo to the public page

The clinic payload carried only uuid/id/name for list_bime, so the public
page fell back to the same placeholder for every insurer and the section
read as broken. The logo has been on the insurance record all along.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
hamed
2026-08-19 23:33:34 +03:30
co-authored by Claude Opus 5
parent e4bd37b3bd
commit b33f38072d
3 changed files with 67 additions and 1 deletions
+4 -1
View File
@@ -150,7 +150,7 @@ limited to the whitelist under `PATCH /api/v1/clinic/{uuid}`.
"linkedin": null "linkedin": null
}, },
"caption": "توضیحات کلینیک", "caption": "توضیحات کلینیک",
"list_bime": [], "list_bime": [{ "uuid": "...", "id": "176", "name": "تامین اجتماعی", "logo_url": "/uploads/insurances/logo/2026-08/tamin.png" }],
"specialties": [{ "uuid": "...", "id": "1", "name": "قلب", "parent": null }], "specialties": [{ "uuid": "...", "id": "1", "name": "قلب", "parent": null }],
"services": [], "services": [],
"clinic_specialty": [{ "uuid": "...", "id": "1", "name": "قلب", "parent": null }], "clinic_specialty": [{ "uuid": "...", "id": "1", "name": "قلب", "parent": null }],
@@ -167,6 +167,9 @@ limited to the whitelist under `PATCH /api/v1/clinic/{uuid}`.
} }
``` ```
> `list_bime[].logo_url` مسیر نسبی روی همین API است (`/uploads/...`) و کلاینت باید آن را با دامنهٔ API کامل کند. بیمهٔ بدون لوگو `null` می‌گیرد، نه کلید غایب.
> 🔒 `phone`/`phone_number` are `null` unless the caller may edit the clinic (`can_edit: true`). The number is not public data; the patient sees the venue phone on their own appointment instead. > 🔒 `phone`/`phone_number` are `null` unless the caller may edit the clinic (`can_edit: true`). The number is not public data; the patient sees the venue phone on their own appointment instead.
> >
> `city`/`state`/`map`/`location`/`phone`/`phone_number` are all resolved from the clinic's **address** (`DoctorAddress` linked by `clinic_id`), not from columns on the clinic. `location` and `phone`/`phone_number` fall back to the deprecated `clinics.address` / `clinics.telephone` columns only when the address record has no value — reading them from different rows made one response describe two different places. Each is an array with a single object (or empty `[]` if the clinic has no address). `doctors` is a **count**; the actual doctor list comes from `GET /api/v1/clinic/doctor-list/{clinicUuid}` (`doctor_list` here is always `null`). > `city`/`state`/`map`/`location`/`phone`/`phone_number` are all resolved from the clinic's **address** (`DoctorAddress` linked by `clinic_id`), not from columns on the clinic. `location` and `phone`/`phone_number` fall back to the deprecated `clinics.address` / `clinics.telephone` columns only when the address record has no value — reading them from different rows made one response describe two different places. Each is an array with a single object (or empty `[]` if the clinic has no address). `doctors` is a **count**; the actual doctor list comes from `GET /api/v1/clinic/doctor-list/{clinicUuid}` (`doctor_list` here is always `null`).
+3
View File
@@ -229,8 +229,11 @@ class Clinic
'clinic_logo' => $this->clinicLogo, 'clinic_logo' => $this->clinicLogo,
'phone_number' => $phone, 'phone_number' => $phone,
'caption' => $this->info, 'caption' => $this->info,
// لوگو هم می‌آید: صفحهٔ عمومی کلینیک بیمه‌ها را با لوگو نشان می‌دهد و بدون
// این فیلد همه به یک تصویر پیش‌فرض یکسان می‌افتادند.
'list_bime' => array_map(fn(Insurance $i) => [ 'list_bime' => array_map(fn(Insurance $i) => [
'uuid' => $i->getUuid(), 'id' => (string) $i->getId(), 'name' => $i->getName(), 'uuid' => $i->getUuid(), 'id' => (string) $i->getId(), 'name' => $i->getName(),
'logo_url' => $i->getLogoUrl(),
], $this->insurances->toArray()), ], $this->insurances->toArray()),
'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(),
+60
View File
@@ -0,0 +1,60 @@
<?php
namespace App\Tests\Clinic;
use App\Clinic\Entity\Clinic;
use App\Insurance\Entity\Insurance;
use App\Insurance\Enum\InsuranceType;
use App\Tests\ApiTestCase;
/**
* The public clinic page renders each contracted insurer with its logo. The
* payload carried only uuid/id/name, so every insurer fell back to the same
* placeholder and the section looked broken.
*/
class ClinicInsuranceLogoTest extends ApiTestCase
{
private const LOGO = '/uploads/insurances/logo/2026-08/tamin.png';
private function makeClinicWithInsurances(): Clinic
{
$withLogo = new Insurance('بیمه لوگودار ' . random_int(1000, 9999), InsuranceType::Basic);
$withLogo->setLogoUrl(self::LOGO);
$this->em->persist($withLogo);
$withoutLogo = new Insurance('بیمه بی‌لوگو ' . random_int(1000, 9999), InsuranceType::Basic);
$this->em->persist($withoutLogo);
$clinic = new Clinic($this->createUser(['ROLE_USER', 'ROLE_CLINIC']));
$clinic->setName('کلینیک تست بیمه');
$clinic->getInsurances()->add($withLogo);
$clinic->getInsurances()->add($withoutLogo);
$this->em->persist($clinic);
$this->em->flush();
return $clinic;
}
public function testClinicPayloadCarriesEachInsurerLogo(): void
{
$clinic = $this->makeClinicWithInsurances();
$list = $clinic->toDetailArray()['list_bime'];
$urls = array_column($list, 'logo_url', 'name');
self::assertCount(2, $list);
self::assertContains(self::LOGO, $urls);
self::assertContains(null, $urls, 'بیمهٔ بدون لوگو باید null بدهد، نه کلید غایب');
}
public function testPublicClinicEndpointExposesTheLogo(): void
{
$clinic = $this->makeClinicWithInsurances();
$this->client->request('GET', '/api/v1/clinic/' . $clinic->getUuid());
$body = json_decode($this->client->getResponse()->getContent(), true);
$payload = $body['data']['data'] ?? $body['data'];
self::assertContains(self::LOGO, array_column($payload['list_bime'], 'logo_url'));
}
}