create(); Role::firstOrCreate(['name' => 'amministratore', 'guard_name' => 'web']); $user->assignRole('amministratore'); DB::table('amministratori')->insertOrIgnore([ 'id' => 1, 'user_id' => $user->id, 'nome' => 'Cecilia', 'cognome' => 'Tordini', 'codice_amministratore' => 'ADMX3PD9', 'created_at' => now(), 'updated_at' => now(), ]); $stabile = Stabile::create([ 'codice_stabile' => '0016', 'denominazione' => 'Condominio Viale Giulio Cesare 171', 'indirizzo' => 'Viale Giulio Cesare 171', 'citta' => 'Roma', 'cap' => '00192', 'provincia' => 'RM', 'codice_fiscale' => '97014690588', 'amministratore_id' => 1, ]); $resOrd = $this->actingAs($user)->get('/admin-filament/comunicazioni/posta-ordinaria'); expect($resOrd->status())->toBeIn([200, 302]); $resPec = $this->actingAs($user)->get('/admin-filament/comunicazioni/posta-pec'); expect($resPec->status())->toBeIn([200, 302]); }); it('correctly parses raw eml content, extracts metadata, body and attachments', function () { $parser = app(EmlParser::class); $rawEml = "From: Mario Rossi \r\n" . "To: amministrazione@condominio.it\r\n" . "Subject: =?UTF-8?B?TGV0dHVyYSBDb250YXRvcmkgQWNxdWE=?=\r\n" . "Date: Fri, 04 Sep 2026 14:30:00 +0200\r\n" . "Message-ID: \r\n" . "MIME-Version: 1.0\r\n" . "Content-Type: text/plain; charset=UTF-8\r\n" . "\r\n" . "Gentile Amministratrice, invio la lettura del contatore: 154 mc."; $parsed = $parser->parse($rawEml); expect($parsed['subject'])->toBe('Lettura Contatori Acqua'); expect($parsed['from']['email'] ?? null)->toBe('mario.rossi@example.com'); expect($parsed['to'][0]['email'] ?? null)->toBe('amministrazione@condominio.it'); expect($parsed['message_id'])->toBe('msg-12345@example.com'); expect($parsed['body_text'])->toContain('lettura del contatore: 154 mc'); }); it('ingests raw eml into communication_messages and associates unit and ticket', function () { $user = User::factory()->create(); Role::firstOrCreate(['name' => 'amministratore', 'guard_name' => 'web']); $user->assignRole('amministratore'); DB::table('amministratori')->insertOrIgnore([ 'id' => 1, 'user_id' => $user->id, 'nome' => 'Cecilia', 'cognome' => 'Tordini', 'codice_amministratore' => 'ADMX3PD9', 'created_at' => now(), 'updated_at' => now(), ]); $stabile = Stabile::create([ 'codice_stabile' => '0016', 'denominazione' => 'Condominio Viale Giulio Cesare 171', 'indirizzo' => 'Viale Giulio Cesare 171', 'citta' => 'Roma', 'cap' => '00192', 'provincia' => 'RM', 'codice_fiscale' => '97014690588', 'amministratore_id' => 1, ]); $unita = UnitaImmobiliare::create([ 'stabile_id' => $stabile->id, 'interno' => '4', 'scala' => 'A', ]); $persona = Persona::create([ 'cognome' => 'Rossi', 'nome' => 'Mario', 'email_principale' => 'mario.rossi@example.com', 'codice_fiscale' => 'RSSMRA80A01H501U', ]); PersonaUnitaRelazione::create([ 'unita_id' => $unita->id, 'persona_id' => $persona->id, 'tipo_relazione' => 'proprietario', 'quota_relazione' => 100, 'data_inizio' => '2020-01-01', 'attivo' => 1, ]); $rawEml = "From: Mario Rossi \r\n" . "To: studio@netgescon.it\r\n" . "Subject: Segnalazione infiltrazione scala A\r\n" . "Date: Fri, 04 Sep 2026 15:00:00 +0200\r\n" . "Message-ID: \r\n" . "MIME-Version: 1.0\r\n" . "Content-Type: text/plain; charset=UTF-8\r\n" . "\r\n" . "Buongiorno, segnalo una perdita d'acqua al soffitto."; $service = app(ImapMailboxService::class); $mailboxConfig = [ 'tipo' => 'imap', 'folder' => 'INBOX', 'crea_ticket_automatico' => true, ]; $res = $service->ingestEmlString($rawEml, $stabile, $mailboxConfig, false, true); expect($res['status'])->toBe('imported'); $msg = CommunicationMessage::where('external_message_id', 'infiltrazione-999@example.com')->first(); expect($msg)->not->toBeNull(); expect((int) $msg->stabile_id)->toBe((int) $stabile->id); expect($msg->metadata['unita_immobiliare_id'] ?? null)->toBe((int) $unita->id); expect($msg->ticket_id)->not->toBeNull(); $ticket = Ticket::find($msg->ticket_id); expect($ticket)->not->toBeNull(); expect((int) $ticket->stabile_id)->toBe((int) $stabile->id); expect((int) $ticket->unita_immobiliare_id)->toBe((int) $unita->id); expect($ticket->titolo)->toContain('Segnalazione infiltrazione scala A'); }); it('verifies nethome sas supplier linkage and mnemonic cod_stabile values', function () { $nethome = Fornitore::firstOrCreate( ['codice_fiscale' => '10055221005'], ['ragione_sociale' => 'NETHOME sas di BARONE M. & C.', 'partita_iva' => '10055221005', 'amministratore_id' => 1] ); expect($nethome->ragione_sociale)->toContain('NETHOME'); $stabile0016 = Stabile::where('codice_stabile', '0016')->first(); if ($stabile0016) { $stabile0016->update(['cod_stabile' => '145']); expect($stabile0016->fresh()->cod_stabile)->toBe('145'); } }); it('ingests studio raw eml without stabile_id and resolves via ArchiveFileResolver', function () { $user = User::factory()->create(); Role::firstOrCreate(['name' => 'amministratore', 'guard_name' => 'web']); $user->assignRole('amministratore'); $adm = \App\Models\Amministratore::firstOrCreate( ['codice_amministratore' => 'ADMX3PD9'], ['user_id' => $user->id, 'nome' => 'Cecilia', 'cognome' => 'Tordini'] ); $service = app(ImapMailboxService::class); $rawEml = "From: Studio Legale \r\n" . "To: studio@amministrazione.it\r\n" . "Subject: Notifica studio generale\r\n" . "Date: Fri, 04 Sep 2026 16:00:00 +0200\r\n" . "Message-ID: \r\n" . "MIME-Version: 1.0\r\n" . "Content-Type: text/plain; charset=UTF-8\r\n" . "\r\n" . "Comunicazione indirizzata direttamente allo studio amministrativo."; $res = $service->ingestStudioEmlString($rawEml, $adm, [ 'tipo' => 'imap', 'folder' => 'INBOX', 'crea_ticket_automatico' => false, ], false); expect($res['status'])->toBe('imported'); $msg = CommunicationMessage::where('external_message_id', 'studio-msg-777@example.com')->first(); expect($msg)->not->toBeNull(); expect($msg->stabile_id)->toBeNull(); expect($msg->metadata['is_studio'] ?? false)->toBeTrue(); // Test ArchiveFileResolver $resolved = \App\Services\Documenti\ArchiveFileResolver::resolve('0016', 'sample_non_existing.pdf'); expect($resolved)->toHaveKeys(['filename', 'exists', 'path', 'size', 'mime', 'is_pdf', 'is_image']); expect($resolved['filename'])->toBe('sample_non_existing.pdf'); expect($resolved['exists'])->toBeFalse(); });