//! jdevis.js let chkPageLoad = true // indique que la page vient d'être chargée pour la première fois let idDevis = 0 let fkUser = 0 let fkRole = 0 let devIp = '0' let fkUserDevis = 0 let fkStatutDevis = 0 let chkValidat = 0 let oldColorLn let oldIdLn let chkChange = 0 let idMarche = '' let idNewMarche = '' // dans le cas on l'utilisateur change de marché sur un devis déjà créé let chkClientsSecteur let chkShowDevisArchives = false // indique si on affiche les devis archivés ou non let chkCreateClient = false // On charge les produits du marché du devis en cours dans un tableau pour ne pas avoir à les recharger à chaque fois let dataProduitsMarche = [] let dataProduitsMercurial = [] // Produits du marché hybride pour l'onglet Mercurial let chkMarcheHybride = false // Indique si le marché du devis est hybride //! Pour ne charger les clients du secteur ou de toute la France qu'en cas de changement de la valeur du chkbox let oldChkClientsSecteur = 2 let clients = [] let chkPrixNets = false // le marché du devis en cours est-il en prix nets ou pas let remiseMarcheDeBase = 0 // la remise de base du marché let chkSaisieRemise = false let chkRemisesMarche = true // indique si toutes les lignes du devis appliquent la remise du marché ou pas let aRemisesMarches = [] let devisTotalHT = 0 let devisTotalRemHT = 0 let devisTotalMarge = 0 let chkRegleSeuilsMarge = false // indique si le marché sélectionné prend en compte les seuils de marge fixés dans les familles de produits let seuilMargeRR = 30 // le seuil de marge du RR sur ce devis, par défaut à 30 % let seuilMargeDV = 20 // le seuil de marge du DV sur ce devis, par défaut à 20 % let intervalRefresh let nbCommentChat = 0 let draggedElement = null // l'élément qui est en train d'être déplacé (la ligne du produit du devis lors d'un drag and drop) window.addEventListener('DOMContentLoaded', (event) => { console.log('#') // Initialisation des éléments utilisés let elCelDevis = document.getElementsByClassName('celDevis') let elCelArchives = document.getElementsByClassName('celArchives') let elBtnDupDevis = document.getElementsByClassName('btnDupDevis') let elBtnSupprDevis = document.getElementsByClassName('btnSupprDevis') let elBtnExpExcelDevis = document.getElementsByClassName('btnExpExcelDevis') let elBtnValDevis = document.getElementsByClassName('btnValDevis') let elBtnPdfDevis = document.getElementsByClassName('btnPdfDevis') let elBtnReactiverDevis = document.getElementsByClassName('btnReactiverDevis') console.log('Nombre de boutons btnReactiverDevis trouvés:', elBtnReactiverDevis.length) let elBtnValidationRR = document.getElementById('btnValidationRR') let elBtnRefusRR = document.getElementById('btnRefusRR') let elBtnCloseRR = document.getElementById('btnCloseRR') let elBtnClosePDF = document.getElementById('btnClosePDF') let elBtnDevisArchives = document.getElementById('btnDevisArchives') let elBtnCreateDevis = document.getElementById('btnCreateDevis') let elBtnCreateClient = document.getElementById('btnCreateClient') let elBtnCancelCreateClient = document.getElementById('btnCancelCreateClient') let elBtnSaveCreateClient = document.getElementById('btnSaveCreateClient') let elBtnSpeciaux = document.getElementById('btnSpeciaux') let elBtnCancelSpeciaux = document.getElementById('btnCancelSpeciaux') let elBtnSaveSpeciaux = document.getElementById('btnSaveSpeciaux') let elBtnSaveEnTete = document.getElementById('btnSaveEnTete') let elBtnSaveSelProduits = document.getElementById('btnSaveSelProduits') let elBtnSaveDevis = document.getElementById('btnSaveDevis') let elBtnSaveDevisAndSend = document.getElementById('btnSaveDevisAndSend') let elChkClientsSecteur = document.getElementById('inp_chk_clients_secteur') let elInputSearchProducts = document.querySelectorAll("input[id^='inpSearchProduct_']") let elInputQtes = document.querySelectorAll("input[name^='inpQte_']") let elInputRemises = document.querySelectorAll("input[name^='inpRemise_']") let elChkVariantes = document.querySelectorAll("input[type='checkbox'][name^='chkVariante_']") let elInputDateDemande = document.getElementById('inp_date_demande') let elInputDateRemise = document.getElementById('inp_date_remise') let elListOngletsProduits = document.getElementById('listOngletsProduits') let elOngletsProduits = document.querySelectorAll('[id^="onglet_"]') let elProdSelect = document.querySelectorAll('input[type="checkbox"][name^="chkBoxProd_"]') let elInpCommentGesteComm = document.getElementById('inpCommentGesteComm') let elChatBtnSend = document.getElementById('chatBtnSend') let elBtnCancelCommentProd = document.getElementById('btnCancelCommentProd') let elBtnSaveCommentProd = document.getElementById('btnSaveCommentProd') //! Au chargement de la page on affiche le menu vertical de choix du devis et on cache les 3 onglets const elDivDevis = document.getElementById('divDevis') const elDossStatuts = document.getElementById('vb-dossiers-statuts') const elDossArchives = document.getElementById('vb-dossiers-archives') // Par défaut on n'affiche pas le chat document.getElementById('chat-container').style.display = 'none' const elVerticalBar = document.getElementById('verticalBar') const elBtnSideBarDevis = document.getElementById('btnSideBarDevis') // par défaut on affiche les dossiers par statuts de devis elDossStatuts.classList.remove('hidden') elDossArchives.classList.add('hidden') elVerticalBar.style.width = '1100px' elDivDevis.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 fkRole = user.fk_role devIp = data.devip const session = data.session }) }) let clickDevisArchives = function () { // click sur le bouton de la sidebar pour afficher les devis archivés ou revenir sur les devis en cours elDossStatuts.classList.toggle('hidden') idDevis = 0 const archivesHidden = elDossArchives.classList.toggle('hidden') if (archivesHidden) { this.innerHTML = 'Mes devis archivés' chkShowDevisArchives = false document.getElementById('chat-message-input').classList.remove('hidden') // Il faut afficher tous les boutons d'enregistrement elBtnSaveEnTete.classList.remove('hidden') elBtnSaveSelProduits.classList.remove('hidden') elBtnSaveDevis.classList.remove('hidden') elBtnSaveDevisAndSend.classList.remove('hidden') elBtnSaveSpeciaux.classList.remove('hidden') } else { this.innerHTML = 'Mes devis en cours' chkShowDevisArchives = true document.getElementById('chat-message-input').classList.add('hidden') // Il faut cacher tous les boutons d'enregistrement elBtnSaveEnTete.classList.add('hidden') elBtnSaveSelProduits.classList.add('hidden') elBtnSaveDevis.classList.add('hidden') elBtnSaveDevisAndSend.classList.add('hidden') elBtnSaveSpeciaux.classList.add('hidden') } document.getElementById('chat-container').style.display = 'none' elDivDevis.style.display = 'none' return false } let clickLigDevis = function () { //! L'utilisateur vient de cliquer sur un devis dans la liste de gauche //! On ne fait rien si l'utilisateur clique sur le même devis if (this.getAttribute('data-rid') != idDevis) { if (chkChange == 1) { if (confirm('Attention, vous avez des modifications non enregistrées sur ce devis. Voulez-vous continuer ?')) { chkChange = 0 } else { return false } } idDevis = this.getAttribute('data-rid') showLoading() // on met à jour l'input caché contenant l'id du devis sélectionné document.getElementById('inpIdDevis').value = idDevis let dataFamilles //! on charge les familles de groupes de produits pour mettre à jour le tableau de chaque onglet fetch('/jxdevis/load_familles', { method: 'POST', headers: { 'Content-Type': 'application/json;charset=utf-8', Accept: 'application/json;charset=utf-8', }, }).then((response) => { if (!response.ok) { showNotification('Erreur', "Le chargement des familles de produits n'a pas abouti", 'error') } else { const ret = response.json() ret.then(function (data) { dataFamilles = data }) } }) // effectue la requête ajax fetch pour charger les produits du marché 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) { fkUserDevis = data[0].fk_user fkStatutDevis = data[0].fk_statut_devis chkValidat = data[0].chk_validat idMarche = data[0].fk_marche idNewMarche = data[0].fk_marche // par défaut le nouveau marché est le même que le marché en cours sur ce devis chkClientsSecteur = data[0].chk_clients_secteur showDevisEnTete(data) updateBtnSpeciaux(data[0].chk_speciaux) 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() //! Boucle sur le résultat de la requête ajax ret.then(function (data) { showDevisMarcheInfos(data) chkRegleSeuilsMarge = data[0].chk_regle_seuils_marge //! On charge ensuite les produits du marché de ce devis fetch('/jxdevis/load_devis_marche_produits', { 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 produits du marché n'a pas abouti", 'error') } else { const ret = response.json() ret.then(function (data) { dataProduitsMarche = data showDevisMarcheProduits(dataFamilles, data) // 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) }) } }) }) } }) }) } }) }) } }) .catch((error) => { showNotification('Erreur', "Le chargement des infos de l'en-tête de ce devis n'a pas abouti", 'error') }) hideLoading() chkPageLoad = false elDivDevis.style.display = 'block' refreshChat() //! On met enfin en évidence la ligne cliquée Array.from(elCelDevis).forEach(function (ligDevis) { if (ligDevis.getAttribute('data-rid') == oldIdLn) { ligDevis.style.backgroundColor = oldColorLn } else if (ligDevis.getAttribute('data-rid') == idDevis) { oldColorLn = ligDevis.style.backgroundColor ligDevis.style.backgroundColor = '#9bbce7' } }) oldIdLn = idDevis chkChange = 0 } } let clickLigArchives = function () { //! L'utilisateur vient de cliquer sur un devis archivé dans la liste de gauche //! On ne fait rien si l'utilisateur clique sur le même devis if (this.getAttribute('data-rid') != idDevis) { if (chkChange == 1) { if ( confirm( 'Attention, vous avez des modifications non enregistrées sur le devis en cours. Voulez-vous continuer ?' ) ) { chkChange = 0 } else { return false } } idDevis = this.getAttribute('data-rid') refreshChat() //! On met enfin en évidence la ligne cliquée Array.from(elCelArchives).forEach(function (ligArchive) { if (ligArchive.getAttribute('data-rid') == oldIdLn) { ligArchive.style.backgroundColor = oldColorLn } else if (ligArchive.getAttribute('data-rid') == idDevis) { oldColorLn = ligArchive.style.backgroundColor ligArchive.style.backgroundColor = '#9bbce7' } }) oldIdLn = idDevis chkChange = 0 } } function showDevisEnTete(ret) { // Affiche les données de l'en-tête du devis const data = ret[0] document.getElementById('inp_rowid').value = data.rowid 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 document.getElementById('inp_fk_user').value = data.fk_user document.getElementById('inp_fk_marche').value = data.fk_marche // On surveille un changement dans le champ fk_marche, ce qui peut provoquer la suppression des produits du devis s'il enregistre ce changement document.getElementById('inp_fk_marche').addEventListener('change', function () { idNewMarche = this.value console.log('idNewMarche :' + idNewMarche) }) if (data.chk_clients_secteur == '1') { document.getElementById('inp_chk_clients_secteur').checked = true } else { document.getElementById('inp_chk_clients_secteur').checked = false } if (data.chk_clients_secteur != oldChkClientsSecteur) { // la valeur du chk_clients_secteur est différente de l'actuelle, on charge les clients du commercial sur son secteur ou sur toute la France changeClientsSecteur() oldChkClientsSecteur == 2 ? (chkChange = 0) : (chkChange = 1) oldChkClientsSecteur = data.chk_clients_secteur } document.getElementById('inp_fk_client').value = data.fk_client console.log('fk_type_new :' + data.type_new_client) if (data.fk_client == 0) { document.getElementById('inp_lib_client').value = data.lib_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 document.getElementById('selTypeEtab').value = data.type_new_client elBtnCreateClient.innerHTML = 'Modifier ce nouveau client' if (elBtnCreateClient.classList.contains('btn-primary')) { elBtnCreateClient.classList.remove('btn-primary') elBtnCreateClient.classList.add('btn-info') } } else { document.getElementById('inp_lib_client').value = data.libelle 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('selTypeEtab').value = data.type_client elBtnCreateClient.innerHTML = 'Créer un nouveau client' if (elBtnCreateClient.classList.contains('btn-info')) { elBtnCreateClient.classList.remove('btn-info') elBtnCreateClient.classList.add('btn-primary') } // Charger les contacts du client et sélectionner le contact du devis loadContactsClient(data.code).then(() => { if (data.fk_contact && data.fk_contact > 0) { document.getElementById('sel_contact').value = data.fk_contact // Afficher les infos du contact const contact = contactsClient.find(c => c.rowid == data.fk_contact) if (contact) { displayContactInfos(contact) } } }) } if (data.chk_devis_photos == '1') { document.getElementById('inp_chk_devis_photos').checked = true } else { document.getElementById('inp_chk_devis_photos').checked = false } // Gestion et affichage des commentaires document.getElementById('inp_commentaire').value = data.commentaire document.getElementById('inpCommentDevis').value = data.comment_devis elInpCommentGesteComm.value = data.comment_geste_comm // On supprime systématiquement la ligne de validation du devis let rowCommentValidatDevis = document.getElementById('rowCommentValidatDevis') if (rowCommentValidatDevis !== null) { rowCommentValidatDevis.remove() } if (fkUserDevis != fkUser && fkRole < 3) { // Le user actuel n'est pas le créateur du devis, et son rôle est le DIR-CO ou un DV const tblBodyComment = document.getElementById('tblCommentDevis').getElementsByTagName('tbody')[0] // Insertion d'une nouvelle ligne et création de ses colonnes : on prend ici le fk_produit let newRowComment = tblBodyComment.insertRow(0) newRowComment.id = 'rowCommentValidatDevis' let celLabel = newRowComment.insertCell(0) celLabel.innerHTML = '' let celComment = newRowComment.insertCell(1) celComment.classList.add('w-60') celComment.innerHTML = '' let celBtnValid = newRowComment.insertCell(2) celBtnValid.classList.add('w-40') celBtnValid.innerHTML = '