clinicWithAddress(); $type = $this->resourceType($address); $resource = new ClinicResource($address, $type, 'دستگاه لیزر ۲'); $this->em->persist($resource); $section = new ServiceSection('clinic', (int) $clinic->getId(), 'لیزر'); $this->em->persist($section); $this->em->flush(); $service = new ServiceItem($section, 'لیزر پا', 8_000_000); $service->setDurationMinutes(30)->setBookable(true); $this->em->persist($service); $this->em->flush(); return [$user, $resource, $service, $address]; } // ── ✅ موفق ────────────────────────────────────────────────────────────── public function testTheServicesOfAResourceComeBackWithResolvedNumbers(): void { [$user, $resource, $service] = $this->clinicWithOfferedService(); $offering = new ResourceServiceOffering($resource, $service); $offering->setDurationMinutes(15); // قیمت تنظیم نشده → باید ارث ببرد $this->em->persist($offering); $this->em->flush(); $body = $this->authJson('GET', "/api/v1/resource/{$resource->getUuid()}/services", $user); self::assertSame(200, $this->responseCode()); self::assertCount(1, $body['data']); $row = $body['data'][0]; self::assertSame('لیزر پا', $row['service_name']); self::assertSame(15, $row['effective_duration_minutes']); self::assertSame('resource_option', $row['duration_source']); // قیمت از خودِ سرویس آمده، و پنل باید همین را کنارش بنویسد. self::assertSame(8_000_000, $row['effective_price_rials']); self::assertSame('service_default', $row['price_source']); } public function testReplacingTheListAddsAndRemoves(): void { [$user, $resource, $service] = $this->clinicWithOfferedService(); $created = $this->authJson('PUT', "/api/v1/resource/{$resource->getUuid()}/services", $user, [ 'services' => [ ['service_uuid' => $service->getUuid(), 'duration_minutes' => 20, 'price_rials' => 9_500_000], ], ]); self::assertSame(200, $this->responseCode()); self::assertSame(20, $created['data'][0]['duration_minutes']); self::assertSame(9_500_000, (int) $created['data'][0]['price_rials']); // فهرست خالی یعنی «این منبع دیگر هیچ سرویسی نمی‌دهد» — جایگزینی کامل است. $emptied = $this->authJson('PUT', "/api/v1/resource/{$resource->getUuid()}/services", $user, ['services' => []]); self::assertSame(200, $this->responseCode()); self::assertSame([], $emptied['data']); } public function testClearingAnOverrideFallsBackToInheritance(): void { [$user, $resource, $service] = $this->clinicWithOfferedService(); $this->authJson('PUT', "/api/v1/resource/{$resource->getUuid()}/services", $user, [ 'services' => [['service_uuid' => $service->getUuid(), 'duration_minutes' => 20]], ]); // رشتهٔ خالی یعنی «ارث»، نه صفر. $body = $this->authJson('PUT', "/api/v1/resource/{$resource->getUuid()}/services", $user, [ 'services' => [['service_uuid' => $service->getUuid(), 'duration_minutes' => '']], ]); self::assertNull($body['data'][0]['duration_minutes']); self::assertSame(30, $body['data'][0]['effective_duration_minutes']); self::assertSame('service_default', $body['data'][0]['duration_source']); } // ── ❌ خطا ─────────────────────────────────────────────────────────────── public function testAServiceFromAnotherEnvironmentIsRejected(): void { [$user, $resource] = $this->clinicWithOfferedService(); [, $otherClinic] = $this->clinicWithAddress('شعبهٔ کلینیک دیگر'); $section = new ServiceSection('clinic', (int) $otherClinic->getId(), 'بخش بیگانه'); $this->em->persist($section); $this->em->flush(); $foreign = new ServiceItem($section, 'سرویس بیگانه', 1_000_000); $this->em->persist($foreign); $this->em->flush(); $this->authJson('PUT', "/api/v1/resource/{$resource->getUuid()}/services", $user, [ 'services' => [['service_uuid' => $foreign->getUuid()]], ]); self::assertSame(422, $this->responseCode()); } public function testAnUnknownServiceIsRejected(): void { [$user, $resource] = $this->clinicWithOfferedService(); $this->authJson('PUT', "/api/v1/resource/{$resource->getUuid()}/services", $user, [ 'services' => [['service_uuid' => '00000000-0000-4000-8000-000000000000']], ]); self::assertSame(422, $this->responseCode()); } public function testTheBodyMustCarryAServicesArray(): void { [$user, $resource] = $this->clinicWithOfferedService(); $this->authJson('PUT', "/api/v1/resource/{$resource->getUuid()}/services", $user, ['wrong' => []]); self::assertSame(422, $this->responseCode()); } }