Script exceeds maximum execution time - google-apps-script

I am using a script to first copy a list of all terminated products from "data" tab of the sheet to the "terminated tab"
The data tab looks like below
The code checks if there is an end date written
if it is - the row is copied and pasted in the "terminated" tab
Once all rows (around 2000) are completed
the code the deletes all rows from the "data" tab that have an end date on it
But the code is not very efficient and data is huge - I get a "maximum execution time exceeded" error
function movingTerms() {
var app = SpreadsheetApp ;
var sheet1 = app.getActiveSpreadsheet().getSheetByName("data") ;
var sheet3 = app.getActiveSpreadsheet().getSheetByName("Terminations");
var range1 = sheet1.getRange(2, 1, sheet1.getLastRow() - 1,9);
var range3 = sheet3.getRange(2, 1, sheet3.getLastRow(), 9);
var values1 = range1.getValues();
var values3 = range3.getValues();
var rowcount = sheet1.getLastRow();
var row_deleted = 0;
for (var i = 0; i < (sheet1.getLastRow() - 1); i++)
{
if (values1[i][4] !== "")
{
var rowtodelete = sheet1.getRange(i + 2, 1, 1, 10);
var rowtoadd = sheet3.getRange(sheet3.getLastRow() + 1, 1);
rowtodelete.copyTo(rowtoadd);
}
}
for (var k = 0; k < values1.length; k++)
{
var row = k + 1 - row_deleted;
if (values1[k][4] !== "")
{
var getridof = row +1;
sheet1.deleteRow(getridof);
row_deleted++;
}
}
}

I generally like to see the spreadsheet to do this correctly but this is the way that I would do it.
function movingTerms() {
var ss=SpreadsheetApp.getActive();
var sheet1=ss.getSheetByName("data") ;
var sheet3=ss.getSheetByName("Terminations");
var range1=sheet1.getRange(2, 1, sheet1.getLastRow()-1,9);
var range3=sheet3.getRange(2, 1, sheet3.getLastRow(),9);//You don't really need this
var values1=range1.getValues();
var values3=range3.getValues();//You don't really need this
var rowcount=sheet1.getLastRow();
var rowsdeleted = 0;
for (var i=0;i<values1.length;i++) {
if (values1[i][4]!="") {//column5
var rowtodelete = sheet1.getRange(i-rowsdeleted+2, 1, 1, 10);
var rowtoadd = sheet3.getRange(sheet3.getLastRow()+1,1);//You could also append to sheet 3 if you wish
rowtodelete.copyTo(rowtoadd);
sheet1.deleteRow(i-rowsdeleted+2);
rowsdeleted++;
}
}
}

Related

Iterate through column A and do until empty cell

My script is working but it times out. I am unsure as to what I can do to keep it from doing this.
function archived(e) {
var sheet = SpreadsheetApp.getActive().getSheetByName('IVA');
const targetSheet = e.source.getSheetByName('Archived Videos');
const numColumnsToMove = 20;
var sheetTo = SpreadsheetApp.getActive().getSheetByName('IVA');
var myValues = sheetTo.getRange('A:A').getValues();
var i;
for (i = 0; i < myValues.length; i++) {
if (myValues[i][0] === '')
return i + 1;
const rangeToMove = sheet.getRange(e.range.rowStart, 1, 1, numColumnsToMove);
const values = rangeToMove.getValues();
appendRowsV(targetSheet, values, 1);
sheet.deleteRows(e.range.rowStart, 1);
var lRow = sheet.getLastRow();
var lCol = sheet.getLastColumn(), range = sheet.getRange(lRow,1,1,lCol);
sheet.insertRowsAfter(lRow, 1);
range.copyTo(sheet.getRange(lRow+1, 1, 1, lCol), {contentsOnly:false});
}
}
As an FYI my sheet has 1500 rows and 15 columns. don't know if that is important or not.
Just in case. As far as I can tell from your code you're trying to append all data from the sheet 'IVA' at the bottom of the sheet 'Archived Videos'. It can be done this way:
function myFunction() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var src_range = ss.getSheetByName('IVA').getDataRange();
var dest_sheet = ss.getSheetByName('Archived Videos');
var last_row = dest_sheet.getLastRow() + 1;
var dest_range = dest_sheet.getRange('A' + last_row);
src_range.copyTo(dest_range);
}

