Làm cách nào để gửi thư hợp nhất từ ​​Bảng tính Google sang Tài liệu Google?


20

Với Microsoft Excel và Microsoft Word, thật dễ dàng để hợp nhất các hàng từ bảng tính thành các trang trong tệp Word. Điều này theo truyền thống được sử dụng để làm thư giấy. Làm cách nào tôi có thể làm tương tự với Google Drive / Google Docs?

Có rất nhiều mẫu cung cấp hợp nhất thư từ bảng tính đến email: Làm cách nào để hợp nhất thư với Gmail? nhưng đó không phải là những gì tôi theo đuổi.


Bạn đã thử sao chép / dán chưa?
Jacob Jan Tuinstra

4
Sao chép / dán cho 10.000 hàng? Không, cám ơn. Word / Excel sẽ làm tốt
Bryce

Câu trả lời:


8

Bạn sẽ cần phải viết một Google Apps Script cho điều đó. Bạn có thể để hàng đầu tiên của bảng tính là tên trường và tạo tài liệu mẫu trong đó các trường được tham chiếu như thế nào [FIELD].

Vì vậy, nếu bảng tính của bạn trông như:

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

... bạn có thể có một tài liệu mẫu như

Kính gửi [TÊN], sống tại [ĐƯỜNG], [TOWN] [ZIP] ...

Tập lệnh của bạn sẽ cần tạo một tài liệu mới, trống và cho mỗi hàng trong bảng tính của bạn, hãy thêm một trang mới và tìm kiếm / thay thế chỗ dành sẵn của trường bằng các giá trị hàng.

Tôi có một phiên bản hoạt động, có thể cần đánh bóng. Nó có thể được gọi ở đây . Nó sẽ tạo ra một tài liệu mới có tên Kết quả hợp nhất thư .

Bạn có thể sử dụng nó như một điểm khởi đầu cho kịch bản của riêng bạn. Hãy cho tôi biết nếu bạn thích điều đó, hoặc tôi có thể dành thêm thời gian để hoàn thành kịch bản.

Nội dung kịch bản:

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
Tại sao bạn chọn sử dụng một ứng dụng độc lập mà không phải là một bản dựng từ trong bảng tính? Điều đó sẽ làm cho OP dễ dàng hơn nhiều. Thứ hai, tại sao có nhiều lệnh gọi Logger trong kịch bản? Nó sẽ làm cho kịch bản quá dày đặc.
Jacob Jan Tuinstra

Kho lưu trữ tập lệnh của Google được sử dụng để có một số tập lệnh được xây dựng sẵn ... có lý do cụ thể nào của bạn hoặc tập lệnh khác sẽ không được tải lên ở đó không?
Bryce

Không nhận thấy bình luận của Jacob cho đến bây giờ, và như ông nói, nó có lẽ nên là một tập lệnh bảng tính thay vì độc lập. Tôi sẽ xem liệu tôi có thể tìm thấy thời gian để làm việc với nó không, và gửi nó đến thư viện Script.
Vidar S. Ramdal

5
Vidar Đây là một câu trả lời tuyệt vời. Tôi đã dọn dẹp nó và cập nhật một số phương thức không dùng nữa và loại bỏ các chức năng không cần thiết, đồng thời sửa đổi nó để được chạy từ trong bảng tính như @JacobJanTuinstra đề xuất. Sau đó, tôi nhận ra rằng có một lỗi phá vỡ hình ảnh và tôi cũng đã khắc phục lỗi này. Tôi cảm thấy rằng bây giờ đủ tốt để được đưa vào Github. Tôi đã đăng nó ở đó và trong đó cung cấp một liên kết đến phản hồi của bạn như là phiên bản bắt đầu của tác phẩm.
hadi

@hadi Làm tốt lắm!
Vidar S. Ramdal 4/03/2015

6

Thông qua các Tiện ích bổ sung Google Drive mới , có một số khả năng hợp nhất thư có sẵn, như "Yet Another Mail Merge".

Để sử dụng nó, bạn phải có Bảng tính Google "mới" và cài đặt tiện ích bổ sung thông qua menu Thêm:

Ảnh chụp màn hình từ Bảng tính Google

Tìm kiếm Mail mergevà bạn sẽ tìm thấy một số tùy chọn.


Lưu ý rằng nó được giới hạn ở 100 email mỗi ngày (miễn phí).
pixeline

5

Bài đăng của riêng Google giải thích cách thiết lập dữ liệu nguồn cấp dữ liệu trong một trang tính và mẫu trong một trang tính khác, thay vì Bảng tính Google + Google Doc: https://developers.google.com/apps-script/articles/mail_merge

Tuy nhiên, kết quả cuối cùng là MailAppđể gửi email, thay vì tài liệu "nhân bản" mong muốn. Tôi sẽ đề nghị kết hợp hướng dẫn và câu trả lời của @ Vidar, một vài thứ thay thế:

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

với

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?

Tài liệu tham khảo ngẫu nhiên:


vừa chạy qua GIST này như một ví dụ khác gist.github.com/mhawksey/1170597
drzaus

3
Câu hỏi đặc biệt không bao gồm email mail hợp nhất.
Bryce

3

Tôi khuyên bạn nên autoCrat . Nó là một Tiện ích bổ sung của Google với giao diện giống như trình hướng dẫn tuyệt vời để giúp bạn thiết lập hợp nhất.


1

Tôi có cùng một vấn đề và đã cố gắng giải quyết nó bằng câu trả lời của Vidar nhưng vì sự phản đối nên nó không hoạt động.

Giải pháp thực tế là liên kết của @hadi trong bình luận về câu trả lời của Vidar.

Vidar :
Đây là một câu trả lời tuyệt vời. Tôi đã dọn dẹp nó và cập nhật một số phương thức không dùng nữa và loại bỏ các chức năng không cần thiết, đồng thời sửa đổi nó để được chạy từ trong bảng tính như @ JacobJanTuinstra đề xuất. Sau đó, tôi nhận ra rằng có một lỗi phá vỡ hình ảnh và tôi cũng đã khắc phục lỗi này. Tôi cảm thấy rằng bây giờ đủ tốt để được đưa vào Github. Tôi đã đăng nó ở đó và trong đó cung cấp một liên kết đến phản hồi của bạn như là phiên bản bắt đầu của tác phẩm.
- hadi 4 tháng 4 '15 lúc 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.

Chỉ cần làm theo các bước trên Readmevà tôi đã có thể tạo một tài liệu được hợp nhất từ ​​một mẫu Google-Doc và Google-Sheet.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.