// jsap.js // Déclaration des variables globales let idDevisEnCours = 0; let idDevisArchives = 0; let panel = 'enCours'; let fkUser = 0; let oldColorLnEnCours = ''; let oldColorLnArchives = ''; let oldIdLnEnCours; let oldIdLnArchives; let nbCommentChat = 0; let selectedXmlDevis = new Set(); let searchSapTimeout = null; const tableSortStates = new Map(); function initTableSort() { const allTables = document.querySelectorAll('[id^="tblDos"], [id^="tblDosArch"]'); allTables.forEach(table => { const tableId = table.id; const headers = table.querySelectorAll('th[data-sortable="true"]'); const tbody = table.querySelector('tbody'); if (!tbody) return; if (!tableSortStates.has(tableId)) { tableSortStates.set(tableId, { originalOrder: null, currentSort: { column: null, direction: null } }); } headers.forEach(header => { header.addEventListener('click', function() { const columnIndex = parseInt(this.getAttribute('data-column-index')); const sortType = this.getAttribute('data-sort-type'); sortTable(tableId, columnIndex, sortType, this); }); }); }); } function sortTable(tableId, columnIndex, sortType, headerElement) { const table = document.getElementById(tableId); const tbody = table.querySelector('tbody'); const rows = Array.from(tbody.querySelectorAll('tr')); const state = tableSortStates.get(tableId); if (!state.originalOrder) { state.originalOrder = rows.slice(); } const allHeaders = table.querySelectorAll('th[data-sortable="true"]'); allHeaders.forEach(h => h.style.fontWeight = 'normal'); let sortedRows; if (state.currentSort.column === columnIndex && state.currentSort.direction === 'desc') { sortedRows = state.originalOrder.slice(); state.currentSort = { column: null, direction: null }; } else { const direction = (state.currentSort.column === columnIndex && state.currentSort.direction === 'asc') ? 'desc' : 'asc'; sortedRows = rows.slice().sort((a, b) => { const aCell = a.cells[columnIndex]; const bCell = b.cells[columnIndex]; if (!aCell || !bCell) return 0; let aValue = aCell.textContent.trim(); let bValue = bCell.textContent.trim(); if (sortType === 'number') { aValue = aValue.replace(/[^\d,.-]/g, '').replace(',', '.'); bValue = bValue.replace(/[^\d,.-]/g, '').replace(',', '.'); aValue = parseFloat(aValue) || 0; bValue = parseFloat(bValue) || 0; return direction === 'asc' ? aValue - bValue : bValue - aValue; } else if (sortType === 'date') { aValue = parseDateFromText(aValue); bValue = parseDateFromText(bValue); if (!aValue && !bValue) return 0; if (!aValue) return direction === 'asc' ? 1 : -1; if (!bValue) return direction === 'asc' ? -1 : 1; return direction === 'asc' ? aValue - bValue : bValue - aValue; } else { const comparison = aValue.localeCompare(bValue, 'fr'); return direction === 'asc' ? comparison : -comparison; } }); state.currentSort = { column: columnIndex, direction }; headerElement.style.fontWeight = 'bold'; } tbody.innerHTML = ''; sortedRows.forEach(row => tbody.appendChild(row)); } function parseDateFromText(dateText) { const match = dateText.match(/(\d{2})\/(\d{2})[\/\s](\d{4})/); if (!match) return null; const [, day, month, year] = match; return new Date(year, month - 1, day); } window.addEventListener('DOMContentLoaded', (event) => { console.log('#'); // Initialisation des éléments utilisés let elCelDevisEnCours = document.getElementsByClassName('celEnCours'); let elCelDevisArchives = document.getElementsByClassName('celArchives'); let elBtnViewDevisEnCours = document.getElementsByClassName('btnViewDevisEnCours'); let elBtnExportDevisEnCours = document.getElementsByClassName('btnExportDevisEnCours'); let elBtnExportDevisXMLEnCours = document.getElementsByClassName('btnExportDevisXMLEnCours'); let elBtnExportSelectedXML = document.querySelector('.btnExportSelectedXML'); let elExportCheckboxes = document.getElementsByClassName('exportXMLCheckbox'); let elBtnImportPDFEnCours = document.getElementsByClassName('btnImportPDFEnCours'); let elBtnUploadPDF = document.getElementById('btnUploadPDF'); let elBtnClosePDF = document.getElementById('btnClosePDF'); let elBtnDeleteDevis = document.getElementsByClassName('btnDeleteDevis'); let elBtnViewDevisArchives = document.getElementsByClassName('btnViewDevisArchives'); let elChatBtnSendEnCours = document.getElementById('chatBtnSendEnCours'); let elBtnSaveComment = document.getElementById('btnSaveComment'); let elBtnDevisEnvoye = document.getElementsByClassName('btnDevisEnvoye'); // Par défaut, on n'affiche pas les chats document.getElementById('chat-container-enCours').style.display = 'none'; document.getElementById('chat-container-archives').style.display = 'none'; //! On récupère les données contextuelles propres à l'utilisateur fetch('/jxpost/get_context', { method: 'POST', headers: { 'Content-Type': 'application/json;charset=utf-8', Accept: 'application/json;charset=utf-8', }, }).then((response) => { const ret = response.json(); ret.then(function (data) { const user = data.user; fkUser = user.rowid; const session = data.session; }); }); //! Si on clique sur l'onglet "En cours", met à jour le panel $('a[data-toggle="tab"]').on('show.bs.tab', function (e) { if ($(this).attr('href') == '#tabEnCours') { panel = 'enCours'; } else if ($(this).attr('href') == '#tabArchives') { panel = 'archives'; } console.log('panel: ' + panel); }); // Fonctions let clickLigDevisEnCours = function () { panel = 'enCours'; //! On ne fait rien si l'utilisateur clique sur le même devis console.log('click ligne devis en cours'); if (this.getAttribute('data-rid') != idDevisEnCours) { idDevisEnCours = this.getAttribute('data-rid'); //! On met enfin en évidence la ligne cliquée Array.from(elCelDevisEnCours).forEach(function (ligDevis) { if (ligDevis.getAttribute('data-rid') == oldIdLnEnCours) { ligDevis.style.backgroundColor = oldColorLnEnCours; } else if (ligDevis.getAttribute('data-rid') == idDevisEnCours) { oldColorLnEnCours = ligDevis.style.backgroundColor; ligDevis.style.backgroundColor = '#9bbce7'; } }); oldIdLnEnCours = idDevisEnCours; console.log('idDevisEnCours: ' + idDevisEnCours); refreshChat(); } }; let clickViewDevis = function () { if (panel == 'enCours') { idDevisEnCours = this.getAttribute('data-rid'); } else { idDevisArchives = this.getAttribute('data-rid'); } const idDevis = panel == 'enCours' ? idDevisEnCours : idDevisArchives; let chkSpeciaux = false; showLoading(); // on charge les infos de l'en-tête du devis fetch('/jxdevis/load_devis', { method: 'POST', body: JSON.stringify({ cid: idDevis }), headers: { 'Content-Type': 'application/json;charset=utf-8', Accept: 'application/json;charset=utf-8', }, }) .then((response) => { if (!response.ok) { showNotification('Erreur', "Le chargement des infos de l'en-tête de ce devis n'a pas abouti", 'error'); } else { const ret = response.json(); ret .then(function (data) { fkUser = data[0].fk_user; idMarche = data[0].fk_marche; chkClientsSecteur = data[0].chk_clients_secteur; chkSpeciaux = data[0].chk_speciaux == '1' ? true : false; if (chkSpeciaux) { document.getElementById('panSpeciaux').classList.remove('hidden'); } else { document.getElementById('panSpeciaux').classList.add('hidden'); } showDevisEnTete(data); showDevisTotaux(data); }) .then(function () { //! Une fois le marché trouvé, on charge les infos du marché préchargé dans l'en-tête du devis fetch('/jxdevis/load_devis_marche_infos', { method: 'POST', body: JSON.stringify({ cid: idMarche }), headers: { 'Content-Type': 'application/json;charset=utf-8', Accept: 'application/json;charset=utf-8', }, }).then((response) => { if (!response.ok) { showNotification('Erreur', "Le chargement des infos du marché n'a pas abouti", 'error'); } else { const ret = response.json(); ret.then(function (data) { showDevisMarcheInfos(data); }); } }); if (chkSpeciaux) { //! On charge les infos des produits spéciaux fetch('/jxdevis/load_devis_speciaux', { method: 'POST', body: JSON.stringify({ cid: idDevis }), headers: { 'Content-Type': 'application/json;charset=utf-8', Accept: 'application/json;charset=utf-8', }, }).then((response) => { if (!response.ok) { showNotification('Erreur', "Le chargement des produits spéciaux de ce devis n'a pas abouti", 'error'); } else { const retSpeciaux = response.json(); retSpeciaux.then(function (dataSpeciaux) { // on vide les 5 lignes de produits spéciaux pour éviter de reprendre des données d'un autre devis for (i = 1; i <= 5; i++) { document.getElementById('inp_specialCode_' + i).value = ''; document.getElementById('inp_specialLibe_' + i).value = ''; document.getElementById('inp_specialQte_' + i).value = ''; document.getElementById('inp_specialCout_' + i).value = ''; document.getElementById('inp_chk_specialEchantillon_' + i).checked = false; document.getElementById('inp_specialDate_' + i).value = ''; document.getElementById('inp_specialConcurrent_' + i).value = ''; document.getElementById('inp_specialDescription_' + i).value = ''; } if (dataSpeciaux.length > 0) { // on a trouvé une ligne dans la table devis_speciaux const data = dataSpeciaux[0]; console.log('on a trouvé une ligne dans la table devis_speciaux'); console.log(data); // on charge les données dans le formulaire if (data.chk_livr_multi == '1') { document.getElementById('inp_chk_livr_multi').checked = true; } else { document.getElementById('inp_chk_livr_multi').checked = false; } document.getElementById('inp_nb_livr').value = data.nb_livr; document.getElementById('inp_date_livr_1').value = data.date_livr_1; for (i = 1; i <= 5; i++) { document.getElementById('inp_specialCode_' + i).value = data[`code_produit_${i}`]; document.getElementById('inp_specialLibe_' + i).value = data[`lib_produit_${i}`]; document.getElementById('inp_specialQte_' + i).value = data[`qte_${i}`]; document.getElementById('inp_specialCout_' + i).value = data[`surcout_${i}`]; if (data[`chk_echantillon_${i}`] == '1') { document.getElementById('inp_chk_specialEchantillon_' + i).checked = true; } else { document.getElementById('inp_chk_specialEchantillon_' + i).checked = false; } if (data[`date_echantillon_${i}`] != '0000-00-00') { document.getElementById('inp_specialDate_' + i).value = data[`date_echantillon_${i}`]; } document.getElementById('inp_specialConcurrent_' + i).value = data[`lib_concurrent_${i}`]; document.getElementById('inp_specialDescription_' + i).value = data[`description_${i}`]; } } else { // on n'a pas trouvé de ligne dans la table devis_speciaux console.log("on n'a pas trouvé de ligne dans la table devis_speciaux"); // on vide les champs du formulaire document.getElementById('inp_idDevis_speciaux').value = idDevis; document.getElementById('frmSpeciaux').reset(); } }); } }); } }); } }) .catch((error) => { showNotification('Erreur', "Le chargement des infos de l'en-tête de ce devis n'a pas abouti", 'error'); }); // on charge les produits enregistrés pour ce devis dans 2 tableaux distincts tblProduitsSelect (2ème onglet) et tblDevisPro (3ème onglet) fetch('/jxdevis/load_devis_produits', { method: 'POST', body: JSON.stringify({ cid: idDevis }), headers: { 'Content-Type': 'application/json;charset=utf-8', Accept: 'application/json;charset=utf-8', }, }).then((response) => { if (!response.ok) { showNotification('Erreur', "Le chargement des produits de ce devis n'a pas abouti", 'error'); } else { const ret = response.json(); //! Boucle sur le résultat de la requête ajax ret.then(function (data) { showDevisProduits(data); }); } }); hideLoading(); if (panel == 'enCours') { //! On ne fait rien si l'utilisateur clique sur le même devis if (this.getAttribute('data-rid') != idDevisEnCours) { idDevisEnCours = this.getAttribute('data-rid'); //! On met enfin en évidence la ligne cliquée Array.from(elCelDevisEnCours).forEach(function (ligDevis) { if (ligDevis.getAttribute('data-rid') == oldIdLnEnCours) { ligDevis.style.backgroundColor = oldColorLnEnCours; } else if (ligDevis.getAttribute('data-rid') == idDevisEnCours) { oldColorLnEnCours = ligDevis.style.backgroundColor; ligDevis.style.backgroundColor = '#9bbce7'; } }); oldIdLnEnCours = idDevisEnCours; console.log('idDevisEnCours: ' + idDevisEnCours); } } else { //! On ne fait rien si l'utilisateur clique sur le même devis if (this.getAttribute('data-rid') != idDevisArchives) { idDevisArchives = this.getAttribute('data-rid'); //! On met enfin en évidence la ligne cliquée Array.from(elCelDevisArchives).forEach(function (ligDevis) { if (ligDevis.getAttribute('data-rid') == oldIdLnArchives) { ligDevis.style.backgroundColor = oldColorLnArchives; } else if (ligDevis.getAttribute('data-rid') == idDevisArchives) { oldColorLnArchives = ligDevis.style.backgroundColor; ligDevis.style.backgroundColor = '#9bbce7'; } }); oldIdLnArchives = idDevisArchives; console.log('idDevisArchives: ' + idDevisArchives); } } refreshChat(); document.getElementById('modViewDevisTitre').innerHTML = 'Consultation du devis n°' + idDevis; showModal(document.getElementById('modalViewDevis')); }; document.getElementById('btnCloseModViewDevis').addEventListener('click', function () { hideModal(document.getElementById('modalViewDevis')); }); function showDevisEnTete(ret) { // Affiche les données de l'en-tête du devis const data = ret[0]; document.getElementById('inp_num_opportunite').value = data.num_opportunite; document.getElementById('inp_date_demande').value = data.date_demande; document.getElementById('inp_date_remise').value = data.date_remise; console.log(data.code); if (data.code === null) { document.getElementById('inp_lib_client').value = data.lib_new_client; document.getElementById('inp_type_client').value = data.type_new_client; document.getElementById('inp_adresse1').value = data.adresse1_new_client; document.getElementById('inp_adresse2').value = data.adresse2_new_client; document.getElementById('inp_adresse3').value = data.adresse3_new_client; document.getElementById('inp_cp').value = data.cp_new_client; document.getElementById('inp_ville').value = data.ville_new_client; document.getElementById('inp_contact_nom').value = data.contact_new_nom; document.getElementById('inp_contact_prenom').value = data.contact_new_prenom; document.getElementById('inp_contact_fonction').value = data.contact_new_fonction; document.getElementById('inp_email').value = data.new_email; document.getElementById('inp_telephone').value = data.new_telephone; document.getElementById('inp_mobile').value = data.new_mobile; } else { document.getElementById('inp_lib_client').value = data.libelle; document.getElementById('inp_type_client').value = data.type_client; document.getElementById('inp_adresse1').value = data.adresse1; document.getElementById('inp_adresse2').value = data.adresse2; document.getElementById('inp_adresse3').value = data.adresse3; document.getElementById('inp_cp').value = data.cp; document.getElementById('inp_ville').value = data.ville; document.getElementById('inp_contact_nom').value = data.contact_nom; document.getElementById('inp_contact_prenom').value = data.contact_prenom; document.getElementById('inp_contact_fonction').value = data.contact_fonction; document.getElementById('inp_email').value = data.email; document.getElementById('inp_telephone').value = data.telephone; document.getElementById('inp_mobile').value = data.mobile; } document.getElementById('inp_lib_marche').value = data.lib_marche; if (data.chk_devis_photos == '1') { document.getElementById('inp_chk_devis_photos').checked = true; } else { document.getElementById('inp_chk_devis_photos').checked = false; } document.getElementById('inp_commentaire').value = data.commentaire; } function showDevisTotaux(ret) { // Affiche les totaux du devis const data = ret[0]; document.getElementById('inpTotalHT').value = data.montant_total_ht; document.getElementById('inpTotalRemHT').value = data.montant_total_ht_remise; document.getElementById('inpTotalMarge').value = data.marge_totale; } function showDevisMarcheInfos(ret) { // On affiche les infos du marché if (ret.length == 1) { let line = ret[0]; $('#tdTxRemiseTrim').text(line.taux_remise_trimestrielle + ' %'); $('#tdTxRemiseSeme').text(line.taux_remise_semestrielle + ' %'); $('#tdTxRemiseAnnu').text(line.taux_remise_annuelle + ' %'); $('#tdDebutFin').text(convertMySQLDateToFrenchDate(line.date_fin)); $('#tdGarantie').text(line.garantie); $('#tdDelaiLivr').text(line.delai_de_livraison); $('#tdRemisesCo').text(line.remises_commerciales); } else { $('#tdTxRemiseTrim').text('-'); $('#tdTxRemiseSeme').text('-'); $('#tdTxRemiseAnnu').text('-'); $('#tdDebutFin').text('-'); $('#tdGarantie').text('-'); $('#tdDelaiLivr').text('-'); $('#tdRemisesCo').text('-'); } } function showDevisProduits(ret) { //! On affiche les produits du devis dans le tableau tblDevisPro // On vide son body let tblBodyPro = document.getElementById('tblDevisPro').getElementsByTagName('tbody')[0]; tblBodyPro.innerHTML = ''; if (ret.length > 0) { // au moins un produit trouvé pour ce devis let nbProduits = ret.length; for (let key in ret) { if (ret.hasOwnProperty(key)) { // Récupération des valeurs de la ligne let val = ret[key]; // Insertion d'une nouvelle ligne et création de ses colonnes : on prend ici le rowid de devis_produits let newRowPro = tblBodyPro.insertRow(0); let celCodePro = newRowPro.insertCell(0); celCodePro.innerHTML = val['code']; let celLibellePro = newRowPro.insertCell(1); celLibellePro.innerHTML = val['libelle']; let celPrixVentePro = newRowPro.insertCell(2); celPrixVentePro.className = 'text-right'; celPrixVentePro.innerHTML = val['prix_vente'] + ' €'; let celQtePro = newRowPro.insertCell(3); celQtePro.innerHTML = ''; let celRemisePro = newRowPro.insertCell(4); celRemisePro.innerHTML = '
%
'; let celHTPro = newRowPro.insertCell(5); celHTPro.innerHTML = '
'; let celVariante = newRowPro.insertCell(6); celVariante.className = 'text-center'; celVariante.innerHTML = ''; let celMargePro = newRowPro.insertCell(7); celMargePro.innerHTML = '
%
'; } } } } let clickLigDevisArchives = function () { panel = 'archives'; //! On ne fait rien si l'utilisateur clique sur le même devis if (this.getAttribute('data-rid') != idDevisArchives) { idDevisArchives = this.getAttribute('data-rid'); //! On met enfin en évidence la ligne cliquée Array.from(elCelDevisArchives).forEach(function (ligDevis) { if (ligDevis.getAttribute('data-rid') == oldIdLnArchives) { ligDevis.style.backgroundColor = oldColorLnArchives; } else if (ligDevis.getAttribute('data-rid') == idDevisArchives) { oldColorLnArchives = ligDevis.style.backgroundColor; ligDevis.style.backgroundColor = '#9bbce7'; } }); oldIdLnArchives = idDevisArchives; console.log('idDevisArchives: ' + idDevisArchives); refreshChat(); } }; let clickExportDevisEnCours = function () { idDevisEncours = this.getAttribute('data-rid'); const url = '/expxls/export_sap_devis/' + idDevisEncours.toString(); console.log('Export Excel : ' + url); window.open(url, '_blank'); panel = 'enCours'; refreshChat(); return false; }; let clickExportDevisXMLEnCours = function () { idDevisEncours = this.getAttribute('data-rid'); const url = '/jxexport/xml_devis/' + idDevisEncours.toString(); console.log('Export xml : ' + url); window.open(url, '_blank'); return false; }; function refreshChat() { console.log('refreshChat()'); if ((idDevisEnCours > 0 && panel == 'enCours') || (idDevisArchives > 0 && panel == 'archives')) { console.log('refreshChat()'); let idDevis = 0; if (panel == 'enCours') { idDevis = idDevisEnCours; } else { idDevis = idDevisArchives; } //! On récupère les données de devis_histo fetch('/jxchat/refresh', { method: 'POST', headers: { 'Content-Type': 'application/json;charset=utf-8', Accept: 'application/json;charset=utf-8', }, body: JSON.stringify({ cid: idDevis, }), }).then((response) => { const ret = response.json(); ret.then(function (data) { // on vérifie si le nombre de commentaires a changé if (nbCommentChat != data.length) { // Si c'est le cas on rafraîchit tous les commentaires // On supprime tous les commentaires const chatContainer = document.getElementById('chat-bubbles-' + panel); const chatBubbles = chatContainer.getElementsByClassName('chat-bubble'); while (chatBubbles.length > 0) { chatBubbles[0].parentNode.removeChild(chatBubbles[0]); } // On ajoute tous les commentaires for (let i = 0; i < data.length; i++) { const chatBubble = document.createElement('div'); chatBubble.classList.add('chat-bubble'); if (data[i].fk_user == fkUser) { chatBubble.classList.add('right-chat-bubble'); } else { chatBubble.classList.add('left-chat-bubble'); } const initiales = data[i].prenom.substring(0, 1) + data[i].libelle.substring(0, 1); const userInfo = document.createElement('div'); userInfo.classList.add('user-info'); const userInitials = document.createElement('div'); userInitials.classList.add('user-initials'); userInitials.innerHTML = initiales; userInfo.appendChild(userInitials); const usernameDate = document.createElement('div'); usernameDate.classList.add('username-date'); const username = document.createElement('span'); username.classList.add('username'); username.innerHTML = data[i].prenom + ' ' + data[i].libelle; usernameDate.appendChild(username); const date = document.createElement('span'); date.classList.add('date'); date.innerHTML = data[i].date_histo; usernameDate.appendChild(date); userInfo.appendChild(usernameDate); chatBubble.appendChild(userInfo); const message = document.createElement('div'); message.classList.add('message'); message.innerHTML = data[i].commentaire; chatBubble.appendChild(message); chatContainer.appendChild(chatBubble); } nbCommentChat = data.length; // et on vide le champ de saisie s'il n'a pas le focus if (!document.getElementById('chatInputMessage').hasFocus) { document.getElementById('chatInputMessage').value = ''; } } const chatCont = document.getElementById('chat-container-' + panel); chatCont.style.display = 'block'; }); }); console.log('Chat refreshed at ' + new Date()); } } let chatSendMessage = function () { // On récupère le message à envoyer const message = document.getElementById('chatInputMessage').value; // On récupère l'id du devis let idDevis = 0; if (panel == 'enCours') { idDevis = idDevisEnCours; } else { idDevis = idDevisArchives; } // On envoie le message fetch('/jxchat/save_message', { method: 'POST', headers: { 'Content-Type': 'application/json;charset=utf-8', Accept: 'application/json;charset=utf-8', }, body: JSON.stringify({ cid: idDevis, message: message, fkuser: fkUser, }), }).then((response) => { const ret = response.json(); ret.then(function (data) { refreshChat(); }); }); }; setInterval(refreshChat, 60000); // Refresh every 60 seconds (1000 ms = 1 second) let clickSaveComment = function () { commentaire = document.getElementById('inpComment').value; if (commentaire == '') { showNotification('Veuillez saisir un commentaire', 'warning'); return false; } // On envoie le message fetch('/jxchat/save_message', { method: 'POST', headers: { 'Content-Type': 'application/json;charset=utf-8', Accept: 'application/json;charset=utf-8', }, body: JSON.stringify({ cid: idDevisEnCours, message: commentaire, fkuser: fkUser, }), }).then((response) => { const ret = response.json(); ret.then(function (data) { hideModal(document.getElementById('modalViewDevis')); refreshChat(); }); }); }; let clickImportPDFEnCours = function () { idDevisEnCours = this.getAttribute('data-rid'); panel = 'enCours'; //! On va chercher les éventuels fichiers déjà uploadés fetch('/jximport/get_files', { method: 'POST', headers: { 'Content-Type': 'application/json;charset=utf-8', Accept: 'application/json;charset=utf-8', }, body: JSON.stringify({ cid: idDevisEnCours, sup: 'devis_pdf_sap', }), }).then(function (response) { const tblBodyPJ = document.getElementById('tblPJ').getElementsByTagName('tbody')[0]; tblBodyPJ.innerHTML = ''; if (response.ok) { const ret = response.json(); ret.then(function (data) { if (data.length > 0) { data.forEach(function (val, idx) { let newRowPJ = tblBodyPJ.insertRow(-1); newRowPJ.className = 'text-center'; let celPJ = newRowPJ.insertCell(0); celPJ.innerHTML = '' + val['fichier'] + ''; let celSup = newRowPJ.insertCell(1); celSup.innerHTML = ''; document.getElementById('btnSupPJ_' + val['rowid']).addEventListener('click', clickDeletePJ); }); } }); } refreshChat(); }); showModal(document.getElementById('modalUploadPDF')); panel = 'enCours'; return false; }; let clickUploadPDF = function () { let file = document.getElementById('txtUploadPDF').files[0]; if (file == undefined) { showNotification('Veuillez sélectionner un fichier PDF', 'warning'); return false; } let formData = new FormData(); formData.append('file', file); formData.append('cid', idDevisEnCours); fetch('/jximport/upload_sap_pdf', { method: 'POST', body: formData, }).then((response) => { const ret = response.json(); ret.then(function (data) { if (data.ret == 'ok') { showNotification(data.msg, 'success'); } else { showNotification(data.msg, 'error'); } hideModal(document.getElementById('modalUploadPDF')); location.reload(); }); }); }; let clickClosePDF = function () { hideModal(document.getElementById('modalUploadPDF')); }; function clickDeletePJ() { const idMedia = this.getAttribute('data-rid'); if (confirm('Voulez-vous vraiment supprimer ce fichier ?')) { let id = this.getAttribute('data-rid'); fetch('/jximport/delete_file', { method: 'POST', headers: { 'Content-Type': 'application/json;charset=utf-8', Accept: 'application/json;charset=utf-8', }, body: JSON.stringify({ cid: idMedia, }), }).then(function (response) { if (response.ok) { const ret = response.json(); ret.then(function () { showNotification('Fichier supprimé avec succès !'); // On rafraichit la liste des PJ const tblBodyPJ = document.getElementById('tblPJ').getElementsByTagName('tbody')[0]; // On supprime la ligne correspondant à la PJ supprimée Array.from(tblBodyPJ.rows).forEach(function (row) { if (row.cells[1].firstChild.getAttribute('data-rid') == idMedia) { row.remove(); } }); }); } }); } return false; } let clickDevisEnvoye = function () { idDevisEnCours = this.getAttribute('data-rid'); panel = 'enCours'; refreshChat(); if (confirm('Ce devis a bien été envoyé au client ? Il sera archivé et ne pourra plus être mis à jour.')) { let data = {}; data['cid'] = idDevisEnCours; data['statut'] = 20; data['commentaire'] = 'Devis envoyé au client et archivé'; fetch('/jxdevis/statut_devis', { method: 'POST', body: JSON.stringify(data), headers: { 'Content-Type': 'application/json', Accept: 'application/json', }, }); showNotification('Devis archivé', 'Le devis est maintenant archivé', 'success'); setTimeout(function () { location.reload(); }, 2000); // 2000 millisecondes = 2 secondes } return false; }; let clickDeleteDevis = function () { idDevisEnCours = this.getAttribute('data-rid'); panel = 'enCours'; refreshChat(); if (confirm('Voulez-vous vraiment supprimer ce devis ?')) { let data = {}; data['cid'] = idDevisEnCours; fetch('/jxdevis/delete_devis', { method: 'POST', body: JSON.stringify(data), headers: { 'Content-Type': 'application/json', Accept: 'application/json', }, }); showNotification('Devis supprimé', 'Le devis a été supprimé', 'success'); setTimeout(function () { location.reload(); }, 2000); // 2000 millisecondes = 2 secondes } return false; }; // Fonctions de recherche SAP let elSearchSAP = document.getElementById('searchSAP'); let elBtnResetSearchSAP = document.getElementById('btnResetSearchSAP'); function restoreSearchSAP() { const storageKey = panel === 'enCours' ? 'sapSearchTermEnCours' : 'sapSearchTermArchives'; const savedTerm = sessionStorage.getItem(storageKey); if (savedTerm && savedTerm.length >= 3) { elSearchSAP.value = savedTerm; elBtnResetSearchSAP.style.display = 'inline-block'; performSearchSAP(savedTerm); } else { elSearchSAP.value = ''; elBtnResetSearchSAP.style.display = 'none'; } } function performSearchSAP(term) { if (term.length < 3) { return; } const context = panel === 'archives' ? 'archives' : 'encours'; fetch('/jxdevis/search_devis_sap', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ term: term, context: context, }), }) .then((response) => response.json()) .then((data) => { if (data.success) { const devisIds = data.devis.map((d) => d.rowid); filterDevisTablesSAP(devisIds, context); updateBadgesSAP(data.nb_devis); } else { console.error('Erreur recherche:', data.message); } }) .catch((error) => { console.error('Erreur AJAX:', error); }); } function filterDevisTablesSAP(devisIds, context) { if (context === 'encours') { const statuts = document.querySelectorAll('[id^="tblBodyDos"]'); statuts.forEach((tbody) => { const rows = tbody.querySelectorAll('tr.ligEnCours'); rows.forEach((row) => { const cells = row.querySelectorAll('.celEnCours'); if (cells.length > 0) { const rowId = parseInt(cells[0].getAttribute('data-rid')); if (devisIds.includes(rowId)) { row.style.display = ''; } else { row.style.display = 'none'; } } }); }); } else { const archives = document.querySelectorAll('[id^="tblBodyDosArch"]'); archives.forEach((tbody) => { const rows = tbody.querySelectorAll('tr'); rows.forEach((row) => { if (row.id && (row.id.startsWith('trArch_') || row.id.startsWith('trArchTous_'))) { const rowId = parseInt(row.id.replace('trArch_', '').replace('trArchTous_', '')); if (devisIds.includes(rowId)) { row.style.display = ''; } else { row.style.display = 'none'; } } }); }); } } function updateBadgesSAP(nbDevis) { Object.keys(nbDevis).forEach((statutId) => { const liElements = document.querySelectorAll('[id^="liStat"]'); liElements.forEach((li) => { li.setAttribute('data-after-text', nbDevis[statutId] || '0'); li.setAttribute('data-after-type', 'orange badge top left'); }); }); } function resetSearchSAP() { elSearchSAP.value = ''; elBtnResetSearchSAP.style.display = 'none'; const storageKey = panel === 'enCours' ? 'sapSearchTermEnCours' : 'sapSearchTermArchives'; sessionStorage.removeItem(storageKey); const context = panel === 'archives' ? 'archives' : 'encours'; if (context === 'encours') { const statuts = document.querySelectorAll('[id^="tblBodyDos"]'); statuts.forEach((tbody) => { const rows = tbody.querySelectorAll('tr'); rows.forEach((row) => { row.style.display = ''; }); }); } else { const archives = document.querySelectorAll('[id^="tblBodyDosArch"]'); archives.forEach((tbody) => { const rows = tbody.querySelectorAll('tr'); rows.forEach((row) => { row.style.display = ''; }); }); const tbodyTous = document.getElementById('tblBodyDosArchTous'); if (tbodyTous) { const rowsTous = tbodyTous.querySelectorAll('tr'); rowsTous.forEach((row) => { row.style.display = ''; }); } } } elSearchSAP.addEventListener('input', function () { const term = this.value.trim(); if (searchSapTimeout) { clearTimeout(searchSapTimeout); } if (term.length >= 3) { elBtnResetSearchSAP.style.display = 'inline-block'; const storageKey = panel === 'enCours' ? 'sapSearchTermEnCours' : 'sapSearchTermArchives'; sessionStorage.setItem(storageKey, term); searchSapTimeout = setTimeout(() => { performSearchSAP(term); }, 300); } else if (term.length === 0) { resetSearchSAP(); } else { elBtnResetSearchSAP.style.display = 'none'; } }); elBtnResetSearchSAP.addEventListener('click', function () { resetSearchSAP(); }); // Hook sur changement d'onglet pour restaurer la recherche appropriée $('a[data-toggle="tab"]').on('shown.bs.tab', function (e) { if ($(this).attr('href') == '#tabEnCours') { panel = 'enCours'; restoreSearchSAP(); } else if ($(this).attr('href') == '#tabArchives') { panel = 'archives'; restoreSearchSAP(); } }); restoreSearchSAP(); initTableSort(); // Gestion des états actifs des onglets départements (multiples