Скрипт для создания документов Google из источника данных электронной таблицы Google

Microsoft Office поддерживает «источники данных» для генерации, например. Письма, счета-фактуры, адресные наклейки и другие повторяющиеся документы на основе шаблона Microsoft Word и данных Microsoft Excel. Это очень распространенная проблема малого бизнеса, и у Office есть решение для нее с середины 90-х годов. Google Apps, облачная альтернатива Microsoft Office, не предлагает подобную функциональность изначально (или, по крайней мере, если они действительно скрывают ее). Тем не менее, вы можете легко создать собственный генератор документов, используя сценарии Google Apps, если вы владеете программированием. В этом блоге я покажу пример, как создать такой скрипт и изучить основы скриптов Google Apps.

1. Ингредиенты генератора документов

У нас есть следующие материалы для нашей бизнес-проблемы

  • Электронная таблица Google Apps, содержащая данные о клиентах.
  • Документ шаблона документов Google. На основе этого мы хотим сгенерировать документ для каждого клиента, заполнив этот шаблонный документ данными из электронной таблицы.
  • Папка на Google Диске, в которой хранятся полученные документы.
  • Скрипт Google Apps, который автоматизирует задачу для нас (на основе Javascript)

Все они хранятся в вашей учетной записи Google Apps на Google Диске. Все редактирование происходит через пользовательский интерфейс Google Apps, никаких внешних инструментов не требуется.

Все они хранятся в вашем аккаунте Google Apps в Google Drive. Все редактирование происходит с помощью Служб Google пользовательского интерфейса, без каких-либо внешних инструментов, необходимых.

Пример исходных данных (затемненный с obfuscate.js )

Пример шаблона документа (затемненный с obfuscate.js ). Вы можете видеть исходные метки источника, незаполненные.

Пример результирующего документа – метки , заполненные и больше не выделены жирным шрифтом (затемненный с obfuscate.js )

2. Краткое введение в Google Apps Script

Скрипты Google Apps можно запускать двумя способами

Поскольку мы не работаем с электронной таблицей, нам нужно использовать прежний подход.

Скрипт  Google  apps- это сценарий JavaScript (версия ECMAScript неизвестна? Запущен ли V8?), который обеспечивает простые способы автоматизации задач в продуктах Google и сторонних службах. Скрипт  Google apps содержит обширную документацию API с примерами и учебными пособиями, но они по-прежнему подвержены значительным изменениям, поскольку почти все отмечено как экспериментальное и уже существует много устаревших методов. Скрипты Google Apps могут также получать доступ к Картам Google, контактам, электронной почте, сайтам, настройкам домена Google Apps и в основном иметь решение для автоматизации почти все, что вы можете делать в облаке Google.

Скрипт выполняется на стороне сервера, и у вас есть немодный локализованный интерфейс на базе браузера для редактирования и отладки вашего скрипта.

Философия и паттерны проектирования пользовательского интерфейса представляют собой шаг назад к 90-м годам, к среде сценариев Visual Basic. Возможно, разработчики Google Apps хотели этого … чтобы разработчики Visual Basic чувствовали себя как дома. Однако из-за веб-разработки, Javascript и общего фона программирования вы обнаружите отсутствие Firebug / Web Inspector, например, нарушение работы консоли. Это не похоже на какую-либо другую разработку Javascript, хотя, безусловно, синтаксис такой же.

Поэтому мои незначительные жалобы включают, но не ограничиваются этим:

  • Возможно ведение журнала из приложений, но трассировка журнала очень нечитабельная в пользовательском интерфейсе
  • У программы нет определенной точки входа, вам нужно выбрать функцию, используя виджет выбора. Это заставляет скрипт чувствовать себя игрушкой.
  • Отладчик (и отсутствие консоли), похоже, не позволяет вам изменять и динамически выставлять объекты во время выполнения (функции вызова и т. Д.),
  • Отладчик немного медленный (туда-обратно к серверам Google, немного), хотя все еще в значительной степени полезный
  • Отсутствие инструментов взаимодействия с конечными пользователями в автономных сценариях (см. Ниже)
  • Документы API и реальность не всегда совпадают (поскольку все еще экспериментально)

Отладчик в действии

Все могло быть лучше, но в итоге мне удалось сделать то, что я искал, и я все еще не плачу ни копейки за Google Apps, поэтому я счастлив. Кроме того, я не хочу возвращаться в Microsoft Office, если мне не нужно писать хорошо отформатированные документы для печати … Документы Google – это игрушка, которая приходит к тяжелому и графически чувствительному авторингу документов, как предложения …. Или презентации … где Keynote – король.

3. Скрипт генератора

