Skip to content

Instantly share code, notes, and snippets.

@cukabeka
Created January 10, 2024 21:21
Show Gist options
  • Save cukabeka/6895032e21127d26a0a5353f3c7b96fa to your computer and use it in GitHub Desktop.
Save cukabeka/6895032e21127d26a0a5353f3c7b96fa to your computer and use it in GitHub Desktop.
MailMerge Google Docs Script für Serienbriefe
BATCH_SIZE=50;
/*
Beim start werden neue Menüpunkte zu Sheets hinzugefügt
*/
function onOpen() {
renderMenu();
}
/*
Aktualisiert das Menü
*/
function renderMenu(){
var ui = SpreadsheetApp.getUi();
var progress=PropertiesService.getDocumentProperties().getProperty('progress');
if(progress>0){
ui.createMenu('Serienbrief')
.addItem('Neu starten', 'startOver')
.addItem('Bei Eintrag '+parseInt(progress)+' fortsetzen', 'createDocuments')
.addToUi();
}else{
ui.createMenu('Serienbrief')
.addItem('Erstellen', 'startOver')
.addToUi();
}
}
/*
Startet einen neuen Vorgang
*/
function startOver(){
PropertiesService.getDocumentProperties().setProperty('progress', 0);
createDocuments();
}
/*
Konvertiere die aktuelle Datarange in ein Object-Array und nutze die erste Zeile als Object-Properties
*/
function spreadSheetToObjects(){
//Alle gefüllten Spalten auslesen
var range=SpreadsheetApp.getActiveSheet().getDataRange().getDisplayValues();
//Array für alle Einträge
var data=[];
for(var row=1; row<range.length; row++){ //Durchläuft alle Zeilen bis auf die Überschriften (daher row=1)
var dataObject={};
for (var col=0; col<range[0].length; col++){ //Durchläuft alle Spalten
var key=range[0][col]; //Übernimmt die Überschrift als Object-Property
var value=range[row][col]; //Schreibt den Wert der aktuellen Zeile ins Objekt
dataObject[key]=value; // Fügt den Eintrag zum Array hinzu
}
data.push(dataObject); //Fügt das Datenobjekt in die Liste hinzu
}
return data; //Gibt das Object-Array zurück
}
/*
Zielordner für die erstellten Dokumente.
Wird als "gen" auf gleicher Ebene wie das Spreadsheet angelegt
*/
function getTargetFolder(){
var folderName="gen"; //Name des Zielordners
//Aktuellen Ordner ermitteln:
var folder=DriveApp.getFileById(SpreadsheetApp.getActiveSpreadsheet().getId()).getParents().next();
//Gibt es einen "gen" Ordner?
var genFolders=folder.getFoldersByName(folderName);
if(genFolders.hasNext()){
return genFolders.next();
}else{
//"gen" Ordner erstellen
return folder.createFolder(folderName);
}
}
function createDocument(dataObject, targetFolder){
//Template-File laden
var templateFile=DriveApp.getFileById(dataObject.template);
//Dann eine Kopie im "gen" Ordner erstellen
var document=templateFile.makeCopy(targetFolder);
//Schauen, ob es sich um eine Präsentation handelt:
if(document.getMimeType()=="application/vnd.google-apps.presentation"){
//Dann das Dokument aus der Präsentation erstellen
var slideApp=SlidesApp.openById(document.getId());
//Alle Slides durchlaufen
slideApp.getSlides().forEach(slide=>{
//Alle Platzhalter ersetzen
for(var key in dataObject){
slide.replaceAllText('{{'+key+'}}',dataObject[key]);
}
});
slideApp.saveAndClose();
}else if(document.getMimeType()=="application/vnd.google-apps.document"){
//Dokument ist ein Textdokument -> Offnen und Platzhalter tauschen
var docApp=DocumentApp.openById(document.getId());
for(var key in dataObject){
docApp.getBody().replaceText('{{'+key+'}}', dataObject[key]);
}
docApp.saveAndClose();
}else{
//unknown type - Hier abbrechen
return;
}
//Create pdf export
var pdfFile=getTargetFolder().createFile(
DriveApp.getFileById(document.getId()).getAs(MimeType.PDF),
).setName(dataObject.filename);
//Originaldokument löschen
document.setTrashed(true);
}
/*
Hauptfunktion, die alle Daten aus dem Spreadsheet ausliest und die Dokumente erzeugt
*/
function createDocuments(){
//Die Dokumente in Objekte umwandeln
var data=spreadSheetToObjects();
var targetFolder=getTargetFolder();
var start=parseInt(PropertiesService.getDocumentProperties().getProperty('progress'));
//Durchlaufe alle Objekte und lege die Dokumente an
for(var i=start; i<data.length && i< (start+BATCH_SIZE); i++){
createDocument(data[i], targetFolder);
}
if(i<data.length){
SpreadsheetApp.getUi().alert("Es sind zu viele Einträge für einen Durchlauf. Nutzen Sie die Funktion \"Fortsetzen\" im Menü um die nächsten Dokumente zu erstellen");
PropertiesService.getDocumentProperties().setProperty('progress', i);
renderMenu();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment