🔧 Google Apps Script Avancé : Modifier un Client avec Suivi Automatisé des Changements
const ss = SpreadsheetApp.getActiveSpreadsheet();
const sourceSheet = ss.getActiveSheet();
const targetSheet = ss.getSheetByName("BDD");
const interventionSheet = ss.getSheetByName("Liste intervention");
const ui = SpreadsheetApp.getUi();
const ligneCible = Number(sourceSheet.getRange("F1").getValue());
const nomClient = sourceSheet.getRange("G2").getValue();
const idEcoleSource = sourceSheet.getRange("H1").getValue();
const personne = sourceSheet.getRange("C1").getValue();
if (!ligneCible || !nomClient || isNaN(ligneCible)) {
ui.alert("❌ Ligne cible invalide ou nom client vide.");
return;
}
if (ligneCible < 11 || ligneCible > 100000) {
ui.alert("❌ Ligne de modification hors plage autorisée.");
return;
}
const headers = targetSheet.getRange(10, 1, 1, targetSheet.getLastColumn()).getValues()[0];
const colIndexByName = Object.fromEntries(headers.map((h, i) => [h, i]));
const idColIndex = colIndexByName["ID Ecole"];
if (idColIndex === undefined) {
ui.alert("❌ Colonne 'ID Ecole' introuvable.");
return;
}
const idEcoleBDD = targetSheet.getRange(ligneCible, idColIndex + 1).getValue();
if (idEcoleBDD !== idEcoleSource) {
ui.alert(`⚠️ L'ID Ecole de la ligne ${ligneCible} ne correspond pas (${idEcoleBDD} ≠ ${idEcoleSource}).`);
return;
}
const confirmation = ui.alert("Confirmation", "Voulez-vous vraiment modifier ce client dans la BDD ?", ui.ButtonSet.YES_NO);
if (confirmation !== ui.Button.YES) return;
// Fonction pour comparer correctement les dates
const compareValues = (oldVal, newVal) => {
if (oldVal instanceof Date && newVal instanceof Date) {
return oldVal.getTime() === newVal.getTime();
}
return oldVal === newVal;
};
// Fonction pour formater les dates dans les observations
const formatDate = d => {
if (!(d instanceof Date)) return d;
return Utilities.formatDate(d, ss.getSpreadsheetTimeZone(), "dd/MM/yyyy");
};
const valeurs = {
"Nom": nomClient
};
// Récupérer les anciennes valeurs AVANT les mises à jour
const ancienneValeurMad = targetSheet.getRange(ligneCible, colIndexByName["Mad Dt MNT"] + 1).getValue();
const ancienneValeureMad = targetSheet.getRange(ligneCible, colIndexByName["eMad Dt MNT"] + 1).getValue();
const ancienneValeurVM = targetSheet.getRange(ligneCible, colIndexByName["Version Mad"] + 1).getValue();
const ancienneValeurSMS = targetSheet.getRange(ligneCible, colIndexByName["SMS Dt MNT"] + 1).getValue();
const ancienneValeurSMSTP = targetSheet.getRange(ligneCible, colIndexByName["SMS TP"] + 1).getValue();
const dynRanges = [
"G1|H1",
"F2|G2", "F3|G3", "F4|G4", "F5|G5", "F6|G6", "F7|G7", "F8|G8",
"I2|J2", "I3|J3", "I4|J4", "I5|J5", "I6|J6", "I7|J7", "I8|J8",
"K2|L2", "K3|L3", "K4|L4", "K5|L5", "K6|L6", "K7|L7", "K8|L8",
"M2|N2", "M3|N3", "M4|N4", "M5|N5", "M6|N6", "M7|N7", "M8|N8",
"O2|P2", "O3|P3", "O4|P4", "O5|P5", "O6|P6", "O7|P7", "O8|P8",
"Q2|R2", "Q3|R3", "Q4|R4", "Q5|R5", "Q6|R6", "Q7|R7", "Q8|R8",
"U8|V8", "S2|S3"
];
const cellsToRead = dynRanges.flatMap(p => p.split("|"));
const cellObjects = sourceSheet.getRangeList(cellsToRead).getRanges();
const cellValues = cellObjects.map(r => r.getValue());
for (let i = 0; i < dynRanges.length; i++) {
const [label, val] = [cellValues[i * 2], cellValues[i * 2 + 1]];
if (label) valeurs[label] = val;
}
// Stocker les nouvelles valeurs pour comparaison ultérieure
let nouvelleValeurMad = valeurs["Mad Dt MNT"];
let nouvelleValeureMad = valeurs["eMad Dt MNT"];
let nouvelleValeurVM = valeurs["Version Mad"];
let nouvelleValeurSMS = valeurs["SMS Dt MNT"];
let nouvelleValeurSMSTP = valeurs["SMS TP"];
// Appliquer toutes les mises à jour en une seule passe
const updates = [];
for (const [colName, val] of Object.entries(valeurs)) {
const colIndex = colIndexByName[colName];
if (colIndex !== undefined) {
updates.push({ col: colIndex + 1, value: val });
}
}
updates.forEach(u => targetSheet.getRange(ligneCible, u.col).setValue(u.value));
// Préparer les en-têtes pour la feuille d'intervention
const intHeaders = interventionSheet.getRange(1, 1, 1, interventionSheet.getLastColumn()).getValues()[0];
const colID = intHeaders.indexOf("ID Ecole");
const colDate = intHeaders.indexOf("DATE Suivie");
const colSuivie = intHeaders.indexOf("SUIVIE");
const colPers = intHeaders.indexOf("Personne");
const colObs = intHeaders.indexOf("Observation");
const colNum = intHeaders.findIndex(h => h === "N°" || h === "Num" || h === "Numéro");
// Fonction pour ajouter une intervention seulement si nécessaire
const ajouterIntervention = (colonne, ancienneVal, nouvelleVal) => {
// Vérifier si la valeur a réellement changé
if (!compareValues(ancienneVal, nouvelleVal) && nouvelleVal !== "") {
interventionSheet.insertRows(2, 1);
if (colID !== -1) interventionSheet.getRange(2, colID + 1).setValue(idEcoleSource);
if (colDate !== -1) {
const dateSuivie = Utilities.formatDate(new Date(), ss.getSpreadsheetTimeZone(), "dd/MM/yyyy");
interventionSheet.getRange(2, colDate + 1).setValue(dateSuivie);
}
if (colSuivie !== -1) interventionSheet.getRange(2, colSuivie + 1).setValue(colonne);
if (colPers !== -1) interventionSheet.getRange(2, colPers + 1).setValue(personne);
if (colObs !== -1) {
let observation = `Avant : ${formatDate(ancienneVal)} | Après : ${formatDate(nouvelleVal)}`;
if (colonne === "SMS Dt MNT") {
observation += ` | ${nouvelleValeurSMSTP}`;
}
interventionSheet.getRange(2, colObs + 1).setValue(observation);
}
if (colNum !== -1 && colIndexByName["Num"] !== undefined) {
const valNum = targetSheet.getRange(ligneCible, colIndexByName["Num"] + 1).getValue();
interventionSheet.getRange(2, colNum + 1).setValue(valNum);
}
return true;
}
return false;
};
// Ajouter les interventions seulement pour les valeurs qui ont changé
ajouterIntervention("Mad Dt MNT", ancienneValeurMad, nouvelleValeurMad);
ajouterIntervention("eMad Dt MNT", ancienneValeureMad, nouvelleValeureMad);
ajouterIntervention("Version Mad", ancienneValeurVM, nouvelleValeurVM);
ajouterIntervention("SMS Dt MNT", ancienneValeurSMS, nouvelleValeurSMS);
// Plages à vider
sourceSheet.getRange("F1").setValue("");
const zones = ["H1", "G2:G8", "J2:J8", "L1:L8", "N2:N8", "P2:P8", "R2:R8", "S3", "V2:V8"];
zones.forEach(range => {
sourceSheet.getRange(range).clearContent();
});
sourceSheet.getRange("A1").setValue("");
ui.alert("✅ Client modifié avec succès dans la BDD !");
}
Ces lignes récupèrent les feuilles actives du classeur et l'interface utilisateur pour afficher des alertes.
Avant de modifier quoi que ce soit, on capture les anciennes valeurs des champs sensibles :
Une fois le client modifié, on vide les champs de saisie pour éviter les erreurs :
Commentaires
Enregistrer un commentaire