Автоматически добавлять новые строки в отчет при добавлении нового счета в папку - PullRequest
0 голосов
/ 22 сентября 2018

Во-первых, я буду честен с тобой.Я действительно новичок в написании скриптов и JavaScript.Я думаю, что я достаточно талантлив, чтобы понять, что я делаю, все же.

Я внештатный сотрудник, и я управляю всеми своими счетами с помощью пакета документов Google в Sheets.Итак, у меня есть папка на моем диске, которая содержит все мои Счета в виде отдельных электронных таблиц, и у меня также есть другая отдельная электронная таблица для отчетов, которая находится в другой папке.Лист отчетов получает свои данные непосредственно из листов счетов, используя функцию IMPORTRANGE.До сих пор я всегда все настраивал вручную в отчете.Я пытаюсь автоматически добавлять новые строки в отчет по мере добавления нового счета в папку.

Я нашел скрипт, который, кажется, выполняет то, что я хочу, но нене работает после того, как я изменил его.Первоначально был создан скрипт для получения адресов электронной почты из листов Google и автоматического импорта их в один мастер-лист.

Я пытался изменить его для своих нужд, но получаю сообщение об ошибке.

Код, который янайдено с форума Google.Запрос был: «Я хочу автоматически извлекать столбец адресов электронной почты из листа Google каждый раз, когда он добавляется на мой диск Google. Это вообще возможно? В настоящий момент лист начинается как лист Excel, но преобразуетсяна лист Google при загрузке через синхронизацию Multcloud. Я знаю, что могу использовать команду importrange с ключом листов, чтобы импортировать нужный диапазон из этого конкретного листа, но есть ли способ получить ключ новых загруженных листов иимпортировать эти диапазоны также?

Если нет, кто-нибудь может придумать лучший способ импортировать диапазон в один и тот же лист каждый раз, когда на диск добавляется новый лист. "

и ответбыло: «Я настроил сценарий, который я использовал для чего-то похожего, что, надеюсь, делает то, что вы ищете. Прежде чем использовать его, создайте папку, в которую вы будете загружать все свои таблицы. Получите идентификатор папкиэто и вставьте его в код, где я прокомментировал. Затем используйте скрипт ниже на листе, где вы быКе, чтобы извлечь все ваши адреса электронной почты.Примечание: я предположил, что электронные письма хранятся в столбце А, если это не так, просто измените код в соответствии с требованиями.Код создает два новых листа, один для электронных писем и один для URL-адресов файлов в папке.Письма добавляются по одному столбцу за раз.Каждый столбец соответствует электронной таблице в папке.URL-адреса сохраняются, чтобы при повторном запуске дубликаты не создавались.Есть одна проблема - вы должны «соединить листы» вручную после выполнения кода.На данный момент кажется, что этого избежать невозможно, но это не займет много времени. "

С исходным кодом:

function emailAddressExtractor() {
  // Change folder ID to match yours. Upload your spreadsheets (with the email addresses) into this folder. 
  var folder = DriveApp.getFolderById("1j3GZqUgVOwywARvKyRJnj6p_gLNMCk__"); 
  var files = folder.getFiles(), file;
  var ss = SpreadsheetApp.getActiveSpreadsheet();


  // Creates sheets for "Email Addresses" and "List of URLs", unless they exist already
  if (ss.getSheetByName("Email Addresses") == null) {
    var create = ss.insertSheet("Email Addresses");
  }
  if (ss.getSheetByName("List of URLs") == null) {
    var create = ss.insertSheet("List of URLs");
  }


  // Variables to make setting active sheet easier
  var emailAddressesSheet = SpreadsheetApp.setActiveSheet(ss.getSheetByName("Email Addresses"));
  var listOfUrlsSheet = SpreadsheetApp.setActiveSheet(ss.getSheetByName("List of URLs"));


  // Finds last rows and columns of emails and URLs, so that they are not overwritten later by new emails and URLs
  var oldUrls = listOfUrlsSheet.getRange("A1:A").getValues();
  var oldUrlsLength = oldUrls.filter(String).length +1;
  var oldEmails = emailAddressesSheet.getRange("1:1").getValues();
  var oldUrlsLength = oldEmails.filter(String).length;


  // Counts number of files in folder and gets URLs 
  var urlsList = [];
  var counter = 0;
  while (files.hasNext()) {
    counter++;
    file = files.next();
    var urls = [];
    urls.push(file.getUrl())
    urlsList.push(urls);
  }


  // Finds new URLs by comparing to old ones 
  Array.prototype.diff = function(a) {
    return this.filter(function(i) {return a.indexOf(i) < 0;});
  }
  var diff = urlsList.diff(oldUrls);  // This is the difference between the old URLs and the new ones
  Logger.log("\n" + diff);

  for (var i = 0; i < diff.length; i++) { // This loop inserts the new URLs into the spreadsheet. This is done so that the next time the code is run it won't duplicate the emails
    var row = i + oldUrlsLength;
    var diffRange = listOfUrlsSheet.getRange("A"+row)
    diffRange.setValue(diff[i]);
  }


  // Inserts IMPORTRANGE formula into sheet, taking column A out of each spreadsheet in the designated folder
  for (var i = 0; i < counter; i++) {  
    var fileUrl = urlsList[i];
    var cell = emailAddressesSheet.getRange(1, oldUrlsLength+i);
    cell.setValue("=IMPORTRANGE(" + '"' + fileUrl + '"' + "," + '"' + "Sheet1!A:A" + '"' + ")" );  

  }
}

