feat(Reminder process): add 4 reminder phases for membership (Retzien)
All checks were successful
Deploy Roxane to Preprod / deploy (push) Successful in 1m21s

This commit is contained in:
2026-09-06 17:03:14 +02:00
parent 98893924ac
commit ba11ee7120
61 changed files with 967 additions and 162 deletions

View File

@@ -45,6 +45,7 @@ class Contact extends Model
{
return __("contacts.fields.$attribute");
}
public function getFullNameAttribute(): string
{
return "{$this->firstname} {$this->lastname}";

View File

@@ -13,7 +13,15 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo;
* @property \Illuminate\Support\Carbon|null $created_at
* @property \Illuminate\Support\Carbon|null $updated_at
* @property-read \App\Models\Member $member
*
* @method static \Illuminate\Database\Eloquent\Builder<static>|ListmonkMember newModelQuery()
* @method static \Illuminate\Database\Eloquent\Builder<static>|ListmonkMember newQuery()
* @method static \Illuminate\Database\Eloquent\Builder<static>|ListmonkMember query()
* @method static \Illuminate\Database\Eloquent\Builder<static>|ListmonkMember whereCreatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|ListmonkMember whereData($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|ListmonkMember whereId($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|ListmonkMember whereListmonkUserId($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|ListmonkMember whereMemberId($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|ListmonkMember whereUpdatedAt($value)
* @mixin \Eloquent
*/
class ListmonkMember extends Model

View File

@@ -19,10 +19,10 @@ use Illuminate\Notifications\Notifiable;
* @property string $nature
* @property int|null $type_id
* @property int|null $group_id
* @property string|null $lastname
* @property string|null $firstname
* @property string|null $lastname
* @property string $email
* @property string $retzien_email
* @property string|null $retzien_email
* @property string|null $company
* @property string|null $date_of_birth
* @property string|null $address
@@ -40,17 +40,23 @@ use Illuminate\Notifications\Notifiable;
* @property-read \App\Models\MemberGroup|null $group
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\IspconfigMember> $ispconfigs
* @property-read int|null $ispconfigs_count
* @property-read \App\Models\Membership|null $lastActiveMembership
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\ListmonkMember> $listmonkMembers
* @property-read int|null $listmonk_members_count
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Membership> $memberships
* @property-read int|null $memberships_count
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\NextCloudMember> $nextcloudAccounts
* @property-read int|null $nextcloud_accounts_count
* @property-read \Illuminate\Notifications\DatabaseNotificationCollection<int, \Illuminate\Notifications\DatabaseNotification> $notifications
* @property-read int|null $notifications_count
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\MemberRenewalReminder> $renewalReminders
* @property-read int|null $renewal_reminders_count
* @property-read \App\Models\MemberType|null $type
* @property-read \App\Models\User|null $user
*
* @method static \Database\Factories\MemberFactory factory($count = null, $state = [])
* @method static \Illuminate\Database\Eloquent\Builder<static>|Member newModelQuery()
* @method static \Illuminate\Database\Eloquent\Builder<static>|Member newQuery()
* @method static \Illuminate\Database\Eloquent\Builder<static>|Member onlyTrashed()
* @method static \Illuminate\Database\Eloquent\Builder<static>|Member query()
* @method static \Illuminate\Database\Eloquent\Builder<static>|Member whereAddress($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|Member whereCity($value)
@@ -77,7 +83,8 @@ use Illuminate\Notifications\Notifiable;
* @method static \Illuminate\Database\Eloquent\Builder<static>|Member whereUserId($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|Member whereWebsiteUrl($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|Member whereZipcode($value)
*
* @method static \Illuminate\Database\Eloquent\Builder<static>|Member withTrashed(bool $withTrashed = true)
* @method static \Illuminate\Database\Eloquent\Builder<static>|Member withoutTrashed()
* @mixin \Eloquent
*/
class Member extends Model
@@ -163,6 +170,11 @@ class Member extends Model
return $this->hasMany(ListmonkMember::class, 'member_id');
}
public function renewalReminders(): HasMany
{
return $this->hasMany(MemberRenewalReminder::class);
}
public function lastActiveMembership(): HasOne
{
return $this->hasOne(Membership::class)->where('status', 'active')->latest();

View File

@@ -32,12 +32,12 @@ class MemberGroup extends Model
protected $fillable = [
'name',
'description',
'identifier'
'identifier',
];
public static function getAttributeLabel(string $attribute): string
{
return __('member_groups.fields.' . $attribute);
return __('member_groups.fields.'.$attribute);
}
public function members(): HasMany

View File

@@ -0,0 +1,107 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
/**
* @property int $id
* @property int $member_id
* @property int $renewal_year
* @property bool $reminder_1_sent
* @property bool $reminder_2_sent
* @property bool $reminder_3_sent
* @property bool $deactivation_sent
* @property \Illuminate\Support\Carbon|null $reminder_1_sent_at
* @property \Illuminate\Support\Carbon|null $reminder_2_sent_at
* @property \Illuminate\Support\Carbon|null $reminder_3_sent_at
* @property \Illuminate\Support\Carbon|null $deactivated_at
* @property \Illuminate\Support\Carbon|null $created_at
* @property \Illuminate\Support\Carbon|null $updated_at
* @property-read \App\Models\Member $member
* @method static \Illuminate\Database\Eloquent\Builder<static>|MemberRenewalReminder newModelQuery()
* @method static \Illuminate\Database\Eloquent\Builder<static>|MemberRenewalReminder newQuery()
* @method static \Illuminate\Database\Eloquent\Builder<static>|MemberRenewalReminder query()
* @method static \Illuminate\Database\Eloquent\Builder<static>|MemberRenewalReminder whereCreatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|MemberRenewalReminder whereDeactivatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|MemberRenewalReminder whereDeactivationSent($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|MemberRenewalReminder whereId($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|MemberRenewalReminder whereMemberId($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|MemberRenewalReminder whereReminder1Sent($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|MemberRenewalReminder whereReminder1SentAt($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|MemberRenewalReminder whereReminder2Sent($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|MemberRenewalReminder whereReminder2SentAt($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|MemberRenewalReminder whereReminder3Sent($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|MemberRenewalReminder whereReminder3SentAt($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|MemberRenewalReminder whereRenewalYear($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|MemberRenewalReminder whereUpdatedAt($value)
* @mixin \Eloquent
*/
class MemberRenewalReminder extends Model
{
protected $fillable = [
'member_id',
'renewal_year',
'reminder_1_sent',
'reminder_2_sent',
'reminder_3_sent',
'deactivation_sent',
'reminder_1_sent_at',
'reminder_2_sent_at',
'reminder_3_sent_at',
'deactivated_at',
];
protected function casts(): array
{
return [
'reminder_1_sent' => 'boolean',
'reminder_2_sent' => 'boolean',
'reminder_3_sent' => 'boolean',
'deactivation_sent' => 'boolean',
'reminder_1_sent_at' => 'datetime',
'reminder_2_sent_at' => 'datetime',
'reminder_3_sent_at' => 'datetime',
'deactivated_at' => 'datetime',
'renewal_year' => 'integer',
];
}
public function member(): BelongsTo
{
return $this->belongsTo(Member::class);
}
public function markAsReminder1Sent(): void
{
$this->update([
'reminder_1_sent' => true,
'reminder_1_sent_at' => now(),
]);
}
public function markAsReminder2Sent(): void
{
$this->update([
'reminder_2_sent' => true,
'reminder_2_sent_at' => now(),
]);
}
public function markAsReminder3Sent(): void
{
$this->update([
'reminder_3_sent' => true,
'reminder_3_sent_at' => now(),
]);
}
public function markAsDeactivated(): void
{
$this->update([
'deactivation_sent' => true,
'deactivated_at' => now(),
]);
}
}

View File

@@ -5,6 +5,29 @@ namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
/**
* @property int $id
* @property string $identifier
* @property string $name
* @property string|null $description
* @property \Illuminate\Support\Carbon|null $created_at
* @property \Illuminate\Support\Carbon|null $updated_at
* @property \Illuminate\Support\Carbon|null $deleted_at
* @method static \Illuminate\Database\Eloquent\Builder<static>|MemberType newModelQuery()
* @method static \Illuminate\Database\Eloquent\Builder<static>|MemberType newQuery()
* @method static \Illuminate\Database\Eloquent\Builder<static>|MemberType onlyTrashed()
* @method static \Illuminate\Database\Eloquent\Builder<static>|MemberType query()
* @method static \Illuminate\Database\Eloquent\Builder<static>|MemberType whereCreatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|MemberType whereDeletedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|MemberType whereDescription($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|MemberType whereId($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|MemberType whereIdentifier($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|MemberType whereName($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|MemberType whereUpdatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|MemberType withTrashed(bool $withTrashed = true)
* @method static \Illuminate\Database\Eloquent\Builder<static>|MemberType withoutTrashed()
* @mixin \Eloquent
*/
class MemberType extends Model
{
use SoftDeletes;
@@ -14,4 +37,4 @@ class MemberType extends Model
'name',
'description',
];
}
}

View File

@@ -16,7 +16,7 @@ use Illuminate\Database\Eloquent\Relations\BelongsToMany;
* @property string $status
* @property string|null $validation_date
* @property string|null $payment_method
* @property string $amount
* @property numeric $amount
* @property string $payment_status
* @property string|null $note_public
* @property string|null $note_private
@@ -30,7 +30,6 @@ use Illuminate\Database\Eloquent\Relations\BelongsToMany;
* @property-read \App\Models\Package $package
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Service> $services
* @property-read int|null $services_count
*
* @method static \Illuminate\Database\Eloquent\Builder<static>|Membership newModelQuery()
* @method static \Illuminate\Database\Eloquent\Builder<static>|Membership newQuery()
* @method static \Illuminate\Database\Eloquent\Builder<static>|Membership query()
@@ -52,7 +51,6 @@ use Illuminate\Database\Eloquent\Relations\BelongsToMany;
* @method static \Illuminate\Database\Eloquent\Builder<static>|Membership whereStatus($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|Membership whereUpdatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|Membership whereValidationDate($value)
*
* @mixin \Eloquent
*/
class Membership extends Model

View File

@@ -22,7 +22,6 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo;
* @method static \Illuminate\Database\Eloquent\Builder<static>|NextCloudMember whereMemberId($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|NextCloudMember whereNextcloudUserId($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|NextCloudMember whereUpdatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|NextCloudMember whereUsername($value)
* @mixin \Eloquent
*/
class NextCloudMember extends Model

View File

@@ -6,6 +6,36 @@ use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
/**
* @property int $id
* @property string $identifier
* @property string $name
* @property string $subject
* @property string $body
* @property array<array-key, mixed>|null $variables
* @property bool $is_active
* @property \Illuminate\Support\Carbon|null $created_at
* @property \Illuminate\Support\Carbon|null $updated_at
* @property \Illuminate\Support\Carbon|null $deleted_at
* @method static \Database\Factories\NotificationTemplateFactory factory($count = null, $state = [])
* @method static \Illuminate\Database\Eloquent\Builder<static>|NotificationTemplate newModelQuery()
* @method static \Illuminate\Database\Eloquent\Builder<static>|NotificationTemplate newQuery()
* @method static \Illuminate\Database\Eloquent\Builder<static>|NotificationTemplate onlyTrashed()
* @method static \Illuminate\Database\Eloquent\Builder<static>|NotificationTemplate query()
* @method static \Illuminate\Database\Eloquent\Builder<static>|NotificationTemplate whereBody($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|NotificationTemplate whereCreatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|NotificationTemplate whereDeletedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|NotificationTemplate whereId($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|NotificationTemplate whereIdentifier($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|NotificationTemplate whereIsActive($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|NotificationTemplate whereName($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|NotificationTemplate whereSubject($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|NotificationTemplate whereUpdatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|NotificationTemplate whereVariables($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|NotificationTemplate withTrashed(bool $withTrashed = true)
* @method static \Illuminate\Database\Eloquent\Builder<static>|NotificationTemplate withoutTrashed()
* @mixin \Eloquent
*/
class NotificationTemplate extends Model
{
use HasFactory, SoftDeletes;

View File

@@ -3,14 +3,13 @@
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
/**
* @property int $id
* @property string $identifier
* @property string $name
* @property string|null $description
* @property string $price
* @property numeric $price
* @property int $is_active
* @property \Illuminate\Support\Carbon|null $created_at
* @property \Illuminate\Support\Carbon|null $updated_at
@@ -40,7 +39,6 @@ class Package extends Model
public static function getAttributeLabel(string $attribute): string
{
return __('packages.fields.' . $attribute);
return __('packages.fields.'.$attribute);
}
}

View File

@@ -43,10 +43,10 @@ class Service extends Model
public static function getAttributeLabel(string $attribute): string
{
return __('services.fields.' . $attribute);
return __('services.fields.'.$attribute);
}
public function memberships() : BelongsToMany
public function memberships(): BelongsToMany
{
return $this->belongsToMany(Membership::class, 'services_memberships', 'service_id', 'membership_id');
}

View File

@@ -30,7 +30,6 @@ use Spatie\Permission\Traits\HasRoles;
* @property-read int|null $permissions_count
* @property-read \Illuminate\Database\Eloquent\Collection<int, \Spatie\Permission\Models\Role> $roles
* @property-read int|null $roles_count
*
* @method static \Database\Factories\UserFactory factory($count = null, $state = [])
* @method static \Illuminate\Database\Eloquent\Builder<static>|User newModelQuery()
* @method static \Illuminate\Database\Eloquent\Builder<static>|User newQuery()
@@ -47,7 +46,6 @@ use Spatie\Permission\Traits\HasRoles;
* @method static \Illuminate\Database\Eloquent\Builder<static>|User whereUpdatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|User withoutPermission($permissions)
* @method static \Illuminate\Database\Eloquent\Builder<static>|User withoutRole($roles, $guard = null)
*
* @mixin \Eloquent
*/
class User extends Authenticatable implements FilamentUser