AndreyElagin
11/9/2016 - 9:53 PM

Использую этот скрипт для выгрузки документов в .csv в гугл таблицы

Использую этот скрипт для выгрузки документов в .csv в гугл таблицы

/**
 * Производит чтение писем из Gmail аккаунта пользователя скрипта,
 * после чего выгружает их содержимое в соответствующую таблицу СЦ.
 * Большая часть реализации вынесена в другии функции.
 */
function importDataFromGmail() {
  var idCollection = {
    client1: "pageID",
    client2: "pageID",
    client3: "pageID",
    client4: "pageID",
    client5: "pageID",
  };

  var threads = GmailApp.getInboxThreads(0, 15);
  var email = "email@email.email";
  var waybills = {};
  var services = {
    client1: [],
    client2: [],
    client3: [],
    client4: [],
    client5: [],
  }

  for (var i = 0; i < threads.length; i++) {
    for (var j = 0; j < threads[i].getMessages().length; j++) {
      if (threads[i].getMessages()[j].getFrom().indexOf(email) > 0 &&
        threads[i].getMessages()[j].getAttachments()[0].getContentType() == "application/octet-stream" && //почему то данные мне передают именно так
        !threads[i].getMessages()[j].isStarred()) {
        var message = threads[i].getMessages()[j];
        var serviceName = message.getSubject().match(/\w+\s\w+$|\w$|Client\s\(\w*?\s\w*?\)$|М\w+-\w+$|[А-Я]+$/); 
        var attachment = sanatize(message.getAttachments()[0].getDataAsString());
        fillServiceCollection(serviceName.toString(), services, attachment);
        threads[i].getMessages()[j].star();//Странное решение, нужно подумать. Отслеживать id письма для того чтобы сделать unStar()
      }
    }
  }

  fillWaybillCollection(services, waybills);
  deliverWaybills(idCollection, waybills);
}
/**
 * Осущствляет выгрузку объектов накладных в соответствующие
 * им листы таблиц СЦ, после чего настраивает отображение данных.
 *
 * @param idCollection объект содержащий в себе id таблиц СЦ
 * @param waybills объект содержащий в себе отображения СЦ на объекты накладных
 */
function deliverWaybills(idCollection, waybills) {
  var hashIdentityArray = [];
  for (var waybillsbBunch in waybills) {
    var currentWaybillBunch = waybills[waybillsbBunch];
    for (var i = 0; i < currentWaybillBunch.length; i++) {
       if (hashIdentityArray.indexOf(currentWaybillBunch[i].hash) < 0) {
        if (!checkHashExistence(currentWaybillBunch[i].name, currentWaybillBunch[i].hash)) {
          var sheet = null;
          try {
            sheet = SpreadsheetApp.openById(idCollection[currentWaybillBunch[i].name]).getSheetByName(getCurrentSheetName()).activate();
            if (sheet.getMaxRows() - sheet.getLastRow() < 1) {
              sheet.insertRowsAfter(sheet.getMaxRows(), 6)
                .getRange(sheet.getLastRow() + 1, 14, sheet.getMaxRows() - sheet.getLastRow())
                .clear({
                  validationsOnly: true
                });
            }
            var headerRange = sheet.getRange(sheet.getLastRow() + 3, 3, 1, 1);
            var dateRange = sheet.getRange(sheet.getLastRow() + 3, 6, 1, 1);
            var estimatingRange = sheet.getRange(sheet.getLastRow() + 3, 9, 1, 1);
            var formulaRange = sheet.getRange(sheet.getLastRow() + 3, 10, 1, 1);
            var bodyRange = sheet.getRange(sheet.getLastRow() + 6, 3, currentWaybillBunch[i].body.length, 6);
            var tableRange = sheet.getRange(sheet.getLastRow() + 6, 3, currentWaybillBunch[i].body.length, 12);
            var dataValidationRange = sheet.getRange(sheet.getLastRow() + 6, 14, currentWaybillBunch[i].body.length, 1);
            headerRange.setValue("Накладная № " + currentWaybillBunch[i].number + " от")
              .setWrap(false)
              .setFontSize(14)
              .setFontWeight("Bold");
            estimatingRange.setValue("Дней в ремонте:")
              .setWrap(false)
              .setFontSize(14)
              .setFontWeight("Bold")
              .setBorder(true, true, true, true, true, true);
            formulaRange.setFormula("=TODAY()-F" + sheet.getLastRow())
              .setWrap(false)
              .setFontSize(14)
              .setFontWeight("Bold")
              .setBorder(true, true, true, true, true, true);
            dateRange.setValue(currentWaybillBunch[i].date)
              .setWrap(false)
              .setFontSize(14)
              .setFontWeight("Bold");
            bodyRange.setValues(currentWaybillBunch[i].body);
            var rule = SpreadsheetApp.newDataValidation()
              .requireValueInList(["Готов", "В работе", "Отказ", "Ожидает запчасти", "Выдан"])
              .setAllowInvalid(true)
              .build();
            var realShit = tableRange.getWraps();
            var copy = Object.create(currentWaybillBunch[i]); //по какой то причине цикл ниже затирает изначальный объект 
            for (var i in realShit) {
              for (var j in realShit[i]) {
                if (!realShit[i][j]) realShit[i][j] = true;
              }
            }
            Logger.log(realShit);
            tableRange.setBorder(true, true, true, true, true, true)
              .setFontSize(10)
              .setFontWeight("Unbold")
              .setWraps(realShit);
            dataValidationRange.setDataValidation(rule);
            checkHashExistence(copy.name, copy.hash, true);
          } catch (e) {
            SpreadsheetApp.getUi().alert(e);
            errorHandler(e, copy);
          }
        }
        hashIdentityArray.push(copy.hash);
      }
    }
  }
}