Вот код, который у меня естьизменен теперь, чтобы получить только номер счета:

function dataExtractor() {
  // Change folder ID to match yours. Upload your spreadsheets (with the Numbers) into this folder. 
  var folder = DriveApp.getFolderById("1jH6M0Ijsepe0MnDLULrmfHHJ8R_Fd3-M"); 
  var files = folder.getFiles(), file;
  var ss = SpreadsheetApp.getActiveSpreadsheet();


  // Creates sheets for "Data" and "List of URLs", unless they exist already
  if (ss.getSheetByName("Report") == null) {
    var create = ss.insertSheet("Report");
  }
  if (ss.getSheetByName("List of URLs") == null) {
    var create = ss.insertSheet("List of URLs");
  }


  // Variables to make setting active sheet easier
  var reportSheet = SpreadsheetApp.setActiveSheet(ss.getSheetByName("Report"));
  var listOfUrlsSheet = SpreadsheetApp.setActiveSheet(ss.getSheetByName("List of URLs"));


  // Finds last rows and columns of Data and URLs, so that they are not overwritten later by new emails and URLs
  var oldUrls = listOfUrlsSheet.getRange("A1:A").getValues();
  var oldUrlsLength = oldUrls.filter(String).length +1;
  var oldNumber = reportSheet.getRange("B7:B").getValues();
  var oldUrlsLength = oldNumber.filter(String).length;


  // Counts number of files in folder and gets URLs 
  var urlsList = [];
  var counter = 0;
  while (files.hasNext()) {
    counter++;
    file = files.next();
    var urls = [];
    urls.push(file.getUrl())
    urlsList.push(urls);
  }


  // Finds new URLs by comparing to old ones 
  Array.prototype.diff = function(a) {
    return this.filter(function(i) {return a.indexOf(i) < 0;});
  }
  var diff = urlsList.diff(oldUrls);  // This is the difference between the old URLs and the new ones
  Logger.log("\n" + diff);

  for (var i = 0; i < diff.length; i++) { // This loop inserts the new URLs into the spreadsheet. This is done so that the next time the code is run it won't duplicate the emails
    var row = i + oldUrlsLength;
    var diffRange = listOfUrlsSheet.getRange("A"+row)
    diffRange.setValue(diff[i]);
  }


  // Inserts IMPORTRANGE formula into sheet, taking column A out of each spreadsheet in the designated folder
  for (var i = 0; i < counter; i++) {  
    var fileUrl = urlsList[i];
    var cell = rapportSheet.getRange(1, oldUrlsLength+i);
    cell.setValue("=IMPORTRANGE(" + '"' + fileUrl + '"' + "," + '"' + "Sheet1!J8" + '"' + ")" );  

  }
}

Мои номера счетов расположены в ячейке J8 каждого счета, и в отчете они начинаются в ячейке B7, спускаясь вниз по всему столбцу.

Ошибка, которую я получаю от редактора сценариев Google: диапазон не найден (строка 50, файл "Код"). Эта строка будет выглядеть так:ссылка на шаблон счета, который у меня есть: https://docs.google.com/spreadsheets/d/1wE4YtvdwBBiriRcuv-k8oFyKyEuN9SSIuKewf106cdg/edit?usp=sharing

Вот ссылка на шаблон отчета, который я использую: https://docs.google.com/spreadsheets/d/1qScJItssyaxpsqAXVnMMrmUlBYUicAsX7CQZA7ky0Rg/edit?usp=sharing

Идентификатор папки для папки моих счетов-фактур будет выглядеть так:1KlGD5Qj9C5pMrOdHSwkYesK-yyq4udNC

Идентификатор папки для моего отчета будет выглядеть следующим образом: 1q0Ta7h4aQHaemgwlWWMS_5YBa1WH-rSz

Большое спасибо, ребята !!! * 1035

1 Ответ

0 голосов
/ 24 сентября 2018

