Publication initiale de RelaisSMS : documentation et sources nettoyees

This commit is contained in:
2026-10-21 09:29:39 +02:00
commit ac186b03b1
158 changed files with 24818 additions and 0 deletions
+216
View File
@@ -0,0 +1,216 @@
<?php
namespace Tests\Feature;
use App\Models\AppSetting;
use App\Models\Contact;
use App\Models\ContactGroup;
use App\Models\User;
use App\Services\Recipients\RecipientResolver;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
class RecipientSelectionTest extends TestCase
{
use RefreshDatabase;
public function test_resolver_returns_unique_valid_mobile_numbers_for_selected_contacts_and_groups(): void
{
$group = ContactGroup::query()->create([
'source' => 'local',
'name' => 'Benevoles',
'slug' => 'benevoles',
]);
$first = $this->createContact('Alice', 'Alpha');
$duplicate = $this->createContact('Bob', 'Beta');
$optOut = $this->createContact('Claire', 'Refus', smsOptOut: true);
$fixed = $this->createContact('Denis', 'Fixe');
$invalid = $this->createContact('Eva', 'Invalide');
$missing = $this->createContact('Fatima', 'Sansphone');
$group->contacts()->attach([$first->id, $optOut->id, $fixed->id, $invalid->id, $missing->id]);
$first->phoneNumbers()->create([
'raw_number' => '06 11 11 11 11',
'normalized_number' => '+33611111111',
'country' => 'FR',
'is_valid' => true,
'is_mobile' => true,
'is_primary' => true,
]);
$duplicate->phoneNumbers()->create([
'raw_number' => '+33 6 11 11 11 11',
'normalized_number' => '+33611111111',
'country' => 'FR',
'is_valid' => true,
'is_mobile' => true,
'is_primary' => true,
]);
$optOut->phoneNumbers()->create([
'raw_number' => '06 22 22 22 22',
'normalized_number' => '+33622222222',
'country' => 'FR',
'is_valid' => true,
'is_mobile' => true,
'is_primary' => true,
]);
$fixed->phoneNumbers()->create([
'raw_number' => '01 44 44 44 44',
'normalized_number' => '+33144444444',
'country' => 'FR',
'is_valid' => true,
'is_mobile' => false,
'is_primary' => true,
]);
$invalid->phoneNumbers()->create([
'raw_number' => '123',
'normalized_number' => null,
'country' => 'FR',
'is_valid' => false,
'is_mobile' => false,
'is_primary' => true,
'validation_error' => 'Numero invalide.',
]);
$result = app(RecipientResolver::class)->resolve([$duplicate->id], [$group->id]);
$summary = $result->summary();
$this->assertSame(1, $summary['ready_numbers']);
$this->assertSame('+33611111111', $result->recipients[0]['number']);
$this->assertSame(1, $summary['duplicate']);
$this->assertSame(1, $summary['opt_out']);
$this->assertSame(1, $summary['non_mobile']);
$this->assertSame(1, $summary['invalid']);
$this->assertSame(1, $summary['missing_phone']);
}
public function test_resolver_trusts_normalized_mobile_flag_instead_of_raw_regex(): void
{
config(['relais_sms.default_settings.mobile_phone_regex' => '/^never-matches$/']);
$contact = $this->createContact('Alice', 'Mobile');
$contact->phoneNumbers()->create([
'raw_number' => '06 11 11 11 11',
'normalized_number' => '+33611111111',
'country' => 'FR',
'is_valid' => true,
'is_mobile' => true,
'is_primary' => true,
]);
$result = app(RecipientResolver::class)->resolve([$contact->id], []);
$this->assertSame(1, $result->summary()['ready_numbers']);
$this->assertSame([], $result->excluded);
}
public function test_resolver_accepts_stale_rows_when_normalized_number_is_a_french_mobile(): void
{
$contact = $this->createContact('Yveline', 'Mobile');
$contact->phoneNumbers()->create([
'raw_number' => '064-201-4207',
'normalized_number' => '+33642014207',
'country' => 'FR',
'is_valid' => true,
'is_mobile' => false,
'is_primary' => true,
]);
$result = app(RecipientResolver::class)->resolve([$contact->id], []);
$this->assertSame(1, $result->summary()['ready_numbers']);
$this->assertSame('+33642014207', $result->recipients[0]['number']);
$this->assertSame([], $result->excluded);
}
public function test_authenticated_user_can_preview_recipient_selection(): void
{
$user = User::factory()->create();
$group = ContactGroup::query()->create([
'source' => 'local',
'name' => 'Membres',
'slug' => 'membres',
]);
$contact = $this->createContact('Marie', 'Durand');
$contact->groups()->attach($group);
$contact->phoneNumbers()->create([
'raw_number' => '07 55 55 00 04',
'normalized_number' => '+33755550004',
'country' => 'FR',
'is_valid' => true,
'is_mobile' => true,
'is_primary' => true,
]);
$this->actingAs($user)
->get('/recipients')
->assertOk()
->assertSee('Composer')
->assertSee('Pour');
$this->actingAs($user)
->getJson('/recipients/search?q=Durand')
->assertOk()
->assertJsonFragment([
'type' => 'contact',
'label' => 'Marie Durand',
]);
$this->actingAs($user)
->getJson('/recipients/search?q=Membres')
->assertOk()
->assertJsonFragment([
'type' => 'group',
'label' => 'Membres',
]);
$this->actingAs($user)
->post('/recipients/preview', [
'group_ids' => [$group->id],
'contact_ids' => [$contact->id],
])
->assertOk()
->assertSee('Liste finale')
->assertSee('+33755550004')
->assertSee('Numeros prets');
}
public function test_composer_shows_configured_sms_header_footer_and_complete_message(): void
{
AppSetting::putString('sms_message_header', 'AFPMA');
AppSetting::putString('sms_message_footer', 'Envoyer STOP SMS pour ne plus etre contacte.');
$user = User::factory()->create();
$contact = $this->createContact('Marie', 'Durand');
$contact->phoneNumbers()->create([
'raw_number' => '07 55 55 00 04',
'normalized_number' => '+33755550004',
'country' => 'FR',
'is_valid' => true,
'is_mobile' => true,
'is_primary' => true,
]);
$this->actingAs($user)
->post('/recipients/preview', [
'contact_ids' => [$contact->id],
'message' => 'Bonjour',
'include_sms_header' => '1',
'include_sms_footer' => '1',
])
->assertOk()
->assertSee('SMS complet')
->assertSee("AFPMA\nBonjour\nEnvoyer STOP SMS pour ne plus etre contacte.");
}
private function createContact(string $firstName, string $lastName, bool $smsOptOut = false): Contact
{
return Contact::query()->create([
'source' => 'local',
'first_name' => $firstName,
'last_name' => $lastName,
'sms_opt_out' => $smsOptOut,
]);
}
}