diff --git a/ecole/public/js/projet-form-fac.js b/ecole/public/js/fac/projet-form-fac.js
similarity index 100%
rename from ecole/public/js/projet-form-fac.js
rename to ecole/public/js/fac/projet-form-fac.js
diff --git a/ecole/public/js/nav-parcours.js b/ecole/public/js/nav-parcours.js
index 560449df..ea8d676f 100644
--- a/ecole/public/js/nav-parcours.js
+++ b/ecole/public/js/nav-parcours.js
@@ -37,7 +37,7 @@ document.addEventListener('DOMContentLoaded', function() {
const parcours = JSON.parse(sessionStorage.getItem('parcours'));
const contrat = JSON.parse(sessionStorage.getItem('contrat'));
- let produit = parcours["@expand"].contrat.produit
+ let produit = String(parcours?.["@expand"]?.contrat?.produit || '').toLowerCase();
const produitObj = contrat?.["@expand"]?.enCours || null;
@@ -60,10 +60,10 @@ document.addEventListener('DOMContentLoaded', function() {
if (submenu === "projet") {
fetchUrl = `/navParcours/${submenu}${produit}?numParcours=${numParcours}`;
- scriptSrc = `/js/projet-form-${produit}.js`;
+ scriptSrc = `/js/${produit}/projet-form-${produit}.js`;
} else if (submenu === "tarif") {
fetchUrl = `/navParcours/${submenu}${produit}?numParcours=${numParcours}`;
- scriptSrc = `/js/tarif-form-${produit}.js`;
+ scriptSrc = `/js/${produit}/tarif-form-${produit}.js`;
} else {
fetchUrl = `/navParcours/${submenu}?numParcours=${numParcours}`;
scriptSrc = `/js/${submenu}-form.js`;
diff --git a/ecole/public/js/projet-form-rc.js b/ecole/public/js/rc/projet-form-rc.js
similarity index 89%
rename from ecole/public/js/projet-form-rc.js
rename to ecole/public/js/rc/projet-form-rc.js
index 43dcc59e..d6b08efa 100644
--- a/ecole/public/js/projet-form-rc.js
+++ b/ecole/public/js/rc/projet-form-rc.js
@@ -1,3 +1,6 @@
+/**
+ * Initialise submenu form.
+ */
function initSubmenuForm() {
// Accéder aux informations stockées du parcours
const parcours = JSON.parse(sessionStorage.getItem('parcours'));
@@ -13,6 +16,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
let hasSavedGrilleData = false; // évite d'écraser une grille déjà enregistrée
let rcProjetGuard = null;
+ /**
+ * Synchronise rcfloating labels.
+ */
function syncRCFloatingLabels() {
if (window.RCValidationUtils && typeof window.RCValidationUtils.syncFloatingLabels === 'function') {
window.RCValidationUtils.syncFloatingLabels(document);
@@ -31,6 +37,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
var tagDemenageurEntrInter = false;
// Initialisation du formulaire et des données
+ /**
+ * Initialise la logique de cette fonction.
+ */
function init() {
// Materialize init select
var select = document.querySelectorAll('select');
@@ -95,19 +104,27 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
}, 700);
}
updatePrimeReferenceRow();
+ updateTarifCommercialRows();
+ syncTotalWithTarifCommercial();
setupRCSafeValidation();
syncRCFloatingLabels();
updateSubmitButtonState('projetForm');
setTimeout(() => {
updatePrimeReferenceRow();
+ updateTarifCommercialRows();
+ syncTotalWithTarifCommercial();
if (rcProjetGuard) rcProjetGuard.refresh();
syncRCFloatingLabels();
+ refreshTarifReferenceFromApi();
}, 350);
}
let tarifOriginalData = null;
+ /**
+ * Recupere linked tarif id.
+ */
function getLinkedTarifId() {
if (tarif && typeof tarif === 'object' && tarif.id) return tarif.id;
if (typeof tarif === 'string' && tarif.trim()) return tarif;
@@ -118,10 +135,16 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
return null;
}
+ /**
+ * Verifie tarif reference.
+ */
function hasTarifReference() {
return Boolean(getLinkedTarifId());
}
+ /**
+ * Gere refresh tarif context from session.
+ */
function refreshTarifContextFromSession() {
try {
const sessionContrat = JSON.parse(sessionStorage.getItem('contrat') || 'null');
@@ -136,6 +159,8 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
window.projet = projet;
window.tarif = tarif;
updatePrimeReferenceRow();
+ updateTarifCommercialRows();
+ syncTotalWithTarifCommercial();
return true;
} catch (error) {
console.warn('Impossible de recharger le contexte RC depuis la session:', error);
@@ -143,6 +168,64 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
}
}
+ /**
+ * Gere refresh tarif reference from api.
+ */
+ async function refreshTarifReferenceFromApi() {
+ const tarifId = getLinkedTarifId();
+ if (!tarifId) return false;
+
+ try {
+ const response = await fetch(`/rc/tarif/${tarifId}`);
+ const data = await response.json();
+ if (!data?.valid || !data?.tarifRc) {
+ return false;
+ }
+
+ tarif = data.tarifRc;
+
+ if (rc && typeof rc === 'object') {
+ rc.tarifRC = tarif;
+ if (!rc["@expand"] || typeof rc["@expand"] !== 'object') {
+ rc["@expand"] = {};
+ }
+ rc["@expand"].tarifRC = tarif;
+ }
+
+ window.rc = rc;
+ window.tarif = tarif;
+ try {
+ const sessionContrat = JSON.parse(sessionStorage.getItem('contrat') || 'null');
+ const sessionRC = sessionContrat?.["@expand"]?.enCours;
+ if (sessionRC && typeof sessionRC === 'object') {
+ sessionRC.tarifRC = tarif?.id || tarif;
+ if (!sessionRC["@expand"] || typeof sessionRC["@expand"] !== 'object') {
+ sessionRC["@expand"] = {};
+ }
+ sessionRC["@expand"].tarifRC = tarif;
+ sessionStorage.setItem('contrat', JSON.stringify(sessionContrat));
+ }
+ } catch (error) {
+ console.warn('Impossible de synchroniser tarifRC en sessionStorage:', error);
+ }
+
+ tarifOriginalData = null;
+ ensureTarifImpactContext();
+ updatePrimeReferenceRow();
+ updateTarifCommercialRows();
+ syncTotalWithTarifCommercial();
+ calcCotTotal();
+ if (rcProjetGuard) rcProjetGuard.refresh();
+ return true;
+ } catch (error) {
+ console.warn('Impossible de recharger le tarif RC depuis l\'API:', error);
+ return false;
+ }
+ }
+
+ /**
+ * Securise tarif impact context.
+ */
function ensureTarifImpactContext() {
if (hasTarifReference() && tarifOriginalData) return true;
@@ -156,6 +239,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
return Boolean(tarifOriginalData);
}
+ /**
+ * Parse validation number.
+ */
function parseValidationNumber(rawValue) {
if (window.RCValidationUtils && typeof window.RCValidationUtils.parseLooseNumber === 'function') {
return window.RCValidationUtils.parseLooseNumber(rawValue);
@@ -169,6 +255,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
return Number.isFinite(parsed) ? parsed : NaN;
}
+ /**
+ * Formate reference amount.
+ */
function formatReferenceAmount(value) {
const number = Number(value);
if (!Number.isFinite(number)) return '0,00 €';
@@ -178,6 +267,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
}) + ' €';
}
+ /**
+ * Normalise franchise choice.
+ */
function normalizeFranchiseChoice(rawChoice) {
const choice = String(rawChoice || '').trim().toLowerCase();
if (!choice) return null;
@@ -187,6 +279,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
return null;
}
+ /**
+ * Resout tarif source for reference.
+ */
function resolveTarifSourceForReference() {
if (tarif && typeof tarif === 'object') return tarif;
if (rc?.["@expand"]?.tarifRC && typeof rc["@expand"].tarifRC === 'object') return rc["@expand"].tarifRC;
@@ -194,6 +289,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
return null;
}
+ /**
+ * Recupere prime reference state.
+ */
function getPrimeReferenceState() {
const tarifSource = resolveTarifSourceForReference();
if (!tarifSource) {
@@ -233,6 +331,35 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
};
}
+ /**
+ * Recupere tarif commercial state.
+ */
+ function getTarifCommercialState() {
+ const tarifSource = resolveTarifSourceForReference();
+ if (!tarifSource) {
+ return {
+ valid: false,
+ reason: 'Aucun tarif RC sélectionné n\'est rattaché à ce dossier.'
+ };
+ }
+
+ const tarifCommercialValue = parseValidationNumber(tarifSource.tarifcommercial);
+ if (!Number.isFinite(tarifCommercialValue) || tarifCommercialValue <= 0) {
+ return {
+ valid: false,
+ reason: 'Aucun tarif commercial saisi n\'est disponible sur le tarif RC.'
+ };
+ }
+
+ return {
+ valid: true,
+ tarifCommercialValue
+ };
+ }
+
+ /**
+ * Met a jour prime reference row.
+ */
function updatePrimeReferenceRow() {
const primeInput = document.getElementById('primeRefHT');
const primeError = document.getElementById('primeRefHT-error');
@@ -251,6 +378,48 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
primeError.style.display = 'block';
}
+ /**
+ * Met a jour tarif commercial rows.
+ */
+ function updateTarifCommercialRows() {
+ const tarifComInput = document.getElementById('tarifComSaisiHT');
+ const tarifComTtcInput = document.getElementById('tarifComSaisiTTC');
+ if (!tarifComInput || !tarifComTtcInput) return;
+
+ const state = getTarifCommercialState();
+ if (state.valid) {
+ const formatted = formatReferenceAmount(state.tarifCommercialValue);
+ tarifComInput.value = formatted;
+ tarifComTtcInput.value = formatted;
+ return;
+ }
+
+ tarifComInput.value = 'Non renseigné';
+ tarifComTtcInput.value = '//';
+ }
+
+ /**
+ * Synchronise total with tarif commercial.
+ */
+ function syncTotalWithTarifCommercial(options = {}) {
+ const totalHTInput = document.getElementById('cotTotalHT');
+ if (!totalHTInput) return;
+
+ const state = getTarifCommercialState();
+ if (!state.valid) return;
+
+ const force = Boolean(options.force);
+ const currentTotal = parseValidationNumber(totalHTInput.value);
+ if (!force && Number.isFinite(currentTotal) && currentTotal > 0) {
+ return;
+ }
+
+ totalHTInput.value = state.tarifCommercialValue.toFixed(2);
+ }
+
+ /**
+ * Configure rcsafe validation.
+ */
function setupRCSafeValidation() {
if (!window.RCValidationUtils || typeof window.RCValidationUtils.createGuard !== 'function') {
return;
@@ -259,13 +428,7 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
rcProjetGuard = window.RCValidationUtils.createGuard({
summaryId: 'rcProjetBlockingSummary',
summaryTitle: 'Impossible d\'enregistrer ou de continuer car :',
- blockTargets: ['#projetFormBtn', '#generateDeclinaison', '#generateProject'],
- onChange: function (messages) {
- const actionsRow = document.getElementById('projetActionsRow');
- if (actionsRow) {
- actionsRow.classList.toggle('rc-tarifettes-hidden', messages.length > 0);
- }
- }
+ blockTargets: ['#projetFormBtn', '#generateDeclinaison', '#generateProject']
});
rcProjetGuard.registerField('#CA', {
@@ -307,6 +470,22 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
});
});
+ rcProjetGuard.registerExternal('legacy-field-errors', function () {
+ const visibleFieldError = Array.from(
+ document.querySelectorAll('#projetForm [id$="-error"].red-text')
+ ).find((node) => {
+ const text = String(node?.textContent || '').trim();
+ const style = window.getComputedStyle(node);
+ return Boolean(text) && style.display !== 'none' && style.visibility !== 'hidden';
+ });
+
+ if (visibleFieldError) {
+ return { valid: false, message: visibleFieldError.textContent.trim() };
+ }
+
+ return { valid: true };
+ });
+
rcProjetGuard.registerField('#nomAdditionnel', {
profile: 'text',
label: 'Nom assuré additionnel'
@@ -422,6 +601,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
rcProjetGuard.refresh();
}
+ /**
+ * Charge modulateurs.
+ */
async function loadModulateurs() {
try {
const response = await fetch('/rc/modulo/activiteRCC');
@@ -464,6 +646,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
}
}
+ /**
+ * Sauvegarde original tarif data.
+ */
function saveOriginalTarifData() {
if (!hasTarifReference()) return;
@@ -544,6 +729,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
};
}
+ /**
+ * Controle activity impact.
+ */
function checkActivityImpact(activityData) {
const activities = ['checkVoiturier', 'checkCommissionnaire', 'checkDemenageur', 'checkLogistique', 'checkAutocariste', 'checkAutres'];
for (let act of activities) {
@@ -556,6 +744,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
return false;
}
+ /**
+ * Controle marchandise impact.
+ */
function checkMarchandiseImpact(marchandiseData) {
const normalizeArray = (arr) => {
if (!arr) return [];
@@ -573,6 +764,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
return false;
}
+ /**
+ * Recupere max zone coefficient.
+ */
function getMaxZoneCoefficient(zones) {
let maxRCC = 1;
let maxRCE = 1;
@@ -611,12 +805,18 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
return { maxRCC, maxRCE };
}
+ /**
+ * Controle zone impact.
+ */
function checkZoneImpact(zoneData) {
const originalMax = getMaxZoneCoefficient(tarifOriginalData);
const currentMax = getMaxZoneCoefficient(zoneData);
return originalMax.maxRCC !== currentMax.maxRCC || originalMax.maxRCE !== currentMax.maxRCE;
}
+ /**
+ * Controle activite compl impact.
+ */
function checkActiviteComplImpact(activiteComplData) {
const activiteKeys = ['activitesVoiturier', 'activitesCommissionnaire', 'activitesDemenageur', 'activitesLogistique'];
for (let key of activiteKeys) {
@@ -627,6 +827,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
return false;
}
+ /**
+ * Recupere current activite compl data.
+ */
function getCurrentActiviteComplData() {
const activitesCompl = {
activitesVoiturier: getActivitesComplFromForm('actComplVoiturier/Loueur'),
@@ -637,6 +840,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
return activitesCompl;
}
+ /**
+ * Recupere activites compl from form.
+ */
function getActivitesComplFromForm(containerName) {
const container = document.querySelector(`[name="${containerName}"]`);
if (!container) return [];
@@ -649,11 +855,17 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
return activites;
}
+ /**
+ * Recupere current type ext confies.
+ */
function getCurrentTypeExtConfies() {
if (document.getElementById('AdValorem')?.checked) return 'ADVALOREM';
return 'VALEUR DECLAREE';
}
+ /**
+ * Capture zone state.
+ */
function captureZoneState() {
const state = {};
for (let i = 1; i <= 6; i++) {
@@ -666,6 +878,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
return state;
}
+ /**
+ * Restaure zone state.
+ */
function restoreZoneState(state) {
if (!state) return;
isRestoringValue = true;
@@ -685,6 +900,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
}
}
+ /**
+ * Normalise impact value.
+ */
function normalizeImpactValue(value) {
if (Array.isArray(value)) {
return value.map((item) => normalizeImpactValue(item)).sort((a, b) => String(a).localeCompare(String(b), 'fr'));
@@ -708,6 +926,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
return value;
}
+ /**
+ * Collecte effective advalorem grid.
+ */
function collectEffectiveAdvaloremGrid(zoneData) {
const activeZones = [];
for (let i = 1; i <= 6; i++) {
@@ -734,27 +955,42 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
};
}
+ /**
+ * Controle cotisation impact.
+ */
function checkCotisationImpact() {
const currentCotisation = document.querySelector('input[name="cotisation"]:checked')?.value || null;
return currentCotisation !== (tarifOriginalData?.typeCotisation || null);
}
+ /**
+ * Controle caimpact.
+ */
function checkCAImpact() {
const currentCA = normalizeImpactValue(document.getElementById('CA')?.value || '');
const originalCA = normalizeImpactValue(tarifOriginalData?.ca || '');
return currentCA !== originalCA;
}
+ /**
+ * Controle pjimpact.
+ */
function checkPJImpact() {
const currentPJ = Boolean(document.getElementById('switchPJ')?.checked);
return currentPJ !== Boolean(tarifOriginalData?.pj);
}
+ /**
+ * Controle rceimpact.
+ */
function checkRCEImpact() {
const currentRCE = Boolean(document.getElementById('choixRCE')?.checked);
return currentRCE !== Boolean(tarifOriginalData?.checkRCE);
}
+ /**
+ * Controle type ext confies impact.
+ */
function checkTypeExtConfiesImpact() {
const currentGaranties = getCurrentGarantieRCCData();
const originalGaranties = Array.isArray(tarifOriginalData?.garantiesRCC) ? tarifOriginalData.garantiesRCC : [];
@@ -765,6 +1001,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
return getCurrentTypeExtConfies() !== (tarifOriginalData?.typeExtConfies || null);
}
+ /**
+ * Parse capital number.
+ */
function parseCapitalNumber(value) {
const normalized = String(value ?? '')
.trim()
@@ -774,6 +1013,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
return Number.isFinite(parsed) ? parsed : 0;
}
+ /**
+ * Controle capital impact by field.
+ */
function checkCapitalImpactByField(fieldId, fieldValue) {
if (!fieldId || !tarifOriginalData) return false;
@@ -812,6 +1054,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
return Math.abs(currentValue - expected) > 0.01;
}
+ /**
+ * Collecte projet data for tarif prefill.
+ */
function collectProjetDataForTarifPrefill() {
const getNumberValue = (id) => {
const element = document.getElementById(id);
@@ -893,6 +1138,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
return payload;
}
+ /**
+ * Gere store projet data for tarif prefill.
+ */
function storeProjetDataForTarifPrefill() {
try {
const payload = collectProjetDataForTarifPrefill();
@@ -906,6 +1154,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
let isTarifImpactModalOpen = false;
const tarifImpactDebugReasons = new Set();
+ /**
+ * Gere log tarif impact skip.
+ */
function logTarifImpactSkip(reason, details = null) {
if (tarifImpactDebugReasons.has(reason)) return;
tarifImpactDebugReasons.add(reason);
@@ -916,6 +1167,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
console.warn(`[RC modal impact] ${reason}`);
}
+ /**
+ * Execute with restore guard.
+ */
function runWithRestoreGuard(callback) {
isRestoringValue = true;
try {
@@ -927,11 +1181,17 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
}
}
+ /**
+ * Recupere displayed style.
+ */
function getDisplayedStyle(id) {
const element = document.getElementById(id);
return element ? element.style.display : '';
}
+ /**
+ * Met a jour displayed style.
+ */
function setDisplayedStyle(id, value) {
const element = document.getElementById(id);
if (element) {
@@ -939,11 +1199,17 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
}
}
+ /**
+ * Gere read input value.
+ */
function readInputValue(id) {
const element = document.getElementById(id);
return element ? element.value : '';
}
+ /**
+ * Gere write input value.
+ */
function writeInputValue(id, value) {
const element = document.getElementById(id);
if (element) {
@@ -951,6 +1217,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
}
}
+ /**
+ * Gere apply cotisation layout.
+ */
function applyCotisationLayout(value) {
if (value === "forfaitaire") {
document.getElementById("checkVehicules").style.display = 'block';
@@ -977,6 +1246,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
}
}
+ /**
+ * Gere recalculate after cachange.
+ */
function recalculateAfterCAChange() {
validateField('CA', true);
updateSubmitButtonState('projetForm');
@@ -989,6 +1261,68 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
if (rcProjetGuard) rcProjetGuard.refresh();
}
+ /**
+ * Vérifie si une saisie numérique contient un format interdit.
+ */
+ function hasInvalidNumericValue(value, maxDecimals = null) {
+ const normalized = String(value ?? '')
+ .trim()
+ .replace(/\s/g, '');
+
+ if (!normalized) return false;
+ if (/[A-Za-z€$£¥]/.test(normalized)) return true;
+ if (/[^0-9.,-]/.test(normalized)) return true;
+
+ if ((normalized.match(/,/g) || []).length > 1) return true;
+ if ((normalized.match(/\./g) || []).length > 1) return true;
+ if (normalized.includes('-') && normalized.indexOf('-') !== 0) return true;
+ if (!/^-?\d+(?:[.,]\d+)?$/.test(normalized)) return true;
+
+ if (Number.isInteger(maxDecimals)) {
+ const decimalPart = normalized.split(/[.,]/)[1];
+ if (decimalPart && decimalPart.length > maxDecimals) return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Coupe un recalcul si la valeur courante n'est pas un nombre valide.
+ */
+ function skipRecomputeIfInvalid(fieldId, maxDecimals = null) {
+ const field = document.getElementById(fieldId);
+ if (!field) return false;
+ if (!hasInvalidNumericValue(field.value, maxDecimals)) return false;
+
+ if (rcProjetGuard) rcProjetGuard.refresh();
+ return true;
+ }
+
+ /**
+ * Exécute un handler de champ sans laisser remonter une erreur JS bloquante.
+ */
+ function runSafeFieldHandler(fieldId, handler) {
+ try {
+ handler();
+ } catch (error) {
+ console.error(`[RC Projet] Erreur sur le champ "${fieldId}"`, error);
+ try {
+ validateField(fieldId, true);
+ } catch (_) {
+ // no-op
+ }
+ try {
+ updateSubmitButtonState('projetForm');
+ } catch (_) {
+ // no-op
+ }
+ if (rcProjetGuard) rcProjetGuard.refresh();
+ }
+ }
+
+ /**
+ * Capture rcestate.
+ */
function captureRCEState() {
return {
checked: Boolean(document.getElementById('choixRCE')?.checked),
@@ -1002,6 +1336,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
};
}
+ /**
+ * Restaure rcestate.
+ */
function restoreRCEState(state) {
if (!state) return;
runWithRestoreGuard(() => {
@@ -1021,6 +1358,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
});
}
+ /**
+ * Capture pjstate.
+ */
function capturePJState() {
return {
checked: Boolean(document.getElementById('switchPJ')?.checked),
@@ -1031,6 +1371,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
};
}
+ /**
+ * Restaure pjstate.
+ */
function restorePJState(state) {
if (!state) return;
runWithRestoreGuard(() => {
@@ -1047,12 +1390,18 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
});
}
+ /**
+ * Capture cotisation state.
+ */
function captureCotisationState() {
return {
value: document.querySelector('input[name="cotisation"]:checked')?.value || null
};
}
+ /**
+ * Restaure cotisation state.
+ */
function restoreCotisationState(state) {
if (!state) return;
runWithRestoreGuard(() => {
@@ -1066,12 +1415,18 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
});
}
+ /**
+ * Capture castate.
+ */
function captureCAState() {
return {
value: document.getElementById('CA')?.value || ''
};
}
+ /**
+ * Restaure castate.
+ */
function restoreCAState(state) {
if (!state) return;
runWithRestoreGuard(() => {
@@ -1083,6 +1438,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
});
}
+ /**
+ * Restaure changed field value.
+ */
function restoreChangedFieldValue(changedElement, previousValue) {
if (!changedElement) return;
@@ -1144,12 +1502,18 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
});
}
+ /**
+ * Redirige to tarif from modal.
+ */
function redirectToTarifFromModal() {
storeProjetDataForTarifPrefill();
const target = `/navParcours?numParcours=${getNumParcoursFromURL()}&submenu=tarif`;
window.location.href = target;
}
+ /**
+ * Affiche tarif impact modal.
+ */
function showTarifImpactModal(options = {}) {
const modal = document.getElementById('modalModif');
if (!modal) {
@@ -1198,6 +1562,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
return true;
}
+ /**
+ * Gere prompt tarif impact if needed.
+ */
function promptTarifImpactIfNeeded(context = {}) {
if (isRestoringValue) {
logTarifImpactSkip('ignore pendant restauration');
@@ -1245,6 +1612,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
});
}
+ /**
+ * Configure tarif impact listeners.
+ */
function setupTarifImpactListeners() {
ensureTarifImpactContext();
setTimeout(() => {
@@ -1609,6 +1979,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
// Décision produit: pas de modal sur les zones textuelles de grille ad valorem.
}
+ /**
+ * Controle garantie rccimpact.
+ */
function checkGarantieRCCImpact(garantieData) {
const garantiesImpactantes = ['contenant-confie', 'tppc'];
const originalGaranties = tarifOriginalData?.garantiesRCC || [];
@@ -1623,6 +1996,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
return false;
}
+ /**
+ * Recupere current activity data.
+ */
function getCurrentActivityData() {
const activitySelector = document.getElementById('activity-selector');
const selectedActivities = Array.from(activitySelector.selectedOptions).map(opt => opt.value);
@@ -1641,6 +2017,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
};
}
+ /**
+ * Recupere current marchandise data.
+ */
function getCurrentMarchandiseData() {
const selectedMarchandises = getSelectedMarchandises();
const marchandiseTexts = selectedMarchandises.map(val => {
@@ -1658,6 +2037,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
};
}
+ /**
+ * Recupere current zone data.
+ */
function getCurrentZoneData() {
const zone1 = document.getElementById("zone1");
const zone2 = document.getElementById("zone2");
@@ -1671,17 +2053,26 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
};
}
+ /**
+ * Recupere current garantie rccdata.
+ */
function getCurrentGarantieRCCData() {
const selector = document.getElementById('garantieRCC-selector');
if (!selector) return [];
return Array.from(selector.selectedOptions).map(opt => opt.value);
}
+ /**
+ * Recupere selected marchandises.
+ */
function getSelectedMarchandises() {
const selector = document.getElementById('marchandise-selector');
return Array.from(selector.selectedOptions).map(opt => opt.value);
}
+ /**
+ * Pre-remplit from tarif.
+ */
function prefillFromTarif() {
if (!tarif || !rc) {
console.log('Pas de donnees tarif/rc pour pre-remplir');
@@ -1693,6 +2084,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
console.log('Pre-remplissage depuis tarif...', { rc, tarif });
+ /**
+ * Parse array.
+ */
function parseArray(value) {
if (Array.isArray(value)) return value;
if (typeof value === 'string') {
@@ -2139,6 +2533,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
}
// Configuration des écouteurs d'événements
+ /**
+ * Configure event listeners.
+ */
function setupEventListeners() {
document.getElementById('projetFormBtn').addEventListener('click', handleSubmitForm);
@@ -2369,6 +2766,18 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
var radioButtonsFract = document.getElementsByName('fractionnement');
for (var i = 0; i < radioButtonsFract.length; i++) {
radioButtonsFract[i].addEventListener('change', function () {
+ const cotFraisHTEl = document.getElementById("cotFraisHT");
+ const cotFraisTTCEl = document.getElementById("cotFraisTTC");
+ const hasExistingFraisValue = Boolean(
+ String(cotFraisHTEl?.value || '').trim() ||
+ String(cotFraisTTCEl?.value || '').trim()
+ );
+
+ if (!hasExistingFraisValue) {
+ calcCotTotal();
+ return;
+ }
+
if (this.value == "mensuel") {
document.getElementById("cotFraisHT").value = 36.00;
document.getElementById("cotFraisTTC").value = 36.00;
@@ -2462,23 +2871,35 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
}
document.getElementById('CA').addEventListener('input', function (e) {
- if (isRestoringValue) {
- recalculateAfterCAChange();
- return;
- }
-
- if (promptTarifImpactIfNeeded({
- isImpacting: () => checkCAImpact(),
- restore: () => restoreCAState(previousCAState),
- onNoImpact: () => {
- previousCAState = captureCAState();
- recalculateAfterCAChange();
+ runSafeFieldHandler('CA', () => {
+ if (isRestoringValue) {
+ if (!skipRecomputeIfInvalid('CA', 2)) {
+ recalculateAfterCAChange();
+ } else {
+ validateField('CA', true);
+ updateSubmitButtonState('projetForm');
+ }
+ return;
}
- })) {
- e.stopImmediatePropagation();
- e.preventDefault();
- return;
- }
+
+ if (promptTarifImpactIfNeeded({
+ isImpacting: () => checkCAImpact(),
+ restore: () => restoreCAState(previousCAState),
+ onNoImpact: () => {
+ previousCAState = captureCAState();
+ if (!skipRecomputeIfInvalid('CA', 2)) {
+ recalculateAfterCAChange();
+ } else {
+ validateField('CA', true);
+ updateSubmitButtonState('projetForm');
+ }
+ }
+ })) {
+ e.stopImmediatePropagation();
+ e.preventDefault();
+ return;
+ }
+ });
});
document.getElementById('cotisationIrreductible').addEventListener('input', function () {
@@ -2487,47 +2908,59 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
});
document.getElementById('tauxRCCHT').addEventListener('input', function () {
- validateField('tauxRCCHT', true);
- updateSubmitButtonState('projetForm');
- calcAddTaxe('tauxRCCHT', 0, 'tauxRCCTTC');
- calcTauxTotal();
- calcCotFromTauxCA('tauxRCCHT', 'cotRCCHT');
- calcAddTaxe('cotRCCHT', 0, 'cotRCCTTC');
- calcCotIrreductible();
- calcCotTotal();
+ runSafeFieldHandler('tauxRCCHT', () => {
+ validateField('tauxRCCHT', true);
+ updateSubmitButtonState('projetForm');
+ if (skipRecomputeIfInvalid('tauxRCCHT', 3)) return;
+ calcAddTaxe('tauxRCCHT', 0, 'tauxRCCTTC');
+ calcTauxTotal();
+ calcCotFromTauxCA('tauxRCCHT', 'cotRCCHT');
+ calcAddTaxe('cotRCCHT', 0, 'cotRCCTTC');
+ calcCotIrreductible();
+ calcCotTotal();
+ });
});
document.getElementById('tauxRCCTTC').addEventListener('input', function () {
- validateField('tauxRCCTTC', true);
- updateSubmitButtonState('projetForm');
- calcSubTaxe('tauxRCCHT', 0, 'tauxRCCTTC');
- calcTauxTotal();
- calcCotFromTauxCA('tauxRCCHT', 'cotRCCHT');
- calcAddTaxe('cotRCCHT', 0, 'cotRCCTTC');
- calcCotIrreductible();
- calcCotTotal();
+ runSafeFieldHandler('tauxRCCTTC', () => {
+ validateField('tauxRCCTTC', true);
+ updateSubmitButtonState('projetForm');
+ if (skipRecomputeIfInvalid('tauxRCCTTC', 3)) return;
+ calcSubTaxe('tauxRCCHT', 0, 'tauxRCCTTC');
+ calcTauxTotal();
+ calcCotFromTauxCA('tauxRCCHT', 'cotRCCHT');
+ calcAddTaxe('cotRCCHT', 0, 'cotRCCTTC');
+ calcCotIrreductible();
+ calcCotTotal();
+ });
});
document.getElementById('tauxRCEHT').addEventListener('input', function () {
- validateField('tauxRCEHT', true);
- updateSubmitButtonState('projetForm');
- calcAddTaxe('tauxRCEHT', 0.09, 'tauxRCETTC');
- calcTauxTotal();
- calcCotFromTauxCA('tauxRCEHT', 'cotRCEHT');
- calcAddTaxe('cotRCEHT', 0.09, 'cotRCETTC');
- calcCotIrreductible();
- calcCotTotal();
+ runSafeFieldHandler('tauxRCEHT', () => {
+ validateField('tauxRCEHT', true);
+ updateSubmitButtonState('projetForm');
+ if (skipRecomputeIfInvalid('tauxRCEHT', 3)) return;
+ calcAddTaxe('tauxRCEHT', 0.09, 'tauxRCETTC');
+ calcTauxTotal();
+ calcCotFromTauxCA('tauxRCEHT', 'cotRCEHT');
+ calcAddTaxe('cotRCEHT', 0.09, 'cotRCETTC');
+ calcCotIrreductible();
+ calcCotTotal();
+ });
});
document.getElementById('tauxRCETTC').addEventListener('input', function () {
- validateField('tauxRCETTC', true);
- updateSubmitButtonState('projetForm');
- calcSubTaxe('tauxRCEHT', 0.09, 'tauxRCETTC');
- calcTauxTotal();
- calcCotFromTauxCA('tauxRCEHT', 'cotRCEHT');
- calcAddTaxe('cotRCEHT', 0.09, 'cotRCETTC');
- calcCotIrreductible();
- calcCotTotal();
+ runSafeFieldHandler('tauxRCETTC', () => {
+ validateField('tauxRCETTC', true);
+ updateSubmitButtonState('projetForm');
+ if (skipRecomputeIfInvalid('tauxRCETTC', 3)) return;
+ calcSubTaxe('tauxRCEHT', 0.09, 'tauxRCETTC');
+ calcTauxTotal();
+ calcCotFromTauxCA('tauxRCEHT', 'cotRCEHT');
+ calcAddTaxe('cotRCEHT', 0.09, 'cotRCETTC');
+ calcCotIrreductible();
+ calcCotTotal();
+ });
});
document.getElementById('tauxTotalHT').addEventListener('input', function () {
@@ -2541,59 +2974,83 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
});
document.getElementById('cotRCCHT').addEventListener('input', function () {
- validateField('cotRCCHT', true);
- updateSubmitButtonState('projetForm');
- calcAddTaxe('cotRCCHT', 0, 'cotRCCTTC');
- calcCotTotal();
+ runSafeFieldHandler('cotRCCHT', () => {
+ validateField('cotRCCHT', true);
+ updateSubmitButtonState('projetForm');
+ if (skipRecomputeIfInvalid('cotRCCHT', 2)) return;
+ calcAddTaxe('cotRCCHT', 0, 'cotRCCTTC');
+ calcCotTotal();
+ });
});
document.getElementById('cotRCCTTC').addEventListener('input', function () {
- validateField('cotRCCTTC', true);
- updateSubmitButtonState('projetForm');
- calcSubTaxe('cotRCCHT', 0, 'cotRCCTTC');
- calcCotTotal();
+ runSafeFieldHandler('cotRCCTTC', () => {
+ validateField('cotRCCTTC', true);
+ updateSubmitButtonState('projetForm');
+ if (skipRecomputeIfInvalid('cotRCCTTC', 2)) return;
+ calcSubTaxe('cotRCCHT', 0, 'cotRCCTTC');
+ calcCotTotal();
+ });
});
document.getElementById('cotRCEHT').addEventListener('input', function () {
- validateField('cotRCEHT', true);
- updateSubmitButtonState('projetForm');
- calcAddTaxe('cotRCEHT', 0.09, 'cotRCETTC');
- calcCotTotal();
+ runSafeFieldHandler('cotRCEHT', () => {
+ validateField('cotRCEHT', true);
+ updateSubmitButtonState('projetForm');
+ if (skipRecomputeIfInvalid('cotRCEHT', 2)) return;
+ calcAddTaxe('cotRCEHT', 0.09, 'cotRCETTC');
+ calcCotTotal();
+ });
});
document.getElementById('cotRCETTC').addEventListener('input', function () {
- validateField('cotRCETTC', true);
- updateSubmitButtonState('projetForm');
- calcSubTaxe('cotRCEHT', 0.09, 'cotRCETTC');
- calcCotTotal();
+ runSafeFieldHandler('cotRCETTC', () => {
+ validateField('cotRCETTC', true);
+ updateSubmitButtonState('projetForm');
+ if (skipRecomputeIfInvalid('cotRCETTC', 2)) return;
+ calcSubTaxe('cotRCEHT', 0.09, 'cotRCETTC');
+ calcCotTotal();
+ });
});
document.getElementById('cotPJHT').addEventListener('input', function () {
- validateField('cotPJHT', true);
- updateSubmitButtonState('projetForm');
- calcAddTaxe('cotPJHT', 0.134, 'cotPJTTC');
- calcCotTotal();
+ runSafeFieldHandler('cotPJHT', () => {
+ validateField('cotPJHT', true);
+ updateSubmitButtonState('projetForm');
+ if (skipRecomputeIfInvalid('cotPJHT', 2)) return;
+ calcAddTaxe('cotPJHT', 0.134, 'cotPJTTC');
+ calcCotTotal();
+ });
});
document.getElementById('cotPJTTC').addEventListener('input', function () {
- validateField('cotPJTTC', true);
- updateSubmitButtonState('projetForm');
- calcSubTaxe('cotPJHT', 0.134, 'cotPJTTC');
- calcCotTotal();
+ runSafeFieldHandler('cotPJTTC', () => {
+ validateField('cotPJTTC', true);
+ updateSubmitButtonState('projetForm');
+ if (skipRecomputeIfInvalid('cotPJTTC', 2)) return;
+ calcSubTaxe('cotPJHT', 0.134, 'cotPJTTC');
+ calcCotTotal();
+ });
});
document.getElementById('cotFraisHT').addEventListener('input', function () {
- validateField('cotFraisHT', true);
- updateSubmitButtonState('projetForm');
- calcAddTaxe('cotFraisHT', 0, 'cotFraisTTC');
- calcCotTotal();
+ runSafeFieldHandler('cotFraisHT', () => {
+ validateField('cotFraisHT', true);
+ updateSubmitButtonState('projetForm');
+ if (skipRecomputeIfInvalid('cotFraisHT', 2)) return;
+ calcAddTaxe('cotFraisHT', 0, 'cotFraisTTC');
+ calcCotTotal();
+ });
});
document.getElementById('cotFraisTTC').addEventListener('input', function () {
- validateField('cotFraisTTC', true);
- updateSubmitButtonState('projetForm');
- calcSubTaxe('cotFraisHT', 0, 'cotFraisTTC');
- calcCotTotal();
+ runSafeFieldHandler('cotFraisTTC', () => {
+ validateField('cotFraisTTC', true);
+ updateSubmitButtonState('projetForm');
+ if (skipRecomputeIfInvalid('cotFraisTTC', 2)) return;
+ calcSubTaxe('cotFraisHT', 0, 'cotFraisTTC');
+ calcCotTotal();
+ });
});
document.getElementById('cotTotalHT').addEventListener('input', function () {
@@ -2806,6 +3263,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
};
// Peupler le formulaire avec les données
+ /**
+ * Gere populate form data.
+ */
function populateFormData() {
//Poupulate select historique : n'afficher que si des entrées existent
const historiqueDiv = document.getElementById('historiqueDiv');
@@ -3233,6 +3693,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
syncRCFloatingLabels();
}
+ /**
+ * Gere populate gr advalo.
+ */
function populateGrAdvalo(jsonData, tableID) {
var table = document.getElementById(tableID);
if (!table) {
@@ -3305,6 +3768,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
}
};
+ /**
+ * Gere gr advalo.
+ */
function handleGrAdvalo() {
for (let i = 1; i <= 6; i++) {
const checkZone = document.getElementById("zone" + i).checked;
@@ -3322,6 +3788,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
}
}
+ /**
+ * Met a jour category values.
+ */
function updateCategoryValues(mode, zone, index, checkZone) {
for (let k = 1; k <= 8; k++) {
const element = document.getElementById(`${mode}Cat${k}Zone${zone}`);
@@ -3364,6 +3833,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
}
}
+ /**
+ * Gere load historique btn.
+ */
function handleLoadHistoriqueBtn() {
var selectedId = document.getElementById('idSelect').value;
@@ -3385,6 +3857,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
}
}
+ /**
+ * Gere activity selection.
+ */
function handleActivitySelection() {
const select = document.getElementById('activity-selector');
const activityFormsContainer = document.getElementById('selected-activities');
@@ -3436,6 +3911,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
});
}
+ /**
+ * Gere garantie rccselection.
+ */
function handleGarantieRCCSelection() {
const select = document.getElementById('garantieRCC-selector');
const garantieRccFormsContainer = document.getElementById('selected-garantieRCC');
@@ -3460,6 +3938,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
});
}
+ /**
+ * Gere garantie rceselection.
+ */
function handleGarantieRCESelection() {
const select = document.getElementById('garantieRCE-selector');
const garantieRceFormsContainer = document.getElementById('selected-garantieRCE');
@@ -3487,6 +3968,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
});
}
+ /**
+ * Gere marchandise selection.
+ */
function handleMarchandiseSelection() {
const select = document.getElementById('marchandise-selector');
const marchandiseFormsContainer = document.getElementById('selected-marchandises');
@@ -3524,6 +4008,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
}
// Ajouter une ligne au tableau
+ /**
+ * Gere add row additionnel.
+ */
function addRowAdditionnel(nomValue, adresseValue, siretValue) {
const table = document.getElementById('empTableAdditionnel');
@@ -3552,6 +4039,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
}
// Ajouter une ligne au tableau Vehicule
+ /**
+ * Gere add row vehicule.
+ */
function addRowVehicule(marqueValue, genreValue, typeValue, immatValue, capitalValue) {
const table = document.getElementById('empTableVehicules');
@@ -3584,12 +4074,18 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
}
// Supprimer une ligne du tableau
+ /**
+ * Gere delete row.
+ */
function deleteRow(btn) {
const row = btn.parentElement.parentElement;
row.parentElement.removeChild(row);
}
// Contruit la structure Assuré additionnel à envoyer à la BDD
+ /**
+ * Gere extract assure additionnel.
+ */
function extractAssureAdditionnel(tableId) {
const jsonArr = [];
const table = document.getElementById(tableId);
@@ -3622,6 +4118,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
}
// Contruit la structure Designation à envoyer à la BDD
+ /**
+ * Gere extract designation vehicule.
+ */
function extractDesignationVehicule(tableId) {
const jsonArr = [];
const table = document.getElementById(tableId);
@@ -3653,6 +4152,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
return "[]"; // Retourne un tableau JSON vide si aucune saisie n'est trouvée dans le tableau
}
+ /**
+ * Gere extract grille advalo.
+ */
function extractGrilleAdvalo(tableID) {
var jsonData = [];
var table = document.getElementById(tableID);
@@ -3736,6 +4238,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
return jsonData;
}
+ /**
+ * Gere extract tempo.
+ */
function extractTempo() {
let tempo = "";
@@ -3747,6 +4252,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
return tempo;
}
+ /**
+ * Gere extract type cot.
+ */
function extractTypeCot() {
let cot = "";
@@ -3756,70 +4264,152 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
return cot;
}
+ /**
+ * Calcule cot total.
+ */
function calcCotTotal() {
- const cotRCCHT = parseFloat(document.getElementById("cotRCCHT").value) || 0
- const cotRCCTTC = parseFloat(document.getElementById("cotRCCTTC").value) || 0
- const cotRCEHT = parseFloat(document.getElementById("cotRCEHT").value) || 0
- const cotRCETTC = parseFloat(document.getElementById("cotRCETTC").value) || 0
- const cotPJHT = parseFloat(document.getElementById("cotPJHT").value) || 0
- const cotPJTTC = parseFloat(document.getElementById("cotPJTTC").value) || 0
- const cotFraisHT = parseFloat(document.getElementById("cotFraisHT").value) || 0
- const cotFraisTTC = parseFloat(document.getElementById("cotFraisTTC").value) || 0
+ const readValue = (id) => {
+ const field = document.getElementById(id);
+ if (!field) return 0;
+ const parsed = parseValidationNumber(field.value);
+ return Number.isFinite(parsed) ? parsed : 0;
+ };
- document.getElementById("cotTotalHT").value = (cotRCCHT + cotRCEHT + cotPJHT + cotFraisHT).toFixed(2);
- document.getElementById("cotTotalTTC").value = (cotRCCTTC + cotRCETTC + cotPJTTC + cotFraisTTC).toFixed(2);
+ const cotRCCHT = readValue("cotRCCHT");
+ const cotRCCTTC = readValue("cotRCCTTC");
+ const cotRCEHT = readValue("cotRCEHT");
+ const cotRCETTC = readValue("cotRCETTC");
+ const cotPJHT = readValue("cotPJHT");
+ const cotPJTTC = readValue("cotPJTTC");
+ const cotFraisHT = readValue("cotFraisHT");
+ const cotFraisTTC = readValue("cotFraisTTC");
+
+ const totalCalcHT = cotRCCHT + cotRCEHT + cotPJHT + cotFraisHT;
+ const totalCalcTTC = cotRCCTTC + cotRCETTC + cotPJTTC + cotFraisTTC;
+
+ const totalHTInput = document.getElementById("cotTotalHT");
+ if (!totalHTInput) return;
+ const currentTotalHT = parseValidationNumber(totalHTInput?.value);
+ if (!Number.isFinite(currentTotalHT) || currentTotalHT <= 0) {
+ const tarifCommercialState = getTarifCommercialState();
+ if (tarifCommercialState.valid) {
+ totalHTInput.value = tarifCommercialState.tarifCommercialValue.toFixed(2);
+ } else {
+ totalHTInput.value = totalCalcHT.toFixed(2);
+ }
+ }
+ const totalTTCInput = document.getElementById("cotTotalTTC");
+ if (totalTTCInput) {
+ const currentTotalTTC = parseValidationNumber(totalTTCInput.value);
+ if (!Number.isFinite(currentTotalTTC) || currentTotalTTC <= 0) {
+ if (totalCalcTTC > 0) {
+ totalTTCInput.value = totalCalcTTC.toFixed(2);
+ }
+ }
+ }
+ updateTarifCommercialRows();
if (rcProjetGuard) rcProjetGuard.refresh();
}
+ /**
+ * Calcule taux total.
+ */
function calcTauxTotal() {
- const tauxRCCHT = parseFloat(document.getElementById("tauxRCCHT").value) || 0
- const tauxRCCTTC = parseFloat(document.getElementById("tauxRCCTTC").value) || 0
- const tauxRCEHT = parseFloat(document.getElementById("tauxRCEHT").value) || 0
- const tauxRCETTC = parseFloat(document.getElementById("tauxRCETTC").value) || 0
+ const tauxRCCHTEl = document.getElementById("tauxRCCHT");
+ const tauxRCCTTCEl = document.getElementById("tauxRCCTTC");
+ const tauxRCEHTEl = document.getElementById("tauxRCEHT");
+ const tauxRCETTCEl = document.getElementById("tauxRCETTC");
+ const tauxTotalHTEl = document.getElementById("tauxTotalHT");
+ const tauxTotalTTCEl = document.getElementById("tauxTotalTTC");
+ if (!tauxRCCHTEl || !tauxRCCTTCEl || !tauxRCEHTEl || !tauxRCETTCEl || !tauxTotalHTEl || !tauxTotalTTCEl) return;
- document.getElementById("tauxTotalHT").value = (tauxRCCHT + tauxRCEHT).toFixed(3);
- document.getElementById("tauxTotalTTC").value = (tauxRCCTTC + tauxRCETTC).toFixed(3);
+ const tauxRCCHT = parseValidationNumber(tauxRCCHTEl.value);
+ const tauxRCCTTC = parseValidationNumber(tauxRCCTTCEl.value);
+ const tauxRCEHT = parseValidationNumber(tauxRCEHTEl.value);
+ const tauxRCETTC = parseValidationNumber(tauxRCETTCEl.value);
+
+ tauxTotalHTEl.value = ((Number.isFinite(tauxRCCHT) ? tauxRCCHT : 0) + (Number.isFinite(tauxRCEHT) ? tauxRCEHT : 0)).toFixed(3);
+ tauxTotalTTCEl.value = ((Number.isFinite(tauxRCCTTC) ? tauxRCCTTC : 0) + (Number.isFinite(tauxRCETTC) ? tauxRCETTC : 0)).toFixed(3);
if (rcProjetGuard) rcProjetGuard.refresh();
}
+ /**
+ * Calcule cot from taux ca.
+ */
function calcCotFromTauxCA(idTaux, idCot) {
- const valueCA = parseFloat(document.getElementById("CA").value) || 0
- const valueTaux = parseFloat(document.getElementById(idTaux).value) || 0
+ const caEl = document.getElementById("CA");
+ const tauxEl = document.getElementById(idTaux);
+ const cotEl = document.getElementById(idCot);
+ if (!caEl || !tauxEl || !cotEl) return;
- document.getElementById(idCot).value = (valueCA * valueTaux / 100).toFixed(2);
+ const valueCA = parseValidationNumber(caEl.value);
+ const valueTaux = parseValidationNumber(tauxEl.value);
+ if (!Number.isFinite(valueCA) || !Number.isFinite(valueTaux)) return;
+
+ cotEl.value = (valueCA * valueTaux / 100).toFixed(2);
}
+ /**
+ * Calcule cot irreductible.
+ */
function calcCotIrreductible() {
- const cotRCCHT = parseFloat(document.getElementById("cotRCCHT").value) || 0
- const cotRCEHT = parseFloat(document.getElementById("cotRCEHT").value) || 0
+ const cotRCCHTEl = document.getElementById("cotRCCHT");
+ const cotRCEHTEl = document.getElementById("cotRCEHT");
+ const cotIrreductibleEl = document.getElementById("cotisationIrreductible");
+ if (!cotRCCHTEl || !cotRCEHTEl || !cotIrreductibleEl) return;
- document.getElementById("cotisationIrreductible").value = ((cotRCCHT + cotRCEHT) * 0.8).toFixed(2);
+ const cotRCCHT = parseValidationNumber(cotRCCHTEl.value);
+ const cotRCEHT = parseValidationNumber(cotRCEHTEl.value);
+ if (!Number.isFinite(cotRCCHT) || !Number.isFinite(cotRCEHT)) return;
+
+ cotIrreductibleEl.value = ((cotRCCHT + cotRCEHT) * 0.8).toFixed(2);
}
+ /**
+ * Calcule add taxe.
+ */
function calcAddTaxe(idHT, valueTaxe, idTTC) {
- const valueHT = parseFloat(document.getElementById(idHT).value) || 0
+ const htEl = document.getElementById(idHT);
+ const ttcEl = document.getElementById(idTTC);
+ if (!htEl || !ttcEl) return;
+
+ const valueHT = parseValidationNumber(htEl.value);
+ if (!Number.isFinite(valueHT)) return;
if (idTTC != "tauxRCCTTC" && idTTC != "tauxRCETTC") {
- document.getElementById(idTTC).value = (valueHT * (1 + valueTaxe)).toFixed(2);
+ ttcEl.value = (valueHT * (1 + valueTaxe)).toFixed(2);
} else {
- document.getElementById(idTTC).value = (valueHT * (1 + valueTaxe)).toFixed(3);
+ ttcEl.value = (valueHT * (1 + valueTaxe)).toFixed(3);
}
}
+ /**
+ * Calcule sub taxe.
+ */
function calcSubTaxe(idHT, valueTaxe, idTTC) {
- const valueTTC = parseFloat(document.getElementById(idTTC).value) || 0
+ const htEl = document.getElementById(idHT);
+ const ttcEl = document.getElementById(idTTC);
+ if (!htEl || !ttcEl) return;
+
+ const valueTTC = parseValidationNumber(ttcEl.value);
+ if (!Number.isFinite(valueTTC)) return;
if (idHT != "tauxRCCHT" && idHT != "tauxRCEHT") {
- document.getElementById(idHT).value = (valueTTC / (1 + valueTaxe)).toFixed(2);
+ htEl.value = (valueTTC / (1 + valueTaxe)).toFixed(2);
} else {
- document.getElementById(idHT).value = (valueTTC / (1 + valueTaxe)).toFixed(3);
+ htEl.value = (valueTTC / (1 + valueTaxe)).toFixed(3);
}
}
// Gérer la soumission du formulaire
+ /**
+ * Gere submit form.
+ */
async function handleSubmitForm(event) {
event.preventDefault();
+ await refreshTarifReferenceFromApi();
updatePrimeReferenceRow();
+ updateTarifCommercialRows();
if (rcProjetGuard && rcProjetGuard.refresh().length > 0) {
M.toast({ html: 'Corrigez les erreurs du formulaire avant de continuer.', classes: 'red' });
@@ -4129,6 +4719,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
}
// Fonction helper pour récupérer valeur ou "Nous consulter"
+ /**
+ * Recupere value or consulter.
+ */
function getValueOrConsulter(id) {
const element = document.getElementById(id);
if (!element) return 'Nous consulter';
@@ -4137,6 +4730,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
}
// Fonction exposée pour sauvegarder le projet sans générer le document
+ /**
+ * Sauvegarde projet rc.
+ */
async function saveProjetRC() {
try {
updatePrimeReferenceRow();
diff --git a/ecole/public/js/rc-data-manager.js b/ecole/public/js/rc/rc-data-manager.js
similarity index 100%
rename from ecole/public/js/rc-data-manager.js
rename to ecole/public/js/rc/rc-data-manager.js
diff --git a/ecole/public/js/rc-orchestrator.js b/ecole/public/js/rc/rc-orchestrator.js
similarity index 100%
rename from ecole/public/js/rc-orchestrator.js
rename to ecole/public/js/rc/rc-orchestrator.js
diff --git a/ecole/public/js/rc-sync-utils.js b/ecole/public/js/rc/rc-sync-utils.js
similarity index 100%
rename from ecole/public/js/rc-sync-utils.js
rename to ecole/public/js/rc/rc-sync-utils.js
diff --git a/ecole/public/js/rc-validation-utils.js b/ecole/public/js/rc/rc-validation-utils.js
similarity index 82%
rename from ecole/public/js/rc-validation-utils.js
rename to ecole/public/js/rc/rc-validation-utils.js
index 380d05ff..45b09901 100644
--- a/ecole/public/js/rc-validation-utils.js
+++ b/ecole/public/js/rc/rc-validation-utils.js
@@ -1,9 +1,15 @@
(function () {
+ /**
+ * Normalise numeric input.
+ */
function normalizeNumericInput(raw) {
if (raw == null) return '';
return String(raw).trim().replace(/\s+/g, '');
}
+ /**
+ * Parse loose number.
+ */
function parseLooseNumber(raw) {
const normalized = normalizeNumericInput(raw).replace(',', '.');
if (!normalized) return NaN;
@@ -11,6 +17,9 @@
return Number.isFinite(parsed) ? parsed : NaN;
}
+ /**
+ * Formate french amount.
+ */
function formatFrenchAmount(value, digits) {
const number = Number(value);
if (!Number.isFinite(number)) return '0.00';
@@ -20,6 +29,9 @@
});
}
+ /**
+ * Synchronise floating labels.
+ */
function syncFloatingLabels(root) {
const scope = root && root.querySelectorAll ? root : document;
const labels = scope.querySelectorAll('.rc-field-label[for]');
@@ -64,6 +76,9 @@
}
}
+ /**
+ * Securise error slot.
+ */
function ensureErrorSlot(field, customErrorId) {
if (!field) return null;
@@ -92,6 +107,9 @@
return sibling;
}
+ /**
+ * Gere pick field label.
+ */
function pickFieldLabel(field, fallbackLabel) {
if (fallbackLabel) return fallbackLabel;
if (!field) return 'Champ';
@@ -110,6 +128,9 @@
return field.name || field.id || 'Champ';
}
+ /**
+ * Met a jour field error.
+ */
function setFieldError(field, errorSlot, message) {
if (!errorSlot) return;
errorSlot.textContent = message || '';
@@ -124,10 +145,16 @@
}
}
+ /**
+ * Verifie forbidden numeric chars.
+ */
function hasForbiddenNumericChars(value) {
return /[A-Za-z€$£¥]/.test(value);
}
+ /**
+ * Gere validate numeric.
+ */
function validateNumeric(value, options) {
const raw = normalizeNumericInput(value);
const decimals = Number.isInteger(options.decimals) ? options.decimals : 2;
@@ -182,6 +209,9 @@
return { valid: true, normalized: raw.replace(',', '.') };
}
+ /**
+ * Gere validate integer.
+ */
function validateInteger(value, options) {
const raw = normalizeNumericInput(value);
const label = options.label || 'Champ';
@@ -209,6 +239,9 @@
return { valid: true };
}
+ /**
+ * Gere validate immat.
+ */
function validateImmat(value, options) {
const raw = String(value || '').trim().toUpperCase();
const label = options.label || 'Immatriculation';
@@ -227,6 +260,9 @@
return { valid: true, normalized: raw };
}
+ /**
+ * Gere validate text safe.
+ */
function validateTextSafe(value, options) {
const raw = String(value || '').trim();
const label = options.label || 'Champ';
@@ -250,6 +286,9 @@
return { valid: true };
}
+ /**
+ * Gere validate number or consult.
+ */
function validateNumberOrConsult(raw, options) {
const value = String(raw || '').trim();
const lower = value.toLowerCase();
@@ -268,6 +307,9 @@
return validateNumeric(value, options);
}
+ /**
+ * Gere evaluate rule.
+ */
function evaluateRule(field, config) {
const profile = config.profile;
const label = pickFieldLabel(field, config.label);
@@ -331,11 +373,17 @@
};
}
+ /**
+ * Gere create summary element.
+ */
function createSummaryElement(summaryId) {
if (!summaryId) return null;
return document.getElementById(summaryId);
}
+ /**
+ * Gere create guard.
+ */
function createGuard(options) {
const summary = createSummaryElement(options.summaryId);
const summaryTitle = String(options.summaryTitle || 'Impossible de continuer car :');
@@ -357,6 +405,9 @@
});
});
+ /**
+ * Gere apply summary.
+ */
function applySummary(messages) {
if (!summary) return;
if (!messages.length) {
@@ -379,6 +430,9 @@
summary.style.display = 'block';
}
+ /**
+ * Gere apply blocking.
+ */
function applyBlocking(hasErrors) {
state.targetButtons.forEach(function (button) {
if (!button) return;
@@ -395,6 +449,9 @@
});
}
+ /**
+ * Gere recompute.
+ */
function recompute() {
const messages = [];
@@ -405,10 +462,15 @@
});
state.externalChecks.forEach(function (entry, key) {
- const checkResult = typeof entry.fn === 'function' ? entry.fn() : { valid: true };
- if (!checkResult || checkResult.valid === false) {
- const message = checkResult && checkResult.message ? checkResult.message : entry.message || key;
- messages.push(message);
+ try {
+ const checkResult = typeof entry.fn === 'function' ? entry.fn() : { valid: true };
+ if (!checkResult || checkResult.valid === false) {
+ const message = checkResult && checkResult.message ? checkResult.message : entry.message || key;
+ messages.push(message);
+ }
+ } catch (error) {
+ console.warn('[RC guard] Check externe en erreur:', key, error);
+ messages.push(entry.message || ('Validation en erreur: ' + key));
}
});
@@ -422,46 +484,65 @@
return messages;
}
+ /**
+ * Gere validate field.
+ */
function validateField(field) {
- const config = state.fieldRules.get(field);
- if (!config) return;
+ try {
+ const config = state.fieldRules.get(field);
+ if (!config) return;
+
+ if (!field || !field.isConnected || field.disabled) {
+ if (config.errorSlot) setFieldError(field, config.errorSlot, '');
+ state.fieldErrors.delete(config.key);
+ recompute();
+ return;
+ }
+
+ if (typeof config.activeWhen === 'function' && !config.activeWhen(field)) {
+ setFieldError(field, config.errorSlot, '');
+ state.fieldErrors.delete(config.key);
+ recompute();
+ return;
+ }
+
+ // Sécurité défaut: sans activeWhen explicite, on ignore un champ masqué.
+ if (typeof config.activeWhen !== 'function' && field.type !== 'hidden' && field.offsetParent === null) {
+ setFieldError(field, config.errorSlot, '');
+ state.fieldErrors.delete(config.key);
+ recompute();
+ return;
+ }
+
+ const result = evaluateRule(field, config);
+ setFieldError(field, config.errorSlot, result.valid ? '' : result.message);
+
+ if (result.valid) {
+ state.fieldErrors.delete(config.key);
+ } else {
+ state.fieldErrors.set(config.key, {
+ message: result.message
+ });
+ }
- if (!field || !field.isConnected || field.disabled) {
- if (config.errorSlot) setFieldError(field, config.errorSlot, '');
- state.fieldErrors.delete(config.key);
recompute();
- return;
- }
-
- if (typeof config.activeWhen === 'function' && !config.activeWhen(field)) {
- setFieldError(field, config.errorSlot, '');
- state.fieldErrors.delete(config.key);
- recompute();
- return;
- }
-
- // Sécurité défaut: sans activeWhen explicite, on ignore un champ masqué.
- if (typeof config.activeWhen !== 'function' && field.type !== 'hidden' && field.offsetParent === null) {
- setFieldError(field, config.errorSlot, '');
- state.fieldErrors.delete(config.key);
- recompute();
- return;
- }
-
- const result = evaluateRule(field, config);
- setFieldError(field, config.errorSlot, result.valid ? '' : result.message);
-
- if (result.valid) {
- state.fieldErrors.delete(config.key);
- } else {
- state.fieldErrors.set(config.key, {
- message: result.message
+ } catch (error) {
+ const config = state.fieldRules.get(field);
+ const key = config && config.key ? config.key : 'champ-inconnu';
+ console.warn('[RC guard] Validation en erreur:', key, error);
+ if (config && config.errorSlot) {
+ setFieldError(field, config.errorSlot, 'Erreur de validation, rechargez la page.');
+ }
+ state.fieldErrors.set(key, {
+ message: 'Erreur de validation sur un champ du formulaire.'
});
+ recompute();
}
-
- recompute();
}
+ /**
+ * Gere attach field.
+ */
function attachField(field, config) {
if (!field) return;
@@ -489,6 +570,9 @@
validateField(field);
}
+ /**
+ * Enregistre field.
+ */
function registerField(selectorOrElement, config) {
if (!selectorOrElement || !config || !config.profile) return;
if (typeof selectorOrElement === 'string') {
@@ -500,6 +584,9 @@
attachField(selectorOrElement, config);
}
+ /**
+ * Gere observe.
+ */
function observe(selector, config) {
if (!selector || !config || !config.profile) return;
@@ -517,6 +604,9 @@
return observer;
}
+ /**
+ * Enregistre external.
+ */
function registerExternal(key, fn, fallbackMessage) {
if (!key || typeof fn !== 'function') return;
state.externalChecks.set(key, {
@@ -526,6 +616,9 @@
recompute();
}
+ /**
+ * Gere refresh.
+ */
function refresh() {
state.fieldRules.forEach(function (_cfg, field) {
validateField(field);
diff --git a/ecole/public/js/tarif-form-rc.js b/ecole/public/js/rc/tarif-form-rc.js
similarity index 98%
rename from ecole/public/js/tarif-form-rc.js
rename to ecole/public/js/rc/tarif-form-rc.js
index b739855c..541f30c8 100644
--- a/ecole/public/js/tarif-form-rc.js
+++ b/ecole/public/js/rc/tarif-form-rc.js
@@ -1,8 +1,14 @@
+/**
+ * Initialise submenu form.
+ */
function initSubmenuForm() {
// Accéder aux informations stockées du parcours
const parcours = JSON.parse(sessionStorage.getItem('parcours'));
}
+/**
+ * Convertit number.
+ */
function toNumber(x) {
if (x == null) return 0;
@@ -45,6 +51,9 @@ function toNumber(x) {
}
// Fonction pour formater un nombre avec X décimales max (sans décimales si entier)
+/**
+ * Formate number.
+ */
function formatNumber(num, decimals = 2) {
if (!num || isNaN(num)) return '0.' + '0'.repeat(decimals);
const factor = Math.pow(10, decimals);
@@ -56,6 +65,9 @@ function formatNumber(num, decimals = 2) {
return rounded.toFixed(decimals);
}
+/**
+ * Recupere element by id flexible.
+ */
function getElementByIdFlexible(id) {
if (!id) return null;
const direct = document.getElementById(id);
@@ -78,12 +90,18 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
let rcTarifGuard = null;
let rcTarifHasErrors = false;
+ /**
+ * Synchronise rcfloating labels.
+ */
function syncRCFloatingLabels() {
if (window.RCValidationUtils && typeof window.RCValidationUtils.syncFloatingLabels === 'function') {
window.RCValidationUtils.syncFloatingLabels(document);
}
}
+ /**
+ * Met a jour tarifettes visibility.
+ */
function updateTarifettesVisibility() {
const tarifettesContainer = document.getElementById('tarifettesContainer');
if (!tarifettesContainer) return;
@@ -95,6 +113,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
// ═══════════════════════════════════════════════════════════════
// Fonction helper : trouver la tranche la plus proche
+ /**
+ * Trouve closest tranche.
+ */
function findClosestTranche(val, tranches) {
if (val <= tranches[0]) return tranches[0];
if (val >= tranches[tranches.length - 1]) return tranches[tranches.length - 1];
@@ -107,6 +128,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
return tranches[tranches.length - 1];
}
+ /**
+ * Met a jour tarif choice buttons state.
+ */
function updateTarifChoiceButtonsState() {
const buttons = document.querySelectorAll('.franchise-card button[name]');
buttons.forEach((button) => {
@@ -122,6 +146,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
updateTarifettesVisibility();
}
+ /**
+ * Configure rcsafe validation.
+ */
function setupRCSafeValidation() {
if (!window.RCValidationUtils || typeof window.RCValidationUtils.createGuard !== 'function') {
return;
@@ -130,7 +157,7 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
rcTarifGuard = window.RCValidationUtils.createGuard({
summaryId: 'rcTarifBlockingSummary',
summaryTitle: 'Impossible de choisir un tarif ou de continuer car :',
- blockTargets: ['#generateDeclinaison', '#generateProject', '#comm-OK'],
+ blockTargets: ['#generateDeclinaison', '#generateProject'],
onChange: function (messages) {
rcTarifHasErrors = messages.length > 0;
updateTarifChoiceButtonsState();
@@ -267,30 +294,6 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
}
});
- rcTarifGuard.registerField('#tarifCom', {
- profile: 'numeric',
- label: 'Tarif commercial',
- min: 0,
- positive: true,
- requiredWhen: function () {
- return Boolean(document.getElementById('modalTarifCom')?.classList.contains('open'));
- },
- activeWhen: function () {
- return Boolean(document.getElementById('modalTarifCom')?.classList.contains('open'));
- }
- });
-
- rcTarifGuard.registerField('#commentaire', {
- profile: 'text',
- label: 'Commentaire explicatif',
- requiredWhen: function () {
- return document.getElementById('tarifCom-error')?.style.display !== 'none';
- },
- activeWhen: function () {
- return document.getElementById('col-commentaire')?.style.display !== 'none';
- }
- });
-
rcTarifGuard.observe('#tabAdvaloTerrestre input[type="text"], #tabAdvaloMultimodal input[type="text"], #tabAdvaloAerien input[type="text"]', {
profile: 'number_or_consulter',
label: 'Valeur ad valorem',
@@ -328,6 +331,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
}
// Fonction pour afficher un avertissement visuel de dépassement %
+ /**
+ * Affiche percentage warning.
+ */
function showPercentageWarning(excess) {
let warningDiv = document.getElementById('percentageWarning');
if (!warningDiv) {
@@ -357,6 +363,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
}
// Fonction pour masquer toutes les primes (quand % invalide)
+ /**
+ * Masque all primes.
+ */
function hideAllPrimes() {
const primeElements = [
'primeChapActRCC', 'primeChapActRCE',
@@ -376,6 +385,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
}
// Fonction pour mettre à jour l'indicateur visuel du total des pourcentages
+ /**
+ * Met a jour percentage indicator.
+ */
function updatePercentageIndicator(total) {
const indicator = document.getElementById('pourcentageTotal');
if (!indicator) return;
@@ -405,6 +417,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
// ═══════════════════════════════════════════════════════════════
// Initialisation du formulaire et des données
+ /**
+ * Initialise la logique de cette fonction.
+ */
function init() {
// Materialize init select
var select = document.querySelectorAll('select');
@@ -467,6 +482,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
}
// Configuration des listeners d'événements
+ /**
+ * Configure event listeners.
+ */
function setupEventListeners() {
// Empêcher la soumission du formulaire avec la touche Enter
const form = document.getElementById('projetForm');
@@ -1181,6 +1199,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
// Le bouton Annuler ferme automatiquement le modal grâce à la classe "modal-close"
}
+ /**
+ * Parse prefill array.
+ */
function parsePrefillArray(value) {
if (Array.isArray(value)) return value;
if (typeof value === 'string') {
@@ -1194,6 +1215,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
return [];
}
+ /**
+ * Normalise prefill value.
+ */
function normalizePrefillValue(value) {
if (Array.isArray(value)) {
return value
@@ -1223,6 +1247,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
return value;
}
+ /**
+ * Gere build projet prefill delta.
+ */
function buildProjetPrefillDelta(snapshot, baseline) {
if (!snapshot || typeof snapshot !== 'object') return null;
if (!baseline || typeof baseline !== 'object') return snapshot;
@@ -1240,6 +1267,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
return Object.keys(delta).length > 0 ? delta : null;
}
+ /**
+ * Gere apply projet data to tarif.
+ */
function applyProjetDataToTarif(projetSource) {
if (!projetSource || typeof projetSource !== 'object') return;
@@ -1503,6 +1533,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
}
// Peupler le formulaire avec les données
+ /**
+ * Gere populate form data.
+ */
function populateFormData() {
//Poupulate select historique
if (!contrat.historique) {
@@ -1877,6 +1910,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
}, 500);
}
+ /**
+ * Calcule mod ca.
+ */
function calcModCA(caRaw){
const ca = Number(String(caRaw || '').replace(/\s/g,'').replace(',','.')) || 0;
const thresholds = Object.keys(modRCCA).map(n => Number(n)).sort((a,b)=>a-b);
@@ -1884,6 +1920,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
return modRCCA[thresholds.at(-1)] ?? 1;
}
+ /**
+ * Calcule mod marchandises.
+ */
function calcModMarchandises(data, activityName, type, cot) {
let m = 1;
@@ -1927,6 +1966,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
return m;
}
+ /**
+ * Recupere zone mods.
+ */
function getZoneMods(data) {
let mRCC = 1;
let mRCE = 1;
@@ -1958,6 +2000,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
return { mRCC, mRCE };
}
+ /**
+ * Calcule mod act compl.
+ */
function calcModActCompl(data, activityName, type, cot) {
let m = 1;
const current = getSelectedActivities().find(a => a.typeActivite === activityName);
@@ -1970,12 +2015,18 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
return m;
}
+ /**
+ * Calcule engag compl.
+ */
function calcEngagCompl(data, primeRCC) {
let prime = primeRCC;
let surPrime = 0;
let modDommImmat = 1;
let infos = [];
+ /**
+ * Gere write to card.
+ */
function writeToCard(inputId, message) {
const inputEl = document.getElementById(inputId);
if (!inputEl) return;
@@ -2078,6 +2129,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
}
// Fonction helper : trouver la tranche la plus proche
+ /**
+ * Trouve closest tranche.
+ */
function findClosestTranche(val, tranches) {
if (val <= tranches[0]) return tranches[0];
if (val >= tranches[tranches.length - 1]) return tranches[tranches.length - 1];
@@ -2092,6 +2146,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
}
// Fonction pour afficher un avertissement visuel de dépassement %
+ /**
+ * Affiche percentage warning.
+ */
function showPercentageWarning(excess) {
// Créer ou récupérer le div d'avertissement
let warningDiv = document.getElementById('percentageWarning');
@@ -2124,6 +2181,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
}
// Fonction pour masquer toutes les primes (quand % invalide)
+ /**
+ * Masque all primes.
+ */
function hideAllPrimes() {
const primeElements = [
'primeChapActRCC', 'primeChapActRCE',
@@ -2143,10 +2203,16 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
}
// Fonction pour afficher toutes les primes (quand % valide)
+ /**
+ * Affiche all primes.
+ */
function showAllPrimes() {
}
// Fonction pour mettre à jour l'indicateur visuel du total des pourcentages
+ /**
+ * Met a jour percentage indicator.
+ */
function updatePercentageIndicator(total) {
const indicator = document.getElementById('pourcentageTotal');
if (!indicator) return;
@@ -2182,6 +2248,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
}
}
+ /**
+ * Calcule gar add.
+ */
function calcGarAdd(data, primeRCC, primeRCE) {
let primeRCCres = Number(primeRCC) || 0;
let primeRCEres = Number(primeRCE) || 0;
@@ -2189,6 +2258,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
const infosRCC = [];
const infosRCE = [];
+ /**
+ * Gere write to card.
+ */
function writeToCard(inputId, message) {
const inputEl = document.getElementById(inputId);
if (!inputEl) return;
@@ -2276,6 +2348,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
+ /**
+ * Calcule sinistre.
+ */
function calcSinistre(data, primeRCC, primeRCE) {
console.log('[calcSinistre] start', { primeRCC, primeRCE });
@@ -2327,6 +2402,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
// --- Fonctions utilitaires ---
+ /**
+ * Recupere max mini rcc.
+ */
function getMaxMiniRCC(activites, cot) {
let maxMini = 0;
activites.forEach(act => {
@@ -2355,6 +2433,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
return maxMini;
}
+ /**
+ * Recupere max mini rce.
+ */
function getMaxMiniRCE(activites, cot) {
let maxMini = 0;
activites.forEach(act => {
@@ -2384,6 +2465,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
}
+ /**
+ * Calcule tarif rcc.
+ */
function calcTarifRCC({
CA,
primeRCCbase,
@@ -2449,6 +2533,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
}
+ /**
+ * Calcule tarifettes.
+ */
function calcTarifettes(primePJ, CA, activites, capitalTPPC, nbVehicules, coefTPPC, primeRCCbase, primeRCEbase) {
const cards = [
{ key: "250", priceId: "priceFr250", rccId: "rccFr250", rceId: "rceFr250", pjId: "pjFr250", txRccId: "tauxRccFr250", txRceId: "tauxRceFr250", txGlobId: "tauxGlobalFr250" },
@@ -2573,6 +2660,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
}
// Fonction pour calculer la PJ selon la prime totale
+ /**
+ * Calcule pj.
+ */
function calcPJ(primeTotale) {
let primePJ = 0;
const tablePJ = modRCGarAdd?.modRCC?.["Protection juridique"];
@@ -2592,6 +2682,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
+ /**
+ * Calcule global.
+ */
function calcGlobal() {
// Vérification des pourcentages AVANT calcul
const allPourcentInputs = Array.from(document.querySelectorAll('.input-pourcent')).filter(p => p.offsetParent != null);
@@ -2631,6 +2724,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
updateTarifChoiceButtonsState();
}
+ /**
+ * Calcule revisable.
+ */
function calcRevisable() {
// ========= Variables centrales (déclarées au début) =========
const capitalTPPCEl = document.getElementById("capital_TPPC");
@@ -2856,6 +2952,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
"Autres activites": "Autres activites"
};
+ /**
+ * Recupere selected activites.
+ */
function getSelectedActivites() {
const activites = [];
document.querySelectorAll('label input[type="checkbox"]:checked').forEach(cb => {
@@ -2885,6 +2984,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
};
}
+ /**
+ * Calcule forfaitaire.
+ */
function calcForfaitaire() {
// ========= Variables centrales =========
let primeBaseRCC = 0;
@@ -3139,6 +3241,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
"Autres activites": "Autres activites"
};
+ /**
+ * Recupere selected activites.
+ */
function getSelectedActivites() {
const activites = [];
document.querySelectorAll('label input[type="checkbox"]:checked').forEach(cb => {
@@ -3167,6 +3272,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
};
}
+ /**
+ * Recupere zone mods.
+ */
function getZoneMods(modRCZone) {
const zones = [
{ id: 'zone1', label: 'France Métropolitaine et pays limitrophes' },
@@ -3191,6 +3299,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
}
+ /**
+ * Gere load historique btn.
+ */
function handleLoadHistoriqueBtn() {
var selectedId = document.getElementById('idSelect').value;
@@ -3213,6 +3324,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
}
//Appel pour recevoir les constantes
+ /**
+ * Gere constants json.
+ */
async function constantsJSON() {
try {
const responsesJSON = await Promise.all([
@@ -3249,6 +3363,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
}
}
+ /**
+ * Gere reset inputs.
+ */
function resetInputs() {
// Sélection des éléments input pourcentage
const pourcentInputs = document.querySelectorAll('.input-pourcent');
@@ -3280,6 +3397,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
}
}
+ /**
+ * Recupere taux base rcc.
+ */
function get_taux_base_RCC(grille_mod_RCC, cot) {
const tauxOptimaux = [];
const selections = getSelectedActivities();
@@ -3340,6 +3460,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
}
+ /**
+ * Recupere taux base rce.
+ */
function get_taux_base_RCE(grille_mod_RCE, cot) {
const tauxOptimaux = [];
const selections = getSelectedActivities();
@@ -3372,6 +3495,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
return tauxOptimaux;
}
+ /**
+ * Recupere selected activities.
+ */
function getSelectedActivities() {
const selections = [];
@@ -3503,6 +3629,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
}
// Fonction pour sauvegarder les données tarifRC dans la base
+ /**
+ * Sauvegarde tarif rc.
+ */
async function saveTarifRC() {
if (!rc || !contrat) {
console.error('Données manquantes pour sauvegarder le tarif RC');
@@ -3741,6 +3870,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
}
// Fonction helper pour collecter les activités complémentaires
+ /**
+ * Collecte activites compl json.
+ */
function collectActivitesComplJSON(typeActivite) {
let name;
switch(typeActivite.toLowerCase()) {
@@ -3770,6 +3902,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
}
// Fonction helper pour collecter les marchandises
+ /**
+ * Collecte marchandises json.
+ */
function collectMarchandisesJSON(typeActivite) {
let name;
switch(typeActivite.toLowerCase()) {
@@ -3805,6 +3940,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
}
// Fonction pour gérer les clics sur les boutons de tariffettes
+ /**
+ * Configure tarifette buttons.
+ */
function setupTarifetteButtons() {
const tarifetteButtons = document.querySelectorAll('.franchise-card button[name]');
tarifetteButtons.forEach(button => {
@@ -3827,6 +3965,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
}
// Fonction pour configurer les alertes de marchandises
+ /**
+ * Configure marchandise alerts.
+ */
function setupMarchandiseAlerts() {
// Alerte pour Animaux Vivants
document.querySelectorAll('[name^="mar"] input[type="checkbox"]').forEach(cb => {
@@ -3843,6 +3984,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
}
// Fonction pour configurer les alertes d'activités
+ /**
+ * Configure activite alerts.
+ */
function setupActiviteAlerts() {
// Alerte pour Autocariste + RCE
const checkAutocariste = document.getElementById('checkAutocariste');
@@ -3862,6 +4006,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
const seuil = 5;
// Fonction pour ouvrir le modal de tarif commercial
+ /**
+ * Ouvre modal tarif com.
+ */
function openModalTarifCom(franchiseValue) {
// Récupérer le tarif de référence selon la franchise
let tarifRef = 0;
@@ -3877,7 +4024,7 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
document.getElementById('tarifRefText').innerText = `Tarif de Référence : ${formatNumber(tarifRef, 2)} €`;
document.getElementById('tarifCom').value = '';
document.getElementById('commentaire').value = '';
- document.getElementById('comm-OK').disabled = false;
+ document.getElementById('comm-OK').disabled = true;
document.getElementById('tarifCom-error').style.display = 'none';
document.getElementById('col-commentaire').style.display = 'none';
document.getElementById('qualiteDiv').style.display = 'none';
@@ -3896,15 +4043,23 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
// Ouvrir le modal
window.modalTarifCom.open();
+ if (rcTarifGuard) rcTarifGuard.refresh();
}
// Fonction pour gérer l'input du tarif commercial
+ /**
+ * Gere tarif com input.
+ */
function handleTarifComInput(e) {
const tarifCom = parseFloat(e.target.value);
const tarifRef = parseFloat(document.getElementById('comm-OK').getAttribute('data-tarif-ref'));
if (!tarifCom || tarifCom <= 0) {
document.getElementById('qualiteDiv').style.display = 'none';
+ document.getElementById('tarifCom-error').style.display = 'none';
+ document.getElementById('col-commentaire').style.display = 'none';
+ document.getElementById('comm-OK').disabled = true;
+ if (rcTarifGuard) rcTarifGuard.refresh();
return;
}
@@ -3952,19 +4107,32 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
document.getElementById('tarifCom-error').style.display = 'none';
document.getElementById('col-commentaire').style.display = 'none';
}
+
+ if (rcTarifGuard) rcTarifGuard.refresh();
}
// Fonction pour gérer l'input du commentaire
+ /**
+ * Gere commentaire input.
+ */
function handleCommentaireInput(e) {
const commentaire = e.target.value.trim();
+ const tarifCom = parseFloat(document.getElementById('tarifCom').value);
const tarifComError = document.getElementById('tarifCom-error').style.display !== 'none';
if (tarifComError) {
- document.getElementById('comm-OK').disabled = !commentaire;
+ document.getElementById('comm-OK').disabled = !commentaire || !tarifCom || tarifCom <= 0;
+ } else {
+ document.getElementById('comm-OK').disabled = !tarifCom || tarifCom <= 0;
}
+
+ if (rcTarifGuard) rcTarifGuard.refresh();
}
// Fonction pour gérer la validation du tarif commercial
+ /**
+ * Gere validate tarif com.
+ */
async function handleValidateTarifCom() {
const tarifCom = parseFloat(document.getElementById('tarifCom').value);
const commentaire = document.getElementById('commentaire').value.trim();
diff --git a/ecole/public/js/projet-form-tppc.js b/ecole/public/js/tppc/projet-form-tppc.js
similarity index 100%
rename from ecole/public/js/projet-form-tppc.js
rename to ecole/public/js/tppc/projet-form-tppc.js
diff --git a/ecole/public/js/tarif-form-tppc.js b/ecole/public/js/tppc/tarif-form-tppc.js
similarity index 100%
rename from ecole/public/js/tarif-form-tppc.js
rename to ecole/public/js/tppc/tarif-form-tppc.js
diff --git a/ecole/public/js/verif-form.js b/ecole/public/js/verif-form.js
index ceb025b1..2d5ec4af 100644
--- a/ecole/public/js/verif-form.js
+++ b/ecole/public/js/verif-form.js
@@ -4,161 +4,187 @@ function isValidEmail(email) {
}
function validateField(fieldId, showErrors = true) {
- const inputElement = document.getElementById(fieldId);
+ try {
+ const inputElement = document.getElementById(fieldId);
- if (!inputElement) {
- return true;
- }
+ if (!inputElement) {
+ return true;
+ }
- const value = document.getElementById(fieldId).value.trim();
- const rule = validationRules[fieldId]; // Importé de js/json/json-verif-form.js
- const errorElement = document.getElementById(`${fieldId}-error`);
+ const rawValue = inputElement.value;
+ const value = typeof rawValue === 'string' ? rawValue.trim() : String(rawValue ?? '').trim();
+ const hasValidationRules = typeof validationRules !== 'undefined' && validationRules;
+ const rule = hasValidationRules ? validationRules[fieldId] : null; // Importé de js/json/json-verif-form.js
+ const errorElement = document.getElementById(`${fieldId}-error`);
- let isValid = true;
- let errorMessage = "";
+ if (!rule) {
+ if (showErrors && errorElement) {
+ errorElement.textContent = "";
+ errorElement.style.display = 'none';
+ }
+ return true;
+ }
- // Vérifie si le champ est requis et vide
+ let isValid = true;
+ let errorMessage = "";
- if (rule.required && (!value || value == '')) {
- errorMessage = "Ce champ est obligatoire.";
- isValid = false;
- }
-
- // Vérifie la longueur de la saisie si spécifié et nécessaire
- if (isValid && value && rule.length && value.length !== rule.length) {
- errorMessage = `Veuillez saisir ${rule.length} caractères, il y en a actuellement ${value.length}.`;
- isValid = false;
- }
-
- // Vérifie si la saisie est un nombre sans décimale ou avec un maximum de deux chiffres après la virgule
- if (isValid && value && rule.numberFormat) {
- const isNumberFormatValid = /^(?:\d+|\d+\.\d{1,2})$/.test(value);
-
- if (!isNumberFormatValid) {
- errorMessage = "Le champ doit être nombre de deux décimal maximum '00.00' ou entier '00'";
+ // Vérifie si le champ est requis et vide
+ if (rule.required && (!value || value == '')) {
+ errorMessage = "Ce champ est obligatoire.";
isValid = false;
}
- }
- // Vérifie si la saisie est un taux sans décimale ou avec un maximum de trois chiffres après la virgule
- if (isValid && value && rule.tauxFormat) {
- const isTauxFormatValid = /^(?:\d+|\d+\.\d{1,3})$/.test(value);
-
- if (!isTauxFormatValid) {
- errorMessage = "Le champ doit être un nombre avec un maximum de trois décimales '00.000' ou entier '00'";
+ // Vérifie la longueur de la saisie si spécifié et nécessaire
+ if (isValid && value && rule.length && value.length !== rule.length) {
+ errorMessage = `Veuillez saisir ${rule.length} caractères, il y en a actuellement ${value.length}.`;
isValid = false;
}
- }
- // Vérifie si le champ doit être compris dans un certain intervalle
- if (isValid && value && rule.range) {
- const numberValue = parseFloat(value);
+ // Vérifie si la saisie est un nombre sans décimale ou avec un maximum de deux chiffres après la virgule
+ if (isValid && value && rule.numberFormat) {
+ const isNumberFormatValid = /^(?:\d+|\d+\.\d{1,2})$/.test(value);
- if (isNaN(numberValue) || numberValue < rule.range.min || numberValue > rule.range.max) {
- errorMessage = rule.errorMsg;
+ if (!isNumberFormatValid) {
+ errorMessage = "Le champ doit être nombre de deux décimal maximum '00.00' ou entier '00'";
+ isValid = false;
+ }
+ }
+
+ // Vérifie si la saisie est un taux sans décimale ou avec un maximum de trois chiffres après la virgule
+ if (isValid && value && rule.tauxFormat) {
+ const isTauxFormatValid = /^(?:\d+|\d+\.\d{1,3})$/.test(value);
+
+ if (!isTauxFormatValid) {
+ errorMessage = "Le champ doit être un nombre avec un maximum de trois décimales '00.000' ou entier '00'";
+ isValid = false;
+ }
+ }
+
+ // Vérifie si le champ doit être compris dans un certain intervalle
+ if (isValid && value && rule.range) {
+ const numberValue = parseFloat(value);
+
+ if (isNaN(numberValue) || numberValue < rule.range.min || numberValue > rule.range.max) {
+ errorMessage = rule.errorMsg;
+ isValid = false;
+ }
+ }
+
+ // Valide l'adresse e-mail seulement si le champ n'est pas vide
+ if (isValid && value && rule.email) {
+ if (!isValidEmail(value)) {
+ errorMessage = rule.errorMsg;
+ isValid = false;
+ }
+ }
+
+ // Vérifie la présence de caractères potentiellement problématiques
+ const specialCharsPattern = /[;">&<]/g;
+ let invalidChars = value.match(specialCharsPattern);
+
+ if (isValid && value && invalidChars) {
+ invalidChars = [...new Set(invalidChars)];
+ errorMessage = `Caractère(s) invalide(s) détecté(s) [ ${invalidChars.join(" ")} ].`;
isValid = false;
}
- }
- // Valide l'adresse e-mail seulement si le champ n'est pas vide
- if (isValid && value && rule.email) {
- if (!isValidEmail(value)) {
- errorMessage = rule.errorMsg;
+ // Vérifie si le champ commence par le caractère spécifié
+ if (isValid && value && rule.startsWith && !value.startsWith(rule.startsWith)) {
+ errorMessage = `Le champ doit commencer par '${rule.startsWith}' majuscule.`;
isValid = false;
}
- }
- // Vérifie la présence de caractères potentiellement problématiques
- const specialCharsPattern = /[;">&<]/g;
- let invalidChars = value.match(specialCharsPattern);
+ // Vérifie si le champ date est correct
+ if (isValid && value && rule.dateFormat) {
+ const isDateFormatValid = /^(0[1-9]|[12][0-9]|3[01])\/(0[1-9]|1[012])\/\d{4}$|^00\/00\/0000$/.test(value);
- if (isValid && value && invalidChars) {
- invalidChars = [...new Set(invalidChars)];
- errorMessage = `Caractère(s) invalide(s) détecté(s) [ ${invalidChars.join(" ")} ].`;
- isValid = false;
- }
-
- // Vérifie si le champ commence par le caractère spécifié
- if (isValid && value && rule.startsWith && !value.startsWith(rule.startsWith)) {
- errorMessage = `Le champ doit commencer par '${rule.startsWith}' majuscule.`;
- isValid = false;
- }
-
- // Vérifie si le champ date est correct
- if (isValid && value && rule.dateFormat) {
- const isDateFormatValid = /^(0[1-9]|[12][0-9]|3[01])\/(0[1-9]|1[012])\/\d{4}$|^00\/00\/0000$/.test(value);
-
- if (!isDateFormatValid) {
- errorMessage = "Le champ doit être au format JJ//MM/AAAA ou 00/00/0000.";
- isValid = false;
+ if (!isDateFormatValid) {
+ errorMessage = "Le champ doit être au format JJ//MM/AAAA ou 00/00/0000.";
+ isValid = false;
+ }
}
- }
- // Vérifie si la saisie ne contient pas d'espace
- if (isValid && value && rule.noSpace) {
- const isNoSpaceValid = /^\S*$/.test(value);
+ // Vérifie si la saisie ne contient pas d'espace
+ if (isValid && value && rule.noSpace) {
+ const isNoSpaceValid = /^\S*$/.test(value);
- if (!isNoSpaceValid) {
- errorMessage = "La saisie ne doit pas contenir d'espaces.";
- isValid = false;
+ if (!isNoSpaceValid) {
+ errorMessage = "La saisie ne doit pas contenir d'espaces.";
+ isValid = false;
+ }
}
- }
- // Vérifie si le champ date est correct au format JJ/MM
- if (isValid && value && rule.dateFormatShort) {
- const isDateFormatShortValid = /^(0[1-9]|[12][0-9]|3[01])\/(0[1-9]|1[012])$|^00\/00$/.test(value);
+ // Vérifie si le champ date est correct au format JJ/MM
+ if (isValid && value && rule.dateFormatShort) {
+ const isDateFormatShortValid = /^(0[1-9]|[12][0-9]|3[01])\/(0[1-9]|1[012])$|^00\/00$/.test(value);
- if (!isDateFormatShortValid) {
- errorMessage = "Le champ doit être au format JJ/MM ou 00/00.";
- isValid = false;
+ if (!isDateFormatShortValid) {
+ errorMessage = "Le champ doit être au format JJ/MM ou 00/00.";
+ isValid = false;
+ }
}
- }
- // Vérifie la casse des caractères si spécifié
- if (isValid && value && rule.case) {
- if (rule.case === "upper" && value !== value.toUpperCase()) {
- errorMessage = "Le champ doit être en majuscules.";
- isValid = false;
- } else if (rule.case === "lower" && value !== value.toLowerCase()) {
- errorMessage = "Le champ doit être en minuscules.";
- isValid = false;
+ // Vérifie la casse des caractères si spécifié
+ if (isValid && value && rule.case) {
+ if (rule.case === "upper" && value !== value.toUpperCase()) {
+ errorMessage = "Le champ doit être en majuscules.";
+ isValid = false;
+ } else if (rule.case === "lower" && value !== value.toLowerCase()) {
+ errorMessage = "Le champ doit être en minuscules.";
+ isValid = false;
+ }
}
- }
- // Vérifie si le champ doit être numérique
- if (isValid && value && rule.digit) {
- const isNumeric = /^\d+$/.test(value); // Vérifie si la chaîne est un nombre entier
+ // Vérifie si le champ doit être numérique
+ if (isValid && value && rule.digit) {
+ const isNumeric = /^\d+$/.test(value); // Vérifie si la chaîne est un nombre entier
- if (!isNumeric) {
- errorMessage = "Le champ doit contenir uniquement des chiffres.";
- isValid = false;
+ if (!isNumeric) {
+ errorMessage = "Le champ doit contenir uniquement des chiffres.";
+ isValid = false;
+ }
}
- }
- // Affiche ou cache le message d'erreur selon la validité du champ
- if (showErrors) {
- errorElement.textContent = errorMessage;
- errorElement.style.display = isValid ? 'none' : 'block';
- }
+ // Affiche ou cache le message d'erreur selon la validité du champ
+ if (showErrors && errorElement) {
+ errorElement.textContent = errorMessage;
+ errorElement.style.display = isValid ? 'none' : 'block';
+ }
- return isValid;
+ return isValid;
+ } catch (error) {
+ console.warn('Validation interrompue pour le champ:', fieldId, error);
+ return false;
+ }
}
function updateSubmitButtonState(formId) {
let allFieldsValid = true;
const form = document.querySelector(`#${formId}`);
+ const hasValidationRules = typeof validationRules !== 'undefined' && validationRules;
if (!form) {
console.error('Formulaire non trouvé:', formId);
return;
}
- for (const fieldId in validationRules) {
- const inputElement = form.querySelector(`#${fieldId}`);
+ if (!hasValidationRules) {
+ return;
+ }
- if (inputElement && !validateField(fieldId, false)) {
- allFieldsValid = false;
+ for (const fieldId in validationRules) {
+ const inputElement = document.getElementById(fieldId);
+
+ if (inputElement && form.contains(inputElement)) {
+ try {
+ if (!validateField(fieldId, false)) {
+ allFieldsValid = false;
+ }
+ } catch (error) {
+ console.warn('Erreur pendant la validation du champ:', fieldId, error);
+ allFieldsValid = false;
+ }
}
}
@@ -169,4 +195,4 @@ function updateSubmitButtonState(formId) {
button.disabled = !allFieldsValid;
})
}
-}
\ No newline at end of file
+}
diff --git a/ecole/src/db/pb_data/data.db b/ecole/src/db/pb_data/data.db
index 7a47c5a3..44ff364e 100644
Binary files a/ecole/src/db/pb_data/data.db and b/ecole/src/db/pb_data/data.db differ
diff --git a/ecole/src/db/pb_data/data.db-shm b/ecole/src/db/pb_data/data.db-shm
index f18b1bf9..b03ca011 100644
Binary files a/ecole/src/db/pb_data/data.db-shm and b/ecole/src/db/pb_data/data.db-shm differ
diff --git a/ecole/src/db/pb_data/data.db-wal b/ecole/src/db/pb_data/data.db-wal
index 8d72c40e..e70acba8 100644
Binary files a/ecole/src/db/pb_data/data.db-wal and b/ecole/src/db/pb_data/data.db-wal differ
diff --git a/ecole/src/db/pb_data/logs.db b/ecole/src/db/pb_data/logs.db
index d098229f..b4d2350f 100644
Binary files a/ecole/src/db/pb_data/logs.db and b/ecole/src/db/pb_data/logs.db differ
diff --git a/ecole/src/db/pb_data/logs.db-shm b/ecole/src/db/pb_data/logs.db-shm
index e803f2b7..9125f7bd 100644
Binary files a/ecole/src/db/pb_data/logs.db-shm and b/ecole/src/db/pb_data/logs.db-shm differ
diff --git a/ecole/src/db/pb_data/logs.db-wal b/ecole/src/db/pb_data/logs.db-wal
index 9dcabf37..0ff2a2c2 100644
Binary files a/ecole/src/db/pb_data/logs.db-wal and b/ecole/src/db/pb_data/logs.db-wal differ
diff --git a/ecole/views/layout.ejs b/ecole/views/layout.ejs
index b906368b..47bb1280 100644
--- a/ecole/views/layout.ejs
+++ b/ecole/views/layout.ejs
@@ -60,17 +60,17 @@
-
+
-
+
-
+
-
+