verifyRole('viewAvance'); $data['page_title'] = $this->pageTitle; $Products = new Products(); $session = session(); $users = $session->get('user'); $store_id = $users['store_id']; $data['products'] = $Products->getProductDataStore($store_id); return $this->render_template('avances/avance', $data); } private function isAdmin($user) { return in_array($user['group_name'], ['SuperAdmin','DAF','Direction']); } private function isCommerciale($user) { return in_array($user['group_name'], ['COMMERCIALE']); } private function isCaissier($user) { return in_array($user['group_name'], ['Caissière']); } /** * Modifier la méthode buildActionButtons pour ajouter l'icône œil pour la Direction */ private function buildActionButtons($value, $isAdmin, $isOwner, $isCaissier = false) { $session = session(); $users = $session->get('user'); $isDirection = in_array($users['group_name'], ['Direction', 'SuperAdmin','DAF']); $buttons = ''; // ✅ Bouton Voir pour Caissière (toujours visible) if ($isCaissier && in_array('viewAvance', $this->permission)) { $buttons .= ' '; } // ✅ Bouton Voir pour Direction (toujours visible, sans impression) if ($isDirection && in_array('viewAvance', $this->permission) && !$isCaissier) { $buttons .= ' '; } // ✅ MODIFIÉ : Bouton Modifier - Le caissier peut maintenant modifier toutes les avances if (in_array('updateAvance', $this->permission) && ($isAdmin || $isOwner || $isCaissier)) { $buttons .= ' '; } // ✅ MODIFIÉ : Bouton Supprimer - Le caissier peut maintenant supprimer toutes les avances if (in_array('deleteAvance', $this->permission) && ($isAdmin || $isOwner || $isCaissier)) { $buttons .= ' '; } return $buttons; } private function buildDataRow($value, $product, $isAdmin, $isCommerciale, $isCaissier, $buttons) { $date_time = date('d-m-Y h:i a', strtotime($value['avance_date'])); // ✅ Afficher product_name si disponible, sinon récupérer depuis la BDD $productName = !empty($value['product_name']) ? $value['product_name'] : $product->getProductNameById($value['product_id']); if ($isAdmin) { return [ $value['customer_name'], $value['customer_phone'], $value['customer_address'], $productName, number_format((int)$value['gross_amount'], 0, ',', ' '), number_format((int)$value['avance_amount'], 0, ',', ' '), number_format((int)$value['amount_due'], 0, ',', ' '), $date_time, $buttons, ]; } elseif ($isCommerciale || $isCaissier) { return [ $value['avance_id'], $productName, number_format((int)$value['avance_amount'], 0, ',', ' '), number_format((int)$value['amount_due'], 0, ',', ' '), $date_time, $buttons, ]; } return []; } private function fetchAvanceDataGeneric($methodName = 'getAllAvanceData') { helper(['url', 'form']); $Avance = new Avance(); $product = new Products(); $result = ['data' => []]; $data = $Avance->$methodName(); $session = session(); $users = $session->get('user'); $isAdmin = $this->isAdmin($users); $isCommerciale = $this->isCommerciale($users); $isCaissier = $this->isCaissier($users); foreach ($data as $key => $value) { $isOwner = $users['id'] === $value['user_id']; // ✅ MODIFIÉ : Passer $isCaissier aux boutons d'action $buttons = $this->buildActionButtons($value, $isAdmin, $isOwner, $isCaissier); $row = $this->buildDataRow($value, $product, $isAdmin, $isCommerciale, $isCaissier, $buttons); if (!empty($row)) { $result['data'][] = $row; } } return $this->response->setJSON($result); } public function fetchAvanceData() { return $this->fetchAvanceDataGeneric('getIncompleteAvances'); } public function fetchAvanceBecameOrder() { return $this->fetchAvanceDataGeneric('getCompletedAvances'); } public function fetchExpiredAvance() { return $this->fetchAvanceDataGeneric('getAllAvanceData2'); } /** * Méthode pour vérifier et envoyer des emails d'alerte 3 jours avant deadline * À exécuter via CRON job quotidiennement */ public function checkDeadlineAlerts() { try { $Avance = new Avance(); $Products = new Products(); // Récupérer toutes les avances actives non converties en commandes $avances = $Avance->getAvancesNearDeadline(3); // 3 jours avant deadline if (!empty($avances)) { foreach ($avances as $avance) { // Vérifier si l'email n'a pas déjà été envoyé pour cette avance if (!$this->hasEmailBeenSent($avance['avance_id'])) { $this->sendDeadlineAlert($avance, $Products); $this->markEmailAsSent($avance['avance_id']); } } } return $this->response->setJSON([ 'success' => true, 'messages' => 'Vérification des alertes terminée', 'alerts_sent' => count($avances) ]); } catch (\Exception $e) { log_message('error', "Erreur vérification deadline: " . $e->getMessage()); return $this->response->setJSON([ 'success' => false, 'messages' => 'Erreur lors de la vérification des deadlines' ]); } } /** * Envoyer un email d'alerte au DAF et à la Directrice */ private function sendDeadlineAlert($avance, $Products) { try { $email = \Config\Services::email(); // Configuration email (à adapter selon votre config) $email->setFrom('noreply@yourcompany.com', 'Système de Gestion des Avances'); // Récupérer les emails du DAF et de la Directrice $recipients = $this->getDAFAndDirectriceEmails($avance['store_id']); $email->setTo($recipients); $email->setSubject('⚠️ ALERTE: Avance arrive à échéance dans 3 jours'); // Récupérer le nom du produit $productName = $Products->getProductNameById($avance['product_id']); // Calcul des jours restants $deadline = new \DateTime($avance['deadline']); $today = new \DateTime(); $daysRemaining = $today->diff($deadline)->days; // Corps de l'email $message = $this->buildEmailMessage($avance, $productName, $daysRemaining); $email->setMessage($message); // Envoyer l'email if ($email->send()) { log_message('info', "Email d'alerte envoyé pour l'avance ID: " . $avance['avance_id']); return true; } else { log_message('error', "Échec envoi email pour avance ID: " . $avance['avance_id'] . " - " . $email->printDebugger()); return false; } } catch (\Exception $e) { log_message('error', "Erreur envoi email alerte: " . $e->getMessage()); return false; } } /** * Récupérer les emails du DAF et de la Directrice */ private function getDAFAndDirectriceEmails($store_id) { $User = new User(); $emails = []; // Récupérer les utilisateurs avec les rôles DAF et Direction pour le store donné $dafUsers = $User->getUsersByRole('DAF', $store_id); $directionUsers = $User->getUsersByRole('Direction', $store_id); // Extraire les emails foreach ($dafUsers as $user) { if (!empty($user['email'])) { $emails[] = $user['email']; } } foreach ($directionUsers as $user) { if (!empty($user['email'])) { $emails[] = $user['email']; } } // Si aucun email trouvé, utiliser des emails par défaut (à configurer) if (empty($emails)) { $emails = [ 'daf@yourcompany.com', 'direction@yourcompany.com' ]; } return array_unique($emails); // Éviter les doublons } /** * Construire le message de l'email */ private function buildEmailMessage($avance, $productName, $daysRemaining) { $typeAvance = strtoupper($avance['type_avance']); $deadlineFormatted = date('d/m/Y', strtotime($avance['deadline'])); $avanceDateFormatted = date('d/m/Y à H:i', strtotime($avance['avance_date'])); $amountDueFormatted = number_format($avance['amount_due'], 0, ',', ' ') . ' FCFA'; $urgencyClass = $daysRemaining <= 1 ? 'style="color: red; font-weight: bold;"' : ''; return "
Une avance arrive à échéance dans {$daysRemaining} jour(s) !
Action requise :
Veuillez contacter le client pour régulariser le paiement avant l'échéance ou prendre les mesures appropriées.
| MARQUE | //N°MOTEUR | //PUISSANCE | //RAP (Ariary) | //
|---|---|---|---|
| {$marque} | //{$numeroMoteur} | //{$puissance} | //{$amountDue} | //
Ry mpanjifa hajaina,
//Natao ity fifanekena ity mba hialana amin'ny fivadihana hampitokisana amin'ny andaniny sy ankilany.
//Ny mpividy dia manao famandrahana amin'ny alalan'ny fandoavambola mihoatra ny 25 isan-jato amin'ny vidin'entana rehetra (avances).
//Rehefa tonga ny moto/pieces dia tsy maintsy mandoa ny 50 isan-jato ny vidin'entana ny mpamandrika.
//Manana 15 andro kosa adoavana ny 25 isan-jato raha misy tsy fahafahana alohan'ny famoahana ny entana.
//Raha toa ka misy antony tsy hakana ny entana indray dia tsy mamerina ny vola efa voaloha (avance) ny société.
//NY MPAMANDRIKA
//NY MPIVAROTRA
//NIF: 401 840 5554
STAT: 46101 11 2024 00317
Contact: +261 34 27 946 35 / +261 34 07 079 69
Antsakaviro en face WWF
Date: {$avanceDate}
N°: {$avanceNumber}
| MARQUE | N°MOTEUR | PUISSANCE | RAP (Ariary) |
|---|---|---|---|
| {$marque} | {$productDetails['numero_moteur']} | {$productDetails['puissance']} | {$amountDue} |
| MARQUE | N°MOTEUR | PUISSANCE | RAP (Ariary) |
|---|---|---|---|
| {$marque} | {$numeroMoteur} | {$puissance} | {$amountDue} |
Ry mpanjifa hajaina,
Natao ity fifanekena ity mba hialana amin'ny fivadihana hampitokisana amin'ny andaniny sy ankilany.
Ny mpividy dia manao famandrahana amin'ny alalan'ny fandoavambola mihoatra ny 25 isan-jato amin'ny vidin'entana rehetra (avances).
Rehefa tonga ny moto/pieces dia tsy maintsy mandoa ny 50 isan-jato ny vidin'entana ny mpamandrika.
Manana 15 andro kosa adoavana ny 25 isan-jato raha misy tsy fahafahana alohan'ny famoahana ny entana.
Raha toa ka misy antony tsy hakana ny entana indray dia tsy mamerina ny vola efa voaloha (avance) ny société.
NY MPAMANDRIKA
NY MPIVAROTRA