commit 08-2025
This commit is contained in:
parent
9b54eb0512
commit
02f2a4c23e
184 changed files with 31653 additions and 22327 deletions
252
app/Console/Commands/PaymentsReminders.php
Normal file
252
app/Console/Commands/PaymentsReminders.php
Normal file
|
|
@ -0,0 +1,252 @@
|
|||
<?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()
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue