You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
313 lines
12 KiB
313 lines
12 KiB
<?php
|
|
|
|
use App\Models\Users;
|
|
use App\Models\Avance;
|
|
use App\Models\AlertMail;
|
|
|
|
/**
|
|
* Vérifier les deadlines et envoyer des alertes email
|
|
*/
|
|
function checkDeadlineAlerts()
|
|
{
|
|
log_message('info', "=== DÉBUT checkDeadlineAlerts ===");
|
|
|
|
$cacheFile = WRITEPATH . 'cache/check_deadline_last_run.txt';
|
|
file_put_contents($cacheFile, time());
|
|
|
|
$avanceModel = new Avance();
|
|
$alertMailModel = new AlertMail();
|
|
$usersModel = new Users();
|
|
|
|
$today = date('Y-m-d');
|
|
log_message('info', "Date du jour: {$today}");
|
|
|
|
// Récupération des avances dans 0-3 jours
|
|
$avances = $avanceModel
|
|
->where('DATE(deadline) >=', $today)
|
|
->where('DATE(deadline) <=', date('Y-m-d', strtotime('+3 days')))
|
|
->where('active', 1)
|
|
->findAll();
|
|
|
|
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')
|
|
->join('user_group', 'user_group.user_id = users.id')
|
|
->join('groups', 'groups.id = user_group.group_id')
|
|
->where('groups.group_name', 'DAF')
|
|
->findAll();
|
|
|
|
log_message('info', "Utilisateurs DAF trouvés: " . json_encode($users));
|
|
|
|
$emails = array_column($users, 'email');
|
|
log_message('info', "Emails extraits: " . json_encode($emails));
|
|
|
|
if (empty($emails)) {
|
|
log_message('error', "Aucun email DAF trouvé");
|
|
|
|
$db = \Config\Database::connect();
|
|
$allGroups = $db->query("SELECT DISTINCT group_name FROM groups")->getResult();
|
|
log_message('info', "Groupes disponibles: " . json_encode($allGroups));
|
|
|
|
return;
|
|
}
|
|
|
|
foreach ($avances as $avance) {
|
|
$deadline = date('Y-m-d', strtotime($avance['deadline']));
|
|
$daysLeft = (int) ceil((strtotime($deadline) - strtotime($today)) / 86400);
|
|
|
|
log_message('info', "Avance ID: {$avance['avance_id']}, Deadline: {$deadline}, Jours restants: {$daysLeft}");
|
|
|
|
// Détermination du type d'alerte
|
|
$alertType = match($daysLeft) {
|
|
3 => 'deadline_3_days',
|
|
2 => 'deadline_2_days',
|
|
1 => 'deadline_1_day',
|
|
0 => 'deadline_today',
|
|
default => null,
|
|
};
|
|
|
|
if ($alertType === null) {
|
|
log_message('info', "Pas d'alerte nécessaire pour {$daysLeft} jours restants");
|
|
continue;
|
|
}
|
|
|
|
log_message('info', "Type d'alerte: {$alertType}");
|
|
|
|
// Vérification si l'alerte a déjà été envoyée
|
|
$alreadySent = $alertMailModel
|
|
->where('avance_id', $avance['avance_id'])
|
|
->where('alert_type', $alertType)
|
|
->first();
|
|
|
|
if ($alreadySent) {
|
|
log_message('info', "Alerte déjà envoyée pour avance_id={$avance['avance_id']} type={$alertType}");
|
|
continue;
|
|
}
|
|
|
|
// Construction du message
|
|
$urgencyText = $daysLeft === 0 ? "ÉCHÉANCE AUJOURD'HUI" : "{$daysLeft} jour(s) restant(s)";
|
|
$message = "
|
|
<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>Client :</strong> {$avance['customer_name']}</p>
|
|
<p><strong>Montant avance :</strong> " . number_format($avance['avance_amount'], 0, ',', ' ') . " Ar</p>
|
|
<p><strong>Montant dû :</strong> " . number_format($avance['amount_due'], 0, ',', ' ') . " Ar</p>
|
|
<p><strong>Deadline :</strong> {$deadline}</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>Adresse client :</strong> {$avance['customer_address']}</p>
|
|
<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>
|
|
</body>
|
|
</html>
|
|
";
|
|
|
|
$emailsSent = 0;
|
|
$subject = $daysLeft === 0
|
|
? "⚠️ AVANCE URGENTE - ÉCHÉANCE AUJOURD'HUI"
|
|
: "⚠️ AVANCE URGENTE - {$daysLeft} jour(s) restant(s)";
|
|
|
|
foreach ($emails as $to) {
|
|
log_message('info', "Tentative d'envoi email à: {$to}");
|
|
|
|
if (sendEmailWithBrevo($to, $subject, $message)) {
|
|
$emailsSent++;
|
|
log_message('info', "Email envoyé avec succès à: {$to}");
|
|
} else {
|
|
log_message('error', "Échec envoi email à: {$to}");
|
|
}
|
|
}
|
|
|
|
// Enregistrement de l'alerte si au moins un email a été envoyé
|
|
if ($emailsSent > 0) {
|
|
log_message('info', "Insertion alerte pour avance_id={$avance['avance_id']} avec type {$alertType}");
|
|
$alertMailModel->insert([
|
|
'avance_id' => $avance['avance_id'],
|
|
'alert_type' => $alertType,
|
|
'sent_date' => date('Y-m-d H:i:s'),
|
|
'status' => 'sent',
|
|
'created_at' => date('Y-m-d H:i:s'),
|
|
]);
|
|
} else {
|
|
log_message('error', "Aucun email envoyé pour avance_id={$avance['avance_id']} avec type {$alertType}");
|
|
}
|
|
}
|
|
checkAndConvertCompletedAvances();
|
|
|
|
log_message('info', "=== FIN checkDeadlineAlerts ===");
|
|
|
|
// ✅ NOUVELLE FONCTIONNALITÉ : Gérer les avances expirées
|
|
handleExpiredAvances();
|
|
}
|
|
|
|
/**
|
|
* ✅ 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 {
|
|
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 (configuration hardcodée pour éviter dépendance .env)
|
|
*/
|
|
function sendEmailWithBrevo($to, $subject, $message)
|
|
{
|
|
try {
|
|
log_message('info', "Préparation envoi email via Brevo à: {$to}");
|
|
|
|
$email = \Config\Services::email();
|
|
|
|
// ✅ Configuration Brevo hardcodée (pas besoin du .env)
|
|
$config = [
|
|
'protocol' => 'smtp',
|
|
'SMTPHost' => 'smtp-relay.brevo.com',
|
|
'SMTPUser' => '8356e1002@smtp-brevo.com',
|
|
'SMTPPass' => '2JT0KhZOfgSVQk9D',
|
|
'SMTPPort' => 587,
|
|
'SMTPCrypto' => 'tls',
|
|
'mailType' => 'html',
|
|
'charset' => 'utf-8',
|
|
'newline' => "\r\n",
|
|
'wordWrap' => true,
|
|
'validation' => true
|
|
];
|
|
|
|
log_message('info', "Configuration Brevo - Host: {$config['SMTPHost']}, Port: {$config['SMTPPort']}, User: {$config['SMTPUser']}");
|
|
|
|
$email->initialize($config);
|
|
|
|
// ✅ Configuration expéditeur hardcodée
|
|
$email->setFrom('noreply@motorbike.mg', 'Système Motorbike - Alertes');
|
|
$email->setTo($to);
|
|
$email->setSubject($subject);
|
|
$email->setMessage($message);
|
|
|
|
log_message('info', "Configuration email Brevo terminée, tentative d'envoi...");
|
|
|
|
if (!$email->send()) {
|
|
$debugInfo = $email->printDebugger(['headers', 'subject', 'body']);
|
|
log_message('error', "Erreur email Brevo à {$to}: " . print_r($debugInfo, true));
|
|
return false;
|
|
}
|
|
|
|
log_message('info', "✅ Email envoyé avec succès via Brevo à: {$to}");
|
|
return true;
|
|
|
|
} catch (\Exception $e) {
|
|
log_message('error', "❌ Exception email Brevo à {$to}: " . $e->getMessage());
|
|
log_message('error', "Stack trace: " . $e->getTraceAsString());
|
|
return false;
|
|
}
|
|
}
|