You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

560 lines
21 KiB

<!-- Content Wrapper. Contains page content -->
<div class="content-wrapper">
<!-- Content Header (Page header) -->
<section class="content-header">
<h1>
Gestion des
<small>Recouvrements</small>
</h1>
<ol class="breadcrumb">
<li><a href="#"><i class="fa fa-dashboard"></i> Accueil</a></li>
<li class="active">Recouvrements</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">&times;</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">&times;</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">&times;</span></button>
<?php echo session()->getFlashdata('errors'); ?>
</div>
<?php endif; ?>
<?php if (in_array('createRecouvrement', $user_permission)): ?>
<button class="btn btn-primary" data-toggle="modal" data-target="#createModal">RECOUVREMENT</button>
<br /><br />
<?php endif; ?>
<div class="box">
<div class="box-header">
<h3 class="box-title">Gérer les recouvrements</h3>
</div>
<div class="box-body">
<table id="manageTable" class="table table-bordered table-striped">
<thead>
<tr>
<th>#</th>
<th>Montant</th>
<th>Date</th>
<th>Caissier</th>
<th>Type de Montant à recouvrer</th>
<th>Destination du Montant à recouvrer</th>
<?php if (in_array('updateRecouvrement', $user_permission) || in_array('deleteRecouvrement', $user_permission)): ?>
<th>Action</th>
<?php endif; ?>
</tr>
</thead>
<tbody>
<tr>
<td></td>
<td class="test"></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
<!-- Totaux -->
<div class="row">
<div class="col-lg-3 col-6">
<div class="small-box" style="background-color:#A9A9A9;">
<div class="inner">
<h3 id="total"><?php echo number_format($total, 0, '', ' '); ?></h3>
<p>Total en caisse </p>
</div>
<div class="icon">
<i class="ion ion-cash"></i>
</div>
</div>
</div>
<div class="col-lg-3 col-6">
<div class="small-box" style="background-color:#A9A9A9;">
<div class="inner">
<h3 id="total_mvola"><?php echo number_format($total_mvola, 0, '.', ' '); ?></h3>
<p>Total en MVOLA</p>
</div>
<div class="icon">
<i class="ion ion-android-phone-portrait"></i>
</div>
</div>
</div>
<div class="col-lg-3 col-6">
<div class="small-box" style="background-color:#A9A9A9;">
<div class="inner">
<h3 id="total_espece"><?php echo number_format($total_espece, 0, '.', ' '); ?></h3>
<p>Total en Espèce</p>
</div>
<div class="icon">
<i class="ion ion-cash"></i>
</div>
</div>
</div>
<div class="col-lg-3 col-6">
<div class="small-box" style="background-color:#A9A9A9;">
<div class="inner">
<h3 id="total_banque"><?php echo number_format($total_virement_bancaire, 0, '.', ' '); ?></h3>
<p>Total en Banque</p>
</div>
<div class="icon">
<i class="ion ion-bank"></i>
</div>
</div>
</div>
</div>
</section>
</div> <!-- /.content-wrapper -->
<!-- ======================== -->
<!-- ⚡ MODALS EN DEHORS DU WRAPPER -->
<!-- ======================== -->
<?php if (in_array('createRecouvrement', $user_permission)): ?>
<div class="modal fade" id="createModal" tabindex="-1" role="dialog">
<div class="modal-dialog modal-lg modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">&times;</button>
<h4 class="modal-title">Ajouter un recouvrement</h4>
</div>
<form action="<?php echo base_url('recouvrement/create') ?>" method="post" id="create_form">
<div class="modal-body">
<div class="form-group">
<label for="sendmode">Type de Montant à recouvrer</label>
<select name="send_mode" id="sendmode" class="form-control">
<option value="MVOLA">MVOLA</option>
<option value="Virement Bancaire">Virement Bancaire</option>
</select>
</div>
<div class="form-group">
<label for="getmode">Destination du Montant à recouvrer</label>
<select name="get_mode" id="getmode" class="form-control">
<option value="MVOLA">MVOLA</option>
<option value="En espèce">En espèce</option>
<option value="Virement Bancaire">Virement Bancaire</option>
</select>
</div>
<div class="form-group">
<label for="recouvrement_montant">Montant du recouvrement</label>
<input type="text" class="form-control" id="recouvrement_montant" name="recouvrement_montant" autocomplete="off">
</div>
<div class="form-group">
<label for="recouvrement_date">Date du recouvrement</label>
<input type="date" class="form-control" id="recouvrement_date" name="recouvrement_date" autocomplete="off">
</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; ?>
<?php if (in_array('updateRecouvrement', $user_permission)): ?>
<div class="modal fade" id="updateModal" tabindex="-1" role="dialog">
<div class="modal-dialog modal-lg modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">&times;</button>
<h4 class="modal-title">Modifier un recouvrement</h4>
</div>
<form action="<?php echo base_url('recouvrement/update') ?>" method="post" id="update_form">
<div class="modal-body">
<div class="form-group">
<label for="recouvrement_montant_edit">Montant du recouvrement</label>
<input type="text" class="form-control" id="recouvrement_montant_edit" name="recouvrement_montant_edit" autocomplete="off">
</div>
<div class="form-group">
<label for="recouvrement_date_edit">Date du recouvrement</label>
<input type="date" class="form-control" id="recouvrement_date_edit" name="recouvrement_date_edit" autocomplete="off">
</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; ?>
<?php if (in_array('deleteRecouvrement', $user_permission)): ?>
<div class="modal fade" id="removeModal" tabindex="-1" role="dialog">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">&times;</button>
<h4 class="modal-title">Supprimer le recouvrement</h4>
</div>
<form action="<?php echo base_url('recouvrement/delete') ?>" method="post" id="removeForm">
<div class="modal-body">
<p>Voulez-vous vraiment supprimer ?</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Fermer</button>
<button type="submit" class="btn btn-primary">Oui</button>
</div>
</form>
</div>
</div>
</div>
<?php endif; ?>
<!-- Inclure SweetAlert2 -->
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
<script>
$(document).ready(function() {
$("#motos").select2();
$("#motos_edit").select2();
$('.mecanic').select2();
$("#recouvrement").addClass('active');
// Check if the URL contains the _ parameter
if (window.location.search.startsWith("?_=")) {
window.location.href = window.location.origin + window.location.pathname;
}
// Configuration DataTable en français
$.extend(true, $.fn.dataTable.defaults, {
language: {
sProcessing: "Traitement en cours...",
sSearch: "Rechercher&nbsp;:",
sLengthMenu: "Afficher _MENU_ &eacute;l&eacute;ments",
sInfo: "Affichage de l'&eacute;lement _START_ &agrave; _END_ sur _TOTAL_ &eacute;l&eacute;ments",
sInfoEmpty: "Affichage de l'&eacute;lement 0 &agrave; 0 sur 0 &eacute;l&eacute;ment",
sInfoFiltered: "(filtr&eacute; de _MAX_ &eacute;l&eacute;ments au total)",
sLoadingRecords: "Chargement en cours...",
sZeroRecords: "Aucun &eacute;l&eacute;ment &agrave; afficher",
sEmptyTable: "Aucune donn&eacute;e disponible dans le tableau",
oPaginate: {
sFirst: "Premier",
sPrevious: "Pr&eacute;c&eacute;dent",
sNext: "Suivant",
sLast: "Dernier"
},
oAria: {
sSortAscending: ": activer pour trier la colonne par ordre croissant",
sSortDescending: ": activer pour trier la colonne par ordre d&eacute;croissant"
}
}
});
// Initialisation du DataTable
manageTable = $('#manageTable').DataTable({
'ajax': '<?= base_url('recouvrement/fetchRecouvrementData') ?>',
'order': [],
'columnDefs': [{
targets: 1,
className: 'text-right rowmontant'
},
{
targets: 4,
className: 'rowtype'
},
{
targets: 5,
className: 'rowdestination'
}
]
});
// ====== FONCTION DE RAFRAÎCHISSEMENT AUTOMATIQUE ======
function refreshData() {
// Recharger le DataTable
manageTable.ajax.reload(null, false);
// Recharger les totaux
fetchTotalData();
}
// Rafraîchir automatiquement toutes les 5 secondes
setInterval(refreshData, 5000);
})
// ====== CRÉATION DE RECOUVREMENT ======
$("#create_form").unbind('submit').on('submit', function() {
var form = $(this);
// Supprimer les messages d'erreur
$(".text-danger").remove();
$.ajax({
url: form.attr('action'),
type: form.attr('method'),
data: form.serialize(),
dataType: 'json',
success: function(response) {
if (response.success === true) {
// Recharger immédiatement les données
manageTable.ajax.reload(null, false);
fetchTotalData();
$("#messages").html('<div class="alert alert-success alert-dismissible" role="alert">' +
'<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button>' +
'<strong> <span class="glyphicon glyphicon-ok-sign"></span> </strong>' + response.messages +
'</div>');
// Fermer le modal
$("#createModal").modal('hide');
// Réinitialiser le formulaire
$("#create_form")[0].reset();
$("#create_form .form-group").removeClass('has-error').removeClass('has-success');
// Faire disparaître le message après 3 secondes
setTimeout(function() {
$("#messages").fadeOut('slow', function() {
$(this).html('').show();
});
}, 3000);
} else {
// Afficher une alerte SweetAlert pour les erreurs de solde
if (response.messages === 'Recouvrement impossible : solde insuffisant pour ce type de transaction') {
Swal.fire({
icon: 'error',
title: 'Recouvrement impossible',
text: 'Le solde est insuffisant pour effectuer ce recouvrement. Veuillez vérifier les totaux disponibles.',
confirmButtonColor: '#3085d6',
confirmButtonText: 'OK'
});
} else if (response.messages instanceof Object) {
$.each(response.messages, function(index, value) {
var id = $("#" + index);
id.closest('.form-group')
.removeClass('has-error')
.removeClass('has-success')
.addClass(value.length > 0 ? 'has-error' : 'has-success');
id.after(value);
});
} else {
$("#messages").html('<div class="alert alert-warning alert-dismissible" role="alert">' +
'<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button>' +
'<strong> <span class="glyphicon glyphicon-exclamation-sign"></span> </strong>' + response.messages +
'</div>');
}
}
},
error: function() {
$("#messages").html('<div class="alert alert-danger alert-dismissible" role="alert">' +
'<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button>' +
'<strong>Erreur!</strong> Une erreur est survenue lors de la création.' +
'</div>');
}
});
return false;
});
// ====== SUPPRESSION DE RECOUVREMENT ======
function removeFunc(id) {
if (id) {
$("#removeForm").unbind('submit').on('submit', function() {
var form = $(this);
$(".text-danger").remove();
$.ajax({
url: form.attr('action'),
type: form.attr('method'),
data: {
recouvrement_id: id
},
dataType: 'json',
success: function(response) {
// Recharger immédiatement les données
manageTable.ajax.reload(null, false);
fetchTotalData();
if (response.success === true) {
$("#messages").html('<div class="alert alert-success alert-dismissible" role="alert">' +
'<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button>' +
'<strong> <span class="glyphicon glyphicon-ok-sign"></span> </strong>' + response.messages +
'</div>');
$("#removeModal").modal('hide');
// Faire disparaître le message après 3 secondes
setTimeout(function() {
$("#messages").fadeOut('slow', function() {
$(this).html('').show();
});
}, 3000);
} else {
$("#messages").html('<div class="alert alert-warning alert-dismissible" role="alert">' +
'<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button>' +
'<strong> <span class="glyphicon glyphicon-exclamation-sign"></span> </strong>' + response.messages +
'</div>');
}
},
error: function() {
$("#messages").html('<div class="alert alert-danger alert-dismissible" role="alert">' +
'<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button>' +
'<strong>Erreur!</strong> Une erreur est survenue lors de la suppression.' +
'</div>');
}
});
return false;
});
}
}
// ====== MODIFICATION DE RECOUVREMENT ======
function editFunc(id) {
$.ajax({
url: '<?= base_url('recouvrement/fetchRecouvrementSingle') ?>/' + id,
type: 'post',
dataType: 'json',
success: function(response) {
$("#recouvrement_montant_edit").val(response.recouvrement_montant).change();
$("#recouvrement_date_edit").val(response.recouvrement_date).change();
// Soumettre le formulaire de modification
$("#update_form").unbind('submit').bind('submit', function() {
var form = $(this);
$(".text-danger").remove();
$.ajax({
url: form.attr('action').replace(/\/?$/, '/') + id,
type: form.attr('method'),
data: form.serialize(),
dataType: 'json',
success: function(response) {
// Recharger immédiatement les données
manageTable.ajax.reload(null, false);
fetchTotalData();
$("#updateModal").modal('hide');
if (response.success === true) {
$("#messages").html('<div class="alert alert-success alert-dismissible" role="alert">' +
'<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button>' +
'<strong> <span class="glyphicon glyphicon-ok-sign"></span> </strong>' + response.messages +
'</div>');
$("#updateForm .form-group").removeClass('has-error').removeClass('has-success');
// Faire disparaître le message après 3 secondes
setTimeout(function() {
$("#messages").fadeOut('slow', function() {
$(this).html('').show();
});
}, 3000);
} else {
if (response.messages instanceof Object) {
$.each(response.messages, function(index, value) {
var id = $("#" + index);
id.closest('.form-group')
.removeClass('has-error')
.removeClass('has-success')
.addClass(value.length > 0 ? 'has-error' : 'has-success');
id.after(value);
});
} else {
$("#messages").html('<div class="alert alert-warning alert-dismissible" role="alert">' +
'<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button>' +
'<strong> <span class="glyphicon glyphicon-exclamation-sign"></span> </strong>' + response.messages +
'</div>');
}
}
},
error: function() {
$("#updateModal").modal('hide');
$("#messages").html('<div class="alert alert-danger alert-dismissible" role="alert">' +
'<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button>' +
'<strong>Erreur!</strong> Une erreur est survenue lors de la modification.' +
'</div>');
}
});
return false;
});
}
});
}
// ====== MISE À JOUR DES TOTAUX ======
const endpoint = '<?= base_url('recouvrement/fetchTotalData') ?>';
async function fetchTotalData() {
try {
let res = await fetch(endpoint, {
headers: {
'Content-Type': 'application/json'
}
});
if (!res.ok) throw new Error(res.status);
let data = await res.json();
// Mettre à jour les totaux avec animation
updateValueWithAnimation('#total', data.total);
updateValueWithAnimation('#total_mvola', data.total_mvola);
updateValueWithAnimation('#total_espece', data.total_espece);
updateValueWithAnimation('#total_banque', data.total_virement_bancaire);
} catch (e) {
console.error('fetchTotalData error', e);
}
}
// Fonction pour mettre à jour une valeur avec animation
function updateValueWithAnimation(selector, newValue) {
const element = $(selector);
const currentText = element.text().replace(/\s/g, '');
const currentValue = parseFloat(currentText) || 0;
const formattedNewValue = formatNum(newValue);
// Si la valeur a changé, ajouter une animation
if (currentText !== formattedNewValue.replace(/\s/g, '')) {
element.fadeOut(200, function() {
$(this).text(formattedNewValue).fadeIn(200);
});
}
}
function formatNum(n) {
n = parseFloat(n) || 0;
return n.toLocaleString('fr-FR').replace(/\s/g, ' ');
}
// Charger les totaux au démarrage
fetchTotalData();
// Rafraîchir les totaux toutes les 3 secondes
setInterval(fetchTotalData, 3000);
</script>