Create an array of values that were looped through

I have a spreadsheet where each row in "MASTER" sheet is a task. It has checkboxes to check if it's done.
On another sheet, "Sin despachar", the data is filtered so that only the tasks which are not done show. There I have empty checkboxes to check when an incomplete task is completed.
I wrote a script so that when a button is pressed, it loops through the whole column in "Sin despachar" to see if checkboxes are checked, and for those that are, it changes the value in a master sheet.
I would like to have a confirmation pop up that mentions all the tasks it'll edit, but for that I need to somehow retrieve that list when the script runs, and I don't know how.
So what I need is to create an array or something else that contains the names of the tasks with the checkbox checked.
Does anyone know how to do this?
The task names are in column 4, and the checkboxes are in column 18.
Thanks in advance!!
function marcarEtiquetado() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = ss.getSheetByName("Sin despachar");
var sheetRange = s.getDataRange();
var sheetValues = sheetRange.getValues();
for (var i=sheetRange.getLastRow()-1; i>1; i--) {
// si valor en columna R (etiquetado) = TRUE
if ( sheetValues[i][17] === true) {
var checkboxRange = s.getRange(i, 18);
var usuariosRange = s.getRange(i, 3)
Logger.log(usuariosRange)
var targetSheet = ss.getSheetByName("*MASTER*");
var targetRow = sheetValues[i][1];
var targetRange = targetSheet.getRange( targetRow, 16);
var targetTS = targetSheet.getRange( targetRow, 17);
checkboxRange.setValue(false)
targetRange.setValue(true);
targetTS.setValue(new Date()).setNumberFormat("dd-mm-yy hh:mm")
} ;
}
s.getRange(3, 18, s.getLastRow()-2).setValue(false)
}
You use alerts to confirm for every checked box individually either and action shall be carried out.
Sample:
function marcarEtiquetado() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = ss.getSheetByName("Sin despachar");
var sheetRange = s.getDataRange();
var sheetValues = sheetRange.getValues();
var ui = SpreadsheetApp.getUi();
for (var i=sheetRange.getLastRow()-1; i>1; i--) {
// si valor en columna R (etiquetado) = TRUE
if ( sheetValues[i][17] === true) {
var checkboxRange = s.getRange(i, 18);
var usuariosRange = s.getRange(i, 3)
var targetSheet = ss.getSheetByName("*MASTER*");
var targetRow = sheetValues[i][1];
var targetRange = targetSheet.getRange(targetRow, 16);
var targetTS = targetSheet.getRange(targetRow, 17);
var response = ui.alert('Do you want to set the timestamp for row ' + (i+1) + '?', ui.ButtonSet.YES_NO);
// Process the user's response.
if (response == ui.Button.YES) {
checkboxRange.setValue(false)
targetRange.setValue(true);
SpreadsheetApp.getActiveSpreadsheet().toast("Timestamp will be set for row " + (i+1));
targetTS.setValue(new Date()).setNumberFormat("dd-mm-yy hh:mm")
} else {
SpreadsheetApp.getActiveSpreadsheet().toast("Timestamp will not be set for row " + (i+1));
}
} ;
}
s.getRange(3, 18, s.getLastRow()-2).setValue(false)
}
If this is not what you wanted and you prefer to have a single confirmation dialog for all checked boxes, you can implement a help array and string as following:
function marcarEtiquetado2() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = ss.getSheetByName("Sin despachar");
var sheetRange = s.getDataRange();
var sheetValues = sheetRange.getValues();
var ui = SpreadsheetApp.getUi();
var rowKeeper = [];
var rowArray = ['\n'];
for (var i=sheetRange.getLastRow()-1; i>1; i--) {
// si valor en columna R (etiquetado) = TRUE
if ( sheetValues[i][17] === true) {
rowKeeper.push(i);
rowArray.push(i+1);
}
}
for (k = 0; k < rowArray.length-4; k += 5) {
rowArray[k+4] = rowArray[k+4] + "\n";
}
var rowString = rowArray.join(" ");
Logger.log(rowString);
var response = ui.alert('Do you want to set the timestamp for rows ' + rowString + '?', ui.ButtonSet.YES_NO);
// Process the user's response.
if (response == ui.Button.YES) {
for (var j = 0; j < rowKeeper.length; j++){
var i = rowKeeper[j];
var checkboxRange = s.getRange(i, 18);
var usuariosRange = s.getRange(i, 3)
var targetSheet = ss.getSheetByName("*MASTER*");
var targetRow = sheetValues[i][1];
var targetRange = targetSheet.getRange(targetRow, 16);
var targetTS = targetSheet.getRange(targetRow, 17);
checkboxRange.setValue(false)
targetRange.setValue(true);
targetTS.setValue(new Date()).setNumberFormat("dd-mm-yy hh:mm")
}
} else {
SpreadsheetApp.getActiveSpreadsheet().toast("No action will be carried out");
}
s.getRange(3, 18, s.getLastRow()-2).setValue(false)
}