Структура ваших счетов-фактур, листов и таблиц не сразу очевидна.С большим уважением, в будущем вы бы хорошо предоставили как можно больше информации о деталях сценария и целях вашего отчета.Например, в этом случае неясно, хранятся ли счета в отдельных таблицах (в нескольких файлах), или это листы в одной таблице (в одном файле).Любой сценарий прост в управлении, но остается сделать предположения.В любом случае, IMHO, код, который вы получили, не был настолько полезен, и вы могли бы столкнуться с ним по касательной.

Следующий код создает отчет на основе счетов, которые существуют как отдельные листы в одном "счет-фактура ».Электронная таблица, содержащая отчет, находится в отдельной электронной таблице, хотя не совсем понятно, зачем вам это нужно.Лично у меня был бы отчет в моей электронной таблице "Счета".

Электронная таблица счетов = so_52459999_invoices
Это скриншот макета.Вы можете просмотреть данные счета-фактуры, а также несколько вкладок для каждого счета-фактуры.Также есть вкладка (raw_data), которая исключена из отчета.enter image description here


Электронная таблица отчета = so_52459999_report
Это снимок экрана макета отчета.Можно было бы нажать кнопку для запуска макроса / скрипта на этой странице, чтобы облегчить процесс.Я не "стер" содержимое любого существующего отчета;это была тонкая настройка, которую вы можете решить, хотите ли вы сделать или нет.Отчет также принимает КАЖДЫЙ счет.Предположительно, поскольку год истекает, вы меньше беспокоитесь о счетах с начала года, но кодирование с учетом даты также является вариантом.enter image description here


function so_5245999() {

    // identify the current spreadsheet
    var ss = SpreadsheetApp.getActiveSpreadsheet()

    // get the Spreadsheet name
    var ReportSheetName = ss.getName();

    // Get the spreadhseet ID
    var ReportSheetID = ss.getId();
    //Logger.log('Report Sheet Name = '+ReportSheetName);
    //Logger.log('Report Sheet ID = '+ReportSheetID);

    // open the Invoices Spreadsheet
    // Supplied the ID
    var InvoiceSheetID = "14PfY_0oeCnr8Z1L-iiHgehAWC3HMsUiv6x1IcK-PLSE";

    var InvoiceSheet = SpreadsheetApp.openById(InvoiceSheetID);

    // get the spreadsheet name
    var InvoiceSheetName = InvoiceSheet.getName();
    //Logger.log('Invoice Sheet Name = '+InvoiceSheetName);
    //Logger.log('Invoice Sheet ID = '+InvoiceSheetID);

    // Move the cursor to cell A3 on Report sheetthis is the start of the invoice report
    var RepSheetActive = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
    var RepSheetRange = RepSheetActive.getRange('A3:A3');
    RepSheetActive.setActiveRange(RepSheetRange);
    //Logger.log('Report sheet = '+ReportSheetName+', and invoice sheet = '+InvoiceSheetName);

    // count the number of invoices
    InvoiceCount = invoiceCount();
    //Logger.log('Invoice count = '+InvoiceCount);  

    // set a varable for the startrow on the reports sheet
    var targetstartrow = 3;

    // Get the Invoice sheets
    var allInvSheets = InvoiceSheet.getSheets();

    // Loop through all the sheets
    for (var s in allInvSheets) {

        // Create some variables to make code and debugging  simpler
        var thisinvoice = allInvSheets[s]
        var thisInvoiceNumber = thisinvoice.getName();
        //Logger.log('Invoice sheet name = '+thisInvoiceNumber);
        //Logger.log('Record Number = '+s); 

        // How to modify startrow if the sheet isn't an invoice sheet and it is the first sheet.
        // Note: "s" is a string; must convert iot to a number.
        if (thisInvoiceNumber == "raw_data" && Number(s) == 0) {
            targetstartrow = targetstartrow + (Number(s));
            //Logger.log('AFTER1: targetstartrow = '+ targetstartrow);   
        }
        // How to modify startrow if the sheet isn't an invoice sheet and it is NOT the first sheet.
        if (thisInvoiceNumber == "raw_data" && !Number(s) == 0) {
            targetstartrow = targetstartrow + (Number(s) - 1);
            //Logger.log('AFTER2: targetstartrow = '+ targetstartrow);   
        }

        // OK, this is an ordinary invoice.
        if (thisInvoiceNumber !== "raw_data") {

            // define the source data
            source = thisinvoice.getRange(1, 2, 4, 1).getValues(); //row, column, numRows, numColumns
            //Logger.log("The values are " + source);


            // source data from a Columnar array to a Row array
            // This is important because Google Sheets don't allow "Transpose" when copying between spreadsheets.
            var rowdata = convertCol2Row(source);

            // Paste the Invoice data into the Report
            RepSheetActive.getRange(targetstartrow, 1, 1, source.length).setValues(rowdata); //row, column, numRows, numColumns

            // Increment the targetstartrow - i.e. move it down the page to the next row.
            targetstartrow = targetstartrow + 1;

        }


    } //end of  sheets loop.

}


