Ответы пользователя по тегу Google Apps Script
  • Скопировать данные из одного листа на другой последнюю не заполненную строку?

    oshliaer
    @oshliaer Куратор тега Google Apps Script
    Google Products Expert
    Я бы сделал так

    /**
     *
     */
    function onOpen() {
      SpreadsheetApp.getUi()
        .createMenu('Custom menu')
        .addItem('Copy to logs', 'userActionsCopyToLogs')
        .addToUi();
    }
    
    /**
     *
     */
    function userActionsCopyToLogs() {
      var headers = ['Name', 'Number'];
    
      var from = SpreadsheetApp.getActiveSheet();
    
      if (from.getName() !== 'Sheet1') {
        SpreadsheetApp.getActive().toast('Activate a range on "Sheet1"');
        return;
      }
    
      var fromValues = from.getDataRange().getValues();
    
      var fromHeaders = fromValues[0].map(function(h) {
        return headers.indexOf(h);
      });
    
      var activeRange = SpreadsheetApp.getActiveRange();
      var rowStart = activeRange.getRow();
      var rowEnd = activeRange.getLastRow();
      var fromData = fromValues
        .filter(function(row, i) {
          return i >= rowStart - 1 && i <= rowEnd - 1;
        })
        .map(function(row) {
          return row.filter(function(_, j) {
            return fromHeaders[j] > -1;
          });
        });
    
      var to =
        SpreadsheetApp.getActive().getSheetByName('Logs') ||
        SpreadsheetApp.getActive().insertSheet('Logs');
    
      to.getRange(to.getLastRow() + 1, 1, fromData.length, fromData[0].length)
        .setValues(fromData)
        .activate();
    }


    screenrecord.gif

    Измените строку var headers = ['Name', 'Number']; так, чтобы копировались данные из нужных вам колонок.

    Полный код
    Ответ написан
    Комментировать
  • Как отправить заявку с сайта на Битриксе в Google sheets?

    oshliaer
    @oshliaer Куратор тега Google Apps Script
    Google Products Expert
    Опубликуйте ваш скрипт от своего имени для всех в интернете.

    5e03728fc004c946730977.png

    Не забудьте, что при внесении изменений в скрипт вам придется публиковать его заново.
    Ответ написан
    1 комментарий
  • Как сделать проверку по определенному столбцу?

    oshliaer
    @oshliaer Куратор тега Google Apps Script
    Google Products Expert
    Если без объяснений кода, то

    function onEdit() {
       run2();
    }
    
    function run2() {
      /* Remove dash */
      var sheet = SpreadsheetApp.getActiveSheet();
      if (sheet.getName() === 'Журнал вода данных') return;
      var archive = SpreadsheetApp.getActive().getSheetByName('Журнал вода данных');
    
      var action = function(values, i, i2) {
        var data = values.slice(i, i + i2);
        archive
          .getRange(archive.getLastRow() + 1, 1, data.length, data[0].length)
          .setValues(data);
      };
    
      var condition = function(values, i) {
        var row = values[i];
        return (
          i > 0 && row[0] !== '' && row[1] !== '' && row[3] !== '' && row[5] !== ''
        );
      };
    
      deleteRowsByConditional_(sheet, condition, action);
    }
    
    function deleteRowsByConditional_(sheet, condition, action) {
      sheet
        .getDataRange()
        .getValues()
        .forEach(
          function(_, i, arr) {
            var j = arr.length - i - 1;
            if (this.condition.apply(null, [arr, j])) {
              this.isContinue++;
              if (j > 0) return;
            }
            if (this.isContinue > 0) {
              var prevPos = j + 1; // It's reversed
              if (action) action(arr, prevPos, this.isContinue);
              this.sheet.deleteRows(prevPos + 1, this.isContinue);
              this.isContinue = 0;
              return;
            }
            return;
          },
          { sheet: sheet, condition: condition, isContinue: 0 }
        );
    }


    Будет работать на любом листе вашей Таблицы. Можно подключить run2() к меню.

    Ссылка на видео https://www.facebook.com/oshliaer/videos/258791787...

    Ссылка на сниппет https://github.com/contributorpw/google-apps-scrip...
    Ответ написан
    Комментировать
  • Ошибка TypeError: Не удается прочитать свойство "postData" объекта undefined. (строка 3, файл Код)?

    oshliaer
    @oshliaer Куратор тега Google Apps Script
    Google Products Expert
    В doPost(e) передается запрос от внешнего источника только тогда, когда ваш сервис опубликован и отправлен запрос POST.

    Чтобы тестировать эту чать, вам необходимо отправлять запросы на ваш эндпоинт, например, вот этим https://www.getpostman.com/

    Ту ошибку, которую вы наблюдаете, можно воспроизвести только одним способом - вызвать doPost из редактора кода.
    Ответ написан
    Комментировать
  • Как добавить вложения в письмо при рассылка писем из Таблицы?

    oshliaer
    @oshliaer Куратор тега Google Apps Script
    Google Products Expert
    Самое простое, это добавить body с сылкой на Диск

    MailApp.sendEmail({
      ...
      body: 'https://drive...',
      ...
    });


    Файл подтянется автоматически. Другой вопрос - это подключение файлов через аттачмент.

    Пример для PDF

    var file = DriveApp.getFilesByName('test123.pdf');
    if (file.hasNext()) {
        MailApp.sendEmail(emailAddress, subject, message, {
        attachments: [file.next().getAs(MimeType.PDF)],
        name: 'Automatic Emailer Script'
    }


    Мой код согласно комментариям

    function sendEmail() {
      var sheet = SpreadsheetApp.getActiveSheet();
      var activeRange = sheet.getActiveRange();
      var data = sheet
        .getRange(
          activeRange.getRow(),
          1,
          activeRange.getLastRow() - activeRange.getRow() + 1,
          6
        )
        .getValues();
    
      data.forEach(function(row) {
        var file = DriveApp.getFilesByName(row[5]);
        if (file.hasNext()) {
          var namesender = row[0];
          var emailAddress = row[1];
          var hiddencopy = row[2];
          var subject = row[3];
          var message = row[5];
          var information = row[4];
          var emailQuotaRemaining = MailApp.getRemainingDailyQuota();
          Logger.log('Remaining email quota: ' + emailQuotaRemaining);
    
          MailApp.sendEmail({
            to: emailAddress,
            bcc: hiddencopy,
            replyTo: 'supportmp@test.ru',
            name: namesender,
            subject: subject + ' ' + information,
            htmlBody: message + ' ' + https,
            attachments: [file.next().getAs(MimeType.PDF)],
          });
        } else {
          Logger.log('Файл для отправки не найден');
        }
      });
    }
    Ответ написан
    7 комментариев
  • Добавление данных в Google Forms из Google Sheets?

    oshliaer
    @oshliaer Куратор тега Google Apps Script
    Google Products Expert
    Этот процесс называется "автоматическое заполнение полей Формы". Поищите подходящий для себя аддон из списка дополнений самой Формы.

    Так же возможна разработка своего собственного скрипта.
    Ответ написан
    Комментировать
  • Как сделать сумму прописью в Таблицах?

    oshliaer
    @oshliaer Куратор тега Google Apps Script
    Google Products Expert
    Можно использовать аддон для Таблиц NUMBERTEXT

    5d9c015768e80721417047.png

    Число прописью в текущей локале

    =NUMBERTEXT(1) // one

    Число прописью в русской локале

    =NUMBERTEXT(1;"ru") // один

    Число прописью в украинской локале

    =NUMBERTEXT(1;"uk") // один

    Число в заданной валюте прописью в текущей локале

    =MONEYTEXT(1; "USD"; "uk") // Один долар США
    Ответ написан
  • Где проблема в скрипте?

    oshliaer
    @oshliaer Куратор тега Google Apps Script
    Google Products Expert
    Потому что вы выбираете квоту запросов на свой ключ. Посмотрите статистику запросов в консоли разработчика.

    Вот этот Utilities.sleep(1000); как мертвому припарка.

    Если вы запускаете скрипт как пользовательскую формулу, то вам нужно делать последовательные вызовы

    5d9bad1a8c877535631892.png

    Пример принципа в Таблице
    Ответ написан
  • Как с помощью UrlFetchApp активировать doGet(e)?

    oshliaer
    @oshliaer Куратор тега Google Apps Script
    Google Products Expert
    Вам же написали:
    Script function not found: doPost


    Вероятно, это помтому, что вы отправляете не GET, а POST запрос. Как минимум GET не имеет никакого body и payload ему ни к чему.
    Ответ написан
    Комментировать
  • В чем проблема со скриптом импорта данных из гугл таблицы в гугл док?

    oshliaer
    @oshliaer Куратор тега Google Apps Script
    Google Products Expert
    У моего линтера кукушку чуть не оторвало. Он даже подумал, что это не JS. Ваш код не валиден для интерпретатора Google Apps Script. Вот форматированный, но непроверенный код

    /* eslint-disable require-jsdoc */
    /* eslint-disable no-undef */
    
    function doAction() {
      var result = readBaseData('22-05-2019');
      // If found data for this date...
      if (result != null) {
        var doc = createNewDoc(' iskovoe ' + result[0][0]);
        fillTemplate(doc, result);
      }
    }
    // inDoc - its a empty template, inData - data for filling template
    function fillTemplate(inDoc, inData) {
      // Getting count of files in folder
      var NUM = DocsList.getFolderById(
        '1a3uCa9wRyOzio-C7FVacOykuLoxCqTs3'
      ).getFiles().length;
    
      // Replace masks (Don't work [NUM] or $NUM or something else)
      inDoc.replaceText(
        'x',
        'https://docs.google.com/spreadsheets/d//edit#gid=0...'
      );
      inDoc.replaceText(
        'x',
        'https://docs.google.com/spreadsheets/d//edit#gid=0...'
      );
      inDoc.replaceText(
        'x',
        'https://docs.google.com/spreadsheets/d//edit#gid=0...'
      );
      inDoc.replaceText(
        'x',
        'https://docs.google.com/spreadsheets/d//edit#gid=0...'
      );
    
      // get first table in document
      var table = curDoc.getTables()[0];
      for (i = 0; i < inData.length; i++) {
        var row = table.appendTableRow();
        row.appendTableCell(inData[i][1]);
        row.appendTableCell(inData[i][2]);
      }
      curDoc.saveAndClose();
    }
    function createNewDoc() {
      // Making copy of blank file
      var blankDoc = DocsList.getFileById(
        '19vYiThaKdgQ6eeiRg5nPewzP_Eab7nkLUwyt49jCC1Q'
      ).makeCopy(iskovoe);
      blankDoc.addToFolder(
        DocsList.getFolderById('1a3uCa9wRyOzio-C7FVacOykuLoxCqTs3')
      );
    
      // return working doc and table base
      return (curDoc = DocumentApp.openById(blankDoc.getId()));
    }
    // get range and sort only for day from parameter
    function readBaseData(inDate) {
      var ssDoc = SpreadsheetApp.openById(
        '1ZCNO6Iae2RwDdKAlQX6TF5mpp4xHHB4v1mXK233uJls'
      ).getActiveSheet();
    
      // get filled range
      var data = ssDoc.getDataRange().getValues();
    
      // create new array with data to inDate,
      // for start from 1 because first row is text column headers
      var filteredData = new Array([]);
      for (i = 1; i < data.length; i++) {
        data[i][0] = convertDate(data[i][0]);
        if (data[i][0] == inDate && data[i][3] == 1) {
          filteredData[i - 1] = data[i];
        }
      }
      return filteredData;
    }


    Что к чему и как - лучше описать в техническом задании и обратиться к специалисту.
    Ответ написан
    Комментировать
  • Google Apps Script как выбрать только гугл таблицы?

    oshliaer
    @oshliaer Куратор тега Google Apps Script
    Google Products Expert
    Возможно, следующая выборка для файлов вам подойдет лучше

    var files = DriveApp.searchFiles('mimeType="application/vnd.google-apps.spreadsheet"');


    Про DriveUser. Это объект системы, поэтому вам необходимо воспользоваться одним из его методов, для получения информации. Например,

    ...
    file.getOwner().getEmail()
    ...
    Ответ написан
    3 комментария
  • Как в Google Script библиотеку заменить на веб-приложение?

    oshliaer
    @oshliaer Куратор тега Google Apps Script
    Google Products Expert
    Скорее всего в коде ничего менять не нужно. Нужно постараться поменять свое представление о проблеме. Это не настольный офис, где кинул пару симлинков, и программа довольна.

    Вы должны изменить подход к решению задачи. Одним из самых удачных вариантов является использование веб-приложения как центральной программы. Но у нее есть свои ограничения, например, чтобы отправить алерт в какую-то Таблицу, придется попыхтеть. Но если пользователь нажимает на кнопку в самом веб-приложении, то вы можете выдавать алерт на его стороне.
    Ответ написан
    Комментировать
  • Как понять, что введенное значение является датой?

    oshliaer
    @oshliaer Куратор тега Google Apps Script
    Google Products Expert
    Вопрос больше к JavaScript, а не к Google Apps Script.

    Проверяйте наличие чего-либо в переменной, а потом проверьте, имеет ли эта переменная метод getTime.

    function isDate(value){
      return value && value.getTime;
    }


    Академический способ, который раньше не работал в скриптах, потому что не хватало чего-то.

    function isDate(date){
      return date instanceof Date && !isNaN(date.valueOf());
    }


    Решение
    Пример с неопределенным результатом без вызова ошибки
    var birthday1 = ss1.getRange("D8").getValue();
    var birthday = isDate(birthday1) ?
      Utilities.formatDate(birthday1, "GMT+3", "dd-MM-yyyy") : 
      undefined;
    Ответ написан
    2 комментария
  • Удаление символов до определенного сочетания в ячейке таблицы Google Sheets/Excel?

    oshliaer
    @oshliaer Куратор тега Google Apps Script
    Google Products Expert
    Не получается скриптами, попробуйте для начала формулами. Например,

    =ARRAYFORMULA(REGEXEXTRACT(A2:A;".*?gclid=(.*)$"))

    5c6fcc3c98a59827080515.png

    Пример скрипта. Переписывает данные в диапазоне

    function run() {
      const sheet = SpreadsheetApp.getActiveSpreadsheet()
        .getSheetByName('Решение (скриптами)');
      const range = sheet.getRange('A:A');
      const values = range.getValues();
      const data = values.map(row => {
        const [undefined, value] = String(row[0]).split('gclid=');
        return [value ?? ''];
      });
      range.setValues(data);
    }


    Таблица с примерами https://docs.google.com/spreadsheets/d/1Nll6tQ-I9a...
    Ответ написан
    Комментировать
  • Google forms POST или api?

    oshliaer
    @oshliaer Куратор тега Google Apps Script
    Google Products Expert
    Единственный на данный момент "правильный" способ управления Формами - использование Google Apps Script. Для реализации API используйте специальный триггер `doGet`.

    У вас должно получиться что-то вроде этого

    function doGet(e){
      /* если `e` содержит параметр на отключение Формы */
      form.setAcceptingResponses(false);
      /* если `e` содержит параметр на разрешение Формы принимать ответы */
      form.setAcceptingResponses(true);
    }


    Опубликуйте скрипт как веб приложение и дергайте из питона сколько лезет. Если сильно заморочиться, то можно опубликовать как API и контролировать доступ к скрипту на уровне авторизации пользователя.
    Ответ написан
    Комментировать
  • Как сравнить два диапазона и выбрать нужные данные?

    oshliaer
    @oshliaer Куратор тега Google Apps Script
    Google Products Expert
    Вам необходимо строить индекс по принципу баз данных, иначе в циклах все будет очень сложно.

    function main() {
      var dataSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(
        'данные'
      );
      var dataArray = dataSheet.getDataRange().getValues();
      var listSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(
        'список сайтов'
      );
      var listArray = listSheet.getDataRange().getValues();
      // Строим индекс
      var listIndex = listArray.map(function(r){
        return r[0];
      });
      for (var j = 1; j < dataArray.length; j++) {
        if(dataArray[j][0] === '') continue;
        var pos = listIndex.indexOf(dataArray[j][0]);
        if (pos >= 0) {
          // Обновляем
          listSheet.getRange(pos + 1, dataArray[j].length + 1).setValue(new Date());
        } else {
          // Добавляем
          listSheet.appendRow([].concat(dataArray[j], new Date()));
        }
      }
    }
    Ответ написан
    Комментировать
  • Google Apps Script для Google таблиц: как переименовать все листы в таблице скриптом?

    oshliaer
    @oshliaer Куратор тега Google Apps Script
    Google Products Expert
    Вам просто необходимо получить листы Таблицы, и переименовать их как надо.

    Решение

    SpreadsheetApp.openById('blah-blah')
      .getSheets()
      .forEach(function(sheet) {
        var name = sheet.getRange('J2').getValue();
        if (name)
          try {
            sheet.setName(name);
          } catch (error) {
            console.error('CATCHED', error);
          }
      });


    Как делают

    Основная идея заключается в том, чтобы перебрать все элементы массива, отсортировать лишнее, а с выбранными элементаи произвести действие. Функция userActionRenameSheets демонстрирует это.

    /* exported userActionRenameSheets */
    
    /**
     * Действие пользователя или триггера. Внешний вызов без параметров
     */
    function userActionRenameSheets() {
      var spreadsheet = SpreadsheetApp.openById('blah-blah');
    
      /** @type {filterSheets} */
      var filterSheets = function(sheet) {
        return true;
      };
    
      /** @type {renameRule} */
      var renameRule = function(sheet) {
        var name = sheet.getRange('J2').getValue();
        if (name)
          try {
            sheet.setName(name);
          } catch (error) {
            console.error('CATCHED', error);
          }
        return sheet;
      };
    
      var sheets = renameSheetsByCellValue_(spreadsheet, filterSheets, renameRule);
      // Делать что-нибудь дальше
    }
    
    /**
     * Переименовывает листы в Таблице согласно заданным правилам
     *
     * @param {GoogleAppsScript.Spreadsheet.Spreadsheet} spreadsheet Таблица,
     *         в которой производим переименование
     * @param {filterSheets} Фильтр листов на всякий случай, вдруг что-то надо да пропустить
     * @param {renameRule} Правило переименования, может возвращать что угодно
     * @param {any[]} Массив отфильрованных результатов функции renameRule
     */
    function renameSheetsByCellValue_(spreadsheet, filterSheets, renameRule) {
      var res;
      var sheets = spreadsheet.getSheets();
      if (filterSheets) res = sheets.filter(filterSheets) || sheets;
      if (renameRule) res = res.map(renameRule);
      return res;
    }
    
    /**
     * Фильтр листов
     * @callback filterSheets
     * @param {GoogleAppsScript.Spreadsheet.Sheet} sheet Текущий лист
     * @param {number} index Текущий индекс массива
     * @param {GoogleAppsScript.Spreadsheet.Sheet[]} sheets Текущий массив
     * @returns {boolean}
     */
    
    /**
     * Правило переименования
     * @callback renameRule
     * @param {GoogleAppsScript.Spreadsheet.Sheet} sheet Текущий лист
     * @param {number} index Текущий индекс массива
     * @param {GoogleAppsScript.Spreadsheet.Sheet[]} sheets Текущий массив
     * @returns {any}
     */
    Ответ написан
  • Как настроить отправку данных из таблицы в виде одной строки в другую закрытую таблицу?

    oshliaer
    @oshliaer Куратор тега Google Apps Script
    Google Products Expert
    Действительно, это не так очевидно с первого раза, но, когда сталкиваешься, то понимаешь, что пользователь должен быть редактором, чтобы вносить изменения. Чтобы решить эту задачу необходимо предоставить другой интерфейс для ввода данных.

    Замените myFunction на что-то вроде:
    function recordToMain(){
      // Берет диапазон 'Источник!B4:B8' активной Таблицы, т.о. это встроенный скрипт
      var data = SpreadsheetApp.getActive().getRange('Источник!B4:B8')
      .getValues().map(function(row){return row[0];});
      var url = 'https://script.google.com/macros/s/ZZZ/exec';
      var options = {
        method: 'POST',
        headers: {
          ContentType: 'application/json'
        },
        payload: JSON.stringify(data),
        muteHttpExceptions: true
      };
      UrlFetchApp.fetch(url, options); 
    };


    Так же создайте новый проект скриптов, в котором создайте функцию вроде:
    function doPost(e) {
      SpreadsheetApp.openById('YYY') // Должна существовать
      .getSheetByName('Приемник')    // Должен быть лист 'Приемник'
      .appendRow([new Date()].concat(JSON.parse(e.postData.contents)));
    }

    Когда вы опубликуете новый проект для всех от имени себя, то получите url_master для первой функции.
    Ответ написан
  • Загрузка картинок из google drive. Какой правильный путь?

    oshliaer
    @oshliaer Куратор тега Google Apps Script
    Google Products Expert
    Оба метода сопоставимы и не имеют никакой разницы в контексте инфраструктуры Гугл. Это все сервисы Диска и дергаете вы АПИ Диска. Которое само по себе не дойная корова. Не стоит расчитывать, что при частом запросе изображений вы не увидите отказа в доступе или отказа в соединении. Исполььзуйте Google Cloud Storage. Потратьте уже наконец $10 в год и получите цивильный, быстрый, надежный удобный доступ к сетевому шарингу.
    Ответ написан
  • Как изменить язык в Google Apps Script?

    oshliaer
    @oshliaer Куратор тега Google Apps Script
    Google Products Expert
    5c0ffc9a09bee441507346.png
    Ответ написан
    Комментировать