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']); } }