/**
 * Создает объекты представления накладных, и наполняет
 * ими объект waybills.
 *
 * @param services объект, который хранит отображения СЦ на списки почтовых вложений
 * @param waybills объект содержащий в себе отображения СЦ на объекты накладных
 */
function fillWaybillCollection(services, waybills) {
  for (var service in services) {
    for (var i = 0; i < services[service].length; i++) {
      var waybill = {};
      waybill["body"] = [];
      waybill["name"] = service;
      waybill["number"] = services[service][i][0][0];
      waybill["date"] = services[service][i][0][1];
      for (var j = 1; j < services[service][i].length; j++) {
        waybill["body"].push(services[service][i][j]);
      }
      waybill["hash"] = evaluateHash(waybill["body"].toString());
      waybills.hasOwnProperty(waybill["name"]) ? waybills[waybill["name"]].push(waybill) : waybills[waybill["name"]] = [waybill];
    }
  }
}

/**
 * Очищает данные почтового вложения от лишних символов,
 * производит замену "$|" на ";" для парсинга и последующего преобразования 
 * в массив.
 *
 * @param data почтовое вложение в виде строки
 * @return data почтовое вложение в виде двумерного массива
 */
function sanatize(data) {
  data = data.replace(/[;"\n]/g, '');
  data = data.replace(/\$\|/g, ';');
  data = data.replace(/\s\s+/g, '');
  data = Utilities.parseCsv(data, ';');
  return data;
}

/**
 * При двух аргументах проверяет наличие хэша текущей накладной 
 * в хранилище. При трех аргументах добавляет хэш текущей накладной
 * в хранилище.
 *
 * @param service название СЦ для проверки
 * @param hash значение хэша для проверки или добавления
 * @param withAddition использутся в true только для добавления хэша в хранилище,
 * при отсутствии или в false функция проверит существование ключа
 * @return true возвращает true в том случае если перадан аргумент withAddition == true
 * и хэш был добавлен в хранилище
 * @return flag true или false, в зависимости от того, был ли найден хэш в хранилище
 */
function checkHashExistence(service, hash, withAddition) {
  var DATA_SS = "pageID";
  var ss = SpreadsheetApp.openById(DATA_SS);
  var sheet = ss.getSheetByName(service);
  sheet = sheet || ss.insertSheet(service);
  if (arguments.length > 2) {
    if (withAddition) {
      sheet.appendRow([hash]);
      return true;
    }
  }
  var range = sheet.getRange(1, 1, 1000);
  var data = range.getDisplayValues();
  var flag = false;
  Object.keys(data).map(function(key) {
    if (data[key] == hash) flag = true;
  }, hash, flag);
  return flag;
}

/**
 * Вычисляет значение хэша для переданного текста, на основе алгоритма MD5
 * Thanks http://stackoverflow.com/questions/16216868/get-back-a-string-representation-from-computedigestalgorithm-value-byte
 *
 * @param message текст на основе которого, будет вычислятся хэш
 * @return signatureStr хэш в виде строки в кодировке UTF-8 
 */
function evaluateHash(message) {
  var signature = Utilities.computeDigest(Utilities.DigestAlgorithm.MD5, message, Utilities.Charset.UTF_8);
  var signatureStr = '';
  for (i = 0; i < signature.length; i++) {
    var byte = signature[i];
    if (byte < 0)
      byte += 256;
    var byteStr = byte.toString(16);
    if (byteStr.length == 1) byteStr = '0' + byteStr;
    signatureStr += byteStr;
  }
  return signatureStr;
}

/**
 * Вычисляте текущий месяц и год, для определения названия листа
 * в таблице СЦ
 *
 * @return название листа в таблице согласования с СЦ
 */
function getCurrentSheetName() {
  var date = new Date();
  var monthArray = ["Январь", "Февраль", "Март", "Апрель", "Май",
    "Июнь", "Июль", "Август", "Сентябрь", "Октябрь", "Ноябрь", "Декабрь"
  ];
  return monthArray[date.getMonth()] + " " + date.getFullYear().toString().slice(2, 4);
}

/**
 * Обрабатывает ошибки возникшие во время исполнения скрипта
 * и добавляет о них в лог-файл
 *
 * @param e объект ошибки
 * @param waybill объект накладной
 */
function errorHandler(e, waybill) {
  var DATA_SS = "pageID";
  var ss = SpreadsheetApp.openById(DATA_SS);
  var sheet = ss.getSheetByName("errors");
  Logger.log(e.stack);
  sheet.appendRow([new Date(), Session.getActiveUser(), waybill.name + " " + waybill.number + " " + waybill.date, waybill.hash, e, e.stack]);
}

/**
 * Наполняет объект services вложениями писем в виде строки
 * 
 * @param serviceName название СЦ
 * @param services объект коллекция
 * @param attachment вложение письма
 */
function fillServiceCollection(serviceName, services, attachment) {
  switch (serviceName) {
    case "client1":
      services.client1.push(attachment);
      break;
    case "client2":
      services.client2.push(attachment);
      break;
    case "client3":
      services.client3.push(attachment);
      break;
    case "client4":
      services.client4.push(attachment);
      break;
    case "client5":
      services.client5.push(attachment);
      break;
  }
}