<!-- CDN SweetAlert2 -->
< script src = "https://cdn.jsdelivr.net/npm/sweetalert2@11" > < / script >
< style >
/* Style pour les champs en lecture seule */
input[readonly], select[disabled], textarea[readonly] {
background-color: #e9ecef !important;
cursor: not-allowed !important;
color: #6c757d;
}
/* Style pour la légende */
.field-legend {
background-color: #f8f9fa;
border-left: 4px solid #007bff;
padding: 10px 15px;
margin-bottom: 20px;
border-radius: 4px;
}
.field-legend i {
margin-right: 5px;
}
.field-legend .legend-item {
display: inline-block;
margin-right: 20px;
margin-top: 5px;
}
/* Effet hover sur les champs éditables */
.form-control:not([readonly]):not([disabled]):hover {
border-color: #007bff;
box-shadow: 0 0 0 0.2rem rgba(0,123,255,.15);
transition: all 0.2s ease-in-out;
}
/* Icône d'édition */
.fa-edit {
font-size: 12px;
}
< / style >
<!-- Content Wrapper. Contains page content -->
< div class = "content-wrapper" >
<!-- Content Header (Page header) -->
< section class = "content-header" >
< h1 >
Gestion des
< small > Décaissement< / small >
< / h1 >
< ol class = "breadcrumb" >
< li > < a href = "#" > < i class = "fa fa-dashboard" > < / i > Accueil< / a > < / li >
< li class = "active" > Décaissement< / li >
< / ol >
< / section >
<!-- Main content -->
< section class = "content" >
< div class = "row" >
< div class = "col-md-12 col-xs-12" >
< div id = "messages" > < / div >
<?php if ( session () -> getFlashdata ( 'success' )) : ?>
< div class = "alert alert-success alert-dismissible" role = "alert" >
< button type = "button" class = "close" data-dismiss = "alert" aria-label = "Close" >
< span aria-hidden = "true" > × < / span >
< / button >
<?php echo session () -> getFlashdata ( 'success' ); ?>
< / div >
<?php elseif ( session () -> getFlashdata ( 'error' )) : ?>
< div class = "alert alert-error alert-dismissible" role = "alert" >
< button type = "button" class = "close" data-dismiss = "alert" aria-label = "Close" >
< span aria-hidden = "true" > × < / span >
< / button >
<?php echo session () -> getFlashdata ( 'error' ); ?>
< / div >
<?php elseif ( session () -> getFlashdata ( 'errors' )) : ?>
< div class = "alert alert-warning alert-dismissible" role = "alert" >
< button type = "button" class = "close" data-dismiss = "alert" aria-label = "Close" >
< span aria-hidden = "true" > × < / span >
< / button >
<?php echo session () -> getFlashdata ( 'errors' ); ?>
< / div >
<?php endif ; ?>
<?php if ( in_array ( 'createSortieCaisse' , $user_permission )) : ?>
< button class = "btn btn-primary" data-toggle = "modal" data-target = "#createModal" > Décaissement< / button >
< br > < br >
<?php endif ; ?>
<!-- FILTRES EN DESSUS DU TABLEAU -->
< div class = "row mb-3" >
< div class = "col-md-2" >
< label for = "startDate" class = "form-label" > Date de début< / label >
< input type = "date" id = "startDate" class = "form-control" >
< / div >
< div class = "col-md-2" >
< label for = "endDate" class = "form-label" > Date de fin< / label >
< input type = "date" id = "endDate" class = "form-control" >
< / div >
< div class = "col-md-2" >
< label for = "pvente" class = "form-label" > Point de vente< / label >
< select id = "pvente" class = "form-control" >
< option value = "TOUS" > TOUS< / option >
<?php foreach ( $stores as $value ) : ?>
< option value = " <? = $value [ 'name' ]; ?> " > <? = $value [ 'name' ]; ?> </ option >
<?php endforeach ; ?>
< / select >
< / div >
< div class = "col-md-2" >
< label for = "s_statut" class = "form-label" > Statut du décaissement< / label >
< select id = "s_statut" class = "form-control" >
< option value = "TOUS" > TOUS< / option >
< option value = "Valider" > Valider< / option >
< option value = "En attente" > En attente< / option >
< option value = "Refuser" > Refuser< / option >
< / select >
< / div >
< div class = "col-md-1" >
< br >
< button id = "filteredB1" class = "btn btn-primary w-100" > Filtrer 🔍< / button >
< / div >
< div class = "col-md-1" >
< br >
<?php $session = session ();
$users = $session->get('user');
$isAdmin = $users['group_name'] == "Direction" || $users['group_name'] == "SuperAdmin" || $users['group_name'] == "DAF";
$isCaissier = $users['group_name'] == "Caissière";
if($isAdmin): ?>
< button id = "validate_filtered" class = "btn btn-primary w-100" > A valider< / button >
<?php endif ; ?>
< / div >
< / div >
< br >
< div class = "box" >
< div class = "box-header" >
< h3 class = "box-title" > Gérer les Décaissements< / h3 >
< / div >
< div class = "box-body" >
< table id = "manageTable" class = "table table-bordered table-striped" >
< thead >
< tr >
<?php
$session = session();
$users = $session->get('user');
if ($users['group_name'] === 'Caissière') {
?>
< th > #< / th >
< th > Montant< / th >
< th > Date< / th >
< th > Caissier< / th >
< th > Motif< / th >
< th > Statut< / th >
< th > Raison< / th >
<?php if ( in_array ( 'updateSortieCaisse' , $user_permission )) { ?>
< th > Action< / th >
<?php } ?>
<?php
} elseif ($users['group_name'] === 'Direction' || $users['group_name'] === 'DAF' || $users['group_name'] === 'SuperAdmin') {
?>
< th > #< / th >
< th > Montant< / th >
< th > Date< / th >
< th > Caissier< / th >
< th > Motif< / th >
< th > Source de fond< / th >
< th > Initiateur de demande< / th >
< th > Point de vente< / th >
< th > Commentaire< / th >
< th > Statut< / th >
<?php if ( in_array ( 'updateSortieCaisse' , $user_permission ) || in_array ( 'validateSortieCaisse' , $user_permission )) { ?>
< th > Action< / th >
<?php } ?>
<?php
} else {
?>
< th > #< / th >
< th > Montant< / th >
< th > Date< / th >
< th > Caissier< / th >
< th > Motif< / th >
< th > Statut< / th >
< th > Raison de validation< / th >
<?php if ( in_array ( 'updateSortieCaisse' , $user_permission )) { ?>
< th > Action< / th >
<?php } ?>
<?php } ?>
< / tr >
< / thead >
< / table >
< / div >
< / div >
< div class = "row mb-3" >
< div class = "col-md-12" >
< div class = "btn-group float-right" role = "group" >
< a href = " <? = base_url ( 'sortieCaisse/exportExcel' ) ?> "
class="btn btn-success">
< i class = "fa fa-file-excel-o" > < / i > Exporter Excel
< / a >
< a href = " <? = base_url ( 'sortieCaisse/exportCsv' ) ?> "
class="btn btn-info">
< i class = "fa fa-file-text-o" > < / i > Exporter CSV
< / a >
< / div >
< / div >
< / div >
<!-- Optionnel: Formulaire de filtres pour l'exportation -->
< div class = "row mb-3" >
< div class = "col-md-12" >
< div class = "card" >
< div class = "card-header" >
< h4 > Exporter avec filtres< / h4 >
< / div >
< div class = "card-body" >
< form id = "exportFilterForm" class = "form-inline" >
< div class = "form-group mr-2" >
< label for = "date_debut" class = "mr-2" > Date début:< / label >
< input type = "date" class = "form-control" id = "date_debut" name = "date_debut" >
< / div >
< div class = "form-group mr-2" >
< label for = "date_fin" class = "mr-2" > Date fin:< / label >
< input type = "date" class = "form-control" id = "date_fin" name = "date_fin" >
< / div >
< div class = "form-group mr-2" >
< label for = "statut" class = "mr-2" > Statut:< / label >
< select class = "form-control" id = "statut" name = "statut" >
< option value = "" > Tous< / option >
< option value = "En attente" > En attente< / option >
< option value = "Valider" > Validé< / option >
< option value = "Refuser" > Refusé< / option >
< / select >
< / div >
< div class = "btn-group" role = "group" >
< button type = "button" class = "btn btn-success" onclick = "exportFiltered('excel')" >
< i class = "fa fa-file-excel-o" > < / i > Excel
< / button >
< button type = "button" class = "btn btn-info" onclick = "exportFiltered('csv')" >
< i class = "fa fa-file-text-o" > < / i > CSV
< / button >
< / div >
< / form >
< / div >
< / div >
< / div >
< / div >
< / div >
< / div >
< / section >
< / div >
<!-- Modal pour la Création -->
<?php if ( in_array ( 'createSortieCaisse' , $user_permission )) : ?>
< div class = "modal fade" tabindex = "-1" role = "dialog" id = "createModal" >
< div class = "modal-dialog modal-lg" role = "document" >
< div class = "modal-content" >
< div class = "modal-header" >
< button type = "button" class = "close" data-dismiss = "modal" aria-label = "Close" >
< span aria-hidden = "true" > × < / span >
< / button >
< h4 class = "modal-title" > Ajouter un décaissement< / h4 >
< / div >
< form role = "form" id = "create_form_sortie" enctype = "multipart/form-data" >
< div class = "modal-body" >
<!-- FORMULAIRE IM1 (Décaissement simple) - CORRIGÉ -->
< div id = "form-im1" >
< div class = "text-center" style = "margin-bottom: 20px;" >
< h3 style = "border-bottom: 2px solid #333; padding-bottom: 10px;" > DEMANDE DE SORTIE DE CAISSE< / h3 >
< / div >
< div class = "row" >
< div class = "col-md-6 mb-3" >
< label for = "nom" class = "form-label" > Nom< / label >
< input type = "text" class = "form-control" id = "nom" name = "nom" placeholder = "Votre nom" autocomplete = "off" required >
< / div >
< div class = "col-md-6 mb-3" >
< label for = "fonction" class = "form-label" > Fonction< / label >
< input type = "text" class = "form-control" id = "fonction" name = "fonction" placeholder = "Votre fonction" autocomplete = "off" required >
< / div >
< / div >
< div class = "row" >
< div class = "col-md-6 mb-3" >
< label for = "motif_select" class = "form-label" > Motif< / label >
<!-- Select avec liste + option "Autre" -->
< select class = "form-control" id = "motif_select_dropdown" name = "motif_select_dropdown" >
<?php
$session = session();
$users = $session->get('user');
$isAdmin = $users['group_name'] == "Direction" || $users['group_name'] == "SuperAdmin" || $users['group_name'] == "DAF";
$isCaissier = $users['group_name'] == "Caissière";
$options = $isAdmin ? $admin_options : $caissier_options;
echo "< option value = '' > Veuillez sélectionner une raison< / option > \n";
foreach ($options as $option) {
echo "< option value = \"" . htmlspecialchars ( $ option ) . " \ " > " . htmlspecialchars($option) . "< / option > \n";
}
?>
< option value = "AUTRE" > ✏️ Autre (saisir manuellement)< / option >
< / select >
<!-- Input caché qui s'affiche quand on choisit "Autre" -->
< input
type="text"
class="form-control"
id="motif_select_custom"
name="motif_select_custom"
placeholder="Saisissez votre motif personnalisé"
style="display: none; margin-top: 10px;"
>
<!-- Champ caché pour envoyer la valeur finale -->
< input type = "hidden" id = "motif_select" name = "motif_select" required >
< small class = "text-muted" style = "display: block; margin-top: 5px;" >
< i class = "fa fa-info-circle" > < / i > Sélectionnez un motif prédéfini ou choisissez "Autre" pour saisir librement
< / small >
< / div >
< div class = "col-md-6 mb-3" >
< label for = "mode_paiement" class = "form-label" > Mode de paiement< / label >
< select class = "form-control" id = "mode_paiement" name = "mode_paiement" required >
< option value = "En espèce" > En espèce< / option >
< option value = "MVOLA" > MVOLA< / option >
< option value = "Virement Bancaire" > Virement Bancaire< / option >
< / select >
< / div >
< / div >
< div class = "row" >
< div class = "col-md-6 mb-3" >
< label for = "montant_retire" class = "form-label" > Montant< / label >
<!-- CORRECTION ICI : id ET name doivent être "montant_retire" -->
< input type = "text" class = "form-control" id = "montant_retire" name = "montant_retire" placeholder = "Montant à retirer" autocomplete = "off" required >
< / div >
< div class = "col-md-6 mb-3" >
< label for = "montant_lettre" class = "form-label" > Montant en lettre< / label >
< input type = "text" class = "form-control" id = "montant_lettre" name = "montant_lettre" placeholder = "Montant en toutes lettres" readonly >
< / div >
< / div >
< div class = "row" >
< div class = "col-md-6 mb-3" >
< label for = "date_demande" class = "form-label" > Date< / label >
< input type = "date" class = "form-control" id = "date_demande" name = "date_demande" required >
< / div >
< div class = "col-md-6 mb-3" >
< label for = "reference" class = "form-label" > Référence< / label >
< input type = "text" class = "form-control" id = "reference" name = "reference" placeholder = "Référence" autocomplete = "off" >
< / div >
< / div >
< div class = "row text-center" style = "margin-top: 30px;" >
< div class = "col-md-4" >
< strong > DEMANDEUR< / strong >
< / div >
< div class = "col-md-4" >
< strong > DIRECTION< / strong >
< / div >
< div class = "col-md-4" >
< strong > CAISSE/COMPTA< / strong >
< / div >
< / div >
< / div >
<!-- FORMULAIRE IM2 et IM3 (Pour montant > 1,000,000 Ar) -->
< div id = "form-im23" style = "display: none;" >
<!-- Bouton de retour -->
< div class = "row mb-3" >
< div class = "col-md-12" >
< button type = "button" id = "back-to-im1" class = "btn btn-default btn-sm" >
< i class = "fa fa-arrow-left" > < / i > Retour à la demande simple
< / button >
< / div >
< / div >
< div class = "text-center" style = "margin-bottom: 20px;" >
< h3 style = "border-bottom: 2px solid #333; padding-bottom: 10px;" > FICHE D'ENGAGEMENT DE DEPENSE< / h3 >
< / div >
< div class = "row" >
< div class = "col-md-6 mb-3" >
< label for = "numero_fiche" class = "form-label" > N°< / label >
< input type = "text" class = "form-control" id = "numero_fiche" name = "numero_fiche" placeholder = "Numéro de fiche" autocomplete = "off" >
< / div >
< div class = "col-md-6 mb-3" >
< label for = "date_fiche" class = "form-label" > Date< / label >
< input type = "date" class = "form-control" id = "date_fiche" name = "date_fiche" >
< / div >
< / div >
< h4 > I. IDENTIFICATION DE LA DEPENSE< / h4 >
< div class = "row" >
< div class = "col-md-6 mb-3" >
< label for = "service_demandeur" class = "form-label" > Service demandeur< / label >
< input type = "text" class = "form-control" id = "service_demandeur" name = "service_demandeur" placeholder = "Service demandeur" autocomplete = "off" >
< / div >
< div class = "col-md-6 mb-3" >
< label for = "nom_demandeur" class = "form-label" > Nom du demandeur< / label >
< input type = "text" class = "form-control" id = "nom_demandeur" name = "nom_demandeur" placeholder = "Nom du demandeur" autocomplete = "off" >
< / div >
< / div >
< div class = "row" >
< div class = "col-md-6 mb-3" >
< label for = "fonction_demandeur" class = "form-label" > Fonction< / label >
< input type = "text" class = "form-control" id = "fonction_demandeur" name = "fonction_demandeur" placeholder = "Fonction" autocomplete = "off" >
< / div >
< div class = "col-md-6 mb-3" >
< label for = "objet_depense" class = "form-label" > Objet de la dépense< / label >
< textarea class = "form-control" id = "objet_depense" name = "objet_depense" rows = "2" placeholder = "Objet de la dépense" > < / textarea >
< / div >
< / div >
< div class = "row" >
< div class = "col-md-12 mb-3" >
< label class = "form-label" > Nature de la dépense< / label > < br >
< div class = "form-check form-check-inline" >
< input class = "form-check-input" type = "radio" name = "nature_depense" id = "achat_materiel" value = "Achat matériel" >
< label class = "form-check-label" for = "achat_materiel" > Achat matériel< / label >
< / div >
< div class = "form-check form-check-inline" >
< input class = "form-check-input" type = "radio" name = "nature_depense" id = "prestation_service" value = "Prestation de service" >
< label class = "form-check-label" for = "prestation_service" > Prestation de service< / label >
< / div >
< div class = "form-check form-check-inline" >
< input class = "form-check-input" type = "radio" name = "nature_depense" id = "frais_mission" value = "Frais de mission / déplacement" >
< label class = "form-check-label" for = "frais_mission" > Frais de mission / déplacement< / label >
< / div >
< div class = "form-check form-check-inline" >
< input class = "form-check-input" type = "radio" name = "nature_depense" id = "avance_fonds" value = "Avance de fonds" >
< label class = "form-check-label" for = "avance_fonds" > Avance de fonds< / label >
< / div >
< div class = "form-check form-check-inline" >
< input class = "form-check-input" type = "radio" name = "nature_depense" id = "autre_nature" value = "Autre" >
< label class = "form-check-label" for = "autre_nature" > Autres (à préciser)< / label >
< / div >
< / div >
< / div >
< div class = "row" >
< div class = "col-md-4 mb-3" >
< label for = "montant_estime" class = "form-label" > Montant estimatif (en ariary)< / label >
< input type = "text" class = "form-control" id = "montant_estime" name = "montant_estime" placeholder = "Montant estimatif" autocomplete = "off" >
< / div >
< div class = "col-md-4 mb-3" >
< label class = "form-label" > Mode de règlement< / label > < br >
< div class = "form-check" >
< input class = "form-check-input" type = "radio" name = "mode_reglement" id = "espece" value = "En espèce" >
< label class = "form-check-label" for = "espece" > En espèce< / label >
< / div >
< div class = "form-check" >
< input class = "form-check-input" type = "radio" name = "mode_reglement" id = "virement" value = "Virement Bancaire" >
< label class = "form-check-label" for = "virement" > Virement Bancaire< / label >
< / div >
< div class = "form-check" >
< input class = "form-check-input" type = "radio" name = "mode_reglement" id = "mvola" value = "MVOLA" >
< label class = "form-check-label" for = "mvola" > MVOLA< / label >
< / div >
< / div >
< div class = "col-md-4 mb-3" >
< label for = "date_paiement_prevue" class = "form-label" > Date prévue de paiement< / label >
< input type = "date" class = "form-control" id = "date_paiement_prevue" name = "date_paiement_prevue" >
< / div >
< / div >
< h4 > II. JUSTIFICATIFS< / h4 >
< div class = "row" >
< div class = "col-md-12 mb-3" >
< div class = "form-check" >
< input class = "form-check-input" type = "checkbox" id = "devis_facture" name = "justificatifs[]" value = "Devis / facture pro forma" >
< label class = "form-check-label" for = "devis_facture" > Devis / facture pro forma< / label >
< / div >
< div class = "form-check" >
< input class = "form-check-input" type = "checkbox" id = "contrat_commande" name = "justificatifs[]" value = "Contrat / bon de commande" >
< label class = "form-check-label" for = "contrat_commande" > Contrat / bon de commande< / label >
< / div >
< div class = "form-check" >
< input class = "form-check-input" type = "checkbox" id = "demande_interne" name = "justificatifs[]" value = "Demande interne" >
< label class = "form-check-label" for = "demande_interne" > Demande interne< / label >
< / div >
< div class = "form-check" >
< input class = "form-check-input" type = "checkbox" id = "autre_justificatif" name = "justificatifs[]" value = "Autre" >
< label class = "form-check-label" for = "autre_justificatif" > Autre :< / label >
< input type = "text" class = "form-control mt-1" id = "autre_justificatif_precis" name = "autre_justificatif_precis" placeholder = "Préciser" >
< / div >
< / div >
< / div >
< h4 > III. VISAS ET VALIDATIONS< / h4 >
< table class = "table table-bordered" >
< thead >
< tr >
< th > Fonction< / th >
< th > Nom et signature< / th >
< th > Date< / th >
< / tr >
< / thead >
< tbody >
< tr >
< td > Demandeur< / td >
< td > < input type = "text" class = "form-control" name = "visa_demandeur" placeholder = "Nom et signature" > < / td >
< td > < input type = "date" class = "form-control" name = "date_visa_demandeur" > < / td >
< / tr >
< tr >
< td > Chef de service / Responsable hiérarchique< / td >
< td > < input type = "text" class = "form-control" name = "visa_chef_service" placeholder = "Nom et signature" > < / td >
< td > < input type = "date" class = "form-control" name = "date_visa_chef_service" > < / td >
< / tr >
< tr >
< td > Direction< / td >
< td > < input type = "text" class = "form-control" name = "visa_direction" placeholder = "Nom et signature" > < / td >
< td > < input type = "date" class = "form-control" name = "date_visa_direction" > < / td >
< / tr >
< tr >
< td > SuperAdmin< / td >
< td > < input type = "text" class = "form-control" name = "visa_superAdmin" placeholder = "Nom et signature" > < / td >
< td > < input type = "date" class = "form-control" name = "date_superAdmin" > < / td >
< / tr >
< / tbody >
< / table >
< h4 > IV. OBSERVATIONS ET REMARQUES< / h4 >
< div class = "row" >
< div class = "col-md-12 mb-3" >
< textarea class = "form-control" id = "observations" name = "observations" rows = "3" placeholder = "Observations et remarques" > < / textarea >
< / div >
< / div >
< div class = "alert alert-info" >
< strong > NB :< / strong > Cette fiche doit être jointe à la demande de sortie de caisse pour toute dépense supérieure à 1 000 000 Ar ou toute dépense nécessitant une traçabilité spécifique
< / div >
< / div >
< / div >
< div class = "modal-footer text-right" style = "margin-top: 15px;" >
< button type = "button" class = "btn btn-default" data-dismiss = "modal" > Annuler< / button >
< button type = "submit" class = "btn btn-primary" > Enregistrer< / button >
< / div >
< / form >
< / div >
< / div >
< / div >
<?php endif ; ?>
<!-- Modal for updatting a recouvrement -->
<!-- Modal for updating a sortie caisse --> <!-- Modal for updating a sortie caisse -->
<?php if ( in_array ( 'updateSortieCaisse' , $user_permission )) : ?>
< div class = "modal fade" tabindex = "-1" role = "dialog" id = "updateModal" >
< div class = "modal-dialog modal-lg" role = "document" >
< div class = "modal-content" >
< div class = "modal-header" >
< button type = "button" class = "close" data-dismiss = "modal" aria-label = "Close" >
< span aria-hidden = "true" > × < / span >
< / button >
< h4 class = "modal-title" > < i class = "fa fa-pencil" > < / i > Modifier un décaissement< / h4 >
< / div >
< form role = "form" id = "update_form" enctype = "multipart/form-data" >
< div class = "modal-body" >
<!-- Légende des champs -->
< div class = "field-legend" >
< div >
< strong > < i class = "fa fa-info-circle" > < / i > Légende :< / strong >
< / div >
< div class = "legend-item" >
< i class = "fa fa-lock text-muted" > < / i > Champs verrouillés (lecture seule)
< / div >
< div class = "legend-item" >
< i class = "fa fa-edit text-primary" > < / i > Champs modifiables
< / div >
< / div >
<!-- Informations de base - VERROUILLÉES -->
< div class = "row" >
< div class = "col-md-6 mb-3" >
< label for = "nom_edit" class = "form-label" > < i class = "fa fa-lock text-muted" > < / i > Nom< / label >
< input type = "text" class = "form-control" id = "nom_edit" name = "nom_edit" placeholder = "Votre nom" autocomplete = "off" required readonly style = "background-color: #e9ecef; cursor: not-allowed;" >
< / div >
< div class = "col-md-6 mb-3" >
< label for = "fonction_edit" class = "form-label" > < i class = "fa fa-lock text-muted" > < / i > Fonction< / label >
< input type = "text" class = "form-control" id = "fonction_edit" name = "fonction_edit" placeholder = "Votre fonction" autocomplete = "off" required readonly style = "background-color: #e9ecef; cursor: not-allowed;" >
< / div >
< / div >
<!-- Motif et Mode de paiement -->
< div class = "row" >
< div class = "col-md-6 mb-3" >
< label for = "motif_select_edit" class = "form-label" >
< i class = "fa fa-lock text-muted" > < / i > Motif
< / label >
<!-- Select désactivé pour l'affichage -->
< select class = "form-control" id = "motif_select_edit_dropdown" disabled style = "background-color: #e9ecef; cursor: not-allowed;" >
<?php
$session = session();
$users = $session->get('user');
$isAdmin = $users['group_name'] == "Direction" || $users['group_name'] == "SuperAdmin" || $users['group_name'] == "DAF";
$options = $isAdmin ? $admin_options : $caissier_options;
echo "< option value = '' > Veuillez sélectionner une raison< / option > \n";
foreach ($options as $option) {
echo "< option value = \"" . htmlspecialchars ( $ option ) . " \ " > " . htmlspecialchars($option) . "< / option > \n";
}
?>
< / select >
<!-- Champ caché pour envoyer la valeur (car le select est disabled) -->
< input type = "hidden" id = "motif_select_edit" name = "motif_select_edit" >
< small class = "motif-help-text" >
< i class = "fa fa-info-circle" > < / i > Le motif ne peut pas être modifié
< / small >
< / div >
< div class = "col-md-6 mb-3" >
< label for = "mode_paiement_edit" class = "form-label" > < i class = "fa fa-edit text-primary" > < / i > Mode de paiement< / label >
< select class = "form-control" id = "mode_paiement_edit" name = "mode_paiement_edit" required >
< option value = "En espèce" > En espèce< / option >
< option value = "MVOLA" > MVOLA< / option >
< option value = "Virement Bancaire" > Virement Bancaire< / option >
< / select >
< small class = "text-muted" > < i class = "fa fa-info-circle" > < / i > Assurez-vous que les fonds sont disponibles pour ce mode< / small >
< / div >
< / div >
<!-- Montant - VERROUILLÉ -->
< div class = "row" >
< div class = "col-md-6 mb-3" >
< label for = "montant_retire_edit" class = "form-label" > < i class = "fa fa-lock text-muted" > < / i > Montant< / label >
< input type = "text" class = "form-control" id = "montant_retire_edit" name = "montant_retire_edit" placeholder = "Montant à retirer" autocomplete = "off" required readonly style = "background-color: #e9ecef; cursor: not-allowed;" >
< / div >
< div class = "col-md-6 mb-3" >
< label for = "montant_lettre_edit" class = "form-label" > < i class = "fa fa-lock text-muted" > < / i > Montant en lettre< / label >
< input type = "text" class = "form-control" id = "montant_lettre_edit" name = "montant_lettre_edit" placeholder = "Montant en toutes lettres" autocomplete = "off" required readonly style = "background-color: #e9ecef; cursor: not-allowed;" >
< / div >
< / div >
<!-- Date et Référence - VERROUILLÉES -->
< div class = "row" >
< div class = "col-md-6 mb-3" >
< label for = "date_demande_edit" class = "form-label" > < i class = "fa fa-lock text-muted" > < / i > Date< / label >
< input type = "date" class = "form-control" id = "date_demande_edit" name = "date_demande_edit" required readonly style = "background-color: #e9ecef; cursor: not-allowed;" >
< / div >
< div class = "col-md-6 mb-3" >
< label for = "reference_edit" class = "form-label" > < i class = "fa fa-lock text-muted" > < / i > Référence< / label >
< input type = "text" class = "form-control" id = "reference_edit" name = "reference_edit" placeholder = "Référence" autocomplete = "off" readonly style = "background-color: #e9ecef; cursor: not-allowed;" >
< / div >
< / div >
< hr style = "border-top: 2px dashed #007bff; margin: 25px 0;" >
< h5 style = "color: #007bff; margin-bottom: 15px;" > < i class = "fa fa-edit" > < / i > Informations modifiables< / h5 >
<!-- Commentaire - ÉDITABLE -->
< div class = "row" >
< div class = "col-md-12 mb-3" >
< label for = "sortie_commentaire_edit" class = "form-label" >
< i class = "fa fa-edit text-primary" > < / i > Commentaire
< / label >
< textarea class = "form-control" id = "sortie_commentaire_edit" name = "sortie_commentaire_edit" rows = "3" style = "resize: vertical;" placeholder = "Votre commentaire" autocomplete = "off" > < / textarea >
< / div >
< / div >
<!-- Informations fournisseur - ÉDITABLES -->
< div class = "row" >
< div class = "col-md-4 mb-3" >
< label for = "sortie_fournisseur_edit" class = "form-label" >
< i class = "fa fa-edit text-primary" > < / i > Fournisseur & Prestataire
< / label >
< input type = "text" class = "form-control" id = "sortie_fournisseur_edit" name = "sortie_fournisseur_edit" placeholder = "Entrer le fournisseur ou le prestataire" autocomplete = "off" >
< / div >
< div class = "col-md-4 mb-3" >
< label for = "sortie_nif_edit" class = "form-label" >
< i class = "fa fa-edit text-primary" > < / i > NIF & CIN
< / label >
< input type = "text" class = "form-control" id = "sortie_nif_edit" name = "sortie_nif_edit" placeholder = "NIF ou CIN" autocomplete = "off" >
< / div >
< div class = "col-md-4 mb-3" >
< label for = "sortie_statistique_edit" class = "form-label" >
< i class = "fa fa-edit text-primary" > < / i > Statistique
< / label >
< input type = "text" class = "form-control" id = "sortie_statistique_edit" name = "sortie_statistique_edit" placeholder = "Statistique du décaissement" autocomplete = "off" >
< / div >
< / div >
<!-- Coordonnées - ÉDITABLES -->
< div class = "row" >
< div class = "col-md-4 mb-3" >
< label for = "sortie_phone_edit" class = "form-label" >
< i class = "fa fa-edit text-primary" > < / i > Numéro téléphone
< / label >
< input type = "text" class = "form-control" id = "sortie_phone_edit" name = "sortie_phone_edit" placeholder = "Entrer le numéro de téléphone" autocomplete = "off" >
< / div >
< div class = "col-md-4 mb-3" >
< label for = "sortie_adresse_edit" class = "form-label" >
< i class = "fa fa-edit text-primary" > < / i > Code postal
< / label >
< input type = "text" class = "form-control" id = "sortie_adresse_edit" name = "sortie_adresse_edit" placeholder = "Entrer le code postal" autocomplete = "off" >
< / div >
< div class = "col-md-4 mb-3" >
< label for = "sortie_preuve_edit" class = "form-label" >
< i class = "fa fa-edit text-primary" > < / i > Preuve d'achat
< small class = "text-muted" > (Facultatif)< / small >
< / label >
< input type = "file" accept = ".pdf, .txt, .xls, .xlsx, .csv" class = "form-control" id = "sortie_preuve_edit" name = "sortie_preuve_edit" >
< small class = "text-muted" id = "current_preuve_text" > < / small >
< / div >
< / div >
< / div >
< div class = "modal-footer text-right" style = "margin-top: 15px;" >
< button type = "button" class = "btn btn-default" data-dismiss = "modal" >
< i class = "fa fa-times" > < / i > Annuler
< / button >
< button type = "submit" class = "btn btn-primary" >
< i class = "fa fa-save" > < / i > Enregistrer les modifications
< / button >
< / div >
< / form >
< / div >
< / div >
< / div >
<?php endif ; ?>
<!-- Modal for validating a recouvrement -->
<?php if ( in_array ( 'validateSortieCaisse' , $user_permission )) : ?>
< div class = "modal fade" tabindex = "-1" role = "dialog" id = "validateModal" >
< div class = "modal-dialog" role = "document" >
< div class = "modal-content" >
< div class = "modal-header" >
< button type = "button" class = "close" data-dismiss = "modal" aria-label = "Close" > < span aria-hidden = "true" > × < / span > < / button >
< h4 class = "modal-title" > Valider un décaissement< / h4 >
< / div >
< form role = "form" action = " <?php echo base_url ( 'sortieCaisse/validateSortieCaisse' ) ?> " method = "post" id = "validate_form" >
< div class = "modal-body" >
< div class = "row form-group" >
< div class = "col-lg-6" >
< label for = "validation" class = "control-label" > statut :< / label >
< / div >
< div class = "col-lg-6" >
< div class = "form-group" >
< label for = "admin_raison" > Raison de validation< / label >
< input type = "text" class = "form-control" id = "admin_raison" name = "admin_raison" >
< / div >
< div class = "form-group" >
< label for = "statut" > Statut du décaissement< / label >
< select name = "statut" id = "statut" class = "form-control" >
< option value = "En attente" selected > En attente< / option >
< option value = "Valider" > ✔ Valider< / option >
< option value = "Refuser" > ✖ Refuser< / option >
< / select >
< / div >
< / div >
< / div >
< / div >
< div class = "modal-footer" >
< button type = "button" class = "btn btn-default" data-dismiss = "modal" > Annuler< / button >
< button type = "submit" class = "btn btn-primary" > Enregistrer< / button >
< / div >
< / form >
< / div >
< / div >
< / div >
<?php endif ; ?>
< script >
// ============================================
// CONVERSION NOMBRE EN LETTRES (FRANÇAIS)
// ============================================
function numberToFrenchWords(n) {
const units = [
'', 'un', 'deux', 'trois', 'quatre', 'cinq', 'six', 'sept', 'huit', 'neuf',
'dix', 'onze', 'douze', 'treize', 'quatorze', 'quinze', 'seize',
'dix-sept', 'dix-huit', 'dix-neuf'
];
const tens = [
'', '', 'vingt', 'trente', 'quarante', 'cinquante',
'soixante', 'soixante', 'quatre-vingt', 'quatre-vingt'
];
if (n === 0) return 'zéro';
if (n < 0 ) return ' moins ' + numberToFrenchWords ( -n ) ;
let words = '';
if (Math.floor(n / 1000000000) > 0) {
words += numberToFrenchWords(Math.floor(n / 1000000000)) + ' milliard' + (n >= 2000000000 ? 's ' : ' ');
n %= 1000000000;
}
if (Math.floor(n / 1000000) > 0) {
words += numberToFrenchWords(Math.floor(n / 1000000)) + ' million' + (n >= 2000000 ? 's ' : ' ');
n %= 1000000;
}
if (Math.floor(n / 1000) > 0) {
if (Math.floor(n / 1000) === 1) {
words += 'mille ';
} else {
words += numberToFrenchWords(Math.floor(n / 1000)) + ' mille ';
}
n %= 1000;
}
if (Math.floor(n / 100) > 0) {
if (Math.floor(n / 100) === 1) {
words += 'cent ';
} else {
words += numberToFrenchWords(Math.floor(n / 100)) + ' cent';
if (n % 100 === 0) words += 's';
words += ' ';
}
n %= 100;
}
if (n > 0) {
if (n < 20 ) {
words += units[n];
} else {
let ten = Math.floor(n / 10);
let unit = n % 10;
if (ten === 7 || ten === 9) {
ten--;
unit += 10;
}
words += tens[ten];
if (unit === 1 & & (ten === 1 || (ten > 1 & & ten < 8 ) ) ) {
words += '-et-un';
} else if (unit > 0) {
words += '-' + units[unit];
}
if (ten === 8 & & unit === 0) words += 's';
}
}
return words.trim();
}
// ============================================
// FORMATAGE PAR GROUPE DE 3
// ============================================
function formatNumberBy3(num) {
return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ' ');
}
// ============================================
// FONCTION D'EXPORTATION FILTRÉE
// ============================================
function exportFiltered(format) {
const dateDebut = document.getElementById('date_debut').value;
const dateFin = document.getElementById('date_fin').value;
const statut = document.getElementById('statut').value;
let url = '<? = base_url ( 'sortieCaisse/exportWithFilters' ) ?> ?format=' + format;
if (dateDebut) url += '& date_debut=' + dateDebut;
if (dateFin) url += '& date_fin=' + dateFin;
if (statut) url += '& statut=' + encodeURIComponent(statut);
window.location.href = url;
}
// ============================================
// SCRIPT PRINCIPAL
// ============================================
$(document).ready(function() {
// Configuration DataTable FR
$.extend(true, $.fn.dataTable.defaults, {
language: {
sProcessing: "Traitement en cours...",
sSearch: "Rechercher :",
sLengthMenu: "Afficher _MENU_ é lé ments",
sInfo: "Affichage de l'é lement _START_ à _END_ sur _TOTAL_ é lé ments",
sInfoEmpty: "Affichage de l'é lement 0 à 0 sur 0 é lé ment",
sInfoFiltered: "(filtré de _MAX_ é lé ments au total)",
sLoadingRecords: "Chargement en cours...",
sZeroRecords: "Aucun é lé ment à afficher",
sEmptyTable: "Aucune donné e disponible dans le tableau",
oPaginate: {
sFirst: "Premier",
sPrevious: "Pré cé dent",
sNext: "Suivant",
sLast: "Dernier"
},
oAria: {
sSortAscending: ": activer pour trier la colonne par ordre croissant",
sSortDescending: ": activer pour trier la colonne par ordre dé croissant"
}
}
});
$("#sortie_caisse_menu").addClass('active');
var manageTable = $('#manageTable').DataTable({
ajax: '<? = base_url ( 'sortieCaisse/fetchSortieCaisseData' ) ?> ',
order: [],
columnDefs: [
{ targets: 1, className: 'text-right rowmontant' }
]
});
// ============================================
// INITIALISATION DES DATES
// ============================================
const today = new Date().toISOString().split('T')[0];
$('#date_demande').val(today);
$('#date_fiche').val(today);
// ============================================
// ✅ GESTION DU CHAMP MOTIF SELECT MODIFIABLE
// ============================================
// Gestion du select motif avec option personnalisée
$('#motif_select_dropdown').on('change', function() {
const selectedValue = $(this).val();
if (selectedValue === 'AUTRE') {
// Afficher le champ de saisie libre
$('#motif_select_custom').show().focus();
$('#motif_select').val(''); // Vider le champ caché
} else {
// Cacher le champ de saisie et utiliser la valeur sélectionnée
$('#motif_select_custom').hide().val('');
$('#motif_select').val(selectedValue);
}
});
// Mettre à jour le champ caché quand on tape dans le champ personnalisé
$('#motif_select_custom').on('input', function() {
const customValue = $(this).val();
$('#motif_select').val(customValue);
});
// ============================================
// GESTION DU MONTANT ET CONVERSION EN LETTRES
// ============================================
const montantInput = $('#montant_retire');
const montantLettreInput = $('#montant_lettre');
montantInput.on('input', function() {
let value = this.value.replace(/\s/g, '');
if (isNaN(value) || value === '') {
montantLettreInput.val('');
return;
}
const num = parseInt(value, 10);
this.value = formatNumberBy3(value);
const words = numberToFrenchWords(num);
montantLettreInput.val(words + ' ariary');
// ✅ Gestion du basculement de formulaire - CORRIGÉ >= 1000000
if (num >= 1000000) {
$('#nom_demandeur').val($('#nom').val());
$('#fonction_demandeur').val($('#fonction').val());
$('#montant_estime').val(this.value);
$('#date_fiche').val($('#date_demande').val());
$('#form-im1').hide();
$('#form-im23').show();
} else {
$('#form-im1').show();
$('#form-im23').hide();
}
});
// Retour au formulaire simple
$('#back-to-im1').on('click', function() {
$('#form-im23').hide();
$('#form-im1').show();
montantInput.val('999999');
montantInput.trigger('input');
});
// Synchronisation des montants
montantInput.on('change', function() {
$('#montant_estime').val($(this).val());
});
$('#montant_estime').on('change', function() {
montantInput.val($(this).val());
montantInput.trigger('input');
});
// ✅ Réinitialisation du modal - AVEC RÉINITIALISATION DU MOTIF
$('#createModal').on('hidden.bs.modal', function () {
$('#form-im1').show();
$('#form-im23').hide();
$('#create_form_sortie')[0].reset();
$('#date_demande').val(today);
$('#date_fiche').val(today);
montantLettreInput.val('');
// ✅ Réinitialiser les champs motif
$('#motif_select_dropdown').val('');
$('#motif_select_custom').hide().val('');
$('#motif_select').val('');
});
// ============================================
// FILTRES
// ============================================
$('#filteredB1').on('click', function () {
const startDate = $('#startDate').val();
const endDate = $('#endDate').val();
const pvente = $('#pvente').val();
const s_statut = $('#s_statut').val();
manageTable.ajax.url('<? = base_url ( 'sortieCaisse/fetchSortieCaisseData' ) ?> ').load(function () {
const filteredData = [];
manageTable.rows().every(function () {
const data = this.data();
const SortieDate = data[2].split(' ')[0];
<?php
$session = session();
$users = $session->get('user');
$isAdmin = $users['group_name'] == "Direction" || $users['group_name'] == "SuperAdmin" || $users['group_name'] == "DAF";
?>
<?php if ( $isAdmin ) : ?>
const sortie_statut1 = data[9].split(' ')[0];
const store = data[7];
<?php else : ?>
const sortie_statut1 = data[5].split(' ')[0];
const store = 'TOUS';
<?php endif ; ?>
const dateMatch = (!startDate & & !endDate) ||
(startDate & & endDate & & SortieDate >= startDate & & SortieDate < = endDate) ||
(startDate & & !endDate & & SortieDate >= startDate) ||
(!startDate & & endDate & & SortieDate < = endDate);
const storeMatch = (pvente === 'TOUS' || pvente === store);
const statutMatch = (s_statut === 'TOUS' || s_statut === sortie_statut1);
if (dateMatch & & storeMatch & & statutMatch) {
filteredData.push(data);
}
});
manageTable.clear().rows.add(filteredData).draw();
});
});
$('#validate_filtered').on('click', function () {
manageTable.ajax.url('<? = base_url ( 'sortieCaisse/fetchSortieCaisseData1' ) ?> ').load();
});
// ============================================
// ✅ CRÉATION AVEC SWEETALERT2 + VALIDATION MOTIF
// ============================================
$("#create_form_sortie").unbind('submit').on('submit', function(e) {
e.preventDefault();
$(".text-danger").remove();
// ✅ Validation du motif
const motifValue = $('#motif_select').val();
if (!motifValue || motifValue.trim() === '') {
Swal.fire({
icon: 'warning',
title: 'Motif requis',
text: 'Veuillez sélectionner ou saisir un motif',
confirmButtonColor: '#f39c12'
});
return false;
}
var formData = new FormData(this);
// CORRECTION : Nettoyer le montant des espaces avant validation
const montantRaw = $('#montant_retire').val();
const montantClean = montantRaw.replace(/\s/g, '');
// Vérification du montant avant l'envoi
const montant = parseFloat(montantClean);
if (isNaN(montant) || montant < = 0) {
Swal.fire({
icon: 'error',
title: 'Montant invalide',
text: 'Veuillez saisir un montant valide supérieur à 0',
confirmButtonColor: '#dc3545'
});
return false;
}
// CORRECTION : Remplacer la valeur dans le FormData
formData.set('montant_retire', montantClean);
// Afficher un loader
Swal.fire({
title: 'Création en cours...',
html: 'Vérification des fonds disponibles...',
allowOutsideClick: false,
showConfirmButton: false,
didOpen: () => {
Swal.showLoading();
}
});
$.ajax({
url: '<? = base_url ( 'sortieCaisse/createSortieCaisse' ) ?> ',
type: 'post',
data: formData,
processData: false,
contentType: false,
dataType: 'json',
success: function(response) {
manageTable.ajax.reload(null, false);
if (response.success === true) {
Swal.fire({
icon: 'success',
title: 'Décaissement créé !',
html: response.messages,
confirmButtonText: 'Fermer',
confirmButtonColor: '#28a745',
customClass: {
popup: 'animated fadeInDown'
}
}).then(() => {
$("#createModal").modal('hide');
$("#create_form_sortie")[0].reset();
$("#create_form_sortie .form-group").removeClass('has-error has-success');
$('#date_demande').val(today);
$('#date_fiche').val(today);
// ✅ Réinitialiser les champs motif
$('#motif_select_dropdown').val('');
$('#motif_select_custom').hide().val('');
$('#motif_select').val('');
});
} else {
// Gestion des erreurs avec SweetAlert
if (response.messages instanceof Object) {
let errorHtml = '< ul style = "text-align: left; margin: 10px 0;" > ';
$.each(response.messages, function(index, value) {
errorHtml += '< li style = "margin: 5px 0;" > ' + value + '< / li > ';
var id = $("#" + index);
id.closest('.form-group')
.removeClass('has-error has-success')
.addClass('has-error');
id.after('< span class = "text-danger" > ' + value + '< / span > ');
});
errorHtml += '< / ul > ';
Swal.fire({
icon: 'warning',
title: 'Erreurs de validation',
html: errorHtml,
confirmButtonText: 'Corriger',
confirmButtonColor: '#f39c12',
customClass: {
popup: 'animated shake'
}
});
} else {
// Affichage amélioré pour les erreurs de fonds insuffisants
const isInsufficientFunds = response.messages.includes('insuffisants');
Swal.fire({
icon: isInsufficientFunds ? 'warning' : 'error',
title: isInsufficientFunds ? '⚠️ Fonds insuffisants' : 'Erreur',
html: '< div style = "text-align: left;" > ' + response.messages + '< / div > ',
confirmButtonText: 'Fermer',
confirmButtonColor: isInsufficientFunds ? '#f39c12' : '#dc3545',
width: '600px',
customClass: {
popup: 'animated fadeInDown'
}
});
}
}
},
error: function(xhr, status, error) {
console.error('Erreur AJAX:', error);
Swal.fire({
icon: 'error',
title: 'Erreur serveur',
html: '< p > Une erreur est survenue lors de la création du décaissement.< / p > ' +
'< p > < small > Détails techniques: ' + error + '< / small > < / p > ',
confirmButtonText: 'Fermer',
confirmButtonColor: '#dc3545'
});
}
});
return false;
});
// ============================================
// ✅ MODIFICATION AVEC SWEETALERT2 + GESTION MOTIF PERSONNALISÉ
// ============================================
window.editFunc = function(id) {
$.ajax({
url: '<? = base_url ( 'sortieCaisse/fetchSortieCaisseSingle' ) ?> /' + id,
type: 'post',
dataType: 'json',
success: function(response) {
// Remplir tous les champs
$("#montant_retire_edit").val(response.montant_retire);
$("#nom_edit").val(response.nom_demandeur);
$("#fonction_edit").val(response.fonction_demandeur);
$("#montant_lettre_edit").val(response.montant_lettre);
$("#date_demande_edit").val(response.date_demande);
$("#reference_edit").val(response.reference);
$("#sortie_commentaire_edit").val(response.commentaire);
$("#sortie_fournisseur_edit").val(response.fournisseur);
$("#sortie_nif_edit").val(response.nif_cin);
$("#sortie_statistique_edit").val(response.statistique);
$("#sortie_phone_edit").val(response.telephone);
$("#sortie_adresse_edit").val(response.code_postal);
const initialModePaiement = response.mode_paiement || 'En espèce';
$("#mode_paiement_edit").val(initialModePaiement);
// ✅ Gérer le motif - AVEC SUPPORT DES MOTIFS PERSONNALISÉS
const motif = response.motif;
const motifSelectDropdown = $("#motif_select_edit_dropdown");
// Vérifier si le motif existe dans la liste
const optionExists = motifSelectDropdown.find('option').filter(function() {
return $(this).val().trim().toLowerCase() === motif.trim().toLowerCase();
}).length > 0;
if (optionExists) {
motifSelectDropdown.val(motif);
} else {
// ✅ Si le motif n'existe pas, l'afficher quand même avec un indicateur
motifSelectDropdown.append('< option value = "' + motif + '" selected > 🔸 ' + motif + ' (personnalisé)< / option > ');
}
// Mettre la valeur dans le champ caché
$("#motif_select_edit").val(motif);
if (response.preuve_achat) {
$("#current_preuve_text").html('< br > < i class = "fa fa-file" > < / i > Fichier actuel: ' + response.preuve_achat);
} else {
$("#current_preuve_text").html('< br > < i class = "text-muted" > Aucun fichier< / i > ');
}
// Listener sur le mode de paiement
$("#mode_paiement_edit").off('change').on('change', function() {
const nouveauMode = $(this).val();
if (nouveauMode !== initialModePaiement) {
Swal.fire({
icon: 'warning',
title: 'Changement de mode de paiement',
html: '< div style = "text-align: center;" > ' +
'< strong > Attention !< / strong > < br > < br > ' +
'Vous changez le mode de paiement :< br > < br > ' +
'< span style = "font-size: 18px;" > ' +
'< span style = "color: #dc3545; font-weight: bold;" > ' + initialModePaiement + '< / span > ' +
' < i class = "fa fa-arrow-right" > < / i > ' +
'< span style = "color: #28a745; font-weight: bold;" > ' + nouveauMode + '< / span > ' +
'< / span > < br > < br > ' +
'< em style = "color: #856404;" > Assurez-vous que les fonds sont disponibles.< / em > ' +
'< / div > ',
showCancelButton: true,
confirmButtonText: '< i class = "fa fa-check" > < / i > Confirmer',
cancelButtonText: '< i class = "fa fa-times" > < / i > Annuler',
confirmButtonColor: '#007bff',
cancelButtonColor: '#6c757d'
}).then((result) => {
if (!result.isConfirmed) {
$("#mode_paiement_edit").val(initialModePaiement);
}
});
}
});
// Soumission du formulaire - CORRIGÉ
$("#update_form").unbind('submit').bind('submit', function(e) {
e.preventDefault();
$(".text-danger").remove();
var formData = new FormData(this);
// CORRECTION : Nettoyer le montant des espaces pour l'édition
const montantRawEdit = $('#montant_retire_edit').val();
const montantCleanEdit = montantRawEdit.replace(/\s/g, '');
formData.set('montant_retire', montantCleanEdit);
Swal.fire({
title: 'Modification en cours...',
html: 'Vérification des fonds disponibles...',
allowOutsideClick: false,
showConfirmButton: false,
didOpen: () => {
Swal.showLoading();
}
});
$.ajax({
url: '<? = base_url ( 'sortieCaisse/updateSortieCaisse' ) ?> /' + id,
type: 'post',
data: formData,
processData: false,
contentType: false,
dataType: 'json',
success: function(response) {
manageTable.ajax.reload(null, false);
if (response.success === true) {
Swal.fire({
icon: 'success',
title: 'Modification réussie !',
html: response.messages,
confirmButtonText: 'Fermer',
confirmButtonColor: '#28a745'
}).then(() => {
$("#updateModal").modal('hide');
$("#update_form")[0].reset();
});
} else {
if (response.messages instanceof Object) {
let errorHtml = '< ul style = "text-align: left;" > ';
$.each(response.messages, function(index, value) {
errorHtml += '< li > ' + value + '< / li > ';
var input = $("#" + index);
input.closest('.form-group').addClass('has-error');
input.after('< span class = "text-danger" > ' + value + '< / span > ');
});
errorHtml += '< / ul > ';
Swal.fire({
icon: 'warning',
title: 'Erreur de validation',
html: errorHtml,
confirmButtonText: 'Corriger',
confirmButtonColor: '#f39c12'
});
} else {
const isInsufficientFunds = response.messages.includes('insuffisants');
Swal.fire({
icon: isInsufficientFunds ? 'warning' : 'error',
title: isInsufficientFunds ? '⚠️ Fonds insuffisants' : 'Erreur',
html: '< div style = "text-align: left;" > ' + response.messages + '< / div > ',
confirmButtonText: 'Fermer',
confirmButtonColor: isInsufficientFunds ? '#f39c12' : '#dc3545',
width: '600px'
});
}
}
},
error: function(xhr, status, error) {
Swal.fire({
icon: 'error',
title: 'Erreur serveur',
text: 'Une erreur est survenue lors de la modification.',
confirmButtonText: 'Fermer',
confirmButtonColor: '#dc3545'
});
}
});
return false;
});
},
error: function(xhr, status, error) {
Swal.fire({
icon: 'error',
title: 'Erreur',
text: 'Impossible de récupérer les données du décaissement',
confirmButtonText: 'Fermer',
confirmButtonColor: '#dc3545'
});
}
});
};
// ============================================
// VALIDATION
// ============================================
window.validateFunc = function(id) {
$.ajax({
url: '<? = base_url ( 'sortieCaisse/fetchSortieCaisseSingle' ) ?> /' + id,
type: 'post',
dataType: 'json',
success: function(response) {
var statut = response.statut;
if (statut === "En attente" || statut === "Refuser") {
$("#statut").val(response.statut);
$("#admin_raison").val(response.admin_raison);
$("#validateModal").modal('show');
$("#validate_form").unbind('submit').bind('submit', function(e) {
e.preventDefault();
$(".text-danger").remove();
$.ajax({
url: '<? = base_url ( 'sortieCaisse/validateSortieCaisse' ) ?> /' + id,
type: 'post',
data: $(this).serialize(),
dataType: 'json',
success: function(response) {
manageTable.ajax.reload(null, false);
if (response.success === true) {
$("#messages").html('< div class = "alert alert-success alert-dismissible" role = "alert" > ' +
'< button type = "button" class = "close" data-dismiss = "alert" > × < / button > ' +
'< strong > < span class = "glyphicon glyphicon-ok-sign" > < / span > < / strong > ' + response.messages +
'< / div > ');
$("#validateModal").modal('hide');
$("#validate_form .form-group").removeClass('has-error has-success');
} else {
if (typeof response.messages === 'object') {
$.each(response.messages, function(index, value) {
var input = $("#" + index);
input.closest('.form-group')
.removeClass('has-error has-success')
.addClass(value.length > 0 ? 'has-error' : 'has-success');
input.after('< span class = "text-danger" > ' + value + '< / span > ');
});
} else {
$("#messages").html('< div class = "alert alert-warning alert-dismissible" role = "alert" > ' +
'< button type = "button" class = "close" data-dismiss = "alert" > × < / button > ' +
'< strong > < span class = "glyphicon glyphicon-exclamation-sign" > < / span > < / strong > ' + response.messages +
'< / div > ');
}
}
},
error: function(xhr, status, error) {
Swal.fire({
icon: 'error',
title: 'Erreur',
text: 'Une erreur est survenue lors de la validation.',
confirmButtonText: 'Fermer',
confirmButtonColor: '#dc3545'
});
}
});
});
} else {
Swal.fire({
icon: 'info',
title: 'Déjà validé',
html: '< p style = "font-size: 16px;" > Ce décaissement est déjà validé et ne peut pas être modifié.< / p > ',
confirmButtonText: 'Fermer',
confirmButtonColor: '#17a2b8',
width: '500px'
});
}
},
error: function() {
Swal.fire({
icon: 'error',
title: 'Erreur',
text: 'Une erreur est survenue lors de la récupération des données.',
confirmButtonText: 'OK'
});
}
});
};
});
// ============================================
// MARQUER COMME PAYÉ
// ============================================
window.markAsPaidFunc = function(id_sortie) {
Swal.fire({
title: '💰 Confirmer le paiement',
html: '< div style = "text-align: center;" > ' +
'< p style = "font-size: 16px; margin: 20px 0;" > Êtes-vous sûr(e) de vouloir marquer ce décaissement comme < strong > PAYÉ< / strong > ?< / p > ' +
'< div style = "background-color: #fff3cd; padding: 15px; border-radius: 5px; border-left: 4px solid #ffc107; margin-top: 15px;" > ' +
'< i class = "fa fa-info-circle" style = "color: #856404;" > < / i > ' +
'< strong style = "color: #856404;" > Cette action va :< / strong > < br > ' +
'< ul style = "text-align: left; margin-top: 10px; color: #856404;" > ' +
'< li > Changer le statut de "Validé" à "Payé"< / li > ' +
'< li > Notifier la Direction et le DAF< / li > ' +
'< li > Enregistrer la date de paiement< / li > ' +
'< / ul > ' +
'< / div > ' +
'< / div > ',
icon: 'question',
showCancelButton: true,
confirmButtonColor: '#28a745',
cancelButtonColor: '#6c757d',
confirmButtonText: '< i class = "fa fa-check" > < / i > Oui, marquer comme payé',
cancelButtonText: '< i class = "fa fa-times" > < / i > Annuler',
customClass: {
popup: 'animated fadeInDown'
}
}).then((result) => {
if (result.isConfirmed) {
// Afficher un loader
Swal.fire({
title: 'Traitement en cours...',
html: 'Mise à jour du statut et envoi des notifications...',
allowOutsideClick: false,
allowEscapeKey: false,
showConfirmButton: false,
didOpen: () => {
Swal.showLoading();
}
});
// Envoi de la requête AJAX
$.ajax({
url: '<? = base_url ( 'sortieCaisse/markAsPaid' ) ?> /' + id_sortie,
type: 'POST',
dataType: 'json',
success: function(response) {
if (response.success === true) {
// ✅ SUCCÈS : Afficher le message puis actualiser
Swal.fire({
icon: 'success',
title: 'Paiement enregistré !',
html: response.messages + '< br > < br > < em > La page va se recharger...< / em > ',
confirmButtonText: 'OK',
confirmButtonColor: '#28a745',
timer: 2500,
timerProgressBar: true,
allowOutsideClick: false,
customClass: {
popup: 'animated bounceIn'
}
}).then(() => {
// ✅ ACTUALISER LA PAGE
location.reload();
});
} else {
// ❌ ERREUR : Afficher le message puis actualiser
Swal.fire({
icon: 'error',
title: 'Erreur',
html: response.messages + '< br > < br > < em > La page va se recharger...< / em > ',
confirmButtonText: 'Fermer',
confirmButtonColor: '#dc3545',
timer: 3000,
timerProgressBar: true,
allowOutsideClick: false,
customClass: {
popup: 'animated shake'
}
}).then(() => {
// ✅ ACTUALISER LA PAGE MÊME EN CAS D'ERREUR
location.reload();
});
}
},
error: function(xhr, status, error) {
console.error('Erreur AJAX markAsPaid:', error);
console.error('Réponse complète:', xhr.responseText);
// ❌ ERREUR SERVEUR : Afficher puis actualiser
Swal.fire({
icon: 'error',
title: 'Erreur serveur',
html: '< p > Une erreur est survenue lors du changement de statut.< / p > ' +
'< p > < small > Détails : ' + error + '< / small > < / p > ' +
'< br > < em > La page va se recharger...< / em > ',
confirmButtonText: 'Fermer',
confirmButtonColor: '#dc3545',
timer: 3000,
timerProgressBar: true,
allowOutsideClick: false
}).then(() => {
// ✅ ACTUALISER LA PAGE
location.reload();
});
}
});
}
});
};
< / script >
< style >
/* Style pour les champs en lecture seule */
input[readonly], select[disabled], textarea[readonly] {
background-color: #e9ecef !important;
cursor: not-allowed !important;
color: #6c757d;
}
/* Style pour la légende */
.field-legend {
background-color: #f8f9fa;
border-left: 4px solid #007bff;
padding: 10px 15px;
margin-bottom: 20px;
border-radius: 4px;
}
.field-legend i {
margin-right: 5px;
}
.field-legend .legend-item {
display: inline-block;
margin-right: 20px;
margin-top: 5px;
}
/* Effet hover sur les champs éditables */
.form-control:not([readonly]):not([disabled]):hover {
border-color: #007bff;
box-shadow: 0 0 0 0.2rem rgba(0,123,255,.15);
transition: all 0.2s ease-in-out;
}
/* Icône d'édition */
.fa-edit {
font-size: 12px;
}
/* ============================================ */
/* ✅ STYLES POUR LE CHAMP MOTIF MODIFIABLE */
/* ============================================ */
/* Animation pour l'apparition du champ personnalisé */
#motif_select_custom {
animation: slideDown 0.3s ease-in-out;
}
@keyframes slideDown {
from {
opacity: 0;
transform: translateY(-10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/* Style pour l'option "Autre" */
#motif_select_dropdown option[value="AUTRE"] {
background-color: #fff3cd;
font-weight: bold;
color: #856404;
}
/* Mettre en évidence le champ actif */
#motif_select_custom:focus {
border-color: #28a745;
box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.25);
}
/* Style pour le champ personnalisé */
#motif_select_custom {
border-left: 4px solid #28a745;
}
/* Style pour le texte d'aide */
.motif-help-text {
font-size: 12px;
color: #6c757d;
margin-top: 5px;
display: block;
}
.motif-help-text i {
margin-right: 3px;
}
< / style >