doctorWithAddress(); self::assertTrue($address->isActive()); self::assertSame(DoctorAddress::DEFAULT_TIMEZONE, $address->getTimezone()); $body = $this->authJson('GET', '/api/v1/branches', $user); self::assertSame(200, $this->responseCode()); self::assertTrue($body['data'][0]['active']); self::assertSame('Asia/Tehran', $body['data'][0]['timezone']); } public function testListReportsWorkingHoursAndRoomCounts(): void { [$user, , $address] = $this->doctorWithAddress(); $before = $this->authJson('GET', '/api/v1/branches', $user); self::assertFalse($before['data'][0]['working_hours_defined']); self::assertSame(0, $before['data'][0]['rooms_count']); $this->authJson('PUT', "/api/v1/branch/{$address->getUuid()}/working-hours", $user, [ 'days' => [1 => [['start_minute' => 540, 'end_minute' => 780]]], ]); $this->authJson('POST', '/api/v1/room', $user, [ 'address_uuid' => $address->getUuid(), 'name' => 'اتاق ۱', ]); $after = $this->authJson('GET', '/api/v1/branches', $user); self::assertTrue($after['data'][0]['working_hours_defined']); self::assertSame(1, $after['data'][0]['rooms_count']); } /** فقط اتاق فعال شمرده می‌شود — اتاق غیرفعال ظرفیت واقعی شعبه نیست. */ public function testInactiveRoomIsNotCounted(): void { [$user, , $address] = $this->doctorWithAddress(); $room = $this->authJson('POST', '/api/v1/room', $user, [ 'address_uuid' => $address->getUuid(), 'name' => 'اتاق بسته', ]); $this->authJson('PATCH', "/api/v1/room/{$room['data']['uuid']}", $user, ['active' => false]); $body = $this->authJson('GET', '/api/v1/branches', $user); self::assertSame(0, $body['data'][0]['rooms_count']); } public function testListShowsOnlyTheCurrentContextBranches(): void { [$doctorUser, , $doctorAddress] = $this->doctorWithAddress('مطب شخصی'); $this->clinicWithAddress('شعبهٔ کلینیک بیگانه'); $body = $this->authJson('GET', '/api/v1/branches', $doctorUser); self::assertCount(1, $body['data']); self::assertSame($doctorAddress->getUuid(), $body['data'][0]['uuid']); } public function testBranchIsDeactivated(): void { [$user, , $address] = $this->doctorWithAddress(); $body = $this->authJson('PATCH', "/api/v1/branch/{$address->getUuid()}", $user, ['active' => false]); self::assertSame(200, $this->responseCode()); self::assertFalse($body['data']['active']); } public function testTimezoneIsUpdated(): void { [$user, , $address] = $this->doctorWithAddress(); $body = $this->authJson('PATCH', "/api/v1/branch/{$address->getUuid()}", $user, [ 'timezone' => 'Asia/Dubai', ]); self::assertSame(200, $this->responseCode()); self::assertSame('Asia/Dubai', $body['data']['timezone']); } /** با DateTimeZone::listIdentifiers سنجیده می‌شود، نه با regex. */ public function testUnknownTimezoneIsRejected(): void { [$user, , $address] = $this->doctorWithAddress(); $body = $this->authJson('PATCH', "/api/v1/branch/{$address->getUuid()}", $user, ['timezone' => 'Tehran']); self::assertSame(422, $this->responseCode()); self::assertSame('timezone', $body['errors'][0]['field']); } public function testForeignBranchCannotBePatched(): void { [$doctorUser] = $this->doctorWithAddress(); [, , $foreignAddress] = $this->clinicWithAddress(); $this->authJson('PATCH', "/api/v1/branch/{$foreignAddress->getUuid()}", $doctorUser, ['active' => false]); self::assertSame(404, $this->responseCode()); } /** شمارش‌ها گروهی‌اند: تعداد کوئری‌ها با تعداد شعبه‌ها رشد نمی‌کند. */ public function testListQueryCountDoesNotGrowWithBranches(): void { // یک کرنل برای هر دو اندازه‌گیری، وگرنه reboot دادهٔ کوئری‌ها را می‌ریزد. $this->client->disableReboot(); [$user, $doctor] = $this->doctorWithAddress(); $queriesForOne = $this->countQueries( fn () => $this->authJson('GET', '/api/v1/branches', $user) ); for ($i = 0; $i < 4; $i++) { $extra = DoctorAddress::forDoctor($doctor); $extra->setName("شعبهٔ $i"); $this->em->persist($extra); } $this->em->flush(); $queriesForFive = $this->countQueries( fn () => $this->authJson('GET', '/api/v1/branches', $user) ); self::assertCount(5, json_decode($this->client->getResponse()->getContent(), true)['data']); self::assertSame($queriesForOne, $queriesForFive); } }