// Utility to count the number of sheets in a spreadsheet.
// This assumes that there is one sheet that is not an invoice; that's why it returns sheets minus one.
function invoiceCount() {
    var invoiceSheet = SpreadsheetApp.openById("14PfY_0oeCnr8Z1L-iiHgehAWC3HMsUiv6x1IcK-PLSE");
    var sheets = invoiceSheet.getSheets().length;
    //if (sheets.length > 1) {
    //Logger.log("Number of sheets = "+sheets);
    //}
    return (sheets - 1);
}



// Function to convert an array from Columns to Rows
// Credit: Riel in https://stackoverflow.com/questions/32444009/google-sheets-script-copy-values-from-array-to-column
function convertCol2Row(column) {
    return [column.map(function(row) {
        return row[0];
    })];
}

ОБНОВЛЕНИЕ Следующее признает, что счета-фактуры являются отдельными электронными таблицами в их собственной папке («Счета-фактуры») иСводка отчета представляет собой отдельную электронную таблицу в отдельной папке.Следующий код предназначен для присоединения к электронной таблице отчетов.Я думаю, этого должно быть достаточно, чтобы вы пошли.

function so_5245999_02() {

    // declare the Invoice Folder name
    var your_folder_id = getInvFolderID('Invoices');

    //Logger.log('folder id = '+your_folder_id);
    //Logger.log('folder name = '+your_folder_id.getName());

    // get the ID for the Invoices folder
    var invfldr = DriveApp.getFolderById(your_folder_id);
    //Logger.log("invfldr: " + invfldr);

    //get the files in the Invoice folder
    var files = invfldr.getFiles();

    //loop through each file
    while (files.hasNext()) {

        //get the first file
        var thisfile = files.next();

        // get its name and ID
        var thisfilename = thisfile.getName();
        var thisfileid = thisfile.getId();
        //Logger.log('Name: file = '+thisfilename);
        //Logger.log('ID: file = '+thisfileid);

        // "open" the Invoice spreadsheet
        var InvoiceSheet = SpreadsheetApp.openById(thisfileid);

        // get all the sheets in the spreadsheet
        var allInvSheets = InvoiceSheet.getSheets();

        // Loop through all the sheets (even though there may onlky be one sheet)
        for (var s in allInvSheets) {

            //Logger.log(' s: '+ s);

            // get the first (and only) sheet
            var this_invoice = allInvSheets[s];
            //Logger.log(' this_invoice: '+ this_invoice);

            //get all the data fields
            var invoicenumber = InvoiceSheet.getRange("J8").getValues();
            //Logger.log('invoicenumber: '+invoicenumber);
            var clientname = InvoiceSheet.getRange("B12").getValues();
            //Logger.log('clientname: '+clientname);
            var invoicedate = InvoiceSheet.getRange("J5").getValues();
            //Logger.log('invoicedate: '+invoicedate);
            var invoiceamount = InvoiceSheet.getRange("K32").getValues();
            //Logger.log('invoiceamount: '+invoiceamount);
            var invoicedesc = InvoiceSheet.getRange("B18").getValues();
            //Logger.log('invoicedesc: '+invoicedesc);

            //wipe the value in any previous sheet.
            var sourcedata = new Array();

            // assign the data values to an array - leave room for cells to be used later
            sourcedata = [invoicenumber, invoicedate, " ", " ", clientname, invoicedesc, invoiceamount];
            //Logger.log('source data: '+ sourcedata);

            //Convert the array to one that will paste into a row
            var rowdata = convertColumn2Row(sourcedata);

            // declare the active spreadsheet
            var ss = SpreadsheetApp.getActiveSpreadsheet();

            //get the sheet
            var sheet = ss.getSheets()[0];

            //insert a new row
            sheet.insertRowAfter(6);

            // paste the data into the new row.
            var reportdestination = sheet.getRange(7, 2, rowdata.length, rowdata[0].length).setValues(rowdata); //row, column, numRows, numColumns

        } // end for  
    } // end while
} // end function

// Function to convert an array from Columns to Rows
// Credit: Riel in https://stackoverflow.com/questions/32444009/google-sheets-script-copy-values-from-array-to-column
function convertColumn2Row(column) {
    return [column.map(function(row) {
        return row[0];
    })];
}


function getInvFolderID(folderName) {
    var folders = DriveApp.getFolders();
    while (folders.hasNext()) {
        var folder = folders.next();
        if (folder.getName() == folderName) {
            return folder.getId();
        }
    }
}

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...