tenant = Tenant::create(['name' => 'CABM', 'entra_tenant_id' => '11111111-1111-1111-1111-111111111111']); $this->agent = DirectoryUser::create([ 'tenant_id' => $this->tenant->id, 'entra_oid' => '22222222-2222-2222-2222-222222222222', 'given_name' => 'Jean', 'surname' => 'Martin', 'job_title' => 'Technicien', 'mobile_phone' => '06 00 00 00 00', 'mail' => 'j.martin@beziers-mediterranee.fr', 'account_enabled' => true, ]); $default = Template::create(['tenant_id' => $this->tenant->id, 'name' => 'Défaut', 'is_default' => true, 'draft_html_full' => 'D {{prenom}}{{#if mobile}} {{mobile}}{{/if}}{{{banniere}}}', 'draft_html_short' => 'd {{prenom}}']); $default->publish(); // Le validateur de jeton est remplacé : on teste ici la logique métier, pas la cryptographie. $this->app->instance(EntraTokenValidator::class, new class extends EntraTokenValidator { public function validate(string $jwt): array { if ($jwt !== 'ok') { throw new RuntimeException('bad'); } return ['tid' => '11111111-1111-1111-1111-111111111111', 'oid' => '22222222-2222-2222-2222-222222222222']; } }); } private function signature(array $q = [], string $token = 'ok') { return $this->withToken($token)->getJson('/api/v1/signature?'.http_build_query($q)); } public function test_refuse_sans_jeton_valide(): void { $this->getJson('/api/v1/signature')->assertStatus(401); $this->signature([], 'bad')->assertStatus(401); } public function test_template_par_defaut_puis_groupe_prioritaire(): void { $this->signature()->assertOk()->assertJson(['html' => 'D Jean 06 00 00 00 00', 'variant' => 'full', 'template' => 'Défaut']); $group = DirectoryGroup::create(['tenant_id' => $this->tenant->id, 'entra_oid' => '33333333-3333-3333-3333-333333333333', 'display_name' => 'signature_mail_directeurs']); $group->members()->attach($this->agent->id); $dir = Template::create(['tenant_id' => $this->tenant->id, 'name' => 'Directeurs', 'draft_html_full' => 'DIR {{nom}}']); $dir->publish(); Assignment::create(['tenant_id' => $this->tenant->id, 'template_id' => $dir->id, 'directory_group_id' => $group->id, 'priority' => 100]); $this->signature()->assertJson(['html' => 'DIR Martin', 'template' => 'Directeurs']); } public function test_variante_reponse_selon_preference(): void { $this->signature(['context' => 'reply'])->assertJson(['html' => 'd Jean', 'variant' => 'short']); UserPreference::create(['directory_user_id' => $this->agent->id, 'reply_variant' => 'none']); $this->signature(['context' => 'reply'])->assertJson(['html' => '', 'variant' => 'none']); } public function test_surcharge_agent_uniquement_si_champ_ouvert(): void { UserOverride::create(['directory_user_id' => $this->agent->id, 'field' => 'mobile', 'value' => '07 11 11 11 11']); $this->signature()->assertJson(['html' => 'D Jean 06 00 00 00 00']); EditableField::create(['tenant_id' => $this->tenant->id, 'field' => 'mobile', 'label' => 'Mobile', 'enabled' => true]); $this->signature()->assertJson(['html' => 'D Jean 07 11 11 11 11']); } public function test_boite_partagee_avec_ou_sans_expediteur(): void { $tpl = Template::create(['tenant_id' => $this->tenant->id, 'name' => 'Accueil', 'draft_html_full' => '{{boite_nom}}{{#if prenom}} / {{prenom}}{{/if}}']); $tpl->publish(); $box = SharedMailbox::create(['tenant_id' => $this->tenant->id, 'address' => 'accueil@beziers-mediterranee.fr', 'display_name' => 'Accueil', 'template_id' => $tpl->id, 'include_sender' => false]); $this->signature(['mailbox' => 'accueil@beziers-mediterranee.fr'])->assertJson(['html' => 'Accueil']); $box->update(['include_sender' => true]); $this->signature(['mailbox' => 'accueil@beziers-mediterranee.fr'])->assertJson(['html' => 'Accueil / Jean']); } public function test_banniere_de_campagne_active_et_ciblee(): void { Campaign::create(['tenant_id' => $this->tenant->id, 'name' => 'Encombrants', 'image_path' => 'campagnes/enc.png', 'alt_text' => 'Collecte', 'starts_at' => now()->subDay(), 'ends_at' => now()->addDay()]); $html = $this->signature()->assertOk()->json('html'); $this->assertStringContainsString('/img/campagnes/enc.png', $html); $this->assertStringContainsString('alt="Collecte"', $html); } public function test_une_seule_banniere_selon_priorite_ciblage_et_periode(): void { $base = ['tenant_id' => $this->tenant->id, 'alt_text' => 'x', 'starts_at' => now()->subDay(), 'ends_at' => now()->addDay()]; $group = DirectoryGroup::create(['tenant_id' => $this->tenant->id, 'entra_oid' => '33333333-3333-3333-3333-333333333333', 'display_name' => 'signature_mail_directeurs']); Campaign::create($base + ['name' => 'Générale', 'image_path' => 'generale.png', 'priority' => 10]); Campaign::create($base + ['name' => 'Directeurs', 'image_path' => 'directeurs.png', 'priority' => 50, 'width' => 450, 'link_url' => 'https://www.beziers-mediterranee.fr/voeux?a=1&b=2'])->groups()->attach($group->id); // Jamais servies, malgré une priorité supérieure : inactive, pas commencée, terminée. Campaign::create($base + ['name' => 'Inactive', 'image_path' => 'inactive.png', 'priority' => 100, 'active' => false]); Campaign::create(['name' => 'Future', 'image_path' => 'future.png', 'priority' => 100, 'starts_at' => now()->addHour()] + $base); Campaign::create(['name' => 'Passée', 'image_path' => 'passee.png', 'priority' => 100, 'ends_at' => now()->subHour()] + $base); // Hors du groupe ciblé : campagne générale. $html = $this->signature()->assertOk()->json('html'); $this->assertStringContainsString('/img/generale.png', $html); $this->assertStringNotContainsString('directeurs.png', $html); // Dans le groupe : la campagne ciblée, plus prioritaire, remplace la générale. $group->members()->attach($this->agent->id); $html = $this->signature()->json('html'); $this->assertStringContainsString('/img/directeurs.png', $html); $this->assertStringContainsString('width="450"', $html); $this->assertStringContainsString('assertSame(1, substr_count($html, 'signature(['context' => 'reply'])->assertJson(['html' => 'd Jean']); } }