Apps Script: Loop Function to Submit Active Google Sheet entries to running log sheet in same file?

Looking to loop through the following script to set values in my target sheet for all entries below cell a21 in the 'order entry template' i've created in the 'PO Template' sheet.
function submit() {
var app = SpreadsheetApp;
var activeSheet = app.getActiveSpreadsheet().getSheetByName("POTemplate");
var PONo = activeSheet.getRange("N3").getValue();
var PODate = activeSheet.getRange("N4").getValue();
var SKU = activeSheet.getRange("a22").getValue();
var SKUDesc = activeSheet.getRange("d22").getValue();
var SKUQty = activeSheet.getRange("k22").getValue();
var UtCost = activeSheet.getRange("m22").getValue();
var ExtCost = activeSheet.getRange("p22").getValue();
var target = "POHistory";
var targetSheet = app.getActiveSpreadsheet().getSheetByName(target);
targetSheet.getRange(2, 1).setValue(PONo);
targetSheet.getRange(2, 2).setValue(PODate);
targetSheet.getRange(2, 3).setValue(SKU);
targetSheet.getRange(2, 4).setValue(SKUDesc);
targetSheet.getRange(2, 5).setValue(SKUQty)
targetSheet.getRange(2, 6).setValue(UtCost);
targetSheet.getRange(2, 7).setValue(ExtCost);
}
Here you are! Need to run now, I'll add comments later:
function submit() {
var app = SpreadsheetApp;
var tplSheet = app.getActiveSpreadsheet().getSheetByName("POTemplate");
// POTemplate range size
// I prefer not having ranges in A1 notation when I'm going to iterate
var tplFRow = 22, tplLRow = tplSheet.getLastRow();
var tplRowsNum = tplLRow - tplFRow + 1;
var tplFCol = 1, tplLCol = 16;
var tplColsNum = tplLCol - tplFCol + 1;
// Get all data at once: less getValue() calls, much faster
var rangeData = tplSheet.getRange(22, 1, tplRowsNum, tplColsNum).getValues();
// Column indexes to filter (A, D, K, M, P)
var colIndexes = [0, 3, 10, 12, 15];
var fData = filterByIndexes(rangeData, colIndexes);
var target = "POHistory";
var targetSheet = app.getActiveSpreadsheet().getSheetByName(target);
// Set size of destination range in POHistory sheet
var tgtRow = targetSheet.getLastRow() + 1;
var tgtRowsNum = fData.length - tgtRow + 1;
var tgtCol = 1;
var tgtColsNum = fData[0].length - 1 + 1;
// Set all values at once
targetSheet.getRange(tgtRow, tgtCol, tgtRowsNum, tgtColsNum).setValues(fData);
}
// Function to extract only the columns you need
function filterByIndexes(twoDArr, indexArr) {
var fData = [];
// Transpose Array to get only the column needed
twoDArr = twoDArr.transpose();
for(var i=0; i<indexArr.length; i++) {
fData.push(twoDArr[indexArr[i]]);
}
// Transpose result Array
return fData.transpose();
}
// Prototype function to transpose a 2D Array
Array.prototype.transpose = function() {
var a = this,
w = a.length ? a.length : 0,
h = a[0] instanceof Array ? a[0].length : 0;
if (h === 0 || w === 0) {return [];}
var i, j, t = [];
for (i = 0; i < h; i++) {
t[i] = [];
for (j = 0; j < w; j++) {
t[i][j] = a[j][i];
}
}
return t;
};

