RC: stabilise projet validation and reorganize product scripts
This commit is contained in:
parent
349c379dc7
commit
7b484f34c9
|
|
@ -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`;
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -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);
|
||||
|
|
@ -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();
|
||||
|
|
@ -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;
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -60,17 +60,17 @@
|
|||
<!-- Feuille de script pour les donnée static JSON de saisie formulaire -->
|
||||
<script src="/js/json/json-verif-form.js"></script>
|
||||
<!-- Utilitaires de validation et blocage RC -->
|
||||
<script src="/js/rc-validation-utils.js"></script>
|
||||
<script src="/js/rc/rc-validation-utils.js"></script>
|
||||
<!-- Feuille de script pour le bon fonctionnement du loader -->
|
||||
<script src="/js/loader.js"></script>
|
||||
<!-- Script pour la navigation AJAX -->
|
||||
<script src="/js/navigation.js"></script>
|
||||
<!-- Utilitaires de synchronisation RC -->
|
||||
<script src="/js/rc-sync-utils.js"></script>
|
||||
<script src="/js/rc/rc-sync-utils.js"></script>
|
||||
<!-- Gestionnaire de données RC -->
|
||||
<script src="/js/rc-data-manager.js"></script>
|
||||
<script src="/js/rc/rc-data-manager.js"></script>
|
||||
<!-- Orchestrateur de synchronisation RC -->
|
||||
<script src="/js/rc-orchestrator.js"></script>
|
||||
<script src="/js/rc/rc-orchestrator.js"></script>
|
||||
|
||||
</main>
|
||||
</body>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
<form id="projetForm">
|
||||
<div id="rcProjetBlockingSummary" class="rc-blocking-summary"></div>
|
||||
<!-- Historique de projet -->
|
||||
<div class="row" id="historiqueDiv">
|
||||
<div class="col s12">
|
||||
|
|
@ -777,8 +776,7 @@
|
|||
</div>
|
||||
<div class="input-field">
|
||||
<i class="material-icons prefix">trending_up</i>
|
||||
<label class="rc-field-label" for="CA">Montant en euros</label>
|
||||
<input id="CA" type="text" placeholder="Ex: 1234567">
|
||||
<input id="CA" type="text" placeholder="100000">
|
||||
<span class="helper-text">Chiffre d'affaires</span>
|
||||
<span id="CA-error" class="helper-text red-text"></span>
|
||||
</div>
|
||||
|
|
@ -792,8 +790,7 @@
|
|||
</div>
|
||||
<div class="input-field">
|
||||
<i class="material-icons prefix">euro_symbol</i>
|
||||
<label class="rc-field-label" for="cotisationIrreductible">Montant en euros</label>
|
||||
<input id="cotisationIrreductible" type="text" placeholder="Ex: 1200">
|
||||
<input id="cotisationIrreductible" type="text" placeholder="200">
|
||||
<span class="helper-text">Cotisation minimale irréductible</span>
|
||||
<span id="cotisationIrreductible-error" class="helper-text red-text"></span>
|
||||
</div>
|
||||
|
|
@ -959,20 +956,20 @@
|
|||
<tr>
|
||||
<td>Frais de répertoire</td>
|
||||
<td>
|
||||
<input type="text" name="cotFraisHT" id="cotFraisHT" value="36.00" />
|
||||
<input type="text" name="cotFraisHT" id="cotFraisHT" placeholder="Ex: 36.00" />
|
||||
<span id="cotFraisHT-error" class="helper-text red-text"></span>
|
||||
</td>
|
||||
<td><input type="text" name="cotFraisTaux" id="cotFraisTaux" value="Sans taxe" disabled />
|
||||
</td>
|
||||
<td>
|
||||
<input type="text" name="cotFraisTTC" id="cotFraisTTC" value="36.00" />
|
||||
<input type="text" name="cotFraisTTC" id="cotFraisTTC" placeholder="Ex: 36.00" />
|
||||
<span id="cotFraisTTC-error" class="helper-text red-text"></span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id="primeRefRow">
|
||||
<td>Prime HT de référence (tarif choisi)</td>
|
||||
<td>
|
||||
<input type="text" name="primeRefHT" id="primeRefHT" readonly />
|
||||
<input type="text" name="primeRefHT" id="primeRefHT" disabled />
|
||||
<span id="primeRefHT-error" class="helper-text red-text"></span>
|
||||
</td>
|
||||
<td>
|
||||
|
|
@ -982,8 +979,20 @@
|
|||
<input type="text" name="primeRefTTC" id="primeRefTTC" value="//" disabled />
|
||||
</td>
|
||||
</tr>
|
||||
<tr id="tarifCommercialRow">
|
||||
<td>Tarif commercial saisi (étape Tarif)</td>
|
||||
<td>
|
||||
<input type="text" name="tarifComSaisiHT" id="tarifComSaisiHT" disabled />
|
||||
</td>
|
||||
<td>
|
||||
<input type="text" name="tarifComSaisiTaxe" id="tarifComSaisiTaxe" value="Tarif saisi" disabled />
|
||||
</td>
|
||||
<td>
|
||||
<input type="text" name="tarifComSaisiTTC" id="tarifComSaisiTTC" value="//" disabled />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Total</td>
|
||||
<td>Total (retenu)</td>
|
||||
<td>
|
||||
<input type="text" name="cotTotalHT" id="cotTotalHT" />
|
||||
<span id="cotTotalHT-error" class="helper-text red-text"></span>
|
||||
|
|
@ -1016,6 +1025,7 @@
|
|||
<h6 class="red-text text-darken-4">Veuillez enregistrer toutes modifications sur le formulaire :</h6>
|
||||
</div>
|
||||
</div>
|
||||
<div id="rcProjetBlockingSummary" class="rc-blocking-summary"></div>
|
||||
<button class="btn" type="submit" id="projetFormBtn">Enregistrer et poursuivre le parcours</button>
|
||||
</div>
|
||||
</form>
|
||||
|
|
|
|||
|
|
@ -1248,7 +1248,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button id="comm-OK" class="waves-effect waves-light btn indigo darken-4">Valider</button>
|
||||
<button id="comm-cancel" class="modal-close waves-effect waves-light btn red darken-1">Annuler</button>
|
||||
<button id="comm-OK" type="button" class="waves-effect waves-light btn indigo darken-4">Valider</button>
|
||||
<button id="comm-cancel" type="button" class="modal-close waves-effect waves-light btn red darken-1">Annuler</button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Reference in New Issue