KlantKompas-Setup-Code.gs
dat is gelukt, ik heb nu 1 sheet die goed is, en een backup sheet die we gaan gebruiken als downloadbare versie voor klanten zodat ze de klantkompas basis kunnen downloaden, dat is: @BASIS Download Ondernemersportaal KlantKompas en de publieke link daarvan is: https://docs.google.com/spreadsheets/d/e/2PACX-1vSKaX1KNT-nI8T7ap1kOMBjQX1N0Bzb1qpahJz73NCHeRI0I7QZ1CobAPFJ0TKM46Rhsgfnxzc-7NpV/pubhtml de gemaakte klantkompas sheet VOOR eigen gebruik en 1e versie is dus: @Ondernemersportaal KlantKompas en hierin staan nu alle tabbladen, deze is nog niet also publieke link gepubliceerd, dus als dat nodig is VOOR gebruik Dan hoor ik dat graag.
Dit is een goede scheiding:
BASIS Download Ondernemersportaal KlantKompas: openbare, lege voorbeeldversie voor klanten.
Ondernemersportaal KlantKompas: jouw afgeschermde werkversie met Apps Script en later echte klantgegevens.
Je eigen werkversie hoeft nadrukkelijk niet via Publiceren op internet openbaar gemaakt te worden. Dat zou ik vanwege klant- en persoonsgegevens juist niet doen. Apps Script kan de gekoppelde Sheet gebruiken zonder dat de Sheet publiek gepubliceerd is. De toegang tot het portaal regel je later via de implementatie-instellingen van de Apps Script-webapp.
De huidige pubhtml-link van de basisversie is vooral geschikt om de Sheet te bekijken of in een website in te sluiten. Google geeft bij zo’n gepubliceerde spreadsheet een vereenvoudigde versie zonder gewone werkbalk; bezoekers kunnen daar niet prettig het volledige werkbestand inclusief formules kopiëren of bewerken. Google legt dit verschil hier uit.
Voor de downloadbare basis adviseer ik daarom:
Houd de bestaande publieke link aan als voorbeeld bekijken.
Deel de basis-Sheet daarnaast als Iedereen met de link – Kijker.
Gebruik daarvan een link waarmee klanten eerst een eigen kopie maken.
Bied eventueel ook een .xlsx-download aan.
Plaats nooit echte klantgegevens, e-mailadressen of interne protocollen in deze openbare basisversie.
Belangrijk: het Apps Script-project wordt niet altijd automatisch meegenomen wanneer iemand alleen een gepubliceerd HTML-overzicht of Excel-download gebruikt. Daarom moeten we het KlantKompas-downloadpakket uiteindelijk aanbieden als:
Kopie van de basis-Sheet
Volledige Code.gs
Index.html
Styles.html
Scripts.html
Korte installatiehandleiding
De publieke voorbeeldlink die je nu hebt kan dus blijven bestaan. De eigen werkversie moet privé blijven. De volgende logische stap is om op het KlantKompas-dashboard twee duidelijke knoppen te plaatsen: Bekijk de basis en Maak/download je eigen KlantKompas.
/**
* KLANTKOMPAS — eenmalige Sheet-installatie
*
* Gebruik:
* 1. Open de lege Google Sheet.
* 2. Kies Extensies > Apps Script.
* 3. Vervang de inhoud van Code.gs door dit bestand.
* 4. Sla op en voer setupKlantKompas() één keer uit.
*
* Het script verwijdert nooit bestaande tabbladen of gegevens.
*/
const KLANTKOMPAS = {
VERSIE: '1.0.0',
KLEUR_DONKER: '#173e36',
KLEUR_ACCENT: '#ef765f',
KLEUR_LICHT: '#f7f5ef'
};
function onOpen() {
SpreadsheetApp.getUi()
.createMenu('KlantKompas')
.addItem('Alle tabbladen installeren', 'setupKlantKompas')
.addItem('Opmaak herstellen', 'herstelKlantKompasOpmaak')
.addSeparator()
.addItem('Controle uitvoeren', 'controleerKlantKompas')
.addToUi();
}
function setupKlantKompas() {
const spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
const schemas = getKlantKompasSchemas_();
Object.keys(schemas).forEach(function (naam) {
maakOfHerstelTabblad_(spreadsheet, naam, schemas[naam]);
});
voegInstellingenToe_();
voegVoorbeeldgegevensToe_();
voegValidatiesToe_();
maakOndernemersoverzicht_();
maakKlantoverzicht_();
sorteerTabbladen_(spreadsheet, Object.keys(schemas));
PropertiesService.getDocumentProperties()
.setProperty('KLANTKOMPAS_VERSIE', KLANTKOMPAS.VERSIE);
SpreadsheetApp.flush();
SpreadsheetApp.getUi().alert(
'KlantKompas is klaar',
'Alle tabbladen, kolommen, instellingen en validaties zijn aangemaakt.',
SpreadsheetApp.getUi().ButtonSet.OK
);
}
function getKlantKompasSchemas_() {
return {
'Inbox': [
'Bericht_ID',
'Klant_ID',
'Datum_Tijd',
'Kanaal',
'Onderwerp',
'Bericht',
'Type',
'Status',
'Prioriteit',
'Eigenaar',
'Reactie_Voor',
'Laatste_Update',
'Bijlage_URL',
'Intern_Notitie'
],
'Klanten': [
'Klant_ID',
'Voornaam',
'Achternaam',
'Bedrijfsnaam',
'Email',
'Telefoon',
'Adres',
'Postcode',
'Plaats',
'Land',
'Status',
'Aangemaakt',
'Toestemming_Updates',
'Voorkeurskanaal',
'Notities'
],
'Offertes_Facturen': [
'Document_ID',
'Klant_ID',
'Type',
'Documentnummer',
'Datum',
'Vervaldatum',
'Omschrijving',
'Bedrag_Excl',
'BTW_Percentage',
'BTW_Bedrag',
'Bedrag_Incl',
'Status',
'Betaaldatum',
'PDF_URL'
],
'Bestellingen': [
'Bestelling_ID',
'Klant_ID',
'Datum',
'Product_Dienst_ID',
'Omschrijving',
'Aantal',
'Prijs_Per_Stuk',
'Totaal',
'Status',
'Track_Trace',
'Verwachte_Levering',
'Geleverd_Op',
'Opmerking'
],
'Producten_Diensten': [
'Item_ID',
'Type',
'Naam',
'Categorie',
'Omschrijving',
'Prijs',
'BTW_Percentage',
'Voorraad',
'Beschikbaar',
'Levertijd_Dagen',
'Garantie',
'Handleiding_URL',
'Afbeelding_URL'
],
'Agenda': [
'Afspraak_ID',
'Klant_ID',
'Start',
'Einde',
'Type',
'Onderwerp',
'Locatie',
'Status',
'Eigenaar',
'Herinnering',
'Notities',
'Calendar_Event_ID'
],
'Kennisbank': [
'Artikel_ID',
'Titel',
'Categorie',
'Vraag',
'Antwoord',
'Doelgroep',
'Status',
'Tags',
'Bron_URL',
'Bijgewerkt',
'Eigenaar'
],
'Persoonlijke_Data': [
'Data_ID',
'Klant_ID',
'Onderdeel',
'Waarde',
'Zichtbaarheid',
'Toestemming',
'Gewijzigd',
'Bewaartermijn',
'Verwijderverzoek',
'Verwijderd_Op'
],
'Klantoverzicht': [
'Klant_ID',
'Naam',
'Open_Gesprekken',
'Open_Bestellingen',
'Open_Facturen',
'Volgende_Afspraak',
'Laatste_Activiteit',
'Status'
],
'Ondernemersoverzicht': [
'Kerncijfer',
'Vandaag',
'Deze_Week',
'Deze_Maand',
'Doel',
'Status',
'Bijgewerkt'
],
'Processen_Protocollen': [
'Proces_ID',
'Naam',
'Categorie',
'Startmoment',
'Stappen',
'Standaard_Antwoord',
'Doorlooptijd_Uren',
'Escalatie_Na_Uren',
'Eigenaar',
'Actief'
],
'Instellingen': [
'Sleutel',
'Waarde',
'Omschrijving'
],
'Log': [
'Datum_Tijd',
'Gebruiker',
'Actie',
'Module',
'Referentie',
'Details'
]
};
}
function maakOfHerstelTabblad_(spreadsheet, naam, koppen) {
let sheet = spreadsheet.getSheetByName(naam);
if (!sheet) {
sheet = spreadsheet.insertSheet(naam);
}
if (sheet.getLastRow() === 0) {
sheet.getRange(1, 1, 1, koppen.length).setValues([koppen]);
} else {
const bestaandeKoppen = sheet
.getRange(
1,
1,
1,
Math.max(sheet.getLastColumn(), 1)
)
.getDisplayValues()[0];
koppen.forEach(function (kop) {
if (bestaandeKoppen.indexOf(kop) === -1) {
sheet
.getRange(1, sheet.getLastColumn() + 1)
.setValue(kop);
bestaandeKoppen.push(kop);
}
});
}
styleTabblad_(sheet);
}
function styleTabblad_(sheet) {
const kolommen = Math.max(sheet.getLastColumn(), 1);
sheet.setFrozenRows(1);
sheet.setHiddenGridlines(false);
sheet
.getRange(1, 1, 1, kolommen)
.setBackground(KLANTKOMPAS.KLEUR_DONKER)
.setFontColor('#ffffff')
.setFontWeight('bold')
.setHorizontalAlignment('left')
.setVerticalAlignment('middle');
sheet.setRowHeight(1, 34);
sheet.autoResizeColumns(1, kolommen);
for (let kolom = 1; kolom <= kolommen; kolom++) {
const huidigeBreedte = sheet.getColumnWidth(kolom);
sheet.setColumnWidth(
kolom,
Math.min(Math.max(huidigeBreedte, 110), 260)
);
}
if (sheet.getMaxRows() > 1) {
sheet
.getRange(
2,
1,
sheet.getMaxRows() - 1,
kolommen
)
.setVerticalAlignment('top')
.setWrap(true);
}
if (!sheet.getFilter() && sheet.getLastRow() >= 1) {
sheet
.getRange(
1,
1,
Math.max(sheet.getLastRow(), 2),
kolommen
)
.createFilter();
}
}
function voegInstellingenToe_() {
voegRijenToeAlsLeeg_('Instellingen', [
[
'Bedrijfsnaam',
'Uw bedrijfsnaam',
'Naam bovenaan het dashboard'
],
[
'Primaire_Kleur',
KLANTKOMPAS.KLEUR_DONKER,
'Hoofdkleur van KlantKompas'
],
[
'Accent_Kleur',
KLANTKOMPAS.KLEUR_ACCENT,
'Kleur voor knoppen en meldingen'
],
[
'Automatisch_Antwoord',
'JA',
'Automatische ontvangstbevestiging'
],
[
'Reactietijd_Uren',
24,
'Beloofde maximale reactietijd'
],
[
'Standaard_Ontvangstbericht',
'Uw bericht is ontvangen. Wij helpen u zo snel mogelijk.',
'Eerste automatische reactie'
],
[
'Contact_Email',
'Stijn.Gabeler@gmail.com',
'Contact met de maker'
],
[
'Contact_WhatsApp',
'+31622869860',
'WhatsApp van de maker'
],
[
'Versie',
KLANTKOMPAS.VERSIE,
'Geïnstalleerde KlantKompas-versie'
]
]);
}
function voegVoorbeeldgegevensToe_() {
voegRijenToeAlsLeeg_('Processen_Protocollen', [
[
'PRO-001',
'Ontvangst klantbericht',
'Communicatie',
'Nieuw bericht',
'1. Bevestig ontvangst | 2. Classificeer vraag | 3. Wijs eigenaar toe | 4. Beantwoord | 5. Sluit af',
'Uw bericht is ontvangen. Wij helpen u zo snel mogelijk.',
24,
48,
'Klantenservice',
'JA'
],
[
'PRO-002',
'Klachtafhandeling',
'Klacht',
'Nieuwe klacht',
'1. Bevestig ontvangst | 2. Verzamel bewijs | 3. Onderzoek | 4. Doe voorstel | 5. Bevestig oplossing',
'Wij nemen uw klacht serieus en komen zo snel mogelijk bij u terug.',
48,
72,
'Klantenservice',
'JA'
]
]);
}
function voegRijenToeAlsLeeg_(tabblad, rijen) {
const sheet = SpreadsheetApp
.getActive()
.getSheetByName(tabblad);
if (sheet.getLastRow() > 1 || rijen.length === 0) {
return;
}
sheet
.getRange(
2,
1,
rijen.length,
rijen[0].length
)
.setValues(rijen);
}
function voegValidatiesToe_() {
const spreadsheet = SpreadsheetApp.getActive();
zetValidatieOpKolom_(
spreadsheet.getSheetByName('Inbox'),
'Status',
[
'Nieuw',
'In behandeling',
'Wacht op klant',
'Opgelost',
'Gesloten'
]
);
zetValidatieOpKolom_(
spreadsheet.getSheetByName('Inbox'),
'Prioriteit',
[
'Laag',
'Normaal',
'Hoog',
'Urgent'
]
);
zetValidatieOpKolom_(
spreadsheet.getSheetByName('Klanten'),
'Status',
[
'Prospect',
'Actief',
'Inactief',
'Geblokkeerd'
]
);
zetValidatieOpKolom_(
spreadsheet.getSheetByName('Klanten'),
'Toestemming_Updates',
[
'JA',
'NEE'
]
);
zetValidatieOpKolom_(
spreadsheet.getSheetByName('Bestellingen'),
'Status',
[
'Nieuw',
'Bevestigd',
'In behandeling',
'Verzonden',
'Geleverd',
'Geannuleerd'
]
);
zetValidatieOpKolom_(
spreadsheet.getSheetByName('Offertes_Facturen'),
'Type',
[
'Offerte',
'Factuur',
'Creditfactuur'
]
);
zetValidatieOpKolom_(
spreadsheet.getSheetByName('Offertes_Facturen'),
'Status',
[
'Concept',
'Verzonden',
'Geaccepteerd',
'Open',
'Betaald',
'Verlopen',
'Geannuleerd'
]
);
zetValidatieOpKolom_(
spreadsheet.getSheetByName('Producten_Diensten'),
'Type',
[
'Product',
'Dienst',
'Service',
'Abonnement'
]
);
zetValidatieOpKolom_(
spreadsheet.getSheetByName('Producten_Diensten'),
'Beschikbaar',
[
'JA',
'NEE'
]
);
}
function zetValidatieOpKolom_(sheet, kop, waarden) {
const koppen = sheet
.getRange(
1,
1,
1,
sheet.getLastColumn()
)
.getDisplayValues()[0];
const index = koppen.indexOf(kop) + 1;
if (!index) {
return;
}
const regel = SpreadsheetApp
.newDataValidation()
.requireValueInList(waarden, true)
.setAllowInvalid(false)
.build();
sheet
.getRange(
2,
index,
sheet.getMaxRows() - 1,
1
)
.setDataValidation(regel);
}
function maakOndernemersoverzicht_() {
const sheet = SpreadsheetApp
.getActive()
.getSheetByName('Ondernemersoverzicht');
if (sheet.getLastRow() > 1) {
return;
}
const nu = new Date();
const rijen = [
[
'Open gesprekken',
'',
'',
'',
'Binnen 24 uur',
'Actief',
nu
],
[
'Actieve klanten',
'',
'',
'',
'Groei',
'Actief',
nu
],
[
'Open bestellingen',
'',
'',
'',
'Op tijd leveren',
'Actief',
nu
],
[
'Open facturen',
'',
'',
'',
'Op tijd betaald',
'Actief',
nu
],
[
'Kennisbankartikelen',
'',
'',
'',
'Blijven uitbreiden',
'Actief',
nu
]
];
sheet
.getRange(
2,
1,
rijen.length,
rijen[0].length
)
.setValues(rijen);
sheet
.getRange('B2')
.setFormula(
'=COUNTIF(Inbox!H:H,"<>Opgelost")-COUNTIF(Inbox!H:H,"Gesloten")-1'
);
sheet
.getRange('B3')
.setFormula(
'=COUNTIF(Klanten!K:K,"Actief")'
);
sheet
.getRange('B4')
.setFormula(
'=COUNTIF(Bestellingen!I:I,"<>Geleverd")-COUNTIF(Bestellingen!I:I,"Geannuleerd")-1'
);
sheet
.getRange('B5')
.setFormula(
'=COUNTIF(Offertes_Facturen!L:L,"Open")'
);
sheet
.getRange('B6')
.setFormula(
'=COUNTA(Kennisbank!A:A)-1'
);
}
function maakKlantoverzicht_() {
const sheet = SpreadsheetApp
.getActive()
.getSheetByName('Klantoverzicht');
if (sheet.getLastRow() > 1) {
return;
}
sheet
.getRange('A2')
.setFormula(
'=IFERROR(FILTER({Klanten!A2:A,Klanten!B2:B&" "&Klanten!C2:C},Klanten!A2:A<>""),"")'
);
}
function sorteerTabbladen_(spreadsheet, volgorde) {
volgorde.forEach(function (naam, index) {
const sheet = spreadsheet.getSheetByName(naam);
spreadsheet.setActiveSheet(sheet);
spreadsheet.moveActiveSheet(index + 1);
});
spreadsheet.setActiveSheet(
spreadsheet.getSheetByName('Ondernemersoverzicht')
);
}
function herstelKlantKompasOpmaak() {
const spreadsheet = SpreadsheetApp.getActive();
Object.keys(getKlantKompasSchemas_()).forEach(function (naam) {
const sheet = spreadsheet.getSheetByName(naam);
if (sheet) {
styleTabblad_(sheet);
}
});
SpreadsheetApp.getUi().alert(
'De KlantKompas-opmaak is hersteld.'
);
}
function controleerKlantKompas() {
const spreadsheet = SpreadsheetApp.getActive();
const verwacht = Object.keys(getKlantKompasSchemas_());
const ontbreekt = verwacht.filter(function (naam) {
return !spreadsheet.getSheetByName(naam);
});
const melding = ontbreekt.length
? 'Ontbrekende tabbladen: ' + ontbreekt.join(', ')
: 'Alle ' + verwacht.length +
' KlantKompas-tabbladen zijn aanwezig.';
SpreadsheetApp.getUi().alert(
'KlantKompas-controle',
melding,
SpreadsheetApp.getUi().ButtonSet.OK
);
}
Na het plakken selecteer je bovenaan setupKlantKompas en klik je op Uitvoeren.
De eerste keer vraagt Google toestemming. Daarna verschijnen automatisch alle tabbladen.
Deze map bevat de complete basis voor een ondernemersportaal dat Google Sheets als database gebruikt.
Maak een lege Google Sheet.
Open Extensies → Apps Script.
Voeg de bestanden toe met exact deze namen: Code.gs, Setup.gs, Index.html, Styles.html en Scripts.html.
Zet via Projectinstellingen → Manifestbestand weergeven de inhoud van appsscript.json in het manifest.
Selecteer setupKlantKompas en klik Uitvoeren. Accepteer de benodigde rechten.
Kies Implementeren → Nieuwe implementatie → Web-app.
Uitvoeren als: Mij. Kies bij toegang wat bij uw organisatie past.
Open de verkregen web-app-URL.
Inbox, Klanten, Offertes_Facturen, Bestellingen, Producten_Diensten, Agenda,
Kennisbank, Persoonlijke_Data, Klantoverzicht, Ondernemersoverzicht,
Instellingen en Log.
Gebruik geen publieke toegang voor echte persoonsgegevens zonder passende beveiliging en privacy-inrichting.
Voeg voor klantlogin een geverifieerde identificatielaag toe; vertrouw nooit alleen op een klantnummer in de browser.
Stel gedeelde toegang tot de Sheet en Drive-map zorgvuldig in.
Test automatische e-mail eerst met interne adressen.
Maak regelmatig een backup via het KlantKompas-menu of het dashboard.
Bedrijfsnaam, huisstijl, automatische beantwoording, reactietijd en contactgegevens staan in het tabblad Instellingen.
Een product van Stichting GODOGOOD.eu en Gabeler.eu Coaching.
Contact: Stijn.Gabeler@gmail.com · WhatsApp +31 6 22869860.
/**
* Voer setupKlantKompas() handmatig één keer uit vanuit de Apps Script-editor.
* Bestaande tabbladen worden niet verwijderd; ontbrekende kopregels worden aangevuld.
*/
function setupKlantKompas() {
const ss = SpreadsheetApp.getActive();
const schemas = getKlantKompasSchemas_();
Object.keys(schemas).forEach(name => createOrPrepareSheet_(ss, name, schemas[name]));
seedKlantKompas_();
applyKlantKompasValidations_();
PropertiesService.getDocumentProperties().setProperty('KLANTKOMPAS_VERSION', KK.VERSION);
SpreadsheetApp.getUi().alert('KlantKompas is ingericht. Alle tabbladen zijn klaar.');
}
function onOpen() {
SpreadsheetApp.getUi().createMenu('KlantKompas')
.addItem('Installeren / herstellen', 'setupKlantKompas')
.addItem('Dashboard openen', 'showKlantKompasSidebar')
.addSeparator()
.addItem('Backup naar Drive', 'exportBackup')
.addToUi();
}
function showKlantKompasSidebar() {
const html = HtmlService.createHtmlOutput('<div style="font:14px Arial;padding:18px"><h2>KlantKompas</h2><p>Publiceer het script via <b>Implementeren → Nieuwe implementatie → Web-app</b>.</p><p>Daarna opent u het dashboard via de URL van de web-app.</p></div>');
SpreadsheetApp.getUi().showSidebar(html.setTitle('KlantKompas'));
}
function getKlantKompasSchemas_() {
return {
Inbox:['Bericht_ID','Klant_ID','Datum_Tijd','Kanaal','Onderwerp','Bericht','Type','Status','Prioriteit','Eigenaar','Laatste_Update','Bijlage_URL'],
Klanten:['Klant_ID','Voornaam','Achternaam','Bedrijfsnaam','Email','Telefoon','Adres','Postcode','Plaats','Land','Status','Aangemaakt','Toestemming_Updates','Notities'],
Offertes_Facturen:['Document_ID','Klant_ID','Type','Documentnummer','Datum','Vervaldatum','Omschrijving','Bedrag_Excl','BTW','Bedrag_Incl','Status','PDF_URL'],
Bestellingen:['Bestelling_ID','Klant_ID','Datum','Product_Dienst_ID','Omschrijving','Aantal','Totaal','Status','Track_Trace','Verwachte_Levering','Opmerking'],
Producten_Diensten:['Item_ID','Type','Naam','Categorie','Omschrijving','Prijs','BTW_Percentage','Voorraad','Beschikbaar','Garantie','Handleiding_URL','Afbeelding_URL'],
Agenda:['Afspraak_ID','Klant_ID','Start','Einde','Type','Onderwerp','Locatie','Status','Eigenaar','Notities','Calendar_Event_ID'],
Kennisbank:['Artikel_ID','Titel','Categorie','Vraag','Antwoord','Doelgroep','Status','Tags','Bron_URL','Bijgewerkt'],
Persoonlijke_Data:['Data_ID','Klant_ID','Onderdeel','Waarde','Zichtbaarheid','Toestemming','Gewijzigd','Verwijderverzoek'],
Klantoverzicht:['Overzicht_ID','Klant_ID','Onderdeel','Open_Aantal','Afgerond_Aantal','Laatste_Activiteit','Actie_URL'],
Ondernemersoverzicht:['Metric_ID','Kerncijfer','Periode','Waarde','Doel','Trend','Bijgewerkt'],
Instellingen:['Sleutel','Waarde','Omschrijving'],
Log:['Datum_Tijd','Gebruiker','Actie','Module','Referentie']
};
}
function createOrPrepareSheet_(ss, name, headers) {
let sheet = ss.getSheetByName(name);
if (!sheet) sheet = ss.insertSheet(name);
if (sheet.getLastRow() === 0) sheet.getRange(1,1,1,headers.length).setValues([headers]);
sheet.setFrozenRows(1);
sheet.getRange(1,1,1,headers.length).setBackground('#173e36').setFontColor('#ffffff').setFontWeight('bold');
sheet.autoResizeColumns(1, headers.length);
if (sheet.getMaxRows() > 1) sheet.getRange(2,1,sheet.getMaxRows()-1,headers.length).setVerticalAlignment('top');
}
function seedKlantKompas_() {
const now = new Date();
seed_('Instellingen',[
['Bedrijfsnaam','Studio Veld','Zichtbare bedrijfsnaam'],
['Primaire_Kleur','#173e36','Huisstijlkleur'],
['Accent_Kleur','#ef765f','Accentkleur'],
['Automatisch_Antwoord','JA','Stuur ontvangstbevestigingen'],
['Reactietijd_Uren','24','Beloofde reactietijd'],
['Contact_Email','Stijn.Gabeler@gmail.com','Contact met maker'],
['Contact_WhatsApp','+31622869860','WhatsApp maker']
]);
seed_('Klanten',[
['KL-0086','Eva','de Wit','','eva@voorbeeld.nl','0612345678','','','','Nederland','Actief',now,'JA',''],
['KL-0085','Mark','Bos','','mark@voorbeeld.nl','0687654321','','','','Nederland','Actief',now,'NEE','']
]);
seed_('Inbox',[
['MSG-0001','KL-0086',now,'E-mail','Vraag over levering','Kan ik mijn bestelling morgen verwachten?','Vraag','Nieuw','Normaal','',now,''],
['MSG-0002','KL-0085',now,'Portaal','Garantieaanvraag #GA-204','Foto’s ontvangen.','Klacht','In behandeling','Hoog','',now,'']
]);
seed_('Producten_Diensten',[
['PR-001','Product','Startpakket','Pakketten','Complete startset',349,21,12,'JA','2 jaar','',''],
['DI-001','Dienst','Adviesgesprek','Advies','Persoonlijk gesprek van 60 minuten',95,21,'','JA','','','']
]);
seed_('Bestellingen',[
['BS-1081','KL-0086',now,'PR-001','Startpakket',1,349,'Onderweg','3SVOORBEELD',now,'']
]);
seed_('Kennisbank',[
['KB-001','Levering volgen','Bestellingen','Hoe volg ik mijn levering?','Open uw bestelling en klik op de track-en-tracecode.','Klant','Online','levering,track trace','',now],
['KB-002','Garantieprocedure','Service','Hoe dien ik garantie in?','Start een nieuw bericht, kies Garantie en voeg foto’s en aankoopbewijs toe.','Iedereen','Online','garantie,service','',now]
]);
}
function seed_(sheetName, rows) {
const sheet = getSheet_(sheetName);
if (sheet.getLastRow() > 1 || !rows.length) return;
sheet.getRange(2,1,rows.length,rows[0].length).setValues(rows);
}
function applyKlantKompasValidations_() {
const statusRule = SpreadsheetApp.newDataValidation().requireValueInList(['Nieuw','In behandeling','Wacht op klant','Opgelost','Gesloten'], true).setAllowInvalid(true).build();
getSheet_('Inbox').getRange('H2:H').setDataValidation(statusRule);
const yesNo = SpreadsheetApp.newDataValidation().requireValueInList(['JA','NEE'], true).setAllowInvalid(true).build();
getSheet_('Klanten').getRange('M2:M').setDataValidation(yesNo);
getSheet_('Producten_Diensten').getRange('I2:I').setDataValidation(yesNo);
}
KlantKompas is uitgebreid en staat live:
Bekijk het vernieuwde KlantKompas OndernemersPortaal
Download hier het complete pakket:
KlantKompas-AppsScript.zip
Losse bestanden:
Code.gs
Setup.gs
Index.html
Styles.html
Scripts.html
appsscript.json
Installatiehandleiding
De setup maakt automatisch deze Sheet-tabbladen:
Inbox
Klanten
Offertes_Facturen
Bestellingen
Producten_Diensten
Agenda
Kennisbank
Persoonlijke_Data
Klantoverzicht
Ondernemersoverzicht
Instellingen
Log
Daarnaast zijn CRUD-opslag, zoeken, automatische ontvangstbevestigingen, klantoverzichten, backups naar Drive, voorbeeldgegevens, validatielijsten en het Apps Script-menu toegevoegd.
Onderaan staat nu ook de gevraagde vermelding van Stichting GODOGOOD.eu, Gabeler.eu Coaching, het e-mailadres, WhatsApp-nummer en de uitnodiging voor een eigen KlantKompas-dashboard.
ik heb een sheet gemaakt die helemaal leeg is maar ik heb wel al de link, @Untitled spreadsheet
misschien kan je nu een Code.gs maken die in deze sheet alle tabbladen maakt, is dat handig?
Ja, dat is juist de handigste eerste stap. Ik maak één zelfstandige Code.gs die je aan deze lege Sheet koppelt; na één keer setupKlantKompas() uitvoeren
worden alle tabbladen, kolomkoppen, kleuren, validaties, instellingen en enkele veilige voorbeeldregels automatisch aangemaakt.
Ik gebruik hiervoor de spreadsheetworkflow en maak er een direct downloadbaar bestand van.