Jak przesłać korespondencję seryjną z arkusza kalkulacyjnego Google do dokumentu Google?


20

Dzięki programom Microsoft Excel i Microsoft Word łatwo jest łączyć wiersze z arkusza kalkulacyjnego ze stronami w pliku Word. Było to tradycyjnie wykorzystywane do wysyłania korespondencji papierowej. Jak mogę zrobić to samo z Dyskiem Google / Dokumentami Google?

Istnieje wiele szablonów, które oferują scalanie poczty z arkusza kalkulacyjnego do wiadomości e-mail: Jak scalić pocztę z Gmailem? ale nie o to mi chodzi.


Czy próbowałeś skopiować / wkleić?
Jacob Jan Tuinstra

4
Skopiować / wkleić 10 000 wierszy? Nie, dziękuję. Word / Excel ma się dobrze.
Bryce,

Odpowiedzi:


8

W tym celu musisz napisać skrypt Google Apps . Możesz pozwolić, aby pierwszy wiersz arkusza kalkulacyjnego był nazwą pola i utworzyć dokument szablonu, do którego odwołuje się pole [FIELD].

Jeśli więc Twój arkusz kalkulacyjny wygląda:

NAME  |  STREET             | ZIP    | TOWN
---------------------------------------------
Vidar | Karl Johans gate 15 | 0200   | Oslo
John  | 3021 Arlington Road | 123456 | Memphis, TN

... możesz mieć szablonowy dokument jak

Drogi [NAME], mieszkam w [STREET], [TOWN] [ZIP] ...

Skrypt będzie musiał utworzyć nowy, pusty dokument, a dla każdego wiersza w arkuszu kalkulacyjnym dodaj nową stronę i wyszukaj / zamień symbole zastępcze pól na wartości wierszy.

Mam nieco działającą wersję, która może wymagać dopracowania. Można ją tutaj wywołać . Utworzy nowy dokument o nazwie Wynik korespondencji seryjnej .

Możesz użyć go jako punktu wyjścia do własnego skryptu. Daj mi znać, jeśli jesteś w to zamieszany, lub mogę poświęcić trochę czasu na ukończenie skryptu.

Treść skryptu:

var selectedTemplateId = null;
var selectedSpreadsheetId = null;
var spreadsheetDocPicker = null;
var templateDocPicker = null;

function mailMerge(app) {
  var app = UiApp.createApplication().setTitle("Mail Merge");
  templateDocPicker = createFilePicker(app, "Choose template", 
         UiApp.FileType.DOCUMENTS, "templateSelectionHandler"); 
  templateDocPicker.showDocsPicker();
  return app;
};

function createFilePicker(app, title, fileType, selectionHandlerName) {
  Logger.log("Creating file picker for " + fileType);
  var docPicker = app.createDocsListDialog();
  docPicker.setDialogTitle(title);
  docPicker.setInitialView(fileType);
  var selectionHandler = app.createServerHandler(selectionHandlerName);
  docPicker.addSelectionHandler(selectionHandler);
  return docPicker;
}

function templateSelectionHandler(e) {
  var app = UiApp.getActiveApplication();
  selectedTemplateId = e.parameter.items[0].id;
  UserProperties.setProperty("templateId", e.parameter.items[0].id);
  Logger.log("Selected template: " + selectedTemplateId);
  var spreadsheetDocPicker = createFilePicker(app, "Choose spreadsheet", 
        UiApp.FileType.SPREADSHEETS, "spreadsheetSelectionHandler");
  spreadsheetDocPicker.showDocsPicker();
  return app;
}

function spreadsheetSelectionHandler(e) {
  var app = UiApp.getActiveApplication();
  UserProperties.setProperty("spreadsheetId", e.parameter.items[0].id);
  selectedSpreadsheetId = e.parameter.items[0].id;
  Logger.log("Selected spreadsheet: " + selectedSpreadsheetId);
  doMerge();
  return app;
}

