credit-direct/assets/js/credit-manager.js
2025-12-18 09:44:42 +01:00

741 lines
29 KiB
JavaScript

/**
* CREDIT MANAGER - JavaScript Functions
* Gestion du modal et des interactions
*/
jQuery(document).ready(function($) {
'use strict';
// Variables globales
let currentCreditId = null;
// Variables pour DataTables
let creditsTable;
// Variables pour les filtres
let currentFilters = {};
// Initialiser Select2
function initSelect2() {
if (typeof $.fn.select2 === 'function') {
$('#credit-type').select2({
placeholder: 'Sélectionnez un type de crédit',
allowClear: true,
width: '100%'
});
// Initialiser Select2 sur les filtres
$('#filter-societe, #filter-status, #filter-type, #filter-credit-code').select2({
allowClear: true,
width: '100%'
});
} else {
// Si Select2 n'est pas encore disponible, réessayer dans 100ms
setTimeout(initSelect2, 100);
}
}
// Initialiser Select2 au chargement du document
$(document).ready(function() {
initSelect2();
});
// Initialiser DataTables
function initDataTable() {
creditsTable = $('#credits-table').DataTable({
processing: true,
serverSide: false,
responsive: true,
pageLength: 25,
lengthMenu: [[10, 25, 50, 100, -1], [10, 25, 50, 100, "Tous"]],
dom: 'Bfrtip',
buttons: [
{
extend: 'excelHtml5',
text: '<i class="fa-solid fa-file-excel"></i> Excel',
className: 'btn-export-excel',
title: 'Export Crédits - ' + new Date().toLocaleDateString('fr-FR'),
exportOptions: {
columns: ':not(:last-child)' // Exclure la colonne Actions
}
},
{
extend: 'csvHtml5',
text: '<i class="fa-solid fa-file-csv"></i> CSV',
className: 'btn-export-csv',
title: 'Export Crédits',
exportOptions: {
columns: ':not(:last-child)' // Exclure la colonne Actions
}
}
],
language: {
"sProcessing": "Traitement en cours...",
"sSearch": "Rechercher:",
"sLengthMenu": "Afficher _MENU_ éléments",
"sInfo": "Affichage de l'élément _START_ à _END_ sur _TOTAL_ éléments",
"sInfoEmpty": "Affichage de l'élément 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",
"paginate": {
"sFirst": "Premier",
"sPrevious": "Précédent",
"sNext": "Suivant",
"sLast": "Dernier"
},
"buttons": {
"excel": "Excel",
"csv": "CSV"
}
},
columns: [
{ data: 'id', title: 'ID', defaultContent: '' },
{ data: 'type_credit', title: 'Type', defaultContent: '' },
{ data: 'nom', title: 'Nom', defaultContent: '' },
{ data: 'prenom', title: 'Prénom', defaultContent: '' },
{ data: 'adresse', title: 'Adresse', defaultContent: '' },
{ data: 'localite', title: 'Localité', defaultContent: '' },
{ data: 'email', title: 'Email', defaultContent: '' },
{
data: null,
title: 'Téléphone/GSM',
render: function(data, type, row) {
let phones = [];
if (row.telephone) phones.push(row.telephone);
if (row.gsm) phones.push(row.gsm);
return phones.join('<br>');
}
},
{ data: 'societe_credit', title: 'Société', defaultContent: '' },
{
data: 'montant',
title: 'Montant',
render: function(data, type, row) {
return formatCurrency(row.montant);
}
},
{
data: 'date',
title: 'Date',
render: function(data, type, row) {
return formatDate(row.date);
}
},
{ data: 'date_signature', title: 'Date Signature', defaultContent: '' },
{ data: 'numero_dossier', title: 'N° Dossier', defaultContent: '' },
{ data: 'code', title: 'Code', defaultContent: '' },
{
data: null,
title: 'Statut',
orderable: false,
searchable: false,
render: function(data, type, row) {
const map = {
'-1': { label: 'Refusé', cls: 'status-refused' },
'0': { label: 'À valider', cls: 'status-pending' },
'1': { label: 'Validé non signé', cls: 'status-accepted-unsigned' },
'2': { label: 'Validé classé', cls: 'status-accepted-filed' }
};
const key = String(row.status ?? '0');
const conf = map[key] || map['0'];
return '<span class="status-badge ' + conf.cls + '">' + conf.label + '</span>';
}
},
{
data: null,
title: 'Actions',
orderable: false,
searchable: false,
render: function(data, type, row) {
// Récupérer le statut actuel
const currentStatus = parseInt(row.status ?? '0');
return `
<div class="credit-actions-grid">
<button type="button" class="credit-action-btn btn-edit" onclick="editCredit(${row.id})" title="Modifier">
<i class="fa-solid fa-pen-to-square"></i>
</button>
<button type="button" class="credit-action-btn btn-accepted-unsigned" onclick="updateCreditStatus(${row.id}, 'accepte_non_signe')" title="Accepté non signé" ${currentStatus === 1 ? 'disabled' : ''}>
<i class="fa-solid fa-check"></i>
</button>
<button type="button" class="credit-action-btn btn-accepted-filed" onclick="updateCreditStatus(${row.id}, 'accepte_classe')" title="Accepté classé" ${currentStatus === 2 ? 'disabled' : ''}>
<i class="fa-solid fa-box-archive"></i>
</button>
<button type="button" class="credit-action-btn btn-refused" onclick="updateCreditStatus(${row.id}, 'refuse')" title="Refusé" ${currentStatus === -1 ? 'disabled' : ''}>
<i class="fa-solid fa-xmark"></i>
</button>
</div>
`;
}
}
]
});
}
// Charger les données des crédits
function loadCredits(options = {}) {
const silent = !!options.silent;
// Vérifier que creditManagerAjax est défini
if (typeof creditManagerAjax === 'undefined') {
console.error('ERROR: creditManagerAjax is not defined!');
showNotification('Erreur de configuration JavaScript', 'error');
return;
}
// Vérifier que le nonce est défini
if (!creditManagerAjax.nonce) {
console.error('ERROR: Nonce is not defined in creditManagerAjax!');
console.log('creditManagerAjax object:', creditManagerAjax);
showNotification('Erreur: Nonce manquant', 'error');
return;
}
// Afficher une notification de chargement (si non silencieux)
if (!silent) {
showNotification('Chargement des crédits...', 'saving');
}
// Préparer les données avec les filtres
let ajaxData = {
action: 'credit_manager_list',
nonce: creditManagerAjax.nonce
};
// Ajouter les filtres s'ils existent
Object.assign(ajaxData, currentFilters);
// Debug: Afficher les données envoyées
console.log('=== AJAX Request ===');
console.log('URL:', creditManagerAjax.ajaxurl);
console.log('Nonce:', creditManagerAjax.nonce);
console.log('Filters:', currentFilters);
console.log('Ajax Data:', ajaxData);
$.ajax({
url: creditManagerAjax.ajaxurl,
type: 'POST',
data: ajaxData,
success: function(response) {
console.log('=== AJAX Response ===');
console.log('Response:', response);
if (response.success) {
console.log('Success! Credits count:', response.data.credits ? response.data.credits.length : 0);
console.log('Status counts:', response.data.status_counts);
// Détruire la table existante si elle existe
if (creditsTable) {
creditsTable.destroy();
}
// Réinitialiser le tableau HTML
$('#credits-table tbody').empty();
// Réinitialiser DataTables
initDataTable();
// Ajouter les données
if (response.data.credits && response.data.credits.length > 0) {
// Assainir les lignes pour correspondre aux colonnes attendues
const requiredFields = ['id','type_credit','nom','prenom','adresse','localite','email','telephone','gsm','societe_credit','montant','date','date_signature','numero_dossier','code'];
const sanitized = response.data.credits.map(function(row, idx){
if (typeof row !== 'object' || row === null) {
console.warn('Row is not an object at index', idx);
row = {};
}
requiredFields.forEach(function(k){
if (typeof row[k] === 'undefined') {
row[k] = (k === 'montant') ? 0 : '';
}
});
return row;
});
creditsTable.clear();
creditsTable.rows.add(sanitized);
creditsTable.draw();
if (!silent) {
showNotification(response.data.credits.length + ' crédit(s) chargé(s)', 'success');
}
} else {
if (!silent) {
showNotification('Aucun crédit trouvé', 'info');
}
}
// Mettre à jour les compteurs avec les données du serveur
if (response.data.status_counts) {
updateStatusCountsFromData(response.data.status_counts, response.data.total_all);
}
} else {
console.error('AJAX Error:', response.data);
showNotification('Erreur: ' + response.data, 'error');
}
},
error: function(xhr, status, error) {
console.error('=== AJAX Connection Error ===');
console.error('Status:', status);
console.error('Error:', error);
console.error('Response:', xhr.responseText);
showNotification('Erreur de connexion: ' + error, 'error');
}
});
}
// Formater la devise
function formatCurrency(amount) {
return new Intl.NumberFormat('fr-FR', {
style: 'currency',
currency: 'EUR'
}).format(amount || 0);
}
// Formater la date
function formatDate(dateString) {
if (!dateString) return '';
return new Date(dateString).toLocaleDateString('fr-FR');
}
/**
* Affiche une notification moderne (style toast)
* @param {string} message - Le message à afficher
* @param {string} type - Le type de notification: 'success', 'saving', 'error', 'info'
*/
function showNotification(message, type = 'success') {
let indicator = $('.auto-save-indicator');
// Créer l'indicateur s'il n'existe pas
if (indicator.length === 0) {
indicator = $('<div class="auto-save-indicator"></div>');
$('body').append(indicator);
}
// Mapper le type 'info' vers 'saving' pour une meilleure visibilité
if (type === 'info') {
type = 'saving';
}
// Retirer toutes les classes de type et ajouter la nouvelle
indicator.removeClass('show saving error').addClass('show ' + type);
indicator.text(message);
// Masquer après 3 secondes (5 secondes pour les erreurs)
const duration = type === 'error' ? 5000 : 3000;
setTimeout(() => {
indicator.removeClass('show');
}, duration);
}
// Alias pour compatibilité avec l'ancien code
function showMessage(message, type) {
showNotification(message, type);
}
// Ouvrir le modal
window.openCreditModal = function(creditId = null) {
currentCreditId = creditId;
if (creditId) {
loadCreditData(creditId);
} else {
$('#credit-form')[0].reset();
$('.credit-modal-header h2').text('Nouveau crédit');
// Réinitialiser Select2
$('#credit-type').val([]).trigger('change');
}
$('.credit-modal').addClass('show').show();
// Réinitialiser Select2 après ouverture de la modal
setTimeout(function() {
if (typeof $.fn.select2 === 'function') {
// Détruire l'instance existante si elle existe
if ($('#credit-type').hasClass('select2-hidden-accessible')) {
$('#credit-type').select2('destroy');
}
initSelect2();
}
}, 100);
};
// Fermer le modal
window.closeCreditModal = function() {
$('.credit-modal').addClass('closing');
setTimeout(function() {
$('.credit-modal').removeClass('show closing').hide();
currentCreditId = null;
}, 300);
};
// Charger les données d'un crédit
function loadCreditData(creditId) {
$.ajax({
url: creditManagerAjax.ajaxurl,
type: 'POST',
data: {
action: 'credit_manager_get',
nonce: creditManagerAjax.nonce,
credit_id: creditId
},
success: function(response) {
if (response.success) {
const credit = response.data.credit;
$('.credit-modal-header h2').text('Modifier le crédit');
// Remplir le formulaire
if (credit.type_credit) {
const typeCreditArray = typeof credit.type_credit === 'string'
? credit.type_credit.split(',')
: credit.type_credit;
$('#credit-type').val(typeCreditArray);
} else {
$('#credit-type').val([]);
}
$('#credit-nom').val(credit.nom || '');
$('#credit-prenom').val(credit.prenom || '');
$('#credit-adresse').val(credit.adresse || '');
$('#credit-localite').val(credit.localite || '');
$('#credit-email').val(credit.email || '');
$('#credit-telephone').val(credit.telephone || '');
$('#credit-gsm').val(credit.gsm || '');
$('#credit-type-habitation').val(credit.type_habitation || '');
$('#credit-societe').val(credit.societe_credit || '');
$('#credit-montant').val(credit.montant || '');
$('#credit-date').val(credit.date || '');
$('#credit-signature').val(credit.date_signature || '');
$('#credit-numero-dossier').val(credit.numero_dossier || '');
$('#credit-code').val(credit.code || '');
$('#credit-remarques').val(credit.remarques || '');
showNotification('Crédit chargé avec succès', 'success');
} else {
showNotification('✕ Erreur lors du chargement: ' + response.data, 'error');
}
},
error: function(xhr, status, error) {
showNotification('✕ Erreur de connexion lors du chargement: ' + error, 'error');
}
});
}
// Sauvegarder le crédit
window.saveCredit = function() {
// Afficher la notification de sauvegarde
showNotification('Sauvegarde en cours...', 'saving');
const formData = {
action: currentCreditId ? 'credit_manager_update' : 'credit_manager_create',
nonce: creditManagerAjax.nonce,
type_credit: $('#credit-type').val(),
nom: $('#credit-nom').val(),
prenom: $('#credit-prenom').val(),
adresse: $('#credit-adresse').val(),
localite: $('#credit-localite').val(),
email: $('#credit-email').val(),
telephone: $('#credit-telephone').val(),
gsm: $('#credit-gsm').val(),
type_habitation: $('#credit-type-habitation').val(),
societe_credit: $('#credit-societe').val(),
montant: $('#credit-montant').val(),
date: $('#credit-date').val(),
signature: $('#credit-signature').val(),
numero_dossier: $('#credit-numero-dossier').val(),
code: $('#credit-code').val(),
remarques: $('#credit-remarques').val()
};
if (currentCreditId) {
formData.credit_id = currentCreditId;
}
$.ajax({
url: creditManagerAjax.ajaxurl,
type: 'POST',
data: formData,
success: function(response) {
if (response.success) {
showNotification('✓ ' + response.data.message, 'success');
closeCreditModal();
loadCredits({ silent: true });
} else {
showNotification('✕ Erreur: ' + response.data, 'error');
}
},
error: function(xhr, status, error) {
showNotification('✕ Erreur de connexion: ' + error, 'error');
}
});
};
// Supprimer un crédit
window.deleteCredit = function(creditId) {
// Confirmation plus détaillée
const confirmMessage = '⚠️ ATTENTION ⚠️\n\n' +
'Vous êtes sur le point de supprimer définitivement ce crédit.\n\n' +
'Cette action est IRRÉVERSIBLE et supprimera toutes les données associées.\n\n' +
'Êtes-vous absolument certain de vouloir continuer ?';
if (!confirm(confirmMessage)) {
return;
}
// Double confirmation pour plus de sécurité
if (!confirm('Dernière chance !\n\nConfirmez-vous la suppression définitive de ce crédit ?')) {
return;
}
// Afficher un message de chargement
showNotification('Suppression en cours...', 'saving');
$.ajax({
url: creditManagerAjax.ajaxurl,
type: 'POST',
data: {
action: 'credit_manager_delete',
nonce: creditManagerAjax.nonce,
credit_id: creditId
},
success: function(response) {
if (response.success) {
showNotification('✓ ' + response.data.message, 'success');
loadCredits({ silent: true });
} else {
showNotification('✕ Erreur: ' + response.data, 'error');
}
},
error: function(xhr, status, error) {
showNotification('✕ Erreur de connexion lors de la suppression: ' + error, 'error');
}
});
};
// Modifier un crédit
window.editCredit = function(creditId) {
openCreditModal(creditId);
};
// Mettre à jour le statut d'un crédit
window.updateCreditStatus = function(creditId, status) {
let statusLabel = '';
let confirmMessage = '';
switch(status) {
case 'accepte_non_signe':
statusLabel = 'Accepté non signé';
confirmMessage = 'Êtes-vous sûr de vouloir marquer ce crédit comme "Accepté non signé" ?';
break;
case 'accepte_classe':
statusLabel = 'Accepté classé';
confirmMessage = 'Êtes-vous sûr de vouloir marquer ce crédit comme "Accepté classé" ?';
break;
case 'refuse':
statusLabel = 'Refusé';
confirmMessage = 'Êtes-vous sûr de vouloir marquer ce crédit comme "Refusé" ?';
break;
}
if (!confirm(confirmMessage)) {
return;
}
showNotification('Mise à jour du statut en cours...', 'saving');
$.ajax({
url: creditManagerAjax.ajaxurl,
type: 'POST',
data: {
action: 'credit_manager_update_status',
nonce: creditManagerAjax.nonce,
credit_id: creditId,
status: status
},
success: function(response) {
if (response.success) {
showNotification('✓ Statut mis à jour : ' + statusLabel, 'success');
loadCredits({ silent: true });
} else {
showNotification('✕ Erreur: ' + response.data, 'error');
}
},
error: function(xhr, status, error) {
showNotification('✕ Erreur de connexion lors de la mise à jour: ' + error, 'error');
}
});
};
// Fermer le modal en cliquant à l'extérieur
$(document).on('click', '.credit-modal', function(e) {
if (e.target === this) {
closeCreditModal();
}
});
// Toggle des filtres
$('#toggle-filters').on('click', function() {
$('#credit-filters-form').slideToggle(300);
$(this).find('.dashicons').toggleClass('dashicons-arrow-down-alt2 dashicons-arrow-up-alt2');
});
// Soumission du formulaire de filtres
$('#credit-filters-form').on('submit', function(e) {
e.preventDefault();
// Récupérer les valeurs du formulaire
currentFilters = {
societe_credit: $('#filter-societe').val(),
code_postal: $('#filter-code-postal').val(),
status: $('#filter-status').val(),
type_credit: $('#filter-type').val(),
credit_code_select: $('#filter-credit-code').val(),
montant_min: $('#filter-montant-min').val(),
montant_max: $('#filter-montant-max').val(),
date_signature_debut: $('#filter-date-debut').val(),
date_signature_fin: $('#filter-date-fin').val()
};
// Compter le nombre de filtres actifs
let activeFiltersCount = 0;
Object.keys(currentFilters).forEach(key => {
if (currentFilters[key] !== '' && currentFilters[key] !== null) {
activeFiltersCount++;
}
});
if (activeFiltersCount > 0) {
showNotification('Application de ' + activeFiltersCount + ' filtre(s)...', 'saving');
}
// Recharger les données avec les filtres
loadCredits();
});
// Réinitialiser les filtres
$('#reset-filters').on('click', function() {
$('#credit-filters-form')[0].reset();
currentFilters = {};
showNotification('Filtres réinitialisés', 'success');
loadCredits();
});
// Fonction pour mettre à jour les compteurs depuis les données du serveur
function updateStatusCountsFromData(statusCounts, totalAll) {
// Mettre à jour les affichages avec les compteurs reçus du serveur
$('[data-count-status="0"]').text('(' + (statusCounts['0'] || 0) + ')');
$('[data-count-status="1"]').text('(' + (statusCounts['1'] || 0) + ')');
$('[data-count-status="2"]').text('(' + (statusCounts['2'] || 0) + ')');
$('[data-count-status="-1"]').text('(' + (statusCounts['-1'] || 0) + ')');
$('#total-count').text('(' + (totalAll || 0) + ')');
console.log('Status counts updated from server:', statusCounts, 'Total:', totalAll);
}
// Gestionnaire pour les boutons de filtre rapide par statut
$('.status-filter-btn').on('click', function() {
const status = $(this).data('status');
// Retirer la classe active de tous les boutons
$('.status-filter-btn').removeClass('active');
// Ajouter la classe active au bouton cliqué
$(this).addClass('active');
// Réinitialiser les autres filtres du formulaire
$('#credit-filters-form')[0].reset();
// Appliquer le filtre de statut
if (status === '') {
// Bouton "Tous" - réinitialiser les filtres
currentFilters = {};
showNotification('Affichage de tous les crédits', 'success');
} else {
// Filtre par statut spécifique
currentFilters = {
status: status
};
const statusLabels = {
'0': 'À valider',
'1': 'Validé non signé',
'2': 'Validé classé',
'-1': 'Refusé'
};
showNotification('Filtre : ' + statusLabels[status], 'saving');
}
// Recharger les crédits
loadCredits();
});
// Mailchimp - tester la connexion (page admin Mailchimp)
$('#cred-mailchimp-test').on('click', function(e) {
e.preventDefault();
var $out = $('#cred-mailchimp-test-result');
if ($out.length) {
$out.text('Test en cours…');
} else {
showNotification('Test de connexion en cours…', 'saving');
}
$.post(creditManagerAjax.ajaxurl, {
action: 'cred_mailchimp_ping',
nonce: creditManagerAjax.mailchimpPingNonce || ''
}).done(function(resp){
if ($out.length) {
$out.text(resp && resp.success ? 'Connexion OK' : ('Échec: ' + ((resp && resp.data && resp.data.message) ? resp.data.message : 'Error')));
} else {
if (resp && resp.success) {
showNotification('Connexion Mailchimp OK', 'success');
} else {
showNotification('Échec: ' + ((resp && resp.data && resp.data.message) ? resp.data.message : 'Error'), 'error');
}
}
}).fail(function(xhr){
var msg = (xhr && xhr.responseJSON && xhr.responseJSON.data && xhr.responseJSON.data.message) ? xhr.responseJSON.data.message : xhr.statusText;
if ($out.length) {
$out.text('Échec: ' + msg);
} else {
showNotification('Échec: ' + msg, 'error');
}
});
});
// Sendy - tester la connexion (page admin Sendy)
$('#cred-sendy-test').on('click', function(e) {
e.preventDefault();
var $out = $('#cred-sendy-test-result');
if ($out.length) {
$out.text('Test en cours…');
} else {
showNotification('Test de connexion en cours…', 'saving');
}
$.post(creditManagerAjax.ajaxurl, {
action: 'cred_sendy_ping',
nonce: creditManagerAjax.sendyPingNonce || ''
}).done(function(resp){
if ($out.length) {
$out.text(resp && resp.success ? 'Connexion OK' : ('Échec: ' + ((resp && resp.data && resp.data.message) ? resp.data.message : 'Error')));
} else {
if (resp && resp.success) {
showNotification('Connexion Sendy OK', 'success');
} else {
showNotification('Échec: ' + ((resp && resp.data && resp.data.message) ? resp.data.message : 'Error'), 'error');
}
}
}).fail(function(xhr){
var msg = (xhr && xhr.responseJSON && xhr.responseJSON.data && xhr.responseJSON.data.message) ? xhr.responseJSON.data.message : xhr.statusText;
if ($out.length) {
$out.text('Échec: ' + msg);
} else {
showNotification('Échec: ' + msg, 'error');
}
});
});
// Initialiser uniquement sur la page Crédit (évite le chargement sur Mailchimp/Sendy)
if (jQuery('#credits-table').length > 0) {
loadCredits();
}
});