GetCell -> GetValue -> SetValue fails

I want to make the below mentioned code working but it doesn't - nothing happens when I run it (also no error), that means the username (sUserName) doesn't get saved in the spreadsheet... And also I don't understand why the columns cant start with 2, 3, 4 (then the timestamp can stay in column #1) instead 1, 2, 3 - if so I get an error.
Here is the code:
var userNameColumn = 1; //Column where the user name is written
var subTypeColumn = 2; //Column where the submitter type is written ex. "Requester"
var sUserNameColumn = 3; //Column where the user name is saved
function saveUserName() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheets()[0];
var rows = sheet.getDataRange();
var numRows = rows.getNumRows();
for (var i = 1; i <= numRows; i++) {
var userNameCell = rows.getCell(i, userNameColumn);
var subTypeCell = rows.getCell(i, subTypeColumn);
var sUserNameCell = rows.getCell(i, sUserNameColumn);
if(sUserNameCell.isBlank() && subTypeCell.getValue() === 'Requester') {
sUserNameCell.setValue(userNameCell)
};
}
}
Here is the link for my spreadsheet and code:
Google Spreadsheet
See if this helps
function saveUserName() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheets()[0];
var rows = sheet.getDataRange().getValues();
for (var i = 1; i < rows.length; i++) {
var userNameCell = rows[i][1];
var subTypeCell = rows[i][2];
var sUserNameCell = rows[i][3];
if (!sUserNameCell && subTypeCell === 'Requester') sheet.getRange(i+1,4).setValue(userNameCell)
}
}

Overlapping Date Formatting in Google Spreadsheet