function doMerge() {
  var selectedSpreadsheetId = UserProperties.getProperty("spreadsheetId");
  var selectedTemplateId = UserProperties.getProperty("templateId");
  Logger.log("Selected spreadsheet: " + selectedSpreadsheetId);
  var sheet = SpreadsheetApp.openById(selectedSpreadsheetId);
  Logger.log("Spreadsheet opened");
  Logger.log("Opening template: " + selectedTemplateId);
  var template = DocumentApp.openById(selectedTemplateId);
  Logger.log("Template opened");
  var templateFile = DocsList.getFileById(selectedTemplateId);
  var templateDoc = DocumentApp.openById(templateFile.getId());
  //var mergedFile = templateFile.makeCopy();
  var mergedDoc = DocumentApp.create("Result of mail merge");
  var bodyCopy = templateDoc.getActiveSection().copy();
  Logger.log("Copy made");
  var rows = sheet.getDataRange();
  var numRows = rows.getNumRows();
  var values = rows.getValues();
  var fieldNames = values[0];

  for (var i = 1; i < numRows; i++) {
    var row = values[i];
    Logger.log("Processing row " + i + " " + row);
    var body = bodyCopy.copy();
    for (var f = 0; f < fieldNames.length; f++) {
      Logger.log("Processing field " + f + " " + fieldNames[f]);
      Logger.log("Replacing [" + fieldNames[f] + "] with " + row[f]);
      body.replaceText("\\[" + fieldNames[f] + "\\]", row[f]);
    }
    var numChildren = body.getNumChildren();
    for (var c = 0; c < numChildren; c++) {
      var child = body.getChild(c);
      child = child.copy();
      if (child.getType() == DocumentApp.ElementType.HORIZONTALRULE) {
        mergedDoc.appendHorizontalRule(child);
      } else if (child.getType() == DocumentApp.ElementType.INLINEIMAGE) {
        mergedDoc.appendImage(child);
      } else if (child.getType() == DocumentApp.ElementType.PARAGRAPH) {
        mergedDoc.appendParagraph(child);
      } else if (child.getType() == DocumentApp.ElementType.LISTITEM) {
        mergedDoc.appendListItem(child);
      } else if (child.getType() == DocumentApp.ElementType.TABLE) {
        mergedDoc.appendTable(child);
      } else {
        Logger.log("Unknown element type: " + child);
      }
   }
   Logger.log("Appending page break");
   mergedDoc.appendPageBreak();
   Logger.log("Result is now " + mergedDoc.getActiveSection().getText());
  }
}

function testMerge() {
  UserProperties.setProperty("templateId", 
    "1pAXWE0uklZ8z-O_Tejuv3pWSTiSv583ptUTGPt2Knm8");
  UserProperties.setProperty("spreadsheetId", 
    "0Avea1NXBTibYdFo5QkZzWWlMYUhkclNSaFpRWUZOTUE");
  doMerge();
}


function doGet() {
  return mailMerge();
}

1
Dlaczego zdecydowałeś się na samodzielną aplikację, a nie jedną wersję z arkusza kalkulacyjnego? To znacznie ułatwi PO. Po drugie, dlaczego w skrypcie jest tyle wywołań Logger? Sprawi, że skrypt będzie zbyt gęsty.
Jacob Jan Tuinstra

Archiwum skryptów Google zawierało kiedyś gotowe skrypty ... czy jest jakiś konkretny powód, dla którego twój lub inny nie zostałby tam przesłany?
Bryce

Do tej pory nie zauważył komentarza Jacoba i, jak mówi, prawdopodobnie powinien to być skrypt arkusza kalkulacyjnego zamiast samodzielnego. Zobaczę, czy mogę znaleźć czas, aby nad tym popracować i przesłać go do galerii skryptów.
Vidar S. Ramdal,

5
Vidar To świetna odpowiedź. Wyczyściłem go i zaktualizowałem niektóre przestarzałe metody, pozbyłem się niepotrzebnych funkcji, a także zmodyfikowałem, aby działał z arkusza kalkulacyjnego, jak sugerował @JacobJanTuinstra. Potem zdałem sobie sprawę, że istnieje błąd, który niszczy obrazy , i podjąłem również obejście błędu. Wydaje mi się, że jest teraz wystarczająco przyjemny, aby umieścić go na Github. Zamieściłem go tam i podałem link do twojej odpowiedzi jako początkowej wersji pracy.
hadi

