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 Driver (Добавить новый … далее … скрипт)
- Непосредственно из электронной таблицы Google Apps (есть запись в меню)
- И более
- Существует также интегрированный общественный сниппет обмен сервис в Google Spreadsheet … хотя интерфейс действительно оставляет возможности для улучшения здесь. Вы также можете продавать скрипты в Google Chrome Web Store .
Поскольку мы не работаем с электронной таблицей, нам нужно использовать прежний подход.
Скрипт 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); } }