const express = require("express"); const router = express.Router(); const fs = require("fs"); const PizZip = require("pizzip"); const Docxtemplater = require("docxtemplater"); const logger = require("../utils/logger"); const path = require("path"); const moment = require("moment"); const parcoursService = require("../services/parcoursService"); const contratService = require("../services/contratService"); const globalService = require("../services/globalService"); const userService = require("../services/userService"); const constantesFAC = require("../constantes/json-modulateur-fac"); require("moment/locale/fr"); moment.locale("fr"); router.post("/fac/projet/:numParcours", async (req, res) => { const content = fs.readFileSync( path.resolve("src/templates/template-projet-fac.docx"), "binary" ); const zip = new PizZip(content); const doc = new Docxtemplater(zip, {paragraphLoop: true, linebreaks: true}); const numParcours = req.params.numParcours.toUpperCase(); const parcours = await parcoursService.getParcoursByNumParcours(numParcours); const contrat = await contratService.getContratById(parcours.contrat); const client = contrat?.["@expand"]?.client || {}; const intermediaire = contrat?.["@expand"]?.intermediaire || {}; const fac = contrat?.["@expand"]?.enCours || null; const projet = fac?.["@expand"]?.projet || null; const moyenTransportList = ["terrestre", "maritime", "aerien", "postal", "fluvial"] const selectedTransportList = [] try { moyenTransportList.forEach((transport) => { if (projet[transport] !== "") { selectedTransportList.push(transport) } }) } catch (error) {} var transportListVirguleEt if (selectedTransportList.length > 1) { transportListVirguleEt = selectedTransportList .slice(0, selectedTransportList.length - 1) .join(', ') + ' et ' + selectedTransportList[selectedTransportList.length - 1] } else { transportListVirguleEt = selectedTransportList.toString() } //au féminin const transportListOuEt = selectedTransportList.join(" et/ou ") .replace('fluvial', "fluviale") .replace('postal', 'postale') .replace('aerien', 'aerienne') const listAssAdd = []; try { projet.assureAdditionnel.forEach((objet) => { listAssAdd.push(objet.nom + " - Adresse : " + objet.adresse + " - Siret : " + objet.siret); }); } catch (error) {} const risqueTransport = { "achat": "des contrats d'achat", "vente": "des contrats de vente", "sav": "des opérations de SAV", "demo": "des démonstrations", "transfert": "des transferts inter-usines" } Object.keys(risqueTransport).forEach((risque) => { if (!projet.risqueTransport.includes(risque)) { delete risqueTransport[risque] } }) const listRisqueTransport = Object.keys(risqueTransport).map((key) => risqueTransport[key]) const mondeEntier = (fac.zones.includes('zone1') && fac.zones.includes('zone2') && fac.zones.includes('zone3') && fac.zones.includes('zone4') && fac.zones.includes('zone5') && fac.zones.includes('zone6')) const hasZone456 = (fac.zones.includes('zone4') && fac.zones.includes('zone5') && fac.zones.includes('zone6')) const hasGarOptAuto = projet.garOpt.includes('auto') const hasGarOptEmballage = projet.garOpt.includes('emballage') const hasGarOptEtiquette = projet.garOpt.includes('etiquette') const hasGarOptTemperature = projet.garOpt.includes('temperature') const hasGarOptMarque = projet.garOpt.includes('marque') const hasTPPC = fac.tppc const hasMarchandiseExposition = fac.nbVehicExpo > 0 const condition4 = (hasGarOptAuto || hasGarOptEmballage || hasGarOptEtiquette || hasGarOptMarque || hasTPPC || hasMarchandiseExposition) const hasGarOpt = projet.garOpt.length > 0 const condition2 = hasGarOpt || hasTPPC || hasMarchandiseExposition const anneeProchaine = moment().add(1, 'years').format('YYYY') const dateFin = (projet.dateFin == "00/00" || projet.dateFin == "00/00/0000") ? "A PRECISER" : projet.dateFin const dateEffet = (projet.dateEffet == "00/00" || projet.dateEffet == "00/00/0000") ? "A PRECISER" : projet.dateEffet const dateEcheance = (projet.dateEcheance == "00/00" || projet.dateEcheance == "00/00/0000") ? "A PRECISER" : projet.dateEcheance + '/' + anneeProchaine const renderObject = { nomClient: client.nom, adrClient: client.adresse, postalClient: client.codePostal, villeClient: client.ville, numClient: client.numClient, nomInter: intermediaire.nom, adrInter: intermediaire.adresse, postalInter: intermediaire.codePostal, villeInter: intermediaire.ville, oriasInter: intermediaire.numOrias, hasOrias: intermediaire.numOrias == "" ? false : true, numInter: intermediaire.numTelephone, mailInter: intermediaire.mail, hasMail: intermediaire.mail ? true : false, numProjet: contrat.numSaisine ? contrat.numSaisine : contrat.numContrat, hasCP: (contrat.type == "AN" || contrat.type == "TEMPORAIRE"), hasRemplacement: (contrat.type == "REMPLACEMENT"), hasRGAuto: (fac.rg == "auto"), hasRGDemande: (fac.rg == 'demande'), hasRG: (fac.rg == 'demande' || fac.rg == 'auto'), hasEtendue: (fac.typeRG == "etendue"), hasWaterborne: (fac.typeRG == "waterborne"), hasProgrammeInternational: projet.programmeInternational, hasAssuresAdditionnels: listAssAdd.length > 0, listAssAdd: listAssAdd, hasTemporaire: contrat.type == "TEMPORAIRE", actAssure: fac.actAssure, typeMar: fac.typeMar, listMoyenTransportEtOu: transportListOuEt, listMoyenTransportVirguleEt: transportListVirguleEt, listRisqueTransport: listRisqueTransport, depart: projet.lieuDepart, arrivee: projet.lieuArrivee, dateJour: moment().format("DD MMMM YYYY"), dateEffet: dateEffet, dateFin: dateFin, dateEcheance: dateEcheance, hasMarchandiseExposition: hasMarchandiseExposition, hasMondeEntier: mondeEntier, hasZone1: fac.zones.includes('zone1'), hasZone2: fac.zones.includes('zone2'), hasZone3: fac.zones.includes('zone3'), hasZone4: fac.zones.includes('zone4'), hasZone5: fac.zones.includes('zone5'), hasZone6: fac.zones.includes('zone6'), hasZone456: hasZone456, hasTPPC: hasTPPC, hasTPPCTousRisques: projet.typeTPPC.includes('tousRisques'), hasTPPCFlotteND: projet.typeTPPC.includes('flotteND'), capitalMax: projet.capitalMax, franchiseTransport: projet.franchiseTransport, condition4: condition4, hasGarOpt: hasGarOpt, condition2: condition2, hasGarOptAuto: hasGarOptAuto, hasGarOptEmballage: hasGarOptEmballage, hasGarOptEtiquette: hasGarOptEtiquette, hasGarOptMarque: hasGarOptMarque, hasGarOptTemperature: hasGarOptTemperature, capitalTPPC: fac.capitalTPPC, franchiseExpo: fac.franchiseExpo, hasCG: projet.valeurAssuree.includes('cg'), hasDerogation: projet.valeurAssuree.includes('derogation'), hasVaBasePrix: projet.valeurAssureeBase.includes('prix'), hasVaBaseAchat: projet.valeurAssureeBase.includes('achat'), hasVaBaseVente: projet.valeurAssureeBase.includes('vente'), hasAerienTousRisques: fac.aerien.includes('tousRisques'), hasAerienEventMaj: fac.aerien.includes('eventMaj'), hasMaritimeTousRisques: fac.maritime.includes('tousRisques'), hasMaritimeEventMaj: fac.maritime.includes('eventMaj'), hasTerrestreTousRisques: fac.terrestre.includes('tousRisques'), hasTerrestreEventMaj: fac.terrestre.includes('eventMaj'), hasPostalTousRisques: fac.postal.includes('tousRisques'), hasPostalEventMaj: fac.postal.includes('eventMaj'), hasFluvialTousRisques: fac.fluvial.includes('tousRisques'), hasFluvialEventMaj: fac.fluvial.includes('eventMaj'), hasFranchiseTransport: projet.franchiseTransport !== "", cotRO: globalService.customFormatNumber(fac.cotRO), cotRG: globalService.customFormatNumber(fac.cotRG), cotProvRO: globalService.customFormatNumber(fac.cotProvRO), cotProvRG: globalService.customFormatNumber(fac.cotProvRG), cotComptant: globalService.customFormatNumber(projet.cotComptant), tauxCotRO: globalService.customFormatNumber(fac.tauxCotRO, true), tauxCotRG: globalService.customFormatNumber(fac.tauxCotRG, true), cotAnnuelle: globalService.customFormatNumber(fac.primeHT), cotIrred: globalService.customFormatNumber(fac.primeMini), capitalTPPC: globalService.customFormatNumber(fac.capitalTPPC), capitalExpo: globalService.customFormatNumber(fac.capitalExpo), franchiseTPPC: globalService.customFormatNumber(fac.franchiseTPPC), chiffreAffaires: globalService.customFormatNumber(fac.ca), hasMensuel: (projet.tempo == "mensuel"), hasChiffreAffaires: (projet.typeContrat == "chiffreAffaires"), hasAvisAliments: (projet.typeContrat == "avisAliments"), hasPartResultat: projet.participationResultat, hasAgentMutualiste: (intermediaire.type == "AGENT MUTUALISTE"), hasAgent: (intermediaire.type == "AGENT MUTUALISTE" || intermediaire.type == "AGENT NON MUTUALISTE"), hasCourtier: (intermediaire.type == "COURTIER"), tempo: projet.tempo, } try { doc.render(renderObject) } catch (error) { const e = { message: error.message, name: error.name, stack: error.stack, properties: error.properties, }; logger.log('error', JSON.stringify({error: e})); // Envoyez une réponse d'erreur si le rendu échoue return res.status(500).send("Erreur lors de la génération du document"); } const buf = doc.getZip().generate({type: "nodebuffer"}); const formattedDate = moment().format('DD-MM-YYYY-HH-mm-ss') // Génération du nom de fichier const sanitizedClientNom = client.nom .replace(/[^\w\s.-]/gi, "") .replace(/\s+/g, "-"); const filename = `Projet-${contrat.produit}-${parcours.numParcours}-${sanitizedClientNom}-${formattedDate}`; // Définit le type de contenu et un nom de fichier par défaut pour le téléchargement res.setHeader( "Content-Type", "application/vnd.openxmlformats-officedocument.wordprocessingml.document" ); res.setHeader( "Content-Disposition", "attachment; filename=" + filename + ".docx" ); // Envoie le buffer au client, déclenchant le téléchargement res.send(buf); }); //generate declinaison tarifaire FAC router.post("/fac/tarif/:numParcours", async (req, res) => { // TODO Attention conditionner en fonction du type de CP const content = fs.readFileSync( path.resolve("src/templates/template-declinaison-tarifaire-fac.docx"), "binary" ); const zip = new PizZip(content); const doc = new Docxtemplater(zip, {paragraphLoop: true, linebreaks: true}); const numParcours = req.params.numParcours.toUpperCase(); const parcours = await parcoursService.getParcoursByNumParcours(numParcours); const contrat = await contratService.getContratById(parcours.contrat); const client = contrat?.["@expand"]?.client || {}; const fac = contrat?.["@expand"]?.enCours || {}; const tarif = fac?.["@expand"]?.tarif || {}; const user = await userService.getUserById(parcours.dernierUtilisateur); function getSelectedFranchise(franchiseId) { switch (franchiseId) { case "sansFranchise": return tarif.sansFranchise case "franchise350": return tarif.franchise350 case "franchise750": return tarif.franchise750 } } function getSelectedFranchiseTitre(franchiseId) { switch (franchiseId) { case "sansFranchise": return "Sans Franchise" case "franchise350": return "Franchise 350 €" case "franchise750": return "Franchise 750 €" } } function initialeMaj(str) { return typeof str == "string" ? str.charAt(0).toUpperCase() + str.slice(1) : "" } const selectedFranchiseTitre = getSelectedFranchiseTitre(tarif.selectedFranchise) const selectedFranchise = getSelectedFranchise(tarif.selectedFranchise) const transports = [] if (fac.terrestre !== "") { transports.push("Terrestre") } if (fac.maritime !== "") { transports.push("Maritime") } if (fac.aerien !== "") { transports.push("Aerien") } if (fac.postal !== "") { transports.push("Postal") } if (fac.fluvial !== "") { transports.push("Fluvial") } if (fac.multimodal !== "") { transports.push('Multimodal') } const listTransports = transports.join(', ') const hasMondeEntier = ( fac.zones.includes("zone1") && fac.zones.includes("zone2") && fac.zones.includes("zone3") && fac.zones.includes("zone4") && fac.zones.includes("zone5") && fac.zones.includes("zone6") ) const typeRO = tarif.typeRO == "tousRisques" ? "Tous Risques" : "Evenements Majeurs" var typePolice switch (tarif.typePolice) { case "ca": typePolice = "Police au Chiffre d'Affaires"; break; case "national": typePolice = "Police au Voyage National"; break; case "international": typePolice = "Police au Voyage International"; break; } try { doc.render({ matricule: user.matricule, hasContrat: contrat.numContrat || false, numContrat: contrat.numContrat, hasSaisine: contrat.numSaisine || false, numSaisine: contrat.numSaisine, nomClient: client.nom, actAssuree: fac.actAssuree, montantSin: tarif.sinistres, franchiseSelected: selectedFranchiseTitre, typeMar: fac.typeMar, ca: fac.ca, montantGarantir: tarif.montantGarantir, conditionnement: constantesFAC.objModCond?.[tarif.conditionnement]?.nom ?? "", typeMar: fac.typeMar, transports: listTransports, hasMondeEntier: hasMondeEntier, hasZone1: fac.zones.includes("zone1"), hasZone2: fac.zones.includes("zone2"), hasZone3: fac.zones.includes("zone3"), hasZone4: fac.zones.includes("zone4"), hasZone5: fac.zones.includes("zone5"), hasZone6: fac.zones.includes("zone6"), hasZone1Achats: tarif.fluxAchats?.zone == "zone1", hasZone2Achats: tarif.fluxAchats?.zone == "zone2", hasZone3Achats: tarif.fluxAchats?.zone == "zone3", hasZone4Achats: tarif.fluxAchats?.zone == "zone4", hasZone5Achats: tarif.fluxAchats?.zone == "zone5", hasZone6Achats: tarif.fluxAchats?.zone == "zone6", conditionnementAchats: constantesFAC.objModCond[tarif.fluxAchats?.conditionnement]?.nom ?? "", hasZone1Ventes: tarif.fluxVentes?.zone == "zone1", hasZone2Ventes: tarif.fluxVentes?.zone == "zone2", hasZone3Ventes: tarif.fluxVentes?.zone == "zone3", hasZone4Ventes: tarif.fluxVentes?.zone == "zone4", hasZone5Ventes: tarif.fluxVentes?.zone == "zone5", hasZone6Ventes: tarif.fluxVentes?.zone == "zone6", conditionnementVentes: constantesFAC.objModCond[tarif.fluxVentes?.conditionnement]?.nom ?? "", hasFluxGlobal: tarif.typeFlux == "global", hasFluxDetailles: tarif.typeFlux == "detailles", hasFluxVentes: (tarif.fluxVentes), hasFluxAchats: (tarif.fluxAchats), hasFluxIntersites: tarif.fluxIntersites, fluxAchats: tarif.fluxAchats, fluxVentes: tarif.fluxVentes, transportVentes: initialeMaj(tarif.fluxVentes?.transport), transportAchats: initialeMaj(tarif.fluxAchats?.transport), typeRO: typeRO, typePolice: typePolice, hasTPPC: fac.tppc, hasMarExpo: (fac.nbVehicExpo > 0), hasRG: fac.rg == "auto", hasRGAchats: (tarif.fluxAchats?.typeRG), hasRGVentes: (tarif.fluxVentes?.typeRG), tarif350: tarif.franchise350.proposition, // pourcentAct350: parseFloat(tarif.franchise350.pourcentAct) * 100, // pourcentCA350: parseFloat(tarif.franchise350.pourcentCA) * 100, // pourcentMar350: parseFloat(tarif.franchise350.pourcentMar) * 100, // pourcentFranchise350: parseFloat(tarif.franchise350.pourcentFranchise) * 100, tauxRO350: tarif.franchise350.tauxRO, tauxRG350: tarif.franchise350.tauxRG, franchiseTPPC350: tarif.franchise350.franchiseTPPC ?? "", franchiseExpo350: tarif.franchise350.franchiseExpo ?? "", tarif750: tarif.franchise750.proposition, // pourcentAct750: parseFloat(tarif.franchise750.pourcentAct) * 100, // pourcentCA750: parseFloat(tarif.franchise750.pourcentCA) * 100, // pourcentMar750: parseFloat(tarif.franchise750.pourcentMar) * 100, // pourcentFranchise750: parseFloat(tarif.franchise750.pourcentFranchise) * 100, tauxRO750: tarif.franchise750.tauxRO, tauxRG750: tarif.franchise750.tauxRG, franchiseTPPC750: tarif.franchise750.franchiseTPPC ?? "", franchiseExpo750: tarif.franchise750.franchiseExpo ?? "", tarifSansFranchise: tarif.sansFranchise.proposition, // pourcentActSansFranchise: parseFloat(tarif.sansFranchise.pourcentAct) * 100, // pourcentCASansFranchise: parseFloat(tarif.sansFranchise.pourcentCA) * 100, // pourcentMarSansFranchise: parseFloat(tarif.sansFranchise.pourcentMar) * 100, // pourcentFranchiseSansFranchise: parseFloat(tarif.sansFranchise.pourcentFranchise) * 100, franchiseTPPCSansFranchise: tarif.sansFranchise.franchiseTPPC ?? "", franchiseExpoSansFranchise: tarif.sansFranchise.franchiseExpo ?? "", tauxROSansFranchise: tarif.sansFranchise.tauxRO, tauxRGSansFranchise: tarif.sansFranchise.tauxRG, tarifSelected: selectedFranchise.proposition, tarifCommercial: fac.primeHT, franchiseTPPCSelected: selectedFranchise.franchiseTPPC ?? "", franchiseExpoSelected: selectedFranchise.franchiseExpo ?? "", tauxROSelected: fac.tauxCotRO, tauxRGSelected: fac.tauxCotRG }); } catch (error) { const e = { message: error.message, name: error.name, stack: error.stack, properties: error.properties, }; logger.log("error", JSON.stringify({error: e})); // Envoyez une réponse d'erreur si le rendu échoue return res.status(500).send("Erreur lors de la génération du document"); } const buf = doc.getZip().generate({type: "nodebuffer"}); const currentDate = new Date(); // Formatage de la date au format "JJ-MM-AAAA-HH-MM-SS" const day = String(currentDate.getDate()).padStart(2, "0"); const month = String(currentDate.getMonth() + 1).padStart(2, "0"); const year = currentDate.getFullYear(); const hours = String(currentDate.getHours()).padStart(2, "0"); const minutes = String(currentDate.getMinutes()).padStart(2, "0"); const seconds = String(currentDate.getSeconds()).padStart(2, "0"); const formattedDate = `${day}-${month}-${year}-${hours}-${minutes}-${seconds}`; // Génération du nom de fichier const sanitizedClientNom = client.nom .replace(/[^\w\s.-]/gi, "") .replace(/\s+/g, "-"); const filename = `Tarif-${contrat.produit}-${parcours.numParcours}-${sanitizedClientNom}-${formattedDate}`; // Définit le type de contenu et un nom de fichier par défaut pour le téléchargement res.setHeader( "Content-Type", "application/vnd.openxmlformats-officedocument.wordprocessingml.document" ); res.setHeader( "Content-Disposition", "attachment; filename=" + filename + ".docx" ); // Envoie le buffer au client, déclenchant le téléchargement res.send(buf); }); module.exports = router;