Publication initiale de RelaisSMS : documentation et sources nettoyees
This commit is contained in:
@@ -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,
|
||||
]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user