Como faço a mala direta da planilha do Google para um documento do Google?


20

Com o Microsoft Excel e o Microsoft Word, é fácil mesclar linhas de uma planilha em páginas em um arquivo do Word. Tradicionalmente, isso era usado para fazer correspondências em papel. Como posso fazer o mesmo com o Google Drive / Google Docs?

Existem vários modelos que oferecem mala direta de planilha para email: como faço para mala direta com o Gmail? mas não é isso que estou procurando.


Você já tentou copiar / colar?
Jacob Jan Tuinstra

4
Copiar / colar para 10.000 linhas? Não, obrigado. Word / Excel vai fazer muito bem.
Bryce

Respostas:


8

Você precisará escrever um script do Google Apps para isso. Você pode deixar a primeira linha da planilha ser nomes de campo e criar um documento de modelo no qual os campos sejam referenciados [FIELD].

Portanto, se sua planilha se parecer com:

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

... você pode ter um documento de modelo como

Caro [NAME], morando em [STREET], [TOWN] [ZIP] ...

Seu script precisará criar um documento novo e vazio e, para cada linha da planilha, adicionar uma nova página e pesquisar / substituir os espaços reservados do campo pelos valores da linha.

Eu tenho uma versão um pouco funcional, que pode precisar de algum polimento. Pode ser invocado aqui . Ele criará um novo documento chamado Resultado da mala direta .

Você pode usá-lo como ponto de partida para seu próprio script. Deixe-me saber se você gosta disso, ou posso passar mais tempo terminando o script.

Conteúdo do script:

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();
}

11
Por que você escolheu usar um aplicativo independente e não criar uma a partir da planilha? Isso tornará muito mais fácil para o OP. Em segundo lugar, por que existem tantas chamadas do Logger no script? Isso tornará o script excessivamente denso.
Jacob Jan Tuinstra

O arquivo de scripts do Google costumava ter alguns scripts pré-criados ... existe algum motivo específico para o seu ou outro não ser enviado para lá?
Bryce

Não percebeu o comentário de Jacob até agora e, como ele diz, provavelmente deveria ser um script de planilha em vez de autônomo. Vou ver se consigo encontrar tempo para trabalhar nele e enviá-lo para a galeria de scripts.
Vidar S. Ramdal

5
Vidar Esta é uma ótima resposta. Limpei-o, atualizei alguns dos métodos obsoletos e me livrei de funções desnecessárias, e também o modifiquei para ser executado a partir da planilha, como sugeriu @JacobJanTuinstra. Então percebi que havia um bug que quebra imagens e também fiz uma solução alternativa para o bug. Eu sinto que agora é bom o suficiente para ser colocado no Github. Eu o publiquei lá e forneci um link para sua resposta como a versão inicial do trabalho.
hadi

@hadi Bom trabalho!
Vidar S. Ramdal

6

Por meio dos novos complementos do Google Drive , existem várias possibilidades de mala direta disponíveis, como "Ainda outra mala direta".

Para usá-lo, você deve ter uma "nova" planilha do Google e instalar o complemento através do menu Complementos:

Captura de tela das planilhas do Google

Pesquise Mail mergee você encontrará várias opções.


Observe que é limitado a 100 e-mails por dia (de graça).
Pixel #

5

A postagem do Google explica como configurar os dados do feed em uma planilha e o modelo em outra, em vez de uma planilha do Google + Documento do Google: https://developers.google.com/apps-script/articles/mail_merge

No entanto, o resultado final é o MailAppenvio de um email, em vez do documento "clonado" desejado. Sugiro combinar o tutorial e a resposta do @ Vidar, algo como substituir:

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

com

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?

Referências aleatórias do AppScripts:


apenas deparei com este GIST como outro exemplo gist.github.com/mhawksey/1170597
drzaus

3
A pergunta exclui especificamente a mala direta por email.
Bryce

3

Eu recomendo o autoCrat . É um complemento do Google com uma excelente interface semelhante a um assistente para ajudá-lo a configurar a mesclagem.


1

Eu tive o mesmo problema e tentei resolvê-lo com a resposta de Vidar, mas devido à depreciação, não funcionou.

A solução real é o link de @hadi no comentário da resposta de Vidar.

Vidar :
Esta é uma ótima resposta. Limpei-o, atualizei alguns dos métodos obsoletos e me livrei de funções desnecessárias, e também o modifiquei para ser executado a partir da planilha, como sugeriu @ JacobJanTuinstra . Então percebi que havia um bug que quebra imagens e também fiz uma solução alternativa para o bug. Eu sinto que agora é bom o suficiente para ser colocado no Github. Eu o publiquei lá e forneci um link para sua resposta como a versão inicial do trabalho.
- hadi 04/03/2015 às 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.

Acabei de seguir as etapas Readmee pude criar um documento mesclado a partir de um modelo Google-Doc e de um Google-Sheet.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.