Google Script
Automatiser le suivi commercial avec Google Apps Script : triggers, emails et synchronisation en temps réel
Google Apps Script est une plateforme puissante pour automatiser des workflows autour de Google Sheets, Gmail et d’autres services Google. Dans cet article, on explore un cas concret : un outil de suivi commercial (prospection, appels, RDV) qui synchronise une app web avec un Google Sheet, clôture les semaines automatiquement et envoie un email récapitulatif chaque vendredi soir.
Architecture : une app web pilotée par Apps Script
L’idée est simple. Une interface web (HTML + JS vanilla) sert de front-end. Google Apps Script joue le rôle de back-end et d’API REST via les fonctions doGet() et doPost(). Les données sont stockées en JSON dans une cellule du Google Sheet, ce qui évite de gérer une base de données externe.
const SPREADSHEET_ID = 'VOTRE_ID_ICI';
function doGet(e) {
const ss = SpreadsheetApp.openById(SPREADSHEET_ID);
const sheet = ss.getSheetByName('data');
const raw = sheet.getRange('A1').getValue() || '{}';
return ContentService
.createTextOutput(raw)
.setMimeType(ContentService.MimeType.JSON);
}
function doPost(e) {
const payload = JSON.parse(e.postData.contents);
const ss = SpreadsheetApp.openById(SPREADSHEET_ID);
const sheet = ss.getSheetByName('data');
sheet.getRange('A1').setValue(JSON.stringify(payload.data));
sheet.getRange('A2').setValue(JSON.stringify(payload.locked));
return ContentService
.createTextOutput(JSON.stringify({ status: 'ok' }))
.setMimeType(ContentService.MimeType.JSON);
}
Le front-end appelle ces endpoints avec fetch() en GET pour charger et en POST pour sauvegarder.
Triggers temporels : déclencher une action chaque vendredi soir
Apps Script permet de créer des triggers basés sur le temps. Ici, on veut clôturer la semaine commerciale chaque vendredi à 23h — sans intervention manuelle.
function installFridayTrigger() {
ScriptApp.getProjectTriggers().forEach(t => {
if (t.getHandlerFunction() === 'autoCloseWeek') {
ScriptApp.deleteTrigger(t);
}
});
ScriptApp.newTrigger('autoCloseWeek')
.timeBased()
.onWeekDay(ScriptApp.WeekDay.FRIDAY)
.atHour(23)
.create();
}
Cette fonction est à exécuter une seule fois depuis l’éditeur Apps Script. Elle supprime d’abord les éventuels doublons, puis crée le trigger hebdomadaire.
Clôture automatique et report des prospects non contactés
Chaque vendredi, autoCloseWeek() identifie la semaine en cours, sépare les entrées contactées de celles qui ne l’ont pas été, et reporte ces dernières vers la semaine suivante.
function autoCloseWeek() {
const ss = SpreadsheetApp.openById(SPREADSHEET_ID);
const sheet = ss.getSheetByName('data');
const data = JSON.parse(sheet.getRange('A1').getValue() || '{}');
const locked = JSON.parse(sheet.getRange('A2').getValue() || '{}');
const today = Utilities.formatDate(new Date(), 'Europe/Brussels', 'yyyy-MM-dd');
let closedWeek = null;
let nextWeek = null;
for (let i = 0; i < WEEKS.length; i++) {
const w = WEEKS[i];
if (w.conge || locked[w.id]) continue;
if (w.end <= today) {
closedWeek = w;
for (let j = i + 1; j < WEEKS.length; j++) {
if (!WEEKS[j].conge) { nextWeek = WEEKS[j]; break; }
}
break;
}
}
if (!closedWeek) return;
const entries = data[closedWeek.id] || [];
const toRoll = entries.filter(c => !c.date);
const keep = entries.filter(c => c.date);
data[closedWeek.id] = keep;
if (nextWeek && toRoll.length > 0) {
data[nextWeek.id] = [
...toRoll.map(c => ({ ...c, _reportedFrom: closedWeek.id })),
...(data[nextWeek.id] || [])
];
}
locked[closedWeek.id] = true;
sheet.getRange('A1').setValue(JSON.stringify(data));
sheet.getRange('A2').setValue(JSON.stringify(locked));
}
Envoi d’un email HTML récapitulatif avec GmailApp
Une fois la semaine clôturée, un email récapitulatif est envoyé automatiquement. GmailApp.sendEmail() accepte un corps HTML, ce qui permet un rendu soigné directement dans la boîte mail.
function sendWeeklyEmail(closedWeek, data) {
const entries = data[closedWeek.id] || [];
const calls = entries.filter(c => c.date);
const rdv = calls.filter(c => c.rdv === 'Oui').length;
const rate = calls.length > 0 ? Math.round(rdv / calls.length * 100) : 0;
const subject = `✅ Clôture ${closedWeek.label} — ${rdv} RDV fixé${rdv !== 1 ? 's' : ''}`;
const html = `
<div style="font-family:Arial,sans-serif;max-width:600px;margin:0 auto">
<h2 style="background:#000059;color:#fff;padding:20px;border-radius:8px 8px 0 0;margin:0">
Semaine clôturée — ${closedWeek.label}
</h2>
<div style="border:1px solid #e2e8f0;padding:20px;border-top:none">
<p><strong>${calls.length}</strong> appels passés</p>
<p><strong>${rdv}</strong> RDV fixés</p>
<p>Taux RDV/appel : <strong>${rate}%</strong></p>
</div>
</div>`;
GmailApp.sendEmail('martin@example.com', subject, '', { htmlBody: html });
}
Point d’attention :
GmailAppnécessite une autorisation OAuth. La première exécution doit être faite manuellement depuis l’éditeur pour déclencher la fenêtre de consentement Google.
Un piège classique : conflit entre clôture client et clôture serveur
Dans une architecture hybride web + Apps Script, il faut veiller à ne pas dupliquer la logique de clôture. Si le front-end verrouille les semaines côté client et synchronise cet état (locked = true) vers le Sheet avant que le trigger vendredi ne tourne, Apps Script ne trouvera plus rien à clôturer — et n’enverra jamais l’email.
La règle à respecter : une seule source de vérité pour la clôture officielle. Soit le client clôture et notifie (et Apps Script ne refait pas le travail), soit Apps Script est seul maître de la clôture. Mélanger les deux sans coordination produit des effets de bord difficiles à déboguer.
Conclusion
Google Apps Script offre une combinaison rare : hébergement gratuit, accès natif à tous les services Google, et un système de triggers robuste. Pour des outils internes légers — suivi commercial, reporting hebdomadaire, gestion de tâches — c’est souvent la solution la plus rapide à mettre en place et la plus facile à maintenir. Le tout sans serveur, sans dépendance externe, et avec un email HTML bien formé dans la boîte de Martin chaque vendredi soir.