clinicWithAddress(); $created = $this->authJson('POST', '/api/v1/resource-types', $user, [ 'code' => 'laser', 'name' => 'دستگاه لیزر', ]); self::assertSame(201, $this->responseCode(), json_encode($created, JSON_UNESCAPED_UNICODE)); self::assertFalse($created['data']['is_system']); self::assertSame(0, $created['data']['resources_count']); $this->createResource($user, $address, $this->typeEntity($created['data']['uuid'])); $list = $this->authJson('GET', '/api/v1/resource-types', $user); self::assertSame(1, $list['data'][0]['resources_count']); } public function testDuplicateCodeInOneEnvironmentIsRejected(): void { [$user] = $this->clinicWithAddress(); $this->authJson('POST', '/api/v1/resource-types', $user, ['code' => 'laser', 'name' => 'لیزر']); $body = $this->authJson('POST', '/api/v1/resource-types', $user, ['code' => 'laser', 'name' => 'لیزر دوم']); self::assertSame(422, $this->responseCode()); self::assertSame('code', $body['errors'][0]['field']); } /** همان کد در محیط دیگر مجاز است — یکتایی per محیط است، نه سراسری. */ public function testSameCodeInAnotherEnvironmentIsAllowed(): void { [$user] = $this->clinicWithAddress(); $this->authJson('POST', '/api/v1/resource-types', $user, ['code' => 'laser', 'name' => 'لیزر']); [$otherUser] = $this->clinicWithAddress('شعبهٔ دیگر'); $this->authJson('POST', '/api/v1/resource-types', $otherUser, ['code' => 'laser', 'name' => 'لیزر']); self::assertSame(201, $this->responseCode()); } public function testInvalidCodeIsRejected(): void { [$user] = $this->clinicWithAddress(); $body = $this->authJson('POST', '/api/v1/resource-types', $user, ['code' => 'Laser Device', 'name' => 'x']); self::assertSame(422, $this->responseCode()); self::assertSame('code', $body['errors'][0]['field']); } public function testTypeInUseCannotBeDeleted(): void { [$user, , $address] = $this->clinicWithAddress(); $created = $this->authJson('POST', '/api/v1/resource-types', $user, ['code' => 'laser', 'name' => 'لیزر']); $this->createResource($user, $address, $this->typeEntity($created['data']['uuid'])); $body = $this->authJson('DELETE', "/api/v1/resource-type/{$created['data']['uuid']}", $user); self::assertSame(422, $this->responseCode()); self::assertStringContainsString('1 منبع', $body['errors'][0]['message']); } public function testUnusedTypeIsDeleted(): void { [$user] = $this->clinicWithAddress(); $created = $this->authJson('POST', '/api/v1/resource-types', $user, ['code' => 'laser', 'name' => 'لیزر']); $this->authJson('DELETE', "/api/v1/resource-type/{$created['data']['uuid']}", $user); self::assertSame(200, $this->responseCode()); } /** نوع سیستمی هرگز حذف نمی‌شود: ResourceLinker با همان کد پل می‌زند. */ public function testSystemTypeCannotBeDeletedEvenWhenUnused(): void { [$user, , $address] = $this->clinicWithAddress(); $type = $this->resourceType($address, 'room', 'اتاق'); $type->markSystem(); $this->em->flush(); $body = $this->authJson('DELETE', "/api/v1/resource-type/{$type->getUuid()}", $user); self::assertSame(422, $this->responseCode()); self::assertStringContainsString('سیستمی', $body['errors'][0]['message']); } public function testForeignTypeIsNotFound(): void { [$user] = $this->clinicWithAddress(); $created = $this->authJson('POST', '/api/v1/resource-types', $user, ['code' => 'laser', 'name' => 'لیزر']); [$otherUser] = $this->clinicWithAddress('شعبهٔ دیگر'); $this->authJson('PATCH', "/api/v1/resource-type/{$created['data']['uuid']}", $otherUser, ['name' => 'x']); self::assertSame(404, $this->responseCode()); } /** `code` عوض نمی‌شود: منابع موجود و ResourceLinker با همان کد پیدا می‌شوند. */ public function testCodeIsImmutable(): void { [$user] = $this->clinicWithAddress(); $created = $this->authJson('POST', '/api/v1/resource-types', $user, ['code' => 'laser', 'name' => 'لیزر']); $body = $this->authJson('PATCH', "/api/v1/resource-type/{$created['data']['uuid']}", $user, [ 'code' => 'something_else', 'name' => 'نام تازه', ]); self::assertSame(200, $this->responseCode()); self::assertSame('laser', $body['data']['code']); self::assertSame('نام تازه', $body['data']['name']); } private function typeEntity(string $uuid): \App\Resource\Entity\ResourceType { return $this->em->getRepository(\App\Resource\Entity\ResourceType::class)->findOneBy(['uuid' => $uuid]); } }