252 lines
No EOL
9.4 KiB
PHP
252 lines
No EOL
9.4 KiB
PHP
<?php
|
|
|
|
namespace App\Console\Commands;
|
|
|
|
use App\Models\PaymentReminder;
|
|
use App\Models\ShoppingPayment;
|
|
use App\Services\PaymentReminderService;
|
|
use Carbon\Carbon;
|
|
use Illuminate\Console\Command;
|
|
|
|
/**
|
|
* Command für automatische Zahlungserinnerungen
|
|
*
|
|
* Dieser Command wird als Cron-Job ausgeführt und sendet automatisch
|
|
* Zahlungserinnerungen basierend auf den konfigurierten Intervallen.
|
|
*
|
|
* Verwendung:
|
|
* php artisan payments:reminders
|
|
*
|
|
* Cron-Job Konfiguration (täglich um 9:00 Uhr):
|
|
* 0 9 * * * cd /path/to/project && php artisan payments:reminders >> /dev/null 2>&1
|
|
*
|
|
* Oder für stündliche Ausführung:
|
|
* 0 * * * * cd /path/to/project && php artisan payments:reminders >> /dev/null 2>&1
|
|
*
|
|
* Logs werden automatisch in storage/logs/laravel.log geschrieben
|
|
*/
|
|
class PaymentsReminders extends Command
|
|
{
|
|
/**
|
|
* The name and signature of the console command.
|
|
*
|
|
* @var string
|
|
*/
|
|
protected $signature = 'payments:reminders';
|
|
protected $description = 'Run Payments Reminders';
|
|
|
|
private $timeStart;
|
|
private $dev = false;
|
|
private $paymentReminderService;
|
|
private $stats = [
|
|
'total_processed' => 0,
|
|
'reminders_sent' => 0,
|
|
'errors' => 0,
|
|
'skipped' => 0
|
|
];
|
|
|
|
public function __construct(PaymentReminderService $paymentReminderService)
|
|
{
|
|
parent::__construct();
|
|
$this->paymentReminderService = $paymentReminderService;
|
|
}
|
|
|
|
/**
|
|
* Execute the console command.
|
|
*
|
|
* @return int
|
|
*/
|
|
public function handle()
|
|
{
|
|
\Log::info('Starting PaymentsReminders Command', ['timestamp' => now()]);
|
|
$this->info('RUN Command Payments Reminders: '.date('d.m.Y H:i'));
|
|
$this->timeStart = microtime(true);
|
|
|
|
try {
|
|
$this->functionReminder();
|
|
|
|
$executionTime = round(microtime(true) - $this->timeStart, 2);
|
|
$this->info("\n=== PAYMENT REMINDERS ABGESCHLOSSEN ===");
|
|
$this->info("Ausführungszeit: {$executionTime} Sekunden");
|
|
$this->info("Statistiken:");
|
|
$this->info(" - Gesamt verarbeitet: {$this->stats['total_processed']}");
|
|
$this->info(" - Erinnerungen gesendet: {$this->stats['reminders_sent']}");
|
|
$this->info(" - Fehler: {$this->stats['errors']}");
|
|
$this->info(" - Übersprungen: {$this->stats['skipped']}");
|
|
|
|
\Log::info('PaymentsReminders Command completed successfully', [
|
|
'execution_time' => $executionTime,
|
|
'stats' => $this->stats
|
|
]);
|
|
return 0;
|
|
} catch (\Exception $e) {
|
|
\Log::error('PaymentsReminders Command failed', [
|
|
'error' => $e->getMessage(),
|
|
'trace' => $e->getTraceAsString()
|
|
]);
|
|
$this->error('Command failed: ' . $e->getMessage());
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Hauptfunktion für die Verarbeitung der Zahlungserinnerungen
|
|
*/
|
|
private function functionReminder()
|
|
{
|
|
$this->info('=== STARTE PAYMENT REMINDERS ===');
|
|
|
|
// Hole alle aktiven PaymentReminder und gruppiere sie nach clearingtype
|
|
$payment_reminders = PaymentReminder::where('active', true)->get();
|
|
$this->info("Gefundene aktive PaymentReminder: " . $payment_reminders->count());
|
|
|
|
if ($payment_reminders->isEmpty()) {
|
|
$this->warn("Keine aktiven PaymentReminder gefunden!");
|
|
return;
|
|
}
|
|
|
|
// Finde für jeden clearingtype das kleinste Intervall (in Tagen)
|
|
$intervals = $this->paymentReminderService->getActiveIntervals();
|
|
|
|
$this->info("Gefundene clearingtypes mit kleinsten Intervallen:");
|
|
foreach($intervals as $clearingtype => $interval){
|
|
$this->line(" - {$clearingtype}: {$interval} Tage");
|
|
}
|
|
|
|
// Verarbeite jeden clearingtype mit seinem kleinsten Intervall
|
|
foreach($intervals as $clearingtype => $interval){
|
|
$this->info("\n--- Verarbeite clearingtype: {$clearingtype} mit Intervall: {$interval} Tage ---");
|
|
|
|
$date = Carbon::now()->subDays($interval);
|
|
$this->line("Suche Zahlungen vor: " . $date->format('d.m.Y H:i:s'));
|
|
|
|
// Hole nur die neueste ShoppingPayment pro shopping_order_id
|
|
$shopping_payments = $this->paymentReminderService->getOpenPaymentsForClearingType($clearingtype, $interval);
|
|
|
|
$this->info("Gefundene offene Zahlungen für {$clearingtype}: " . $shopping_payments->count());
|
|
|
|
if ($shopping_payments->isEmpty()) {
|
|
$this->line(" Keine Zahlungen für {$clearingtype} gefunden.");
|
|
continue;
|
|
}
|
|
|
|
// Verarbeite jede Zahlung
|
|
foreach($shopping_payments as $shopping_payment){
|
|
$this->processPayment($shopping_payment, $clearingtype);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Verarbeitet eine einzelne Zahlung und sendet ggf. eine Erinnerung
|
|
*/
|
|
private function processPayment($shopping_payment, $clearingtype)
|
|
{
|
|
$this->stats['total_processed']++;
|
|
|
|
try {
|
|
$this->line(" Verarbeite Order ID: {$shopping_payment->shopping_order_id}, Created: {$shopping_payment->created_at->format('d.m.Y H:i:s')}, Amount: {$shopping_payment->amount}, Reminder: {$shopping_payment->reminder}");
|
|
|
|
// Prüfe ob eine Erinnerung gesendet werden soll
|
|
if ($this->shouldSendReminder($shopping_payment, $clearingtype)) {
|
|
$this->sendReminderForPayment($shopping_payment);
|
|
} else {
|
|
$this->line(" ⏭️ Übersprungen - Keine Erinnerung fällig");
|
|
$this->stats['skipped']++;
|
|
}
|
|
|
|
} catch (\Exception $e) {
|
|
$this->error(" ❌ Fehler bei Order ID {$shopping_payment->shopping_order_id}: " . $e->getMessage());
|
|
$this->stats['errors']++;
|
|
|
|
\Log::error('Error processing payment reminder', [
|
|
'order_id' => $shopping_payment->shopping_order_id,
|
|
'payment_id' => $shopping_payment->id,
|
|
'error' => $e->getMessage()
|
|
]);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Prüft ob eine Erinnerung für diese Zahlung gesendet werden soll
|
|
*
|
|
* Logik:
|
|
* - Erste Erinnerung: Nach X Tagen ab Bestelldatum
|
|
* - Weitere Erinnerungen: Nach Y Tagen ab letzter Erinnerung
|
|
*/
|
|
private function shouldSendReminder($shopping_payment, $clearingtype)
|
|
{
|
|
// Hole alle aktiven Erinnerungen für diesen Clearingtype
|
|
$payment_reminders = PaymentReminder::where('active', true)
|
|
->where('clearingtype', $clearingtype)
|
|
->orderBy('interval', 'asc')
|
|
->get();
|
|
|
|
if ($payment_reminders->isEmpty()) {
|
|
return false;
|
|
}
|
|
|
|
// Wenn alle Erinnerungen bereits gesendet wurden
|
|
if ($shopping_payment->reminder >= $payment_reminders->count()) {
|
|
return false;
|
|
}
|
|
|
|
// Hole die nächste Erinnerung
|
|
$next_reminder = $payment_reminders[$shopping_payment->reminder];
|
|
|
|
// Wenn noch keine Erinnerung gesendet wurde, prüfe das erste Intervall
|
|
if ($shopping_payment->reminder == 0) {
|
|
$daysSinceOrder = $shopping_payment->created_at->diffInDays(now());
|
|
return $daysSinceOrder >= $next_reminder->interval;
|
|
}
|
|
|
|
// Wenn bereits Erinnerungen gesendet wurden, prüfe das nächste Intervall
|
|
if ($shopping_payment->reminder_date) {
|
|
$current_reminder = $payment_reminders[$shopping_payment->reminder - 1];
|
|
$interval_difference = $next_reminder->interval - $current_reminder->interval;
|
|
|
|
$next_reminder_date = Carbon::parse($shopping_payment->reminder_date)->addDays($interval_difference);
|
|
return now()->gte($next_reminder_date);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Sendet eine Erinnerung für eine spezifische Zahlung
|
|
*/
|
|
private function sendReminderForPayment($shopping_payment)
|
|
{
|
|
try {
|
|
$this->line(" 📧 Sende Erinnerung...");
|
|
|
|
$result = $this->paymentReminderService->sendReminder($shopping_payment);
|
|
|
|
if ($result) {
|
|
$this->line(" ✅ Erinnerung erfolgreich gesendet");
|
|
$this->stats['reminders_sent']++;
|
|
|
|
// Log für Cron-Job
|
|
\Log::info('Payment reminder sent via cron', [
|
|
'order_id' => $shopping_payment->shopping_order_id,
|
|
'payment_id' => $shopping_payment->id,
|
|
'reminder_count' => $shopping_payment->reminder + 1,
|
|
'email' => $shopping_payment->shopping_order->shopping_user->billing_email ?? 'N/A'
|
|
]);
|
|
} else {
|
|
$this->line(" ⚠️ Keine Erinnerung gesendet (keine weitere Erinnerung verfügbar)");
|
|
$this->stats['skipped']++;
|
|
}
|
|
|
|
} catch (\Exception $e) {
|
|
$this->error(" ❌ Fehler beim Senden der Erinnerung: " . $e->getMessage());
|
|
$this->stats['errors']++;
|
|
|
|
\Log::error('Error sending payment reminder', [
|
|
'order_id' => $shopping_payment->shopping_order_id,
|
|
'payment_id' => $shopping_payment->id,
|
|
'error' => $e->getMessage()
|
|
]);
|
|
}
|
|
}
|
|
} |