Compare commits
5 Commits
2c3c12103e
...
b4845511a6
| Author | SHA1 | Date | |
|---|---|---|---|
| b4845511a6 | |||
| a886bdd947 | |||
| bb9b5d405f | |||
| 7111b70c65 | |||
| 3710bccd5a |
@@ -26,7 +26,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Ping IPv6 preprod server
|
- name: Ping IPv6 preprod server
|
||||||
run: |
|
run: |
|
||||||
ping6 -c 3 2a01:e0a:bfe:a8a0::205
|
ping6 -c 3 2a01:e0a:ef9:d10::205
|
||||||
|
|
||||||
- name: Configure SSH
|
- name: Configure SSH
|
||||||
env:
|
env:
|
||||||
@@ -118,6 +118,9 @@ jobs:
|
|||||||
|
|
||||||
echo "[<>] Restarting queue workers..."
|
echo "[<>] Restarting queue workers..."
|
||||||
php artisan queue:restart || true
|
php artisan queue:restart || true
|
||||||
|
sudo supervisorctl reread
|
||||||
|
sudo supervisorctl update
|
||||||
|
sudo supervisorctl restart roxane-worker:*
|
||||||
|
|
||||||
echo "[OK] Roxane deployed successfully to preprod!"
|
echo "[OK] Roxane deployed successfully to preprod!"
|
||||||
EOF
|
EOF
|
||||||
|
|||||||
@@ -28,32 +28,32 @@ class ServiceToggleAction extends Action
|
|||||||
$this->serviceIdentifier = $serviceIdentifier;
|
$this->serviceIdentifier = $serviceIdentifier;
|
||||||
|
|
||||||
return $this
|
return $this
|
||||||
->label(fn (Member|Membership $record) => $this->getMember($record)?->hasService($serviceIdentifier)
|
->label(fn (Member|Membership|null $record) => $this->getMember($record)?->hasService($serviceIdentifier)
|
||||||
? 'Service actif'
|
? 'Service actif'
|
||||||
: 'Activer le service'
|
: 'Activer le service'
|
||||||
)
|
)
|
||||||
->icon(fn (Member|Membership $record) => $this->getMember($record)?->hasService($serviceIdentifier)
|
->icon(fn (Member|Membership|null $record) => $this->getMember($record)?->hasService($serviceIdentifier)
|
||||||
? 'heroicon-o-check-circle'
|
? 'heroicon-o-check-circle'
|
||||||
: 'heroicon-o-x-circle'
|
: 'heroicon-o-x-circle'
|
||||||
)
|
)
|
||||||
->color(fn (Member|Membership $record) => $this->getMember($record)?->hasService($serviceIdentifier)
|
->color(fn (Member|Membership|null $record) => $this->getMember($record)?->hasService($serviceIdentifier)
|
||||||
? 'success'
|
? 'success'
|
||||||
: 'warning'
|
: 'warning'
|
||||||
)
|
)
|
||||||
->requiresConfirmation()
|
->requiresConfirmation()
|
||||||
->modalHeading(fn (Member|Membership $record) => $this->getMember($record)?->hasService($serviceIdentifier)
|
->modalHeading(fn (Member|Membership|null $record) => $this->getMember($record)?->hasService($serviceIdentifier)
|
||||||
? 'Désactiver le service'
|
? 'Désactiver le service'
|
||||||
: 'Activer le service'
|
: 'Activer le service'
|
||||||
)
|
)
|
||||||
->modalDescription(fn (Member|Membership $record) => $this->getMember($record)?->hasService($serviceIdentifier)
|
->modalDescription(fn (Member|Membership|null $record) => $this->getMember($record)?->hasService($serviceIdentifier)
|
||||||
? 'Êtes-vous sûr·e de vouloir désactiver ce service pour ce membre ?'
|
? 'Êtes-vous sûr·e de vouloir désactiver ce service pour ce membre ?'
|
||||||
: 'Êtes-vous sûr·e de vouloir activer ce service pour ce membre ?'
|
: 'Êtes-vous sûr·e de vouloir activer ce service pour ce membre ?'
|
||||||
)
|
)
|
||||||
->modalSubmitActionLabel(fn (Member|Membership $record) => $this->getMember($record)?->hasService($serviceIdentifier)
|
->modalSubmitActionLabel(fn (Member|Membership|null $record) => $this->getMember($record)?->hasService($serviceIdentifier)
|
||||||
? 'Désactiver'
|
? 'Désactiver'
|
||||||
: 'Activer'
|
: 'Activer'
|
||||||
)
|
)
|
||||||
->action(function (Member|Membership $record) {
|
->action(function (Member|Membership|null $record) {
|
||||||
$member = $this->getMember($record);
|
$member = $this->getMember($record);
|
||||||
|
|
||||||
if (! $member) {
|
if (! $member) {
|
||||||
@@ -76,8 +76,12 @@ class ServiceToggleAction extends Action
|
|||||||
/**
|
/**
|
||||||
* Get the member associated with the given record.
|
* Get the member associated with the given record.
|
||||||
*/
|
*/
|
||||||
protected function getMember(Member|Membership $record): ?Member
|
protected function getMember(Member|Membership|null $record): ?Member
|
||||||
{
|
{
|
||||||
|
if ($record === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
return $record instanceof Member ? $record : $record->member;
|
return $record instanceof Member ? $record : $record->member;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,8 +4,12 @@ namespace App\Filament\Resources\Memberships\Pages;
|
|||||||
|
|
||||||
use App\Filament\Resources\Memberships\MembershipResource;
|
use App\Filament\Resources\Memberships\MembershipResource;
|
||||||
use App\Models\Membership;
|
use App\Models\Membership;
|
||||||
|
use App\Notifications\MembershipValidatedNotification;
|
||||||
|
use Filament\Actions\Action;
|
||||||
use Filament\Actions\DeleteAction;
|
use Filament\Actions\DeleteAction;
|
||||||
|
use Filament\Forms\Components\DatePicker;
|
||||||
use Filament\Resources\Pages\EditRecord;
|
use Filament\Resources\Pages\EditRecord;
|
||||||
|
use Filament\Support\Icons\Heroicon;
|
||||||
use Illuminate\Contracts\Support\Htmlable;
|
use Illuminate\Contracts\Support\Htmlable;
|
||||||
|
|
||||||
class EditMembership extends EditRecord
|
class EditMembership extends EditRecord
|
||||||
@@ -15,14 +19,37 @@ class EditMembership extends EditRecord
|
|||||||
protected function getHeaderActions(): array
|
protected function getHeaderActions(): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
|
Action::make('validate')
|
||||||
|
->label(__('memberships.actions.validate'))
|
||||||
|
->icon(Heroicon::OutlinedCheckCircle)
|
||||||
|
->color('success')
|
||||||
|
->visible(fn (Membership $record) => $record->status === 'pending')
|
||||||
|
->form([
|
||||||
|
DatePicker::make('start_date')
|
||||||
|
->label(Membership::getAttributeLabel('start_date'))
|
||||||
|
->required(),
|
||||||
|
DatePicker::make('end_date')
|
||||||
|
->label(Membership::getAttributeLabel('end_date'))
|
||||||
|
->required(),
|
||||||
|
])
|
||||||
|
->fillForm(fn (Membership $record): array => [
|
||||||
|
'start_date' => $record->start_date,
|
||||||
|
'end_date' => $record->end_date,
|
||||||
|
])
|
||||||
|
->action(function (Membership $record, array $data): void {
|
||||||
|
$record->update([
|
||||||
|
'status' => 'active',
|
||||||
|
'start_date' => $data['start_date'],
|
||||||
|
'end_date' => $data['end_date'],
|
||||||
|
]);
|
||||||
|
$record->member->notify(new MembershipValidatedNotification($record->fresh(['member', 'package'])));
|
||||||
|
}),
|
||||||
DeleteAction::make(),
|
DeleteAction::make(),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @property Membership $record
|
* @property Membership $record
|
||||||
* @return string|Htmlable
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public function getTitle(): string|Htmlable
|
public function getTitle(): string|Htmlable
|
||||||
{
|
{
|
||||||
|
|||||||
54
app/Notifications/MemberNewRequestMemberNotification.php
Normal file
54
app/Notifications/MemberNewRequestMemberNotification.php
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Notifications;
|
||||||
|
|
||||||
|
use App\Models\Member;
|
||||||
|
use App\Models\NotificationTemplate;
|
||||||
|
use App\Models\Package;
|
||||||
|
use Illuminate\Bus\Queueable;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
use Illuminate\Notifications\Messages\MailMessage;
|
||||||
|
use Illuminate\Notifications\Notification;
|
||||||
|
|
||||||
|
class MemberNewRequestMemberNotification extends Notification implements ShouldQueue
|
||||||
|
{
|
||||||
|
use Queueable;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
public readonly Member $member,
|
||||||
|
public readonly Package $package,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array<int, string>
|
||||||
|
*/
|
||||||
|
public function via(object $notifiable): array
|
||||||
|
{
|
||||||
|
return ['mail'];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toMail(object $notifiable): MailMessage
|
||||||
|
{
|
||||||
|
$template = NotificationTemplate::findByIdentifier('member_new_request_member');
|
||||||
|
|
||||||
|
$vars = [
|
||||||
|
'member_name' => $this->member->full_name,
|
||||||
|
'package_name' => $this->package->name,
|
||||||
|
'app_name' => 'Le Retzien Libre',
|
||||||
|
];
|
||||||
|
|
||||||
|
return (new MailMessage)
|
||||||
|
->subject($template->renderSubject($vars))
|
||||||
|
->view('notifications.mail-template', [
|
||||||
|
'body' => $template->renderBody($vars),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array<string, mixed>
|
||||||
|
*/
|
||||||
|
public function toArray(object $notifiable): array
|
||||||
|
{
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
52
app/Notifications/MembershipValidatedNotification.php
Normal file
52
app/Notifications/MembershipValidatedNotification.php
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Notifications;
|
||||||
|
|
||||||
|
use App\Models\Membership;
|
||||||
|
use App\Models\NotificationTemplate;
|
||||||
|
use Illuminate\Bus\Queueable;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
use Illuminate\Notifications\Messages\MailMessage;
|
||||||
|
use Illuminate\Notifications\Notification;
|
||||||
|
|
||||||
|
class MembershipValidatedNotification extends Notification implements ShouldQueue
|
||||||
|
{
|
||||||
|
use Queueable;
|
||||||
|
|
||||||
|
public function __construct(public readonly Membership $membership) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array<int, string>
|
||||||
|
*/
|
||||||
|
public function via(object $notifiable): array
|
||||||
|
{
|
||||||
|
return ['mail'];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toMail(object $notifiable): MailMessage
|
||||||
|
{
|
||||||
|
$template = NotificationTemplate::findByIdentifier('membership_validated');
|
||||||
|
|
||||||
|
$vars = [
|
||||||
|
'member_name' => $this->membership->member->full_name,
|
||||||
|
'package_name' => $this->membership->package->name,
|
||||||
|
'start_date' => $this->membership->start_date?->format('d/m/Y') ?? '',
|
||||||
|
'end_date' => $this->membership->end_date?->format('d/m/Y') ?? '',
|
||||||
|
'app_name' => config('app.name'),
|
||||||
|
];
|
||||||
|
|
||||||
|
return (new MailMessage)
|
||||||
|
->subject($template->renderSubject($vars))
|
||||||
|
->view('notifications.mail-template', [
|
||||||
|
'body' => $template->renderBody($vars),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array<string, mixed>
|
||||||
|
*/
|
||||||
|
public function toArray(object $notifiable): array
|
||||||
|
{
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,6 +9,7 @@ use App\Models\Package;
|
|||||||
use App\Notifications\MemberDeactivatedAdminNotification;
|
use App\Notifications\MemberDeactivatedAdminNotification;
|
||||||
use App\Notifications\MemberDeactivatedMemberNotification;
|
use App\Notifications\MemberDeactivatedMemberNotification;
|
||||||
use App\Notifications\MemberNewRequestAdminNotification;
|
use App\Notifications\MemberNewRequestAdminNotification;
|
||||||
|
use App\Notifications\MemberNewRequestMemberNotification;
|
||||||
use Illuminate\Support\Facades\Notification;
|
use Illuminate\Support\Facades\Notification;
|
||||||
|
|
||||||
class MemberService
|
class MemberService
|
||||||
@@ -55,6 +56,8 @@ class MemberService
|
|||||||
Notification::route('mail', config('app.admin_email'))
|
Notification::route('mail', config('app.admin_email'))
|
||||||
->notify(new MemberNewRequestAdminNotification($member, $package, (float) $data['amount']));
|
->notify(new MemberNewRequestAdminNotification($member, $package, (float) $data['amount']));
|
||||||
|
|
||||||
|
$member->notify(new MemberNewRequestMemberNotification($member, $package));
|
||||||
|
|
||||||
event(new MemberRegistered($member));
|
event(new MemberRegistered($member));
|
||||||
|
|
||||||
return $member;
|
return $member;
|
||||||
|
|||||||
@@ -41,6 +41,8 @@ return [
|
|||||||
|
|
||||||
'debug' => (bool) env('APP_DEBUG', false),
|
'debug' => (bool) env('APP_DEBUG', false),
|
||||||
|
|
||||||
|
'debug_mail_token' => env('DEBUG_MAIL_TOKEN'),
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
| Application URL
|
| Application URL
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ namespace Database\Factories;
|
|||||||
|
|
||||||
use App\Models\Member;
|
use App\Models\Member;
|
||||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||||
use Illuminate\Support\Carbon;
|
|
||||||
|
|
||||||
class MemberFactory extends Factory
|
class MemberFactory extends Factory
|
||||||
{
|
{
|
||||||
@@ -13,18 +12,16 @@ class MemberFactory extends Factory
|
|||||||
public function definition(): array
|
public function definition(): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'keycloak_id' => $this->faker->word(),
|
|
||||||
'email' => $this->faker->unique()->safeEmail(),
|
'email' => $this->faker->unique()->safeEmail(),
|
||||||
'firstname' => $this->faker->firstName(),
|
'firstname' => $this->faker->firstName(),
|
||||||
'lastname' => $this->faker->lastName(),
|
'lastname' => $this->faker->lastName(),
|
||||||
'phone' => $this->faker->phoneNumber(),
|
'phone1' => $this->faker->phoneNumber(),
|
||||||
'address' => $this->faker->address(),
|
'address' => $this->faker->streetAddress(),
|
||||||
'city' => $this->faker->city(),
|
'city' => $this->faker->city(),
|
||||||
'zipcode' => $this->faker->word(),
|
'zipcode' => $this->faker->postcode(),
|
||||||
'last_login_at' => Carbon::now(),
|
'country' => 'FR',
|
||||||
'created_at' => Carbon::now(),
|
'status' => 'pending',
|
||||||
'updated_at' => Carbon::now(),
|
'nature' => 'physical',
|
||||||
'deleted_at' => Carbon::now(),
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,45 @@ class NotificationTemplateSeeder extends Seeder
|
|||||||
{
|
{
|
||||||
public function run(): void
|
public function run(): void
|
||||||
{
|
{
|
||||||
|
NotificationTemplate::updateOrCreate(
|
||||||
|
['identifier' => 'member_new_request_member'],
|
||||||
|
[
|
||||||
|
'name' => 'Nouvelle demande d\'adhésion — membre',
|
||||||
|
'subject' => 'Votre demande d\'adhésion a bien été reçue — {app_name}',
|
||||||
|
'body' => '<p>Bonjour {member_name},</p>'
|
||||||
|
.'<p>Nous avons bien reçu votre demande d\'adhésion pour la formule <strong>{package_name}</strong>.</p>'
|
||||||
|
.'<p>Votre dossier est en attente de validation par notre équipe. Vous recevrez un e-mail dès que votre adhésion aura été traitée.</p>'
|
||||||
|
.'<p>Merci pour votre confiance et bienvenue dans l\'association !</p>',
|
||||||
|
'variables' => [
|
||||||
|
'member_name' => 'Nom complet du membre',
|
||||||
|
'package_name' => 'Nom de la formule choisie',
|
||||||
|
'app_name' => 'Nom de l\'application',
|
||||||
|
],
|
||||||
|
'is_active' => true,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
NotificationTemplate::updateOrCreate(
|
||||||
|
['identifier' => 'membership_validated'],
|
||||||
|
[
|
||||||
|
'name' => 'Adhésion validée — membre',
|
||||||
|
'subject' => 'Votre adhésion a été validée — {app_name}',
|
||||||
|
'body' => '<p>Bonjour {member_name},</p>'
|
||||||
|
.'<p>Votre adhésion pour la formule <strong>{package_name}</strong> a été validée par notre équipe.</p>'
|
||||||
|
.'<p><strong>Début :</strong> {start_date}<br><strong>Fin :</strong> {end_date}</p>'
|
||||||
|
.'<p>Vous pouvez dès à présent accéder à vos services. Pour toute question, n\'hésitez pas à nous contacter.</p>'
|
||||||
|
.'<p>Merci pour votre adhésion !</p>',
|
||||||
|
'variables' => [
|
||||||
|
'member_name' => 'Nom complet du membre',
|
||||||
|
'package_name' => 'Nom de la formule',
|
||||||
|
'start_date' => 'Date de début de l\'adhésion',
|
||||||
|
'end_date' => 'Date de fin de l\'adhésion',
|
||||||
|
'app_name' => 'Nom de l\'application',
|
||||||
|
],
|
||||||
|
'is_active' => true,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
NotificationTemplate::updateOrCreate(
|
NotificationTemplate::updateOrCreate(
|
||||||
['identifier' => 'subscription_expired_phase1'],
|
['identifier' => 'subscription_expired_phase1'],
|
||||||
[
|
[
|
||||||
|
|||||||
@@ -49,5 +49,7 @@ return [
|
|||||||
|
|
||||||
'actions' => [
|
'actions' => [
|
||||||
'view_profile' => 'View member profile',
|
'view_profile' => 'View member profile',
|
||||||
|
'validate' => 'Validate membership',
|
||||||
|
'validate_missing_dates' => 'Please fill in the start and end dates before validating.',
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -49,5 +49,7 @@ return [
|
|||||||
|
|
||||||
'actions' => [
|
'actions' => [
|
||||||
'view_profile' => 'Voir le profil du membre',
|
'view_profile' => 'Voir le profil du membre',
|
||||||
|
'validate' => 'Valider l\'adhésion',
|
||||||
|
'validate_missing_dates' => 'Veuillez renseigner les dates de début et de fin avant de valider.',
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -53,3 +53,24 @@ Route::get('/test/isp-mails', function() {
|
|||||||
});*/
|
});*/
|
||||||
|
|
||||||
// Test info user on Front
|
// Test info user on Front
|
||||||
|
|
||||||
|
// Temporary mail test route — remove after debugging
|
||||||
|
Route::get('/test/mail', function (\Illuminate\Http\Request $request) {
|
||||||
|
$token = config('app.debug_mail_token');
|
||||||
|
|
||||||
|
if (! $token || $request->query('token') !== $token) {
|
||||||
|
abort(403);
|
||||||
|
}
|
||||||
|
|
||||||
|
$to = $request->query('to');
|
||||||
|
|
||||||
|
if (! $to || ! filter_var($to, FILTER_VALIDATE_EMAIL)) {
|
||||||
|
return response()->json(['error' => 'Provide a valid ?to=email@example.com'], 422);
|
||||||
|
}
|
||||||
|
|
||||||
|
\Illuminate\Support\Facades\Mail::raw('Test mail from Roxane — SMTP is working.', function ($message) use ($to) {
|
||||||
|
$message->to($to)->subject('Roxane — SMTP test');
|
||||||
|
});
|
||||||
|
|
||||||
|
return response()->json(['status' => 'sent', 'to' => $to]);
|
||||||
|
});
|
||||||
|
|||||||
@@ -24,6 +24,6 @@ Route::get('/confidentialite', fn () => Inertia::render('legal/confidentialite')
|
|||||||
require __DIR__.'/settings.php';
|
require __DIR__.'/settings.php';
|
||||||
require __DIR__.'/auth.php';
|
require __DIR__.'/auth.php';
|
||||||
require __DIR__.'/forms.php';
|
require __DIR__.'/forms.php';
|
||||||
if (app()->environment('local')) {
|
if (app()->environment('local', 'staging', 'preprod')) {
|
||||||
require __DIR__.'/dev-routes.php';
|
require __DIR__.'/dev-routes.php';
|
||||||
}
|
}
|
||||||
|
|||||||
96
tests/Feature/MemberNewRequestMemberNotificationTest.php
Normal file
96
tests/Feature/MemberNewRequestMemberNotificationTest.php
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Tests\Feature;
|
||||||
|
|
||||||
|
use App\Models\Member;
|
||||||
|
use App\Models\NotificationTemplate;
|
||||||
|
use App\Models\Package;
|
||||||
|
use App\Notifications\MemberNewRequestAdminNotification;
|
||||||
|
use App\Notifications\MemberNewRequestMemberNotification;
|
||||||
|
use App\Services\MemberService;
|
||||||
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||||
|
use Illuminate\Support\Facades\Notification;
|
||||||
|
use Tests\TestCase;
|
||||||
|
|
||||||
|
class MemberNewRequestMemberNotificationTest extends TestCase
|
||||||
|
{
|
||||||
|
use RefreshDatabase;
|
||||||
|
|
||||||
|
private function createPackage(): Package
|
||||||
|
{
|
||||||
|
return Package::create([
|
||||||
|
'identifier' => 'one-year',
|
||||||
|
'name' => 'Adhésion annuelle',
|
||||||
|
'price' => 12.00,
|
||||||
|
'is_active' => true,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function memberData(Package $package): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'firstname' => 'Jean',
|
||||||
|
'lastname' => 'Dupont',
|
||||||
|
'email' => 'jean.dupont@example.com',
|
||||||
|
'phone1' => '0600000000',
|
||||||
|
'address' => '1 rue de la Paix',
|
||||||
|
'zipcode' => '44000',
|
||||||
|
'city' => 'Nantes',
|
||||||
|
'package' => $package->identifier,
|
||||||
|
'amount' => 12.00,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_member_receives_confirmation_notification_on_registration(): void
|
||||||
|
{
|
||||||
|
Notification::fake();
|
||||||
|
|
||||||
|
NotificationTemplate::factory()->create(['identifier' => 'member_new_request_admin', 'is_active' => true]);
|
||||||
|
NotificationTemplate::factory()->create(['identifier' => 'member_new_request_member', 'is_active' => true]);
|
||||||
|
|
||||||
|
$package = $this->createPackage();
|
||||||
|
|
||||||
|
(new MemberService)->registerNewMember($this->memberData($package));
|
||||||
|
|
||||||
|
$member = Member::where('email', 'jean.dupont@example.com')->firstOrFail();
|
||||||
|
|
||||||
|
Notification::assertSentTo($member, MemberNewRequestMemberNotification::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_confirmation_notification_contains_correct_member_and_package(): void
|
||||||
|
{
|
||||||
|
Notification::fake();
|
||||||
|
|
||||||
|
NotificationTemplate::factory()->create(['identifier' => 'member_new_request_admin', 'is_active' => true]);
|
||||||
|
NotificationTemplate::factory()->create(['identifier' => 'member_new_request_member', 'is_active' => true]);
|
||||||
|
|
||||||
|
$package = $this->createPackage();
|
||||||
|
|
||||||
|
(new MemberService)->registerNewMember($this->memberData($package));
|
||||||
|
|
||||||
|
$member = Member::where('email', 'jean.dupont@example.com')->firstOrFail();
|
||||||
|
|
||||||
|
Notification::assertSentTo(
|
||||||
|
$member,
|
||||||
|
MemberNewRequestMemberNotification::class,
|
||||||
|
function (MemberNewRequestMemberNotification $notification) use ($member, $package): bool {
|
||||||
|
return $notification->member->id === $member->id
|
||||||
|
&& $notification->package->id === $package->id;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_admin_notification_is_also_sent_on_registration(): void
|
||||||
|
{
|
||||||
|
Notification::fake();
|
||||||
|
|
||||||
|
NotificationTemplate::factory()->create(['identifier' => 'member_new_request_admin', 'is_active' => true]);
|
||||||
|
NotificationTemplate::factory()->create(['identifier' => 'member_new_request_member', 'is_active' => true]);
|
||||||
|
|
||||||
|
$package = $this->createPackage();
|
||||||
|
|
||||||
|
(new MemberService)->registerNewMember($this->memberData($package));
|
||||||
|
|
||||||
|
Notification::assertSentOnDemand(MemberNewRequestAdminNotification::class);
|
||||||
|
}
|
||||||
|
}
|
||||||
86
tests/Feature/MembershipValidatedNotificationTest.php
Normal file
86
tests/Feature/MembershipValidatedNotificationTest.php
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Tests\Feature;
|
||||||
|
|
||||||
|
use App\Models\Member;
|
||||||
|
use App\Models\Membership;
|
||||||
|
use App\Models\NotificationTemplate;
|
||||||
|
use App\Models\Package;
|
||||||
|
use App\Notifications\MembershipValidatedNotification;
|
||||||
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||||
|
use Illuminate\Support\Facades\Notification;
|
||||||
|
use Tests\TestCase;
|
||||||
|
|
||||||
|
class MembershipValidatedNotificationTest extends TestCase
|
||||||
|
{
|
||||||
|
use RefreshDatabase;
|
||||||
|
|
||||||
|
private function createPendingMembership(): Membership
|
||||||
|
{
|
||||||
|
$package = Package::create([
|
||||||
|
'identifier' => 'one-year',
|
||||||
|
'name' => 'Adhésion annuelle',
|
||||||
|
'price' => 12.00,
|
||||||
|
'is_active' => true,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$member = Member::factory()->create([
|
||||||
|
'status' => 'pending',
|
||||||
|
'nature' => 'physical',
|
||||||
|
]);
|
||||||
|
|
||||||
|
return Membership::create([
|
||||||
|
'member_id' => $member->id,
|
||||||
|
'package_id' => $package->id,
|
||||||
|
'status' => 'pending',
|
||||||
|
'amount' => 12.00,
|
||||||
|
'payment_status' => 'unpaid',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_member_receives_notification_when_membership_is_validated(): void
|
||||||
|
{
|
||||||
|
Notification::fake();
|
||||||
|
|
||||||
|
NotificationTemplate::factory()->create(['identifier' => 'membership_validated', 'is_active' => true]);
|
||||||
|
|
||||||
|
$membership = $this->createPendingMembership();
|
||||||
|
|
||||||
|
$membership->update(['status' => 'active']);
|
||||||
|
$membership->member->notify(new MembershipValidatedNotification($membership->fresh(['member', 'package'])));
|
||||||
|
|
||||||
|
Notification::assertSentTo($membership->member, MembershipValidatedNotification::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_validated_notification_contains_correct_membership(): void
|
||||||
|
{
|
||||||
|
Notification::fake();
|
||||||
|
|
||||||
|
NotificationTemplate::factory()->create(['identifier' => 'membership_validated', 'is_active' => true]);
|
||||||
|
|
||||||
|
$membership = $this->createPendingMembership();
|
||||||
|
|
||||||
|
$membership->update(['status' => 'active']);
|
||||||
|
$freshMembership = $membership->fresh(['member', 'package']);
|
||||||
|
$freshMembership->member->notify(new MembershipValidatedNotification($freshMembership));
|
||||||
|
|
||||||
|
Notification::assertSentTo(
|
||||||
|
$membership->member,
|
||||||
|
MembershipValidatedNotification::class,
|
||||||
|
function (MembershipValidatedNotification $notification) use ($membership): bool {
|
||||||
|
return $notification->membership->id === $membership->id;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_notification_is_not_sent_when_status_is_not_active(): void
|
||||||
|
{
|
||||||
|
Notification::fake();
|
||||||
|
|
||||||
|
NotificationTemplate::factory()->create(['identifier' => 'membership_validated', 'is_active' => true]);
|
||||||
|
|
||||||
|
$membership = $this->createPendingMembership();
|
||||||
|
|
||||||
|
Notification::assertNotSentTo($membership->member, MembershipValidatedNotification::class);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user