service = app(FastRequestService::class); } protected function payload(array $overrides = []): array { return array_merge([ 'modality' => DocumentModalityEnum::Mri->value, 'priority' => DocumentPriorityEnum::High->name, 'pet' => ['name' => 'Rex', 'type' => PetTypeEnum::Dog->name], ], $overrides); } public function test_create_stores_document_with_generated_code_and_registered_status(): void { Carbon::setTestNow('2026-09-21 10:00:00'); $requester = User::factory()->create(); $document = $this->service->create($requester, $this->payload(['note' => 'یادداشت'])); $this->assertMatchesRegularExpression('/^\d{6}$/', $document->code); $this->assertSame(DocumentStatusEnum::Registered, $document->fresh()->status); $this->assertSame(DocumentPriorityEnum::High, $document->priority); $this->assertTrue($document->submitted_at->eq(Carbon::parse('2026-09-21 10:00:00'))); $this->assertDatabaseHas('documents', [ 'id' => $document->id, 'modality' => DocumentModalityEnum::Mri->value, 'note' => 'یادداشت', 'requester_id' => $requester->id, ]); } public function test_create_creates_pending_invoice_priced_by_modality(): void { $document = $this->service->create(User::factory()->create(), $this->payload()); $this->assertDatabaseHas('invoices', [ 'document_id' => $document->id, 'user_id' => $document->requester_id, 'amount' => DocumentModalityEnum::Mri->price(), 'status' => InvoiceStatusEnum::Pending->value, ]); } public function test_create_creates_pet_for_requester_from_payload(): void { Carbon::setTestNow('2026-09-21 10:00:00'); $requester = User::factory()->create(); $document = $this->service->create($requester, $this->payload(['pet' => [ 'name' => 'Rex', 'type' => PetTypeEnum::Dog->name, 'gender' => PetGenderEnum::Male->name, 'breed' => 'ژرمن', 'weight' => 20, 'sterilized' => true, 'age' => 3, ]])); $this->assertDatabaseHas('pets', [ 'id' => $document->pet_id, 'name' => 'Rex', 'type' => PetTypeEnum::Dog->value, 'gender' => PetGenderEnum::Male->value, 'breed' => 'ژرمن', 'weight' => 20, 'sterilized' => 1, 'owner_id' => $requester->id, ]); $this->assertTrue(Pet::find($document->pet_id)->birthday->isSameDay(Carbon::parse('2023-09-21'))); } public function test_create_defaults_pet_gender_to_unknown(): void { $document = $this->service->create(User::factory()->create(), $this->payload()); $this->assertSame(PetGenderEnum::Unknown, Pet::find($document->pet_id)->gender); } public function test_create_uses_existing_pet_of_requester(): void { $requester = User::factory()->create(); $pet = Pet::factory()->create(['owner_id' => $requester->id]); $document = $this->service->create($requester, $this->payload(['pet_id' => $pet->id, 'pet' => null])); $this->assertSame($pet->id, $document->pet_id); $this->assertDatabaseCount('pets', 1); } public function test_create_rejects_pet_of_another_user(): void { $pet = Pet::factory()->create(); $this->expectException(ModelNotFoundException::class); $this->service->create(User::factory()->create(), $this->payload(['pet_id' => $pet->id, 'pet' => null])); } public function test_create_attaches_history_and_scan_files_to_their_collections(): void { $document = $this->service->create( User::factory()->create(), $this->payload(), [UploadedFile::fake()->create('history.pdf', 10, 'application/pdf')], [UploadedFile::fake()->image('scan1.jpg'), UploadedFile::fake()->image('scan2.jpg')] ); $this->assertCount(1, $document->historyFiles); $this->assertCount(2, $document->primaryFiles); $this->assertDatabaseCount('media', 3); Storage::disk('public')->assertExists($document->primaryFiles->first()->path); } public function test_create_assigns_given_doctor_as_radiologist(): void { $doctor = User::factory()->create(['level' => UserEnum::Doctor->value]); $document = $this->service->create(User::factory()->create(), $this->payload(['doctor_id' => $doctor->id])); $this->assertDatabaseHas('document_assignments', [ 'document_id' => $document->id, 'user_id' => $doctor->id, 'role' => 'رادیولوژیست', ]); } public function test_create_auto_selects_on_shift_doctor_when_none_given(): void { Carbon::setTestNow('2026-09-21 10:00:00'); $doctor = User::factory()->create(['level' => UserEnum::Doctor->value]); Shift::factory()->onDate('2026-09-21')->between('08:00', '16:00')->forDoctor($doctor)->create(); $document = $this->service->create(User::factory()->create(), $this->payload()); $this->assertDatabaseHas('document_assignments', ['document_id' => $document->id, 'user_id' => $doctor->id]); } public function test_create_leaves_document_unassigned_when_no_doctor_is_available(): void { $document = $this->service->create(User::factory()->create(), $this->payload()); $this->assertDatabaseCount('document_assignments', 0); $this->assertSame($document->id, $document->fresh()->id); } public function test_create_dispatches_request_registered_sms(): void { config(['services.iranpayamak.patterns.request_registered' => 'pattern-code']); $this->service->create(User::factory()->create(), $this->payload()); Queue::assertPushed(SendPatternSms::class, 1); } public function test_create_rolls_back_everything_when_pet_lookup_fails(): void { $requester = User::factory()->create(); try { $this->service->create($requester, $this->payload(['pet_id' => 999, 'pet' => null])); } catch (ModelNotFoundException) { } $this->assertDatabaseCount('documents', 0); $this->assertDatabaseCount('invoices', 0); Queue::assertNothingPushed(); } }