refactor(resource): drop the branch domain from resources
Resources never needed a branch: devices and rooms belong to the clinic itself, and the picker always had exactly one option — a mandatory click that decided nothing. - `address_uuid` is now optional on resource and pool creation; when it is missing the environment's own address is used. Clients still sending it keep working. - The panel no longer asks for or displays a branch anywhere: resource form, list column and filter, pool form and column, detail row, and the resource-first booking page. - Availability no longer gates on `doctor_addresses.active`. That gate shut down every device of a clinic whose address row happened to be inactive, with a message no page in the panel could act on — no endpoint writes that column at all. `address_id` stays on the resource: the timezone and the tenant pair are derived from it. It is simply no longer the user's decision. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,128 @@
|
||||
<?php
|
||||
|
||||
namespace App\Tests\Resource;
|
||||
|
||||
use App\Auth\Entity\User;
|
||||
use App\Clinic\Entity\Clinic;
|
||||
use App\Doctor\Entity\DoctorAddress;
|
||||
|
||||
/**
|
||||
* منابع دامنهٔ «شعبه» ندارند.
|
||||
*
|
||||
* آدرس هنوز زیرِ منبع هست — منطقهٔ زمانی و جفتِ محیط از آن میآیند — ولی از کاربر
|
||||
* پرسیده نمیشود و روشن/خاموش بودنش هیچ چیزی را گیت نمیکند. پیش از این، یک ردیفِ
|
||||
* `doctor_addresses.active = 0` همهٔ دستگاههای کلینیک را با پیامی خاموش میکرد که هیچ
|
||||
* جای پنل راهی برای رفعش نداشت.
|
||||
*/
|
||||
class ResourceWithoutBranchTest extends ResourceTestCase
|
||||
{
|
||||
private function nextSaturday(): int
|
||||
{
|
||||
return (new \DateTimeImmutable('next saturday', new \DateTimeZone('Asia/Tehran')))
|
||||
->setTime(0, 0)
|
||||
->getTimestamp();
|
||||
}
|
||||
|
||||
// ── ✅ موفق ──────────────────────────────────────────────────────────────
|
||||
|
||||
public function testAResourceIsCreatedWithoutAskingForABranch(): void
|
||||
{
|
||||
[$user, , $address] = $this->clinicWithAddress();
|
||||
$type = $this->resourceType($address);
|
||||
|
||||
$body = $this->authJson('POST', '/api/v1/resource', $user, [
|
||||
'type_uuid' => $type->getUuid(),
|
||||
'name' => 'لیزر بدون شعبه',
|
||||
'supervisor_doctor_uuid' => $this->supervisorFor($address)->getUuid(),
|
||||
]);
|
||||
|
||||
self::assertSame(201, $this->responseCode(), json_encode($body, JSON_UNESCAPED_UNICODE));
|
||||
// آدرسِ خودِ محیط برداشته میشود، نه چیزی که کاربر انتخاب کند.
|
||||
self::assertSame($address->getUuid(), $body['data']['address_uuid']);
|
||||
}
|
||||
|
||||
public function testAPoolIsCreatedWithoutABranchToo(): void
|
||||
{
|
||||
[$user, , $address] = $this->clinicWithAddress();
|
||||
$type = $this->resourceType($address);
|
||||
|
||||
$body = $this->authJson('POST', '/api/v1/resource-pools', $user, [
|
||||
'type_uuid' => $type->getUuid(),
|
||||
'name' => 'لیزرهای آلکساندرایت',
|
||||
]);
|
||||
|
||||
self::assertSame(201, $this->responseCode(), json_encode($body, JSON_UNESCAPED_UNICODE));
|
||||
self::assertSame($address->getUuid(), $body['data']['address_uuid']);
|
||||
}
|
||||
|
||||
/** کلاینتی که هنوز `address_uuid` میفرستد نباید بشکند. */
|
||||
public function testAnExplicitAddressIsStillAccepted(): void
|
||||
{
|
||||
[$user, $clinic, $address] = $this->clinicWithAddress();
|
||||
$second = $this->extraAddress($clinic);
|
||||
$type = $this->resourceType($address);
|
||||
|
||||
$body = $this->authJson('POST', '/api/v1/resource', $user, [
|
||||
'address_uuid' => $second->getUuid(),
|
||||
'type_uuid' => $type->getUuid(),
|
||||
'name' => 'لیزر آدرس دوم',
|
||||
'supervisor_doctor_uuid' => $this->supervisorFor($address)->getUuid(),
|
||||
]);
|
||||
|
||||
self::assertSame(201, $this->responseCode());
|
||||
self::assertSame($second->getUuid(), $body['data']['address_uuid']);
|
||||
}
|
||||
|
||||
// ── ⚠️ مرزی ─────────────────────────────────────────────────────────────
|
||||
|
||||
/** آدرسِ خاموش دیگر تقویم منبع را خالی نمیکند. */
|
||||
public function testAnInactiveAddressNoLongerBlanksTheDay(): void
|
||||
{
|
||||
[$user, , $address] = $this->clinicWithAddress();
|
||||
$type = $this->resourceType($address);
|
||||
$created = $this->createResource($user, $address, $type, ['name' => 'اپراتور مریم']);
|
||||
$uuid = $created['data']['uuid'];
|
||||
|
||||
$this->authJson('PUT', "/api/v1/resource/$uuid/calendar", $user, [
|
||||
'days' => [0 => [['start_minute' => 540, 'end_minute' => 1020]]],
|
||||
]);
|
||||
self::assertSame(200, $this->responseCode());
|
||||
|
||||
$address->setActive(false);
|
||||
$this->em->flush();
|
||||
|
||||
$saturday = $this->nextSaturday();
|
||||
$body = $this->authJson('GET', "/api/v1/resource/$uuid/availability?from=$saturday&to=$saturday", $user);
|
||||
|
||||
self::assertSame(200, $this->responseCode());
|
||||
self::assertSame(480, $body['data']['days'][0]['total_minutes']);
|
||||
self::assertNotContains('address_inactive', $body['data']['days'][0]['reasons']);
|
||||
}
|
||||
|
||||
// ── ❌ خطا ───────────────────────────────────────────────────────────────
|
||||
|
||||
/** محیطی که هیچ آدرسی ندارد، منبع نمیسازد — ولی پیامش میگوید چه کار کند. */
|
||||
public function testAnEnvironmentWithNoAddressIsToldToCompleteItsAddressFirst(): void
|
||||
{
|
||||
$user = $this->createUser(['ROLE_USER', 'ROLE_CLINIC']);
|
||||
$clinic = new Clinic($user);
|
||||
$clinic->setName('کلینیک بیآدرس');
|
||||
$this->em->persist($clinic);
|
||||
$this->em->flush();
|
||||
|
||||
// نوع منبع به آدرس نیاز ندارد؛ فقط جفتِ محیط را میخواهد.
|
||||
$probe = DoctorAddress::forClinic($clinic->getId());
|
||||
$type = $this->resourceType($probe);
|
||||
$this->em->remove($probe);
|
||||
$this->em->flush();
|
||||
|
||||
$body = $this->authJson('POST', '/api/v1/resource', $user, [
|
||||
'type_uuid' => $type->getUuid(),
|
||||
'name' => 'لیزر بیخانمان',
|
||||
'supervisor_doctor_uuid' => $this->supervisorFor($probe)->getUuid(),
|
||||
]);
|
||||
|
||||
self::assertSame(422, $this->responseCode(), json_encode($body, JSON_UNESCAPED_UNICODE));
|
||||
self::assertStringContainsString('آدرسی ثبت نشده', $body['errors'][0]['message']);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user