0% ont trouvé ce document utile (0 vote)
2 vues50 pages

Const API

Le document contient un script JavaScript pour gérer une application de facturation avec des configurations réactives pour différents appareils. Il inclut des fonctionnalités telles que la génération de numéros de factures, le chargement de données depuis une API, et la gestion d'événements pour filtrer et afficher les factures. Le script est conçu pour être responsive et inclut des fonctions pour créer, afficher et manipuler des factures.

Transféré par

fenoantra akasia
Copyright
© All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd
0% ont trouvé ce document utile (0 vote)
2 vues50 pages

Const API

Le document contient un script JavaScript pour gérer une application de facturation avec des configurations réactives pour différents appareils. Il inclut des fonctionnalités telles que la génération de numéros de factures, le chargement de données depuis une API, et la gestion d'événements pour filtrer et afficher les factures. Le script est conçu pour être responsive et inclut des fonctions pour créer, afficher et manipuler des factures.

Transféré par

fenoantra akasia
Copyright
© All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd

const API_BASE_URL_FACTURES = "[Link]

1:8000/api";

// CONFIGURATION RESPONSIVE

const RESPONSIVE_CONFIG = {

large: { // 17+ pouces

itemsPerPage: 15,

tableFontSize: '0.9rem',

showExport: true,

columns: ['numero', 'date', 'client', 'statut', 'montant', 'actions']

},

medium: { // 13-16 pouces

itemsPerPage: 12,

tableFontSize: '0.8rem',

showExport: true,

columns: ['numero', 'date', 'client', 'statut', 'montant', 'actions']

},

small: { // Tablettes

itemsPerPage: 10,

tableFontSize: '0.75rem',

showExport: false,

columns: ['numero', 'date', 'statut', 'montant', 'actions']

},

mobile: { // Mobiles

itemsPerPage: 8,

tableFontSize: '0.7rem',

showExport: false,

columns: ['numero', 'statut', 'montant', 'actions']

};

let currentConfig = RESPONSIVE_CONFIG.medium;


let ITEMS_PER_PAGE = [Link];

let currentPage = 1;

let allFactures = [];

let facturesFiltrees = [];

[Link](' [Link] chargé - Démarrage IMMÉDIAT');

// FONCTION POUR GÉNÉRER LE NUMÉRO DE FACTURE (RESET ANNUELLE)

function genererNumeroFacture() {

const maintenant = new Date();

const anneeActuelle = [Link]();

const mois = ([Link]() + 1).toString().padStart(2, '0');

const jour = [Link]().toString().padStart(2, '0');

// Format: FA_YYYY/MM/DD

const prefixe = `FA_${anneeActuelle}/${mois}/${jour}`;

// FILTRER LES FACTURES DE L'ANNÉE EN COURS SEULEMENT

const facturesAnneeCourante = [Link](facture => {

try {

const dateFacture = new Date([Link]);

return [Link]() === anneeActuelle;

} catch {

return false;

});

// Trouver le dernier numéro pour cette date dans l'année courante

const facturesDuJour = [Link](f =>

[Link](prefixe)

);
// Déterminer le prochain numéro séquentiel (RESET chaque année)

const prochainNumero = [Link] + 1;

return `${prefixe}_${[Link]().padStart(3, '0')}`;

// DÉTECTION AUTOMATIQUE DE LA TAILLE D'ÉCRAN

function getScreenSize() {

const width = [Link];

if (width >= 1600) return 'large';

if (width >= 1366) return 'medium';

if (width >= 768) return 'small';

return 'mobile';

// INITIALISATION RESPONSIVE

function initialiserResponsive() {

mettreAJourConfiguration();

[Link]('resize', function() {

clearTimeout([Link]);

[Link] = setTimeout(mettreAJourConfiguration, 250);

});

function mettreAJourConfiguration() {

const screenSize = getScreenSize();

currentConfig = RESPONSIVE_CONFIG[screenSize];

ITEMS_PER_PAGE = [Link];
appliquerStylesResponsives();

afficherFactures();

mettreAJourStatistiques();

mettreAJourPagination();

function appliquerStylesResponsives() {

const table = [Link]('facturesTable');

if (table) {

[Link] = [Link];

const exportBtn = [Link]('.export-btn');

if (exportBtn) {

[Link] = [Link] ? 'flex' : 'none';

// DÉMARRAGE IMMÉDIAT

function demarrerApplication() {

[Link](' Démarrage IMMÉDIAT de l\'application...');

const tbody = [Link]('facturesTableBody');

const stats = [Link]('statsSection');

const pagination = [Link]('paginationSection');

if (!tbody || !stats || !pagination) {

[Link](' Éléments manquants!');

setTimeout(demarrerApplication, 200);

return;

}
[Link](' Éléments trouvés!');

initialiserApplication();

function initialiserApplication() {

[Link](' Initialisation en cours...');

// Initialiser le responsive

initialiserResponsive();

// Configurer les événements

const statutFilter = [Link]('statutFilter');

const searchInput = [Link]('searchInput');

if (statutFilter) {

[Link]('change', filtrerFactures);

if (searchInput) {

[Link]('input', function() {

setTimeout(filtrerFactures, 300);

});

// Exposer les fonctions globales

[Link] = filtrerFactures;

[Link] = changerPage;

[Link] = fermerModal;

[Link] = afficherDetailsFacture;

[Link] = exporterFactures;
[Link] = payerFacture;

[Link] = confirmerPaiement;

[Link] = annulerPaiement;

[Link] = selectionnerModePaiement;

[Link] = modifierFacture;

[Link] = supprimerFacture;

[Link] = creerNouvelleFacture;

[Link] = confirmerAnnulation;

[Link](' Début du chargement des données...');

chargerToutesLesFactures();

// CHARGEMENT DES DONNÉES

async function chargerToutesLesFactures() {

[Link](' Chargement depuis API...');

try {

const response = await fetch(`${API_BASE_URL_FACTURES}/factures?statut=tous&limit=200`);

if ([Link]) {

const text = await [Link]();

const cleanedText = cleanApiResponse(text);

const result = [Link](cleanedText);

[Link](' Réponse API:', result);

if ([Link] && [Link]) {

allFactures = transformApiData([Link]);

[Link](` ${[Link]} factures chargées depuis API`);

afficherNotification(` ${[Link]} factures chargées`, 'success');


} else {

throw new Error('Données API invalides');

} else {

throw new Error('API non disponible');

} catch (error) {

[Link](' Erreur API:', error);

chargerDonneesTest();

return;

afficherFactures();

mettreAJourStatistiques();

mettreAJourPagination();

function chargerDonneesTest() {

[Link](' Chargement des données de test...');

allFactures = [

id: 1,

numeroFacture: "FA_202312_0001",

dateCreation: "2023-12-15 10:30:00",

societe: "SARL Madagascar Import",

numTicket: "TKT001",

statut: "payee",

montantTotal: 150000.0,

datePaiement: "2023-12-15 11:00:00",

motifAnnulation: null,
commentaire: null,

ventes: [

id: 1,

produit: { id: 1, nom: "Produit A" },

quantite: 2,

prix_unitaire: 50000,

prix_total: 100000,

num_ticket: "TKT001"

},

id: 2,

produit: { id: 2, nom: "Produit B" },

quantite: 1,

prix_unitaire: 50000,

prix_total: 50000,

num_ticket: "TKT001"

},

id: 2,

numeroFacture: "FA_202312_0002",

dateCreation: "2023-12-16 14:20:00",

societe: "EPIC Tana Distribution",

numTicket: "TKT002",

statut: "en_attente",

montantTotal: 75000.0,

datePaiement: null,

motifAnnulation: null,

commentaire: "Facture en attente de paiement",


ventes: [

id: 3,

produit: { id: 3, nom: "Produit C" },

quantite: 3,

prix_unitaire: 25000,

prix_total: 75000,

num_ticket: "TKT002"

},

id: 3,

numeroFacture: "FA_202312_0003",

dateCreation: "2023-12-17 09:15:00",

societe: "GIE Antsirabe Commerce",

numTicket: "TKT003",

statut: "annulee",

montantTotal: 120000.0,

datePaiement: null,

motifAnnulation: "Commande annulée par le client",

commentaire: "Facture annulée - Motif: Commande annulée par le client",

ventes: [

id: 4,

produit: { id: 4, nom: "Produit D" },

quantite: 4,

prix_unitaire: 30000,

prix_total: 120000,

num_ticket: "TKT003"

}
]

];

[Link](` ${[Link]} factures de test chargées`);

afficherNotification(' Données de test affichées', 'warning');

// TRANSFORMATION DES DONNÉES API

function transformApiData(apiData) {

[Link](' Transformation des données API...');

return [Link](facture => {

// Formater le numéro de facture selon les nouvelles règles

let numeroFactureFormate = facture.numero_facture || 'N/A';

// Remplacer les tirets par des underscores et supprimer l'heure si présent

if (numeroFactureFormate !== 'N/A') {

// Remplacer tous les tirets par des underscores

numeroFactureFormate = [Link](/-/g, '_');

// Supprimer l'heure si présente (format: YYYY_MM_DD_HH_MM_SS)

numeroFactureFormate =
[Link](/(\d{4}_\d{2}_\d{2})_\d{2}_\d{2}_\d{2}/, '$1');

// S'assurer que le numéro commence par FA_

if (![Link]('FA_')) {

numeroFactureFormate = 'FA_' + numeroFactureFormate;

}
return {

id: [Link] || 0,

numeroFacture: numeroFactureFormate,

dateCreation: facture.date_creation || new Date().toISOString(),

societe: [Link]?.nom || 'Client inconnu',

numTicket: facture.num_ticket || `TKT${[Link]}`,

statut: [Link] || 'en_attente',

montantTotal: facture.montant_total || 0,

datePaiement: facture.date_paiement || null,

motifAnnulation: facture.motif_annulation || null,

commentaire: [Link] || null, // INTÉGRATION DE LA COLONNE


COMMENTAIRE

ventes: [Link] ? [Link](vente => ({

id: [Link],

produit: [Link] ? {

id: [Link],

nom: [Link]

} : null,

quantite: [Link] || 1,

prix_unitaire: vente.prix_unitaire || 0,

prix_total: vente.prix_total || (vente.prix_unitaire * [Link]) || 0,

num_ticket: vente.num_ticket || ''

})) : []

};

});

// FONCTION POUR CRÉER UNE NOUVELLE FACTURE

async function creerNouvelleFacture() {

[Link](' Création nouvelle facture...');


try {

const nouveauNumero = genererNumeroFacture();

[Link](` Numéro généré: ${nouveauNumero}`);

// Appel API pour créer la facture

const response = await fetch(`${API_BASE_URL_FACTURES}/factures`, {

method: 'POST',

headers: {

'Content-Type': 'application/json',

'Accept': 'application/json'

},

body: [Link]({

numero_facture: nouveauNumero,

date_creation: new Date().toISOString(),

statut: 'en_attente',

montant_total: 0,

commentaire: 'Nouvelle facture créée' // COMMENTAIRE PAR DÉFAUT

})

});

if ([Link]) {

const text = await [Link]();

const result = [Link](cleanApiResponse(text));

if ([Link]) {

// Recharger les factures

await chargerToutesLesFactures();

afficherNotification(` Nouvelle facture ${nouveauNumero} créée`, 'success');

} else {

throw new Error([Link] || 'Erreur création facture');

}
} else {

// Simulation si l'API n'est pas disponible

const nouvelleFacture = {

id: [Link](...[Link](f => [Link])) + 1,

numeroFacture: nouveauNumero,

dateCreation: new Date().toISOString(),

societe: 'Nouveau client',

numTicket: `TKT${[Link](...[Link](f => parseInt([Link]('TKT', '')) ||


0)) + 1}`,

statut: 'en_attente',

montantTotal: 0,

datePaiement: null,

motifAnnulation: null,

commentaire: 'Nouvelle facture créée',

ventes: []

};

[Link](nouvelleFacture);

afficherFactures();

mettreAJourStatistiques();

mettreAJourPagination();

afficherNotification(` Nouvelle facture ${nouveauNumero} créée (simulation)`, 'success');

} catch (error) {

[Link](' Erreur création facture:', error);

afficherNotification(' Erreur lors de la création de la facture', 'error');

// AFFICHAGE PRINCIPAL RESPONSIVE


function afficherFactures() {

[Link](' Affichage du tableau responsive...');

const tbody = [Link]('facturesTableBody');

if (!tbody) return;

facturesFiltrees = [Link](facture => {

const statut = [Link]('statutFilter')?.value || 'tous';

const search = [Link]('searchInput')?.[Link]() || '';

if (statut !== 'tous' && [Link] !== statut) return false;

if (search && ![Link]().includes(search) &&

![Link]().includes(search)) return false;

return true;

});

const startIndex = (currentPage - 1) * ITEMS_PER_PAGE;

const facturesPage = [Link](startIndex, startIndex + ITEMS_PER_PAGE);

[Link](` ${[Link]} factures, ${[Link]} sur la page`);

if ([Link] === 0) {

[Link] = `

<tr>

<td colspan="${[Link]}" style="padding: 30px; text-align: center;


color: #666;">

<i class="fas fa-file-invoice" style="font-size: 1.5rem; margin-bottom: 8px; display:


block;"></i>

<div style="font-size: 0.8rem;">Aucune facture trouvée</div>

</td>

</tr>
`;

return;

// CONSTRUCTION RESPONSIVE DES LIGNES - AVEC STYLES INLINE POUR LES BOUTONS

[Link] = [Link](facture => {

let rowHTML = '<tr style="border-bottom: 1px solid #2d2d2d;">';

if ([Link]('numero')) {

rowHTML += `

<td style="padding: 8px 10px; color: #e74c3c; font-weight: bold; font-family: monospace;">

${[Link]}

</td>

`;

if ([Link]('date')) {

rowHTML += `

<td style="padding: 8px 10px; color: #ccc;">

${formatDateTableau([Link])}

</td>

`;

if ([Link]('client')) {

rowHTML += `

<td style="padding: 8px 10px; color: #ccc; overflow: hidden; text-overflow: ellipsis; white-
space: nowrap;" title="${[Link]}">

${[Link]}

</td>

`;
}

if ([Link]('statut')) {

rowHTML += `

<td style="padding: 8px 10px; text-align: center;">

<span style="padding: 4px 8px; border-radius: 12px; font-size: 0.7rem; font-weight: bold;
text-transform: uppercase;

${[Link] === 'payee' ? 'background: #27ae60; color: white;' :

[Link] === 'en_attente' ? 'background: #f39c12; color: white;' :

'background: #e74c3c; color: white;'}">

${getStatutText([Link])}

</span>

${[Link] ? `

<br><small style="font-size: 0.6rem; color: #888; cursor: help;"


title="${[Link]}">

<i class="fas fa-info-circle"></i> motif

</small>

` : ''}

</td>

`;

if ([Link]('montant')) {

rowHTML += `

<td style="padding: 8px 10px; text-align: right; font-weight: bold; color: #fff;">

${formatMontantComplet([Link])}

</td>

`;

if ([Link]('actions')) {

rowHTML += `
<td style="padding: 8px 10px; text-align: center;">

<div style="display: flex; gap: 5px; justify-content: center; align-items: center;">

${[Link] === 'en_attente' ? `

<button onclick="payerFacture(${[Link]})"

style="width: 28px; height: 28px; border: none; border-radius: 4px; cursor:


pointer; display: flex; align-items: center; justify-content: center; transition: all 0.3s ease; background:
#27ae60; color: white;"

onmouseover="[Link]='#219653';
[Link]='scale(1.1)'"

onmouseout="[Link]='#27ae60'; [Link]='scale(1)'"

title="Payer la facture">

<i class="fas fa-credit-card" style="font-size: 0.8rem;"></i>

</button>

` : ''}

<button onclick="afficherDetailsFacture(${[Link]})"

style="width: 28px; height: 28px; border: none; border-radius: 4px; cursor: pointer;
display: flex; align-items: center; justify-content: center; transition: all 0.3s ease; background:
#3498db; color: white;"

onmouseover="[Link]='#2980b9'; [Link]='scale(1.1)'"

onmouseout="[Link]='#3498db'; [Link]='scale(1)'"

title="Voir les détails">

<i class="fas fa-eye" style="font-size: 0.8rem;"></i>

</button>

${[Link] !== 'annulee' ? `

<button onclick="modifierFacture(${[Link]})"

style="width: 28px; height: 28px; border: none; border-radius: 4px; cursor:


pointer; display: flex; align-items: center; justify-content: center; transition: all 0.3s ease; background:
#f39c12; color: white;"

onmouseover="[Link]='#e67e22';
[Link]='scale(1.1)'"

onmouseout="[Link]='#f39c12'; [Link]='scale(1)'"

title="Modifier la facture">
<i class="fas fa-edit" style="font-size: 0.8rem;"></i>

</button>

<button onclick="supprimerFacture(${[Link]})"

style="width: 28px; height: 28px; border: none; border-radius: 4px; cursor:


pointer; display: flex; align-items: center; justify-content: center; transition: all 0.3s ease; background:
#e74c3c; color: white;"

onmouseover="[Link]='#c0392b';
[Link]='scale(1.1)'"

onmouseout="[Link]='#e74c3c'; [Link]='scale(1)'"

title="Annuler la facture">

<i class="fas fa-ban" style="font-size: 0.8rem;"></i>

</button>

`:`

<button style="width: 28px; height: 28px; border: none; border-radius: 4px;


background: #666; color: #999; cursor: not-allowed;"

title="Facture annulée - non modifiable">

<i class="fas fa-lock" style="font-size: 0.8rem;"></i>

</button>

`}

</div>

</td>

`;

rowHTML += '</tr>';

return rowHTML;

}).join('');

[Link](' Tableau responsive mis à jour!');

}
// FONCTIONS POUR LES ACTIONS

function modifierFacture(factureId) {

[Link]('✏️ Modification facture:', factureId);

afficherNotification('Fonction de modification à implémenter', 'info');

// FONCTION DE SUPPRESSION/ANNULATION AMÉLIORÉE

async function supprimerFacture(factureId) {

[Link](' Annulation facture:', factureId);

const facture = [Link](f => [Link] === factureId);

if (!facture) {

afficherNotification('Facture non trouvée', 'error');

return;

if ([Link] === 'annulee') {

afficherNotification('Cette facture est déjà annulée', 'warning');

return;

// Afficher le modal de confirmation avec champ motif

[Link]('factureDetails').innerHTML = `

<div style="max-width: 500px;">

<h3 style="color: #e74c3c; margin-bottom: 15px; border-bottom: 2px solid #e74c3c; padding-
bottom: 8px; font-size: 1.1rem;">

<i class="fas fa-ban"></i> Annuler la Facture

</h3>

<div style="background: #2d2d2d; padding: 12px; border-radius: 4px; margin-bottom: 15px;">

<h4 style="color: #fff; margin-bottom: 10px; font-size: 0.9rem;">Détails de la facture</h4>


<div style="display: grid; gap: 6px; font-size: 0.8rem;">

<div><strong>N° Facture:</strong> ${[Link]}</div>

<div><strong>Client:</strong> ${[Link]}</div>

<div><strong>Date:</strong> ${formatDateTableau([Link])}</div>

<div><strong>Montant:</strong> ${formatMontantComplet([Link])}</div>

<div><strong>Statut actuel:</strong> <span style="color: ${[Link] === 'payee' ?


'#27ae60' : '#f39c12'}">${getStatutText([Link])}</span></div>

</div>

</div>

<div style="background: #2d2d2d; padding: 12px; border-radius: 4px; margin-bottom: 15px;">

<h4 style="color: #fff; margin-bottom: 10px; font-size: 0.9rem;">Motif de l'annulation</h4>

<textarea id="motifAnnulation"

placeholder="Veuillez saisir le motif de l'annulation de cette facture..."

style="width: 100%; height: 80px; background: #1a1a1a; border: 1px solid #444;
border-radius: 4px; color: #fff; padding: 8px; font-size: 0.8rem; resize: vertical;"

required></textarea>

<small style="color: #888; font-size: 0.7rem;">

<i class="fas fa-info-circle"></i> Ce motif sera enregistré dans la colonne COMMENTAIRE


de la base de données

</small>

</div>

<div style="display: flex; gap: 8px; justify-content: flex-end;">

<button onclick="fermerModal()"

style="background: #666; color: white; border: none; padding: 8px 16px; border-radius:
4px; cursor: pointer; font-size: 0.8rem;">

Retour

</button>

<button onclick="confirmerAnnulation(${factureId})"

style="background: #e74c3c; color: white; border: none; padding: 8px 16px; border-
radius: 4px; cursor: pointer; font-weight: bold; font-size: 0.8rem;"

id="btnConfirmerAnnulation">
<i class="fas fa-ban"></i> Confirmer l'Annulation

</button>

</div>

</div>

`;

[Link]('factureModal').[Link] = 'block';

// FONCTION DE MODIFICATION AVEC CHOIX DE MODE DE PAIEMENT

async function modifierFacture(factureId) {

[Link]('✏️ Modification facture:', factureId);

const facture = [Link](f => [Link] === factureId);

if (!facture) {

afficherNotification('Facture non trouvée', 'error');

return;

// Vérifier si la facture peut être modifiée

if ([Link] === 'annulee') {

afficherNotification('Une facture annulée ne peut pas être modifiée', 'warning');

return;

// Options de mode de paiement avec icônes

const modesPaiement = [

{ value: null, label: 'Non spécifié', icon: 'fa-question-circle', color: '#888' },

{ value: 'especes', label: 'Espèces', icon: 'fa-money-bill-wave', color: '#27ae60' },

{ value: 'carte', label: 'Carte bancaire', icon: 'fa-credit-card', color: '#3498db' },

{ value: 'mobile_money', label: 'Mobile Money', icon: 'fa-mobile-alt', color: '#9b59b6' },


{ value: 'virement', label: 'Virement bancaire', icon: 'fa-university', color: '#f39c12' },

{ value: 'cheque', label: 'Chèque', icon: 'fa-file-invoice', color: '#1abc9c' },

{ value: 'autres', label: 'Autres', icon: 'fa-ellipsis-h', color: '#95a5a6' }

];

// HTML DU MODAL DE MODIFICATION AVEC CHOIX DE MODE DE PAIEMENT

[Link]('factureDetails').innerHTML = `

<div style="max-width: 500px;">

<h3 style="color: #3498db; margin-bottom: 15px; border-bottom: 2px solid #3498db; padding-
bottom: 8px; font-size: 1.1rem;">

<i class="fas fa-edit"></i> Modifier la Facture

</h3>

<div style="background: #2d2d2d; padding: 12px; border-radius: 4px; margin-bottom: 15px;">

<h4 style="color: #fff; margin-bottom: 10px; font-size: 0.9rem;">Informations de la


facture</h4>

<div style="display: grid; gap: 6px; font-size: 0.8rem;">

<div><strong>N° Facture:</strong> ${[Link]}</div>

<div><strong>Client:</strong> ${[Link]}</div>

<div><strong>Date création:</strong> ${formatDateTableau([Link])}</div>

<div><strong>Montant total:</strong>
${formatMontantComplet([Link])}</div>

<div><strong>Statut:</strong>

<span style="color: ${[Link] === 'payee' ? '#27ae60' : [Link] ===


'en_attente' ? '#f39c12' : '#e74c3c'}">

${getStatutText([Link])}

</span>

</div>

</div>

</div>

<!-- SECTION MODE DE PAIEMENT (CHOIX) -->


<div style="background: #2d2d2d; padding: 12px; border-radius: 4px; margin-bottom: 15px;">

<h4 style="color: #fff; margin-bottom: 10px; font-size: 0.9rem;">

<i class="fas fa-credit-card"></i> Mode de paiement

</h4>

<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(110px, 1fr)); gap:


8px; margin-bottom: 10px;">

${[Link](mode => `

<button type="button"

class="mode-paiement-btn ${[Link] === [Link] ? 'selected' :


''}"

data-value="${[Link]}"

onclick="selectionnerModePaiementModal(this, '${[Link]}')"

style="background: ${[Link]}15; border: 2px solid ${[Link]


=== [Link] ? [Link] : '#444'};

padding: 10px; border-radius: 6px; cursor: pointer; transition: all 0.3s;

color: #fff; text-align: center;">

<i class="fas ${[Link]}" style="font-size: 1rem; margin-bottom: 5px; display: block;


color: ${[Link]};"></i>

<div style="font-size: 0.7rem;">${[Link]}</div>

</button>

`).join('')}

</div>

<small style="color: #888; font-size: 0.7rem;">

<i class="fas fa-info-circle"></i> Sélectionnez le mode de paiement utilisé pour cette


facture

</small>

</div>

<!-- SECTION COMMENTAIRE -->

<div style="background: #2d2d2d; padding: 12px; border-radius: 4px; margin-bottom: 15px;">

<h4 style="color: #fff; margin-bottom: 10px; font-size: 0.9rem;">

<i class="fas fa-sticky-note"></i> Commentaire

</h4>
<textarea id="commentaireFacture"

placeholder="Ajoutez un commentaire sur cette facture (max 1000 caractères)..."

style="width: 100%; height: 80px; background: #1a1a1a; border: 1px solid #444;
border-radius: 4px; color: #fff; padding: 8px; font-size: 0.8rem; resize: vertical;"

maxlength="1000">${[Link] || ''}</textarea>

<div style="display: flex; justify-content: space-between; margin-top: 5px;">

<small style="color: #888; font-size: 0.7rem;">

<i class="fas fa-info-circle"></i> Ce commentaire sera enregistré avec la facture

</small>

<small id="charCount" style="color: #888; font-size: 0.7rem;">

${([Link] || '').length}/1000

</small>

</div>

</div>

<!-- BOUTONS D'ACTION -->

<div style="display: flex; gap: 8px; justify-content: flex-end;">

<button onclick="fermerModal()"

style="background: #666; color: white; border: none; padding: 8px 16px; border-radius:
4px; cursor: pointer; font-size: 0.8rem;">

Annuler

</button>

<button onclick="sauvegarderModificationsFacture(${factureId})"

style="background: #3498db; color: white; border: none; padding: 8px 16px; border-
radius: 4px; cursor: pointer; font-weight: bold; font-size: 0.8rem;"

id="btnSauvegarderModifications">

<i class="fas fa-save"></i> Sauvegarder

</button>

</div>

</div>

`;
// Ajouter le CSS pour les boutons sélectionnés

const style = [Link]('style');

[Link] = `

.[Link] {

transform: scale(1.05);

box-shadow: 0 0 0 2px ${[Link] ? '#3498db' : '#666'};

.mode-paiement-btn:hover {

transform: scale(1.05);

border-color: #3498db !important;

`;

[Link](style);

// Gestion du compteur de caractères

const textarea = [Link]('commentaireFacture');

const charCount = [Link]('charCount');

if (textarea && charCount) {

[Link]('input', function() {

const length = [Link];

[Link] = `${length}/1000`;

[Link] = length > 900 ? '#e74c3c' : length > 700 ? '#f39c12' : '#888';

});

[Link]('factureModal').[Link] = 'block';

// Stocker le mode de paiement sélectionné

[Link] = [Link];

}
// FONCTION POUR SÉLECTIONNER UN MODE DE PAIEMENT DANS LE MODAL

function selectionnerModePaiementModal(button, value) {

// Désélectionner tous les boutons

[Link]('.mode-paiement-btn').forEach(btn => {

[Link]('selected');

[Link] = '#444';

});

// Sélectionner le bouton cliqué

[Link]('selected');

// Stocker la sélection

[Link] = value;

[Link](' Mode de paiement sélectionné:', value);

// FONCTION POUR SAUVEGARDER LES MODIFICATIONS DE LA FACTURE

async function sauvegarderModificationsFacture(factureId) {

[Link](' Sauvegarde modifications facture:', factureId);

const btnSauvegarder = [Link]('btnSauvegarderModifications');

if (btnSauvegarder) {

[Link] = true;

[Link] = '<i class="fas fa-spinner fa-spin"></i> Sauvegarde...';

try {

const facture = [Link](f => [Link] === factureId);

if (!facture) {
throw new Error('Facture non trouvée');

// COLLECTE DES DONNÉES DU FORMULAIRE

const modePaiement = [Link];

const commentaire = [Link]('commentaireFacture')?.[Link]() || '';

const donneesMiseAJour = {};

// Ajouter mode de paiement seulement s'il a changé

if (modePaiement !== [Link]) {

donneesMiseAJour.mode_paiement = modePaiement;

// Ajouter commentaire seulement s'il a changé

if (commentaire !== ([Link] || '')) {

[Link] = commentaire;

// Vérifier s'il y a des modifications

if ([Link](donneesMiseAJour).length === 0) {

afficherNotification('Aucune modification à sauvegarder', 'info');

if (btnSauvegarder) {

[Link] = false;

[Link] = '<i class="fas fa-save"></i> Sauvegarder';

return;

[Link](' Données à envoyer:', donneesMiseAJour);


// APPEL API DE MISE À JOUR

const response = await fetch(`${API_BASE_URL_FACTURES}/factures/${factureId}`, {

method: 'PUT',

headers: {

'Content-Type': 'application/json',

'Accept': 'application/json'

},

body: [Link](donneesMiseAJour)

});

[Link](' Statut réponse:', [Link]);

if (![Link]) {

const errorText = await [Link]();

const errorData = [Link](cleanApiResponse(errorText));

throw new Error([Link] || `Erreur serveur: ${[Link]}`);

const text = await [Link]();

const result = [Link](cleanApiResponse(text));

if ([Link]) {

// MISE À JOUR LOCALE DES DONNÉES

const factureIndex = [Link](f => [Link] === factureId);

if (factureIndex !== -1) {

allFactures[factureIndex] = {

...allFactures[factureIndex],

...(donneesMiseAJour.mode_paiement !== undefined && {

modePaiement: donneesMiseAJour.mode_paiement

}),

...([Link] !== undefined && {


commentaire: [Link]

})

};

afficherNotification(' Facture modifiée avec succès', 'success');

fermerModal();

afficherFactures();

mettreAJourStatistiques();

mettreAJourPagination();

} else {

throw new Error([Link] || 'Erreur lors de la mise à jour');

} catch (error) {

[Link](' Erreur sauvegarde:', error);

afficherNotification(` Erreur: ${[Link]}`, 'error');

if (btnSauvegarder) {

[Link] = false;

[Link] = '<i class="fas fa-save"></i> Sauvegarder';

// CONFIRMATION DE L'ANNULATION AVEC INTÉGRATION DANS LA COLONNE COMMENTAIRE

async function confirmerAnnulation(factureId) {

const motif = [Link]('motifAnnulation')?.[Link]();


if (!motif) {

afficherNotification('Veuillez saisir le motif de l\'annulation', 'error');

return;

const btnConfirmer = [Link]('btnConfirmerAnnulation');

if (btnConfirmer) {

[Link] = true;

[Link] = '<i class="fas fa-spinner fa-spin"></i> Traitement...';

try {

[Link](` Annulation de la facture ${factureId} avec motif: ${motif}`);

// INTÉGRATION DU MOTIF DANS LA COLONNE COMMENTAIRE

const commentaireAnnulation = `Facture annulée - Motif: ${motif}`;

// Appel API pour annuler la facture avec le motif dans la colonne commentaire

const response = await fetch(`${API_BASE_URL_FACTURES}/factures/${factureId}/annuler`, {

method: 'POST',

headers: {

'Content-Type': 'application/json',

'Accept': 'application/json'

},

body: [Link]({

motif_annulation: motif,

commentaire: commentaireAnnulation // INTÉGRATION DANS LA COLONNE


COMMENTAIRE

})

});
if (![Link]) {

// Si l'API n'est pas disponible, simuler l'annulation localement

throw new Error('API non disponible - simulation locale');

const text = await [Link]();

const result = [Link](cleanApiResponse(text));

if ([Link]) {

// Mettre à jour localement

const factureIndex = [Link](f => [Link] === factureId);

if (factureIndex !== -1) {

allFactures[factureIndex] = {

...allFactures[factureIndex],

statut: 'annulee',

motifAnnulation: motif,

commentaire: commentaireAnnulation, // MISE À JOUR LOCALE

datePaiement: null

};

afficherNotification(` Facture ${allFactures[factureIndex]?.numeroFacture} annulée avec


succès`, 'success');

} else {

throw new Error([Link] || 'Erreur lors de l\'annulation');

} catch (error) {

[Link](' Erreur annulation:', error);


// Simulation locale si l'API échoue

const factureIndex = [Link](f => [Link] === factureId);

if (factureIndex !== -1) {

const commentaireAnnulation = `Facture annulée - Motif: ${motif}`;

allFactures[factureIndex] = {

...allFactures[factureIndex],

statut: 'annulee',

motifAnnulation: motif,

commentaire: commentaireAnnulation, // MISE À JOUR LOCALE EN SIMULATION

datePaiement: null

};

afficherNotification(` Facture ${allFactures[factureIndex].numeroFacture} annulée (mode


simulation)`, 'success');

} else {

afficherNotification(' Erreur lors de l\'annulation', 'error');

return;

fermerModal();

afficherFactures();

mettreAJourStatistiques();

mettreAJourPagination();

// FONCTION POUR PAYER UNE FACTURE

function payerFacture(factureId) {

[Link](' Paiement facture:', factureId);


const facture = [Link](f => [Link] === factureId);

if (!facture) {

afficherNotification('Facture non trouvée', 'error');

return;

if ([Link] === 'annulee') {

afficherNotification('Impossible de payer une facture annulée', 'error');

return;

[Link]('factureDetails').innerHTML = `

<div style="max-width: 500px;">

<h3 style="color: #e74c3c; margin-bottom: 15px; border-bottom: 2px solid #e74c3c; padding-
bottom: 8px; font-size: 1.1rem;">

<i class="fas fa-credit-card"></i> Paiement Facture

</h3>

<div style="background: #2d2d2d; padding: 12px; border-radius: 4px; margin-bottom: 15px;">

<h4 style="color: #fff; margin-bottom: 10px; font-size: 0.9rem;">Détails de la facture</h4>

<div style="display: grid; gap: 6px; font-size: 0.8rem;">

<div><strong>N° Facture:</strong> ${[Link]}</div>

<div><strong>Client:</strong> ${[Link]}</div>

<div><strong>Date:</strong> ${formatDateTableau([Link])}</div>

<div><strong>Montant à payer:</strong> <span style="color: #e74c3c; font-weight: bold;


font-size: 1rem;">${formatMontantComplet([Link])}</span></div>

</div>

</div>

<div style="background: #2d2d2d; padding: 12px; border-radius: 4px; margin-bottom: 15px;">

<h4 style="color: #fff; margin-bottom: 10px; font-size: 0.9rem;">Mode de paiement</h4>

<div style="display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 8px;">


<button onclick="selectionnerModePaiement('especes')"

style="background: #1a1a1a; border: 2px solid #444; padding: 12px; border-radius:


4px; color: #ccc; cursor: pointer; transition: all 0.3s; font-size: 0.8rem;"

id="btnEspeces">

<i class="fas fa-money-bill-wave" style="font-size: 1.2rem; margin-bottom: 4px; display:


block;"></i>

<div>Espèces</div>

</button>

<button onclick="selectionnerModePaiement('carte')"

style="background: #1a1a1a; border: 2px solid #444; padding: 12px; border-radius:


4px; color: #ccc; cursor: pointer; transition: all 0.3s; font-size: 0.8rem;"

id="btnCarte">

<i class="fas fa-credit-card" style="font-size: 1.2rem; margin-bottom: 4px; display:


block;"></i>

<div>Carte</div>

</button>

<button onclick="selectionnerModePaiement('mobile_money')"

style="background: #1a1a1a; border: 2px solid #444; padding: 12px; border-radius:


4px; color: #ccc; cursor: pointer; transition: all 0.3s; font-size: 0.8rem;"

id="btnMobileMoney">

<i class="fas fa-mobile-alt" style="font-size: 1.2rem; margin-bottom: 4px; display:


block;"></i>

<div>Mobile Money</div>

</button>

</div>

<div id="detailsPaiement" style="margin-top: 12px; display: none;"></div>

</div>

<div style="display: flex; gap: 8px; justify-content: flex-end;">

<button onclick="annulerPaiement()"
style="background: #666; color: white; border: none; padding: 8px 16px; border-radius:
4px; cursor: pointer; font-size: 0.8rem;">

Annuler

</button>

<button onclick="confirmerPaiement(${[Link]})"

style="background: #27ae60; color: white; border: none; padding: 8px 16px; border-
radius: 4px; cursor: pointer; font-weight: bold; font-size: 0.8rem;"

id="btnConfirmerPaiement">

Confirmer le Paiement

</button>

</div>

</div>

`;

[Link]('factureModal').[Link] = 'block';

[Link] = factureId;

[Link] = null;

// FONCTIONS POUR LE PAIEMENT

function selectionnerModePaiement(mode) {

[Link](' Mode sélectionné:', mode);

[Link] = mode;

const buttons = ['btnEspeces', 'btnCarte', 'btnMobileMoney'];

[Link](btnId => {

const btn = [Link](btnId);

if (btn) [Link] = '#444';

});

const selectedBtn = [Link]('btn' + [Link](0).toUpperCase() +


[Link](1).replace('_', ''));
if (selectedBtn) [Link] = '#27ae60';

const detailsPaiement = [Link]('detailsPaiement');

[Link] = 'block';

let detailsHTML = '';

switch(mode) {

case 'especes':

detailsHTML = `

<div style="background: #1a1a1a; padding: 10px; border-radius: 4px;">

<h5 style="color: #fff; margin-bottom: 8px; font-size: 0.8rem;">Paiement en Espèces</h5>

<div style="color: #ccc; font-size: 0.8rem;">

<p> Le client paie en espèces. Merci de préparer la monnaie si nécessaire.</p>

</div>

</div>

`;

break;

case 'carte':

detailsHTML = `

<div style="background: #1a1a1a; padding: 10px; border-radius: 4px;">

<h5 style="color: #fff; margin-bottom: 8px; font-size: 0.8rem;">Paiement par Carte</h5>

<div style="color: #ccc; font-size: 0.8rem;">

<p> Insérez ou tapez la carte du client.</p>

</div>

</div>

`;

break;

case 'mobile_money':
detailsHTML = `

<div style="background: #1a1a1a; padding: 10px; border-radius: 4px;">

<h5 style="color: #fff; margin-bottom: 8px; font-size: 0.8rem;">Paiement par Mobile


Money</h5>

<div style="color: #ccc; font-size: 0.8rem;">

<p> Envoyez une demande de paiement au client</p>

</div>

</div>

`;

break;

[Link] = detailsHTML;

function cleanApiResponse(text) {

return [Link](/<!--.*?-->/g, '').trim();

async function confirmerPaiement(factureId) {

if (![Link]) {

afficherNotification('Veuillez sélectionner un mode de paiement', 'error');

return;

const btnConfirmer = [Link]('btnConfirmerPaiement');

if (btnConfirmer) {

[Link] = true;

[Link] = '<i class="fas fa-spinner fa-spin"></i> Traitement...';

}
try {

[Link](` Paiement facture ${factureId} via ${[Link]}`);

const facture = [Link](f => [Link] === factureId);

if (!facture) {

throw new Error('Facture non trouvée');

if ([Link] !== 'en_attente') {

throw new Error('Cette facture n\'est pas en attente de paiement');

const response = await fetch(`${API_BASE_URL_FACTURES}/factures/${factureId}/payer`, {

method: 'POST',

headers: {

'Accept': 'application/json'

});

[Link](' Statut réponse:', [Link]);

if (![Link]) {

const errorText = await [Link]();

const errorData = [Link](cleanApiResponse(errorText));

throw new Error([Link] || `Erreur serveur: ${[Link]}`);

const text = await [Link]();

const result = [Link](cleanApiResponse(text));

if ([Link]) {
const factureIndex = [Link](f => [Link] === factureId);

if (factureIndex !== -1) {

allFactures[factureIndex] = {

...allFactures[factureIndex],

statut: 'payee',

datePaiement: [Link].date_paiement || new Date().toISOString(),

modePaiement: [Link],

commentaire: `Facture payée - Mode: ${[Link]}` //


COMMENTAIRE DE PAIEMENT

};

const factureNumero = [Link]?.numero_facture || [Link];

afficherNotification(` Facture ${factureNumero} payée avec succès


(${[Link]})`, 'success');

fermerModal();

afficherFactures();

mettreAJourStatistiques();

mettreAJourPagination();

} else {

throw new Error([Link] || 'Erreur lors du paiement');

} catch (error) {

[Link](' Erreur paiement:', error);

afficherNotification(` Échec du paiement: ${[Link]}`, 'error');

if (btnConfirmer) {

[Link] = false;
[Link] = 'Confirmer le Paiement';

function annulerPaiement() {

[Link](' Paiement annulé');

fermerModal();

afficherNotification('Paiement annulé', 'info');

// AFFICHAGE DES DÉTAILS AVEC DESIGN COMPACT

async function afficherDetailsFacture(factureId) {

[Link](' Détails facture:', factureId);

try {

// Forcer la largeur à 6cm (environ 227 pixels)

const modalContent = [Link]('.modal-content');

[Link] = '227px';

[Link] = '227px';

[Link] = '227px';

const response = await fetch(`${API_BASE_URL_FACTURES}/factures/${factureId}`);

if (![Link]) {

throw new Error(`Erreur API: ${[Link]}`);

const text = await [Link]();

const cleanedText = cleanApiResponse(text);

const result = [Link](cleanedText);


if (![Link] || ![Link]) {

throw new Error('Données non disponibles');

const facture = [Link];

const ventes = [Link] || [];

let produitsHTML = '';

if ([Link] > 0) {

produitsHTML = `

<div style="margin-top: 10px;">

<div style="display: flex; justify-content: space-between; align-items: center; margin-


bottom: 8px;">

<h4 style="color: #fff; font-size: 0.75rem; margin: 0;">

<i class="fas fa-shopping-cart" style="font-size: 0.7rem;"></i> Produits

</h4>

<span style="background: #e74c3c; color: white; padding: 1px 6px; border-radius: 10px;
font-size: 0.6rem; font-weight: bold;">

${[Link]}

</span>

</div>

<div style="max-height: 150px; overflow-y: auto; border: 1px solid #2d2d2d; border-
radius: 4px;">

`;

let totalGeneral = 0;

[Link]((vente, index) => {

const produit = [Link] || {};

const nomProduit = [Link] || 'Produit inconnu';


const quantite = [Link] || 0;

const prixUnitaire = vente.prix_unitaire || 0;

const prixTotal = vente.prix_total || 0;

totalGeneral += prixTotal;

// Tronquer le nom du produit si trop long

const nomTronque = [Link] > 20 ? [Link](0, 20) + '...' :


nomProduit;

produitsHTML += `

<div style="padding: 6px; border-bottom: 1px solid #2d2d2d; ${index % 2 === 0 ?


'background: #1a1a1a;' : 'background: #222;'}">

<div style="font-weight: 600; color: #fff; font-size: 0.65rem; margin-bottom: 3px;"


title="${nomProduit}">

${nomTronque}

</div>

<div style="display: flex; justify-content: space-between; color: #888; font-size:


0.6rem;">

<span>${quantite} × ${formatMontantComplet(prixUnitaire)}</span>

<span style="color: #e74c3c; font-weight:


bold;">${formatMontantComplet(prixTotal)}</span>

</div>

</div>

`;

});

produitsHTML += `

</div>

<div style="background: linear-gradient(135deg, #e74c3c, #c0392b); padding: 8px; border-


radius: 4px; margin-top: 8px;">

<div style="display: flex; justify-content: space-between; align-items: center;">

<span style="color: white; font-weight: bold; font-size: 0.7rem;">TOTAL</span>

<span style="color: white; font-weight: bold; font-size:


0.8rem;">${formatMontantComplet(totalGeneral)}</span>
</div>

</div>

</div>

`;

} else {

produitsHTML = `

<div style="text-align: center; padding: 15px; color: #888; background: #1a1a1a; border-
radius: 4px; margin-top: 10px;">

<i class="fas fa-box-open" style="font-size: 1.5rem; margin-bottom: 8px; display: block;


color: #555;"></i>

<div style="font-size: 0.7rem;">Aucun produit</div>

</div>

`;

// Affichage du motif d'annulation et commentaire si présent

const commentaireHTML = [Link] ? `

<div style="background: #2d2d2d; padding: 10px; border-radius: 4px; margin-bottom: 10px;


border-left: 4px solid #3498db;">

<div style="display: flex; align-items: center; margin-bottom: 6px;">

<i class="fas fa-comment" style="color: #3498db; margin-right: 6px; font-size:


0.7rem;"></i>

<h4 style="color: #fff; margin: 0; font-size: 0.7rem;">Commentaire</h4>

</div>

<div style="color: #ccc; font-size: 0.65rem; font-style: italic;">

"${[Link]}"

</div>

</div>

` : '';

[Link]('factureDetails').innerHTML = `

<div style="max-width: 100%;">


<!-- EN-TÊTE COMPACTE -->

<div style="background: linear-gradient(135deg, #e74c3c, #c0392b); padding: 12px; border-


radius: 6px 6px 0 0; margin: -15px -15px 12px -15px;">

<div style="text-align: center;">

<h3 style="color: white; margin: 0 0 3px 0; font-size: 0.85rem; font-weight: bold;">

<i class="fas fa-file-invoice" style="font-size: 0.8rem;"></i> Détails

</h3>

<div style="color: rgba(255,255,255,0.9); font-size: 0.65rem; margin-bottom: 5px;">

${facture.numero_facture || 'N/A'}

</div>

<span class="statut-badge statut-${[Link]}" style="font-size: 0.6rem; padding:


2px 8px;">

${getStatutText([Link])}

</span>

</div>

</div>

${commentaireHTML}

<!-- INFORMATIONS CLIENT COMPACTES -->

<div style="background: #2d2d2d; padding: 10px; border-radius: 4px; margin-bottom:


10px;">

<div style="display: flex; align-items: center; margin-bottom: 6px;">

<i class="fas fa-building" style="color: #e74c3c; margin-right: 6px; font-size:


0.7rem;"></i>

<h4 style="color: #fff; margin: 0; font-size: 0.7rem;">Client</h4>

</div>

<div style="font-size: 0.65rem;">

<div style="color: #fff; font-weight: 500; margin-bottom: 4px; overflow: hidden; text-
overflow: ellipsis; white-space: nowrap;" title="${[Link]?.nom || 'Client inconnu'}">

${[Link]?.nom || 'Client inconnu'}

</div>
<div style="display: flex; justify-content: space-between; color: #ccc; margin-bottom:
3px;">

<span>Date:</span>

<span>${formatDateTableau(facture.date_creation)}</span>

</div>

${facture.date_paiement ? `

<div style="display: flex; justify-content: space-between; color: #27ae60; font-size:


0.6rem;">

<span>Payé le:</span>

<span>${formatDateTableau(facture.date_paiement)}</span>

</div>

` : ''}

</div>

</div>

<!-- PRODUITS COMPACTS -->

${produitsHTML}

<!-- BOUTON FERMER COMPACT -->

<div style="display: flex; justify-content: center; margin-top: 12px;">

<button onclick="fermerModal()"

style="background: #e74c3c; color: white; border: none; padding: 6px 15px; border-
radius: 3px; cursor: pointer; font-weight: 500; font-size: 0.65rem; transition: background 0.3s;"

onmouseover="[Link]='#c0392b'"

onmouseout="[Link]='#e74c3c'">

<i class="fas fa-times" style="font-size: 0.6rem;"></i> Fermer

</button>

</div>

</div>

`;

[Link]('factureModal').[Link] = 'block';
} catch (error) {

[Link](' Erreur chargement détails:', error);

afficherNotification(`Erreur: ${[Link]}`, 'error');

// FONCTIONS UTILITAIRES RESPONSIVES

function mettreAJourStatistiques() {

const total = [Link];

const payees = [Link](f => [Link] === 'payee').length;

const enAttente = [Link](f => [Link] === 'en_attente').length;

const annulees = [Link](f => [Link] === 'annulee').length;

const statsSection = [Link]('statsSection');

if (statsSection) {

[Link] = `

<div class="stat-item">

<span class="stat-number">${total}</span>

<span class="stat-label">Total</span>

</div>

<div class="stat-item" style="border-left-color: #27ae60;">

<span class="stat-number" style="color: #27ae60;">${payees}</span>

<span class="stat-label">Payées</span>

</div>

<div class="stat-item" style="border-left-color: #f39c12;">

<span class="stat-number" style="color: #f39c12;">${enAttente}</span>

<span class="stat-label">En attente</span>

</div>

<div class="stat-item" style="border-left-color: #e74c3c;">

<span class="stat-number" style="color: #e74c3c;">${annulees}</span>


<span class="stat-label">Annulées</span>

</div>

`;

function mettreAJourPagination() {

const totalPages = [Link]([Link] / ITEMS_PER_PAGE) || 1;

const paginationSection = [Link]('paginationSection');

if (paginationSection) {

[Link] = `

<button onclick="changerPage(${currentPage - 1})" ${currentPage <= 1 ? 'disabled' : ''}

class="page-btn">

<i class="fas fa-chevron-left"></i> Précédent

</button>

<span class="page-info">

Page ${currentPage} / ${totalPages}

</span>

<button onclick="changerPage(${currentPage + 1})" ${currentPage >= totalPages ? 'disabled' :


''}

class="page-btn">

Suivant <i class="fas fa-chevron-right"></i>

</button>

`;

// FORMATAGE DE DATE : JJ/MM/AAAA


function formatDateTableau(dateString) {

try {

const date = new Date(dateString);

const jour = [Link]().toString().padStart(2, '0');

const mois = ([Link]() + 1).toString().padStart(2, '0');

const annee = [Link]();

return `${jour}/${mois}/${annee}`;

} catch {

return dateString;

// FORMATAGE DES PRIX COMPLETS : 1 000, 10 000, 100 000

function formatMontantComplet(montant) {

return new [Link]('fr-FR').format(montant) + ' Ar';

function formatDateResponsive(dateString) {

return formatDateTableau(dateString);

function formatMontantResponsive(montant) {

return formatMontantComplet(montant);

function getStatutText(statut) {

const texts = {

'payee': 'Payée',

'en_attente': 'En attente',

'annulee': 'Annulée'

};
return texts[statut] || statut;

function filtrerFactures() {

currentPage = 1;

afficherFactures();

mettreAJourStatistiques();

mettreAJourPagination();

function changerPage(page) {

currentPage = page;

afficherFactures();

mettreAJourPagination();

function fermerModal() {

[Link]('factureModal').[Link] = 'none';

[Link] = null;

[Link] = null;

function exporterFactures() {

alert('Export PDF à implémenter');

function afficherNotification(message, type) {

[Link](` ${type}: ${message}`);

const notification = [Link]('div');

[Link] = `

position: fixed;
top: 20px;

right: 20px;

padding: 12px 16px;

border-radius: 4px;

color: white;

font-weight: bold;

z-index: 10000;

font-size: 0.8rem;

background: ${type === 'success' ? '#27ae60' : type === 'error' ? '#e74c3c' : '#f39c12'};

`;

[Link] = message;

[Link](notification);

setTimeout(() => {

[Link](notification);

}, 3000);

// DÉMARRAGE IMMÉDIAT

[Link](' Démarrage dans 100ms...');

setTimeout(demarrerApplication, 100);

Vous aimerez peut-être aussi