I just started exploring these spreadsheet scripts on Google Docs. I want to write a script that finds date overlaps between projects (changes the bg color of the given cell to red) and creates a new column that shows the number of conflicts on that project type. If you can provide me some examples or a way to do it, I would be very appreciated.
Here is my data set.
Data
What I tried is this. This only works for the first column though.
function formatting() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Sheet1'); // get the sheet
var columnF = sheet.getRange(1, 6, sheet.getLastRow(), 1).setBackgroundColor('white'); // get all the rows and clear colors
var columnG = sheet.getRange(1, 7, sheet.getLastRow(), 1).setBackgroundColor('white'); // get all the rows and clear colors
var fValues = columnF.getValues(); // get the values
var gValues = columnG.getValues();
var day = 24*3600*1000
Logger.log(gValues)
var startDay1 = parseInt(fValues[0][0].getTime()/day)
var endDay1 = parseInt(gValues[0][0].getTime()/day)
var startDay2 = parseInt(fValues[1][0].getTime()/day)
var endDay2 = parseInt(gValues[1][0].getTime()/day)
if (startDay1<endDay2 && startDay2<endDay1) {sheet.getRange(1, 6, 1, 1).setBackgroundColor('red')}
else {sheet.getRange(1, 6, 1, 1).setBackgroundColor('green')}
}
The code needed to loop through each row. Not sure how you want to contend with the last project, since there is no date to compare it to.
An easy way to keep count of the projects flagged red is to create a javascript object (projects), and store each of the projects, and their counts. Here is some documentation on javascript objects: Javascript.info - Objects
function formatting() {
try{
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Sheet1'); // get the sheet
// Going to need the column for project type
var projects = {};
var eValues = sheet.getRange(1, 5, sheet.getLastRow(), 1).getValues();
var columnF = sheet.getRange(1, 6, sheet.getLastRow(), 1).setBackgroundColor('white'); // get all the rows and clear colors
var columnG = sheet.getRange(1, 7, sheet.getLastRow(), 1).setBackgroundColor('white'); // get all the rows and clear colors
var fValues = columnF.getValues(); // get the values
var gValues = columnG.getValues();
var day = 24*3600*1000
Logger.log(gValues)
// loop through all the rows in the dataset
for(var r = 0; r < (fValues.length - 1); r++){
var startDay1 = parseInt(fValues[r][0].getTime()/day);
var endDay1 = parseInt(gValues[r][0].getTime()/day);
var startDay2 = parseInt(fValues[(r+1)][0].getTime()/day);
var endDay2 = parseInt(gValues[(r+1)][0].getTime()/day);
if (startDay1<endDay2 && startDay2<endDay1) {
sheet.getRange((r+1), 6, 1, 1).setBackgroundColor('red');
var projectName = eValues[r][0];
if(projects[projectName] !== undefined) { // strict(!) comparison
// add one to this projects count
projects[projectName] += 1;
}else{
// create the first count for this project
projects[projectName] = 1;
}
}
else {
sheet.getRange((r+1), 6, 1, 1).setBackgroundColor('green');
}
}
// updating is done, need to create the counts
// shove the results in column L
var rowCount = 1;
for(var key in projects) {
var val = projects[key];
sheet.getRange(rowCount, 12, 1, 1).setValue(key+": "+val);
rowCount += 1;
}
}catch(e){
Logger.log(e.lineNumber + ' - ' + e);
}
}
Here is the answer in case anyone is interested.
function formatting(m, d) {
try {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Sheet1'); // get the sheet
var output = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Sheet2'); // output sheet
output.clear()
// Going to need the column for project type
var counts = {};
var eValues = sheet.getRange(1, 3, sheet.getLastRow(), 1).getValues();
var columnF = sheet.getRange(1, 1, sheet.getLastRow(), 1).setBackgroundColor('white'); // get all the rows and clear colors
var columnG = sheet.getRange(1, 2, sheet.getLastRow(), 1).setBackgroundColor('white'); // get all the rows and clear colors
var columnD = sheet.getRange(1, 4, sheet.getLastRow(), 1).setBackgroundColor('white').clearContent(); // get all the rows and clear colors
var columnCritical = sheet.getRange(1, 7, sheet.getLastRow(), 1).setBackgroundColor('white').clearContent(); // get all the rows and clear colors
var fValues = columnF.getValues(); // get the values
var gValues = columnG.getValues();
var day = 24 * 3600 * 1000
// loop through all the rows in the dataset
for (var r = 0; r < (fValues.length - 1); r++) {
var startDay1 = parseInt(fValues[r][0].getTime() / day);
var endDay1 = parseInt(gValues[r][0].getTime() / day);
// loop through all the rows for given date
for (var z = 0; z < (fValues.length - 1); z++) {
var startDay2 = parseInt(fValues[(z)][0].getTime() / day);
var endDay2 = parseInt(gValues[(z)][0].getTime() / day);
// if the date is the same go to the next one
if (startDay1 == startDay2 && endDay2 == endDay1) continue;
// check for conflicts
else if (startDay1 < endDay2 && startDay2 < endDay1) {
//Here is our conflict!!!;
var projectn = r + 1
if (counts[projectn] !== undefined) { // strict(!) comparison
// add one to this projects count
counts[projectn] += 1;
} else {
// create the first count for this project
counts[projectn] = 1;
}
} else {
// if there is no conflict
}
} //end of for loop for var z
// change the background of the counts to red and set values
if (counts[r + 1] == undefined) {
sheet.getRange(r + 1, 4, 1, 1).setValue(counts[r + 1]).setBackground('green');
} else {
sheet.getRange(r + 1, 4, 1, 1).setValue(counts[r + 1]).setBackground('red');
}
} // end of for loop for var r
// show if there is any errors
} catch (e) {
Logger.log(e.lineNumber + ' - ' + e);
}
}