В начале скрипта у вас есть константы, которые определяют, по каким данным работать. Вы можете создать пользовательский интерфейс, делающий скрипт для полного веб-приложения, но это слишком громоздкий подход для такой небольшой задачи. Конструктор пользовательского интерфейса казался приятным, но определенно излишним. Хотя в браузере существуют методы API сценариев Google Apps для выполнения простого запроса prompt (), по какой-то причине они не поддерживались в автономных сценариях … поэтому самый быстрый подход для ввода данных в скрипт заключался в том, чтобы просто редактировать сценарий перед каждым запуском. Я ооочень начал пропускать командную строку … первый раз в моей жизни.

Итак, в начале скрипта вы определяете исходные данные

  • Идентификатор электронной таблицы (вы можете выбрать его из URL-адреса при редактировании документа)
  • Идентификатор документа шаблона (вы можете выбрать его из URL-адреса при редактировании документа)
  • Идентификатор клиента, который является номером строки таблицы, для текущего запуска скрипта.
  • Идентификатор папки для драйверов Google, куда будет помещен полученный документ для совместного использования. Опять же, вы можете выбрать идентификатор из URL-адреса при открытии папки.

Затем скрипт просто заменяет слова данными. Ключевое слово, подлежащее замене в документе шаблона, идентифицируется как метки столбцов (1-я строка) в данных электронной таблицы. Я вполне уверен, что для этого были бы более эффективные методы, но я не хотел тратить время на то, чтобы поглубже нанести удар по GS, чтобы выяснить его нюансы.

А затем сценарий … пожалуйста, не стесняйтесь модифицировать в соответствии с вашими потребностями (generator.gs):

/**
 * Generate Google Docs based on a template document and data incoming from a Google Spreadsheet
 *
 * License: MIT
 *
 * Copyright 2013 Mikko Ohtamaa, http://opensourcehacker.com
 */

// Row number from where to fill in the data (starts as 1 = first row)
var CUSTOMER_ID = 1;

// Google Doc id from the document template
// (Get ids from the URL)
var SOURCE_TEMPLATE = "xxx";

// In which spreadsheet we have all the customer data
var CUSTOMER_SPREADSHEET = "yyy";

// In which Google Drive we toss the target documents
var TARGET_FOLDER = "zzz";

/**
 * Return spreadsheet row content as JS array.
 *
 * Note: We assume the row ends when we encounter
 * the first empty cell. This might not be 
 * sometimes the desired behavior.
 *
 * Rows start at 1, not zero based!!! 🙁
 *
 */
function getRowAsArray(sheet, row) {
  var dataRange = sheet.getRange(row, 1, 1, 99);
  var data = dataRange.getValues();
  var columns = [];

  for (i in data) {
    var row = data[i];

    Logger.log("Got row", row);

    for(var l=0; l<99; l++) {
        var col = row[l];
        // First empty column interrupts
        if(!col) {
            break;
        }

        columns.push(col);
    }
  }

  return columns;
}

/**
 * Duplicates a Google Apps doc
 *
 * @return a new document with a given name from the orignal
 */
function createDuplicateDocument(sourceId, name) {
    var source = DocsList.getFileById(sourceId);
    var newFile = source.makeCopy(name);

    var targetFolder = DocsList.getFolderById(TARGET_FOLDER);
    newFile.addToFolder(targetFolder);

    return DocumentApp.openById(newFile.getId());
}

/**
 * Search a paragraph in the document and replaces it with the generated text 
 */
function replaceParagraph(doc, keyword, newText) {
  var ps = doc.getParagraphs();
  for(var i=0; i<ps.length; i++) {
    var p = ps[i];
    var text = p.getText();

    if(text.indexOf(keyword) >= 0) {
      p.setText(newText);
      p.setBold(false);
    }
  } 
}

/**
 * Script entry point
 */
function generateCustomerContract() {

  var data = SpreadsheetApp.openById(CUSTOMER_SPREADSHEET);

  // XXX: Cannot be accessed when run in the script editor?
  // WHYYYYYYYYY? Asking one number, too complex?
  //var CUSTOMER_ID = Browser.inputBox("Enter customer number in the spreadsheet", Browser.Buttons.OK_CANCEL);
  if(!CUSTOMER_ID) {
      return; 
  }

  // Fetch variable names
  // they are column names in the spreadsheet
  var sheet = data.getSheets()[0];
  var columns = getRowAsArray(sheet, 1);

  Logger.log("Processing columns:" + columns);

  var customerData = getRowAsArray(sheet, CUSTOMER_ID);  
  Logger.log("Processing data:" + customerData);

  // Assume first column holds the name of the customer
  var customerName = customerData[0];

  var target = createDuplicateDocument(SOURCE_TEMPLATE, customerName + " agreement");

  Logger.log("Created new document:" + target.getId());

  for(var i=0; i<columns.length; i++) {
      var key = columns[i] + ":"; 
      // We don't replace the whole text, but leave the template text as a label
      var text = customerData[i] || ""; // No Javascript undefined
      var value = key + " " + text;
      replaceParagraph(target, key, value);
  }

}
 

 

Leave a Reply

Your email address will not be published. Required fields are marked *