@hadi Dobra robota!
Vidar S. Ramdal,

6

Dzięki nowym dodatkom do Dysku Google dostępnych jest kilka możliwości korespondencji seryjnej, na przykład „Yet Another Merge Mail”.

Aby z niego korzystać, musisz mieć „nowy” arkusz kalkulacyjny Google i zainstalować dodatek za pomocą menu Dodatki:

Zrzut ekranu z Arkuszy kalkulacyjnych Google

Wyszukaj Mail merge, a znajdziesz kilka opcji.


Pamiętaj, że jest on ograniczony do 100 wiadomości e-mail dziennie (bezpłatnie).
pixeline,

5

Własny post Google wyjaśnia, jak skonfigurować dane kanału w jednym arkuszu, a szablon w innym, zamiast arkusza kalkulacyjnego Google + Dokumentu Google: https://developers.google.com/apps-script/articles/mail_merge

Jednak wynikiem końcowym jest MailAppwysłanie wiadomości e-mail zamiast pożądanego „sklonowanego” dokumentu. Sugerowałbym połączenie samouczka i odpowiedzi @ Vidara, coś w stylu zastąpienia:

MailApp.sendEmail(rowData.emailAddress, emailSubject, emailText);

z

var mergedDoc, bodyContent,
    // you'd have to make the DocumentTitle column for the following
    newTitle = rowData.DocumentTitle /* or set to a static title, etc */;

// make a copy of the template document -- see http://stackoverflow.com/a/13243070/1037948
// or start a new one if you aren't using the template, but rather text from a template field
if( usingTemplateFile ) {
    mergedDoc = templateDoc.makeCopy(newTitle)
    bodyContent = mergedDoc.getBody();
} else {
    mergedDoc = DocumentApp.create(newTitle);
    bodyContent = mergedDoc.getBody();
    bodyContent.setText(templateFieldContents);
}

// tweak the fillInTemplateFromObject to accept a document Body and use .replaceText() instead of .match as in mailmerge example
// .replaceText see https://developers.google.com/apps-script/reference/document/body#replaceText(String,String)
fillInTemplateFromObject(bodyContent, rowData);

// no append needed?

Losowe odwołania do skryptów AppScript:


właśnie natknąłem się na tę GIST jako kolejny przykład gist.github.com/mhawksey/1170597
drzaus

3
Pytanie wyraźnie wyklucza korespondencję seryjną.
Bryce,

3

Polecam autoCrat . Jest to dodatek Google z doskonałym interfejsem przypominającym kreatora, który pomaga w konfiguracji scalania.


1

Miałem ten sam problem i próbowałem go rozwiązać za pomocą odpowiedzi Vidara, ale z powodu zaniechania nie zadziałało.

Rzeczywistym rozwiązaniem jest link @hadi w komentarzu do odpowiedzi Vidara.

Vidar :
To świetna odpowiedź. Oczyściłem go i zaktualizowałem niektóre przestarzałe metody, pozbyłem się niepotrzebnych funkcji, a także zmodyfikowałem, aby działał z arkusza kalkulacyjnego, jak sugerował @ JacobJanTuinstra . Potem zdałem sobie sprawę, że istnieje błąd, który niszczy obrazy, i podjąłem również obejście błędu. Wydaje mi się, że jest teraz wystarczająco przyjemny, aby umieścić go na Github. Zamieściłem go tam i podałem link do twojej odpowiedzi jako początkowej wersji pracy.
- hadi 4 marca 2015 o 19:24 ”

https://github.com/hadaf/SheetsToDocsMerge :

  A Google Apps Script that merges information from a Google Sheet into a 
  Template created by Google Docs. The result is a new Google Docs file 
  that is populated by the Sheet data.

Postępowałem zgodnie z instrukcjami na stronie Readmei mogłem utworzyć scalony dokument z szablonu Google-Doc i Google-Sheet.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.