19 changed files with 4946 additions and 1223 deletions
File diff suppressed because it is too large
File diff suppressed because it is too large
@ -4,13 +4,14 @@ use App\Models\Users; |
|||||
use App\Models\Avance; |
use App\Models\Avance; |
||||
use App\Models\AlertMail; |
use App\Models\AlertMail; |
||||
|
|
||||
|
/** |
||||
|
* Vérifier les deadlines et envoyer des alertes email |
||||
|
*/ |
||||
function checkDeadlineAlerts() |
function checkDeadlineAlerts() |
||||
{ |
{ |
||||
log_message('info', "=== DÉBUT checkDeadlineAlerts ==="); |
log_message('info', "=== DÉBUT checkDeadlineAlerts ==="); |
||||
|
|
||||
$cacheFile = WRITEPATH . 'cache/check_deadline_last_run.txt'; |
$cacheFile = WRITEPATH . 'cache/check_deadline_last_run.txt'; |
||||
|
|
||||
// On enlève la vérification de 24h pour s'assurer que le script tourne quotidiennement |
|
||||
file_put_contents($cacheFile, time()); |
file_put_contents($cacheFile, time()); |
||||
|
|
||||
$avanceModel = new Avance(); |
$avanceModel = new Avance(); |
||||
@ -20,15 +21,16 @@ function checkDeadlineAlerts() |
|||||
$today = date('Y-m-d'); |
$today = date('Y-m-d'); |
||||
log_message('info', "Date du jour: {$today}"); |
log_message('info', "Date du jour: {$today}"); |
||||
|
|
||||
// Modification pour vérifier les avances dans 0-3 jours |
// Récupération des avances dans 0-3 jours |
||||
$avances = $avanceModel |
$avances = $avanceModel |
||||
->where('DATE(deadline) >=', $today) // Inclut le jour même |
->where('DATE(deadline) >=', $today) |
||||
->where('DATE(deadline) <=', date('Y-m-d', strtotime('+3 days'))) |
->where('DATE(deadline) <=', date('Y-m-d', strtotime('+3 days'))) |
||||
->where('active', 1) |
->where('active', 1) |
||||
->findAll(); |
->findAll(); |
||||
|
|
||||
log_message('info', "Nombre d'avances trouvées (0-3 jours): " . count($avances)); |
log_message('info', "Nombre d'avances trouvées (0-3 jours): " . count($avances)); |
||||
|
|
||||
|
// Récupération des utilisateurs DAF |
||||
$users = $usersModel->select('users.email, users.firstname, users.lastname') |
$users = $usersModel->select('users.email, users.firstname, users.lastname') |
||||
->join('user_group', 'user_group.user_id = users.id') |
->join('user_group', 'user_group.user_id = users.id') |
||||
->join('groups', 'groups.id = user_group.group_id') |
->join('groups', 'groups.id = user_group.group_id') |
||||
@ -56,7 +58,7 @@ function checkDeadlineAlerts() |
|||||
|
|
||||
log_message('info', "Avance ID: {$avance['avance_id']}, Deadline: {$deadline}, Jours restants: {$daysLeft}"); |
log_message('info', "Avance ID: {$avance['avance_id']}, Deadline: {$deadline}, Jours restants: {$daysLeft}"); |
||||
|
|
||||
// Modification des types d'alerte pour 0, 1, 2, 3 jours |
// Détermination du type d'alerte |
||||
$alertType = match($daysLeft) { |
$alertType = match($daysLeft) { |
||||
3 => 'deadline_3_days', |
3 => 'deadline_3_days', |
||||
2 => 'deadline_2_days', |
2 => 'deadline_2_days', |
||||
@ -83,10 +85,12 @@ function checkDeadlineAlerts() |
|||||
continue; |
continue; |
||||
} |
} |
||||
|
|
||||
// Message modifié pour inclure le cas du jour même |
// Construction du message |
||||
$urgencyText = $daysLeft === 0 ? "ÉCHÉANCE AUJOURD'HUI" : "{$daysLeft} jour(s) restant(s)"; |
$urgencyText = $daysLeft === 0 ? "ÉCHÉANCE AUJOURD'HUI" : "{$daysLeft} jour(s) restant(s)"; |
||||
$message = " |
$message = " |
||||
<h3>⚠️ URGENT : Avance approchant de la deadline</h3> |
<html> |
||||
|
<body style='font-family: Arial, sans-serif; color: #333;'> |
||||
|
<h3 style='color: #d9534f;'>⚠️ URGENT : Avance approchant de la deadline</h3> |
||||
<p><strong>ID Avance :</strong> {$avance['avance_id']}</p> |
<p><strong>ID Avance :</strong> {$avance['avance_id']}</p> |
||||
<p><strong>Client :</strong> {$avance['customer_name']}</p> |
<p><strong>Client :</strong> {$avance['customer_name']}</p> |
||||
<p><strong>Montant avance :</strong> " . number_format($avance['avance_amount'], 0, ',', ' ') . " Ar</p> |
<p><strong>Montant avance :</strong> " . number_format($avance['avance_amount'], 0, ',', ' ') . " Ar</p> |
||||
@ -95,19 +99,21 @@ function checkDeadlineAlerts() |
|||||
<p><strong>Statut :</strong> <span style='color: red; font-weight: bold;'>{$urgencyText}</span></p> |
<p><strong>Statut :</strong> <span style='color: red; font-weight: bold;'>{$urgencyText}</span></p> |
||||
<p><strong>Téléphone client :</strong> {$avance['customer_phone']}</p> |
<p><strong>Téléphone client :</strong> {$avance['customer_phone']}</p> |
||||
<p><strong>Adresse client :</strong> {$avance['customer_address']}</p> |
<p><strong>Adresse client :</strong> {$avance['customer_address']}</p> |
||||
<hr> |
<hr style='border: 1px solid #ddd;'> |
||||
<p><em>Cette avance " . ($daysLeft === 0 ? "arrive à échéance aujourd'hui" : "arrivera à échéance dans {$daysLeft} jour(s)") . ". Action requise immédiatement.</em></p> |
<p><em>Cette avance " . ($daysLeft === 0 ? "arrive à échéance aujourd'hui" : "arrivera à échéance dans {$daysLeft} jour(s)") . ". Action requise immédiatement.</em></p> |
||||
|
</body> |
||||
|
</html> |
||||
"; |
"; |
||||
|
|
||||
$emailsSent = 0; |
$emailsSent = 0; |
||||
foreach ($emails as $to) { |
|
||||
log_message('info', "Tentative d'envoi email à: {$to}"); |
|
||||
|
|
||||
$subject = $daysLeft === 0 |
$subject = $daysLeft === 0 |
||||
? "⚠️ AVANCE URGENTE - ÉCHÉANCE AUJOURD'HUI" |
? "⚠️ AVANCE URGENTE - ÉCHÉANCE AUJOURD'HUI" |
||||
: "⚠️ AVANCE URGENTE - {$daysLeft} jour(s) restant(s)"; |
: "⚠️ AVANCE URGENTE - {$daysLeft} jour(s) restant(s)"; |
||||
|
|
||||
if (sendEmailInBackground($to, $subject, $message)) { |
foreach ($emails as $to) { |
||||
|
log_message('info', "Tentative d'envoi email à: {$to}"); |
||||
|
|
||||
|
if (sendEmailWithBrevo($to, $subject, $message)) { |
||||
$emailsSent++; |
$emailsSent++; |
||||
log_message('info', "Email envoyé avec succès à: {$to}"); |
log_message('info', "Email envoyé avec succès à: {$to}"); |
||||
} else { |
} else { |
||||
@ -115,6 +121,7 @@ function checkDeadlineAlerts() |
|||||
} |
} |
||||
} |
} |
||||
|
|
||||
|
// Enregistrement de l'alerte si au moins un email a été envoyé |
||||
if ($emailsSent > 0) { |
if ($emailsSent > 0) { |
||||
log_message('info', "Insertion alerte pour avance_id={$avance['avance_id']} avec type {$alertType}"); |
log_message('info', "Insertion alerte pour avance_id={$avance['avance_id']} avec type {$alertType}"); |
||||
$alertMailModel->insert([ |
$alertMailModel->insert([ |
||||
@ -128,49 +135,182 @@ function checkDeadlineAlerts() |
|||||
log_message('error', "Aucun email envoyé pour avance_id={$avance['avance_id']} avec type {$alertType}"); |
log_message('error', "Aucun email envoyé pour avance_id={$avance['avance_id']} avec type {$alertType}"); |
||||
} |
} |
||||
} |
} |
||||
|
checkAndConvertCompletedAvances(); |
||||
|
|
||||
log_message('info', "=== FIN checkDeadlineAlerts ==="); |
log_message('info', "=== FIN checkDeadlineAlerts ==="); |
||||
|
|
||||
|
// ✅ NOUVELLE FONCTIONNALITÉ : Gérer les avances expirées |
||||
|
handleExpiredAvances(); |
||||
} |
} |
||||
|
|
||||
function sendEmailInBackground($to, $subject, $message) |
/** |
||||
|
* ✅ NOUVELLE FONCTION : Gérer automatiquement les avances expirées |
||||
|
* - Libérer les produits (remettre en stock) |
||||
|
* - Désactiver les avances |
||||
|
*/ |
||||
|
function handleExpiredAvances() |
||||
{ |
{ |
||||
|
log_message('info', "=== DÉBUT handleExpiredAvances ==="); |
||||
|
|
||||
|
$avanceModel = new Avance(); |
||||
|
$productsModel = new \App\Models\Products(); |
||||
|
|
||||
|
$today = date('Y-m-d'); |
||||
|
log_message('info', "Vérification des avances expirées au: {$today}"); |
||||
|
|
||||
|
// Récupérer les avances expirées et encore actives |
||||
|
$expiredAvances = $avanceModel |
||||
|
->where('DATE(deadline) <', $today) |
||||
|
->where('active', 1) |
||||
|
->where('is_order', 0) |
||||
|
->findAll(); |
||||
|
|
||||
|
log_message('info', "Nombre d'avances expirées trouvées: " . count($expiredAvances)); |
||||
|
|
||||
|
if (empty($expiredAvances)) { |
||||
|
log_message('info', "Aucune avance expirée à traiter"); |
||||
|
log_message('info', "=== FIN handleExpiredAvances ==="); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
$processedCount = 0; |
||||
|
$errorCount = 0; |
||||
|
|
||||
|
foreach ($expiredAvances as $avance) { |
||||
try { |
try { |
||||
log_message('info', "Préparation envoi email à: {$to}"); |
log_message('info', "Traitement avance expirée ID: {$avance['avance_id']}, Client: {$avance['customer_name']}, Deadline: {$avance['deadline']}"); |
||||
|
|
||||
|
// ✅ Désactiver l'avance |
||||
|
$updateResult = $avanceModel->update($avance['avance_id'], ['active' => 0]); |
||||
|
|
||||
|
if (!$updateResult) { |
||||
|
log_message('error', "Échec désactivation avance ID: {$avance['avance_id']}"); |
||||
|
$errorCount++; |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
log_message('info', "Avance ID {$avance['avance_id']} désactivée avec succès"); |
||||
|
|
||||
|
// ✅ Libérer le produit UNIQUEMENT pour les avances "sur terre" avec product_id |
||||
|
if ($avance['type_avance'] === 'terre' && !empty($avance['product_id'])) { |
||||
|
$productUpdateResult = $productsModel->update($avance['product_id'], ['product_sold' => 0]); |
||||
|
|
||||
|
if ($productUpdateResult) { |
||||
|
log_message('info', "Produit ID {$avance['product_id']} libéré (remis en stock)"); |
||||
|
} else { |
||||
|
log_message('warning', "Échec libération produit ID: {$avance['product_id']}"); |
||||
|
} |
||||
|
} elseif ($avance['type_avance'] === 'mere') { |
||||
|
log_message('info', "Avance 'sur mer' - Pas de produit à libérer (product_name: {$avance['product_name']})"); |
||||
|
} else { |
||||
|
log_message('info', "Pas de product_id à libérer pour avance ID: {$avance['avance_id']}"); |
||||
|
} |
||||
|
|
||||
|
$processedCount++; |
||||
|
|
||||
|
} catch (\Exception $e) { |
||||
|
log_message('error', "Erreur traitement avance expirée ID {$avance['avance_id']}: " . $e->getMessage()); |
||||
|
$errorCount++; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
log_message('info', "Avances expirées traitées: {$processedCount}, Erreurs: {$errorCount}"); |
||||
|
log_message('info', "=== FIN handleExpiredAvances ==="); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* ✅ Vérifier et convertir automatiquement les avances complètes en commandes |
||||
|
* À appeler dans checkDeadlineAlerts() ou via un cron job |
||||
|
*/ |
||||
|
function checkAndConvertCompletedAvances() |
||||
|
{ |
||||
|
log_message('info', "=== DÉBUT checkAndConvertCompletedAvances ==="); |
||||
|
|
||||
|
$avanceModel = new \App\Models\Avance(); |
||||
|
|
||||
|
// Récupérer toutes les avances complètes non encore converties |
||||
|
$completedAvances = $avanceModel |
||||
|
->where('amount_due', 0) |
||||
|
->where('is_order', 0) // Pas encore converties |
||||
|
->where('active', 1) // Encore actives |
||||
|
->findAll(); |
||||
|
|
||||
|
log_message('info', "Avances complètes trouvées : " . count($completedAvances)); |
||||
|
|
||||
|
$convertedCount = 0; |
||||
|
$errorCount = 0; |
||||
|
|
||||
|
foreach ($completedAvances as $avance) { |
||||
|
log_message('info', "Traitement avance complète ID: {$avance['avance_id']}, Client: {$avance['customer_name']}"); |
||||
|
|
||||
|
$order_id = $avanceModel->convertToOrder($avance['avance_id']); |
||||
|
|
||||
|
if ($order_id) { |
||||
|
$convertedCount++; |
||||
|
log_message('info', "✅ Avance {$avance['avance_id']} convertie en commande {$order_id}"); |
||||
|
} else { |
||||
|
$errorCount++; |
||||
|
log_message('error', "❌ Échec conversion avance {$avance['avance_id']}"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
log_message('info', "Avances converties : {$convertedCount}, Erreurs : {$errorCount}"); |
||||
|
log_message('info', "=== FIN checkAndConvertCompletedAvances ==="); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* Envoyer un email via Brevo |
||||
|
*/ |
||||
|
function sendEmailWithBrevo($to, $subject, $message) |
||||
|
{ |
||||
|
try { |
||||
|
log_message('info', "Préparation envoi email via Brevo à: {$to}"); |
||||
|
|
||||
$email = \Config\Services::email(); |
$email = \Config\Services::email(); |
||||
|
|
||||
|
// Configuration Brevo depuis le fichier .env |
||||
$config = [ |
$config = [ |
||||
'protocol' => 'smtp', |
'protocol' => env('email.protocol', 'smtp'), |
||||
'SMTPHost' => 'smtp.gmail.com', |
'SMTPHost' => env('email.SMTPHost', 'smtp-relay.brevo.com'), |
||||
'SMTPUser' => '[email protected]', |
'SMTPUser' => env('email.SMTPUser'), |
||||
'SMTPPass' => 'loirqovmfuxnasrm', |
'SMTPPass' => env('email.SMTPPass'), |
||||
'SMTPPort' => 587, |
'SMTPPort' => env('email.SMTPPort', 587), |
||||
'SMTPCrypto' => 'tls', |
'SMTPCrypto' => env('email.SMTPCrypto', 'tls'), |
||||
'mailType' => 'html', |
'mailType' => 'html', |
||||
'charset' => 'utf-8', |
'charset' => 'utf-8', |
||||
'newline' => "\r\n" |
'newline' => "\r\n", |
||||
|
'wordWrap' => true, |
||||
|
'validation' => true |
||||
]; |
]; |
||||
|
|
||||
|
log_message('info', "Configuration Brevo - Host: {$config['SMTPHost']}, Port: {$config['SMTPPort']}, User: {$config['SMTPUser']}"); |
||||
|
|
||||
$email->initialize($config); |
$email->initialize($config); |
||||
|
|
||||
$email->setFrom('[email protected]', 'Système Motorbike - Alertes Avances'); |
// Utilisation de l'email configuré dans .env |
||||
|
$fromEmail = env('email.fromEmail', '[email protected]'); |
||||
|
$fromName = env('email.fromName', 'Système Motorbike - Alertes'); |
||||
|
|
||||
|
$email->setFrom($fromEmail, $fromName); |
||||
$email->setTo($to); |
$email->setTo($to); |
||||
$email->setSubject($subject); |
$email->setSubject($subject); |
||||
$email->setMessage($message); |
$email->setMessage($message); |
||||
|
|
||||
log_message('info', "Configuration email terminée, tentative d'envoi..."); |
log_message('info', "Configuration email Brevo terminée, tentative d'envoi..."); |
||||
|
|
||||
if (!$email->send()) { |
if (!$email->send()) { |
||||
$debugInfo = $email->printDebugger(['headers']); |
$debugInfo = $email->printDebugger(['headers', 'subject', 'body']); |
||||
log_message('error', "Erreur email à {$to}: " . print_r($debugInfo, true)); |
log_message('error', "Erreur email Brevo à {$to}: " . print_r($debugInfo, true)); |
||||
return false; |
return false; |
||||
} |
} |
||||
|
|
||||
log_message('info', "Email envoyé avec succès à: {$to}"); |
log_message('info', "Email envoyé avec succès via Brevo à: {$to}"); |
||||
return true; |
return true; |
||||
|
|
||||
} catch (\Exception $e) { |
} catch (\Exception $e) { |
||||
log_message('error', "Exception email à {$to}: " . $e->getMessage()); |
log_message('error', "Exception email Brevo à {$to}: " . $e->getMessage()); |
||||
|
log_message('error', "Stack trace: " . $e->getTraceAsString()); |
||||
return false; |
return false; |
||||
} |
} |
||||
} |
} |
||||
File diff suppressed because it is too large
Loading…
Reference in new issue