Mitgliedschaft: Erinnerungen und eigenes Verlaengerungs-Produkt

Die Erinnerungsmails vor Ablauf der Mitgliedschaft beschrieben noch den
abgeschafften SEPA-Einzug und verlinkten auf die Hauptdomain, wo
/user/membership nicht existiert. Das Produkt fuer die Verlaengerung war
zudem dasselbe wie bei der Registrierung und sprach deshalb vom
Neuabschluss.

- Erinnerungen: nur noch Stufen 31/33/34/35, SEPA-Stufen 32/36/37 samt
  :price und :pay_date entfallen; Button verlinkt auf my.mivita.care;
  fehlt ein Text zum Status, wird die Mail geloggt statt roh versendet.
- Alle Erinnerungstexte (de/en/es/fr) erklaeren jetzt, dass ohne Zahlung
  der Account pausiert und offene Provisionen ausgezahlt werden.
- Eigenes Produkt fuer die Verlaengerung (identifier show_renewal) als
  Kopie des Mitgliedschafts-Produkts inkl. Preisen, Kategorien und
  Uebersetzungen fuer en/es/fr; die Mitgliedschaftsseite faellt ohne
  dieses Produkt auf das bisherige zurueck.
- Mitgliedschaftsseite auf ein Paket reduziert: Upgrade-, Wechsel- und
  Abo-Optionen entfernt, Texte auf die manuelle Verlaengerung umgestellt.
- Alte Cron-Weboberflaeche entfernt, der Versand laeuft ueber den
  Scheduler (payments:check-accounts).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Kevin 2026-08-26 08:24:32 +00:00
parent 0bdb6eabc6
commit 30fb031d12
30 changed files with 810 additions and 1223 deletions

View file

@ -2,16 +2,16 @@
namespace App\Console\Commands;
use Carbon\Carbon;
use App\User;
use App\Services\Util;
use App\Mail\MailCustomMessage;
use App\Models\UserHistory;
use App\Models\UserMessage;
use App\Mail\MailCustomMessage;
use App\Services\Util;
use App\User;
use Carbon\Carbon;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\Lang;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Mail;
class CheckPaymentsAccount extends Command
{
@ -38,71 +38,74 @@ class CheckPaymentsAccount extends Command
$this->info('COMMAND [payments:check-accounts] started.');
// Die Logik wurde 1:1 aus der checkPaymentsAccounts-Methode übernommen
$renewalDate = Carbon::now()->modify('+' . (config('mivita.remind_first_days') + 1) . ' days');
Log::channel('cron')->info('Erneuerungsdatum für Zahlungen: ' . $renewalDate->format('Y-m-d H:i:s'));
$renewalDate = Carbon::now()->modify('+'.(config('mivita.remind_first_days') + 1).' days');
Log::channel('cron')->info('Erneuerungsdatum für Zahlungen: '.$renewalDate->format('Y-m-d H:i:s'));
$users = User::where('payment_account', '!=', NULL)
$users = User::where('payment_account', '!=', null)
->where('active', '=', 1)
->where('blocked', '!=', 1)
->where('payment_account', '<', $renewalDate)
->get();
Log::channel('cron')->info('Found ' . $users->count() . ' users for payment reminders.');
$this->info('Found ' . $users->count() . ' users for payment reminders.');
Log::channel('cron')->info('Found '.$users->count().' users for payment reminders.');
$this->info('Found '.$users->count().' users for payment reminders.');
foreach ($users as $user) {
Log::channel('cron')->info('Prüfe Zahlungserinnerungen für Benutzer: ' . $user->email);
Log::channel('cron')->info('Prüfe Zahlungserinnerungen für Benutzer: '.$user->email);
$this->checkReminderPayments($user);
}
Log::channel('cron')->info('COMMAND [payments:check-accounts] finished.');
$this->info('COMMAND [payments:check-accounts] finished.');
return 0; // Success
}
/**
* Überprüft und sendet Zahlungserinnerungen basierend auf Benutzerkontostand
*
* RULES:
* > 21 remind_first_days = 31 reminder_first
* > 21 remind_first_days + sepa = 32 reminder_first_sepa
* > 14 remind_sec_days = 33 reminder_sec
* > 2 remind_last_days = 34 reminder_last
* > 0 deaktiv = 35 reminder_deaktiv
* > 0 deaktiv + sepa = 36 reminder_deaktiv_sepa
* == 7 abo_booking_days + sepa + cron = 37 reminder_collect_sepa
*
* @param User $user Benutzer
* RULES:
* > 14 remind_sec_days = 31 reminder_first
* <= 14 remind_sec_days = 33 reminder_sec
* <= 2 remind_last_days = 34 reminder_last
* Mitgliedschaft abgelaufen = 35 reminder_deaktiv
*
* Die SEPA-Stati 32/36/37 sind entfallen, den Lastschrifteinzug gibt es nicht mehr.
*
* @param User $user Benutzer
* @return void
*/
private function checkReminderPayments(User $user)
{
//35 reminder_deaktiv, 36 reminder_deaktiv_sepa
if (!$user->isActiveAccount()) {
Log::channel('cron')->info('Inaktives Konto für Benutzer: ' . $user->email);
// 35 reminder_deaktiv, 36 reminder_deaktiv_sepa
if (! $user->isActiveAccount()) {
Log::channel('cron')->info('Inaktives Konto für Benutzer: '.$user->email);
$this->checkIsReminderSend($user, 35);
return;
}
//34 reminder_last
// 34 reminder_last
if ($user->daysActiveAccount() <= config('mivita.remind_last_days')) {
Log::channel('cron')->info('Letzte Erinnerung für Benutzer: ' . $user->email . ' (Tage aktiv: ' . $user->daysActiveAccount() . ')');
Log::channel('cron')->info('Letzte Erinnerung für Benutzer: '.$user->email.' (Tage aktiv: '.$user->daysActiveAccount().')');
$this->checkIsReminderSend($user, 34);
return;
}
//33 reminder_sec
// 33 reminder_sec
if ($user->daysActiveAccount() <= config('mivita.remind_sec_days')) {
Log::channel('cron')->info('Zweite Erinnerung für Benutzer: ' . $user->email . ' (Tage aktiv: ' . $user->daysActiveAccount() . ')');
Log::channel('cron')->info('Zweite Erinnerung für Benutzer: '.$user->email.' (Tage aktiv: '.$user->daysActiveAccount().')');
$this->checkIsReminderSend($user, 33);
return;
}
//31 reminder_first
// 31 reminder_first
if ($user->daysActiveAccount() > config('mivita.remind_sec_days')) {
Log::channel('cron')->info('Erste Erinnerung für Benutzer: ' . $user->email . ' (Tage aktiv: ' . $user->daysActiveAccount() . ')');
Log::channel('cron')->info('Erste Erinnerung für Benutzer: '.$user->email.' (Tage aktiv: '.$user->daysActiveAccount().')');
$this->checkIsReminderSend($user, 31);
return;
}
}
@ -110,8 +113,8 @@ class CheckPaymentsAccount extends Command
/**
* Überprüft, ob eine Erinnerung bereits gesendet wurde
*
* @param User $user Benutzer
* @param int $status Status-Code der Erinnerung
* @param User $user Benutzer
* @param int $status Status-Code der Erinnerung
* @return bool
*/
private function checkIsReminderSend(User $user, $status)
@ -124,11 +127,12 @@ class CheckPaymentsAccount extends Command
->first();
if ($isSend) {
Log::channel('cron')->info('Erinnerung bereits gesendet für Benutzer: ' . $user->email . ' (Status: ' . $status . ')');
Log::channel('cron')->info('Erinnerung bereits gesendet für Benutzer: '.$user->email.' (Status: '.$status.')');
return true;
}
Log::channel('cron')->info('Sende neue Erinnerung für Benutzer: ' . $user->email . ' (Status: ' . $status . ')');
Log::channel('cron')->info('Sende neue Erinnerung für Benutzer: '.$user->email.' (Status: '.$status.')');
$referenz = $this->sendReminderMail($user, $status);
UserHistory::create([
@ -136,7 +140,7 @@ class CheckPaymentsAccount extends Command
'action' => 'reminder_payments',
'referenz' => $referenz,
'identifier' => $user->payment_account,
'status' => $status
'status' => $status,
]);
return false;
@ -145,61 +149,62 @@ class CheckPaymentsAccount extends Command
/**
* Sendet eine Erinnerungs-E-Mail an den Benutzer
*
* @param User $user Benutzer
* @param int $status Status-Code der Erinnerung
* @param User $user Benutzer
* @param int $status Status-Code der Erinnerung
* @return int
*/
private function sendReminderMail(User $user, $status)
{
$days = abs($user->daysActiveAccount());
$pay_date = Carbon::parse($user->payment_account)->modify('- ' . config('mivita.abo_booking_days') . ' days')->format('d.m.Y');
$datetime = $user->getPaymentAccountDateFormat();
$price = "";
if (! Lang::has('reminder.copy_first_'.$status)) {
Log::channel('cron')->error('Kein Erinnerungstext für Status '.$status.' vorhanden, Mail an '.$user->email.' wird übersprungen.');
if ($user->payment_order_id && isset($user->payment_order_product->price)) {
$price = 'von ' . $user->payment_order_product->getFormattedPrice() . ' EUR';
return 0;
}
$message = __('reminder.copy_first_' . $status, ['days' => $days, 'datetime' => $datetime, 'price' => $price, 'pay_date' => $pay_date]);
$message_last = __('reminder.copy_last_' . $status, ['days' => $days, 'datetime' => $datetime, 'price' => $price, 'pay_date' => $pay_date]);
$button = __('reminder.button_' . $status);
$days = abs($user->daysActiveAccount());
$datetime = $user->getPaymentAccountDateFormat();
$message = preg_replace("/[\n\r]/", "", $message);
$message_last = preg_replace("/[\n\r]/", "", $message_last);
$message = __('reminder.copy_first_'.$status, ['days' => $days, 'datetime' => $datetime]);
$message_last = __('reminder.copy_last_'.$status, ['days' => $days, 'datetime' => $datetime]);
$button = __('reminder.button_'.$status);
$message = preg_replace("/[\n\r]/", '', $message);
$message_last = preg_replace("/[\n\r]/", '', $message_last);
$data = [
'subject' => __('reminder.subject') . " | ID: " . $status,
'subject' => __('reminder.subject').' | ID: '.$status,
'message' => $message,
'message_last' => $message_last,
'url' => config('app.url') . '/user/membership',
'url' => rtrim(Util::getMyMivitaUrl(), '/').'/user/membership',
'button' => $button,
];
$sender = User::find(1);
$customer_mail = UserMessage::create(['user_id' => $user->id, 'send_user_id' => $sender->id, 'email' => $user->email, 'subject' => $data['subject'], 'message' => $data['message'] . " " . $data['message_last']]);
$customer_mail = UserMessage::create(['user_id' => $user->id, 'send_user_id' => $sender->id, 'email' => $user->email, 'subject' => $data['subject'], 'message' => $data['message'].' '.$data['message_last']]);
try {
if (!Util::isTestSystem()) {
if (! Util::isTestSystem()) {
if ($status >= 34) {
Log::channel('cron')->info('Sende kritische Erinnerung mit BCC an: ' . $user->email);
Log::channel('cron')->info('Sende kritische Erinnerung mit BCC an: '.$user->email);
Mail::to($user->email)
->locale($user->getLocale())
->bcc(config('app.default_mail'))
->send(new MailCustomMessage($user, $data, $sender, false));
} else {
Log::channel('cron')->info('Sende normale Erinnerung an: ' . $user->email);
Log::channel('cron')->info('Sende normale Erinnerung an: '.$user->email);
Mail::to($user->email)
->locale($user->getLocale())
->send(new MailCustomMessage($user, $data, $sender, false));
}
} else {
Log::channel('cron')->info('Testsystem: E-Mail-Versand simuliert für: ' . $user->email);
Log::channel('cron')->info('Testsystem: E-Mail-Versand simuliert für: '.$user->email);
}
} catch (\Exception $e) {
Log::channel('cron')->error('Mail-Fehler für Benutzer ' . $user->email . ': ' . $e->getMessage());
Log::channel('cron')->error('Mail-Fehler für Benutzer '.$user->email.': '.$e->getMessage());
$customer_mail->fail = true;
$customer_mail->error = $e->getMessage();
$customer_mail->save();
return 0;
}
@ -207,7 +212,8 @@ class CheckPaymentsAccount extends Command
$customer_mail->sent_at = now();
$customer_mail->save();
Log::channel('cron')->info('Erinnerungsmail erfolgreich gesendet an: ' . $user->email);
Log::channel('cron')->info('Erinnerungsmail erfolgreich gesendet an: '.$user->email);
return 1;
}
}