Google App Script: Speed up script - Conditional copy to another tab - google-apps-script

There are 2 tabs:
Alerts
MASTER
The script:
In Alerts tab, if A is empty and H >= 45, copies the value from G to A, on the next empty row, in MASTER
Ads specific values to some columns in tab MASTER, on the recently added row. All new rows will have those same values.
The script was retrieving ocasionally some timeouts and I tried to add some
SpreadsheetApp.flush();
With our without any relation to these additions, the script started to work better but I'm sure it will return more timeouts as the list may grow.
Is it possible to speed it up?
function CopyPendingPayment(){
var sheet = SpreadsheetApp.getActive();
var sourceSheet = sheet.getSheetByName("Alerts");
var destination = sheet.getSheetByName("MASTER");
var lastRow = sourceSheet.getDataRange().getLastRow();
var column = destination.getRange('A' + destination.getMaxRows())
SpreadsheetApp.flush();
for(var row=3; row<=lastRow; row++){
if(sourceSheet.getRange(row,1).getValue() == "" & sourceSheet.getRange(row,8).getValue() >= "45"){
var rangeToCopy = "G"+row+":G"+row;
var lastFilledRow = parseInt(column.getNextDataCell(SpreadsheetApp.Direction.UP).getA1Notation().slice(1))
SpreadsheetApp.flush();
sourceSheet.getRange(rangeToCopy).copyTo(destination.getRange(lastFilledRow+1,1)),{contentsOnly:true};
destination.getRange(lastFilledRow+1, 9).setValue("No Payment Received");
destination.getRange(lastFilledRow+1, 10).setValue(new Date());
destination.getRange(lastFilledRow+1, 12).setValue("PENDING");
destination.getRange(lastFilledRow+1, 13).setValue("- Reminder sent");
destination.getRange(lastFilledRow+1, 14).setValue(new Date());
}
}
}
I guess at least the part where it ads the values on the different columns it could be done quicker, right?
Can anyone give me a hand?
Thank you in advance
Sample

I believe your goal is as follows.
You want to reduce the process cost of your script.
In this case, how about the following modification?
Modified script:
function CopyPendingPayment() {
var sheet = SpreadsheetApp.getActive();
var sourceSheet = sheet.getSheetByName("Alerts");
var destination = sheet.getSheetByName("MASTER");
// I modified below script.
var srcValues = sourceSheet.getRange("A3:H" + sourceSheet.getLastRow()).getValues();
var lastRow = destination.getLastRow();
var obj = srcValues.reduce((o, [a,,,,,,g,h], i) => {
if (a == "" && h >= 45) {
o.values.push([g]);
o["No Payment Received"].push(`I${lastRow + i + 1}`);
o["date"].push(`J${lastRow + i + 1}`, `N${lastRow + i + 1}`);
o["PENDING"].push(`L${lastRow + i + 1}`);
o["- Reminder sent"].push(`M${lastRow + i + 1}`);
}
return o;
}, {values: [], "No Payment Received": [], "date": [], "PENDING": [], "- Reminder sent": []});
destination.getRange(lastRow + 1, 1, obj.values.length).setValues(obj.values);
["No Payment Received", "date", "PENDING", "- Reminder sent"].forEach(e => destination.getRangeList(obj[e]).setValue(e == "date" ? new Date() : e));
}
In this modification, the value of column "A" is put with setValues of Class Range. And, the values of columns "I", "J", "L", "M" and "N" are put with setValue of Class RangeList. Because I thought that you might want to keep other columns.
As another method, I think that your goal can be also achieved by overwriting the cells of the destination sheet. In that case, how about the following script?
function CopyPendingPayment() {
var sheet = SpreadsheetApp.getActive();
var sourceSheet = sheet.getSheetByName("Alerts");
var destination = sheet.getSheetByName("MASTER");
var srcValues = sourceSheet.getRange("A3:H" + sourceSheet.getLastRow()).getValues();
var lastRow = destination.getLastRow();
var values = srcValues.reduce((ar, [a,,,,,,g,h], i) => {
if (a == "" && h >= 45) {
var date = new Date();
ar.push([g,,,,,,,,"No Payment Received", date,,"PENDING","- Reminder sent",date]);
}
return ar;
}, []);
destination.getRange(lastRow + 1, 1, values.length, values[0].length).setValues(values);
}
References:
setValues(values) of Class Range
setValue(value) of Class RangeList
Added:
From your following replying,
It seems a lot quicker, indeed. I've tested your versions vs mine. The only problem is that if there is an array in any ot the destination sheet columns, the values are pasted below. The original version takes into consideration that and pastes the values on the 1st blank cell of column A.
How about the following sample script?
Sample script:
function CopyPendingPayment_C() {
// This is from https://stackoverflow.com/a/44563639
Object.prototype.get1stEmptyRowFromTop = function (columnNumber, offsetRow = 1) {
const range = this.getRange(offsetRow, columnNumber, 2);
const values = range.getDisplayValues();
if (values[0][0] && values[1][0]) {
return range.getNextDataCell(SpreadsheetApp.Direction.DOWN).getRow() + 1;
} else if (values[0][0] && !values[1][0]) {
return offsetRow + 1;
}
return offsetRow;
};
var sheet = SpreadsheetApp.getActive();
var sourceSheet = sheet.getSheetByName("Alerts");
var destination = sheet.getSheetByName("MASTER");
// I modified below script.
var srcValues = sourceSheet.getRange("A3:H" + sourceSheet.getLastRow()).getValues();
var lastRow = destination.get1stEmptyRowFromTop(1) - 1;
// I modified below part.
var obj = srcValues.reduce((o, [a,,,,,,g,h]) => {
if (a == "" && h >= 45) {
o.offset++;
o.values.push([g]);
o["No Payment Received"].push(`I${o.offset}`);
o["date"].push(`J${o.offset}`, `N${o.offset}`);
o["PENDING"].push(`L${o.offset}`);
o["- Reminder sent"].push(`M${o.offset}`);
}
return o;
}, {values: [], "No Payment Received": [], "date": [], "PENDING": [], "- Reminder sent": [], offset: lastRow});
destination.getRange(lastRow + 1, 1, obj.values.length).setValues(obj.values);
["No Payment Received", "date", "PENDING", "- Reminder sent"].forEach(e => destination.getRangeList(obj[e]).setValue(e == "date" ? new Date() : e));
}

Related

How to find the correct rowId when using a limited range from Google Sheet?

I have the below code that checks through a sheet for the words "CASH". Once it's found, it will copy the row to a new sheet then delete the row.
Prior, my range for the values was set up as so:
var range = ss1.getRange(2, 1, lr, lc);
But now that my sheet has 6000+ rows, this is highly inefficient. I've changed it so that it only looks through a range that is lr-100 so that it doesn't have to dig so deep.
Since making that change, my old code to delete rows ss1.deleteRow(i+2) is no longer valid, because i references the row only within that particular range (i.e., if it's the 90th row out of that 100, i = 90, and that would end up deleting the 90th row in my sheet when it should have been, for example, 6500.
question How do I find the correct row# in this new way my script is setup?
var etfar = ["BOTZ"]
function doCash() {
for (var i = 0; i < etfar.length; i++) {
cashMoney(etfar[i])
}
};
function cashMoney(etf) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var ss1 = ss.getSheetByName(etf);
var ss2 = ss.getSheetByName("Cash");
var lr = ss1.getLastRow();
var lc = ss1.getLastColumn();
var range = ss1.getRange(lr-100, 1, lr, lc);
var data = range.getValues();
for (var i = data.length - 1; i >= 0; i--)
{
var check = data[i][4] // ith row, 3rd column
if (check.includes("CASH")) {
var rowUsd = data[i];
// something has to happen here to find the exact row
ss2.appendRow(rowUsd);
//ss1.deleteRow(i+2); <-- this is old code. Prior, in my 'range' I used to start my rows from "2", but that was highly inefficient and I've changed it to "lr-100" so that it begins checking from the last 100 rows instead
}
};
};
From now that my sheet has 6000+ rows, this is highly inefficient., in your situation, in order to reduce the process cost of the script, how about using Sheets API? When Sheets API is used for your situation, all rows might be able to be processed. When Sheets API is used for your script, it becomes as follows.
Modified script:
This script uses Sheets API. So, please enable Sheets API at Advanced Google services. And, please set etfar.
function sample() {
var etfar = ["Sheet1", "Sheet2",,,]; // Please set your sheet names.
var ss = SpreadsheetApp.getActiveSpreadsheet();
var dstSheet = ss.getSheetByName("Cash");
var dstSheetId = dstSheet.getSheetId();
var lastRow = dstSheet.getLastRow();
var { copyRows, deleteRows } = etfar.reduce((o, e) => {
var srcSheet = ss.getSheetByName(e);
var srcSheetId = srcSheet.getSheetId();
srcSheet.getRange("E2:E" + srcSheet.getLastRow()).getValues().forEach(([v], i) => {
if (v == "CASH") {
o.copyRows.push({ copyPaste: { source: { sheetId: srcSheetId, startRowIndex: i + 1, endRowIndex: i + 2, startColumnIndex: 0 }, destination: { sheetId: dstSheetId, startRowIndex: lastRow, endRowIndex: lastRow + 1, startColumnIndex: 0 } } });
o.deleteRows.push({ deleteDimension: { range: { sheetId: srcSheetId, dimension: "ROWS", startIndex: i + 1, endIndex: i + 2 } } });
lastRow++;
}
});
return o;
}, { copyRows: [], deleteRows: [] });
var requests = [...copyRows, ...deleteRows.reverse()];
if (requests.length == 0) return;
Sheets.Spreadsheets.batchUpdate({ requests }, ss.getId());
}
When this script is run, the values searched by the column "E" are retrieved from the sheets of etfar, and those values are appended to the destination sheet "Cash". And also, the copied rows of each sheet are removed.
In this script, these processes can be run by one API call.
Note:
When I saw your script, from var check = data[i][4] // ith row, 3rd column, I thought that data[i][4] is the coumn "E". But you say 3rd column. It's the column "C". If you want to search the value of "CASH" from the column "C", please modify getRange("E2:E" + srcSheet.getLastRow()) to getRange("C2:C" + srcSheet.getLastRow()).
References:
Method: spreadsheets.batchUpdate
CopyPasteRequest
DeleteDimensionRequest
I think this is what you want
function cashMoney(etf) {
var ss = SpreadsheetApp.getActive();
var sh1 = ss.getSheetByName(etf);
var sh2 = ss.getSheetByName("Cash");
var lr = sh1.getLastRow();
var lc = sh1.getLastColumn();
var range = sh1.getRange(lr - 100, 1, 101, lc);
var data = range.getValues();
var d = 0;
for (var i = data.length - 1; i >= 0; i--) {
var check = data[i][4] // ith row, 3rd column
if (check.includes("CASH")) {
var rowUsd = data[i];
sh2.appendRow(rowUsd);
sh.deleteRow(lr - 100 + i - d++);The row is data start row + i
}
};
}
The d keeps track of the rows that have already been deleted from the spreadsheet which is necessary because they have not been deleted from the data set.

Exporting sheet data to JSON file

This is my simple Sheet divided by freezed rows to Head and Body:
And this is what the final output(json) should look like:
{
"3":{
"AB1":{
"A2":"A3",
"B2":"B3"
},
"C1":{
"C2":"C3"
}
},
"4":{
"AB1":{
"A2":"A4",
"B2":"B4"
},
"C1":{
"C2":"C4"
}
},
...
}
My code look like this:
function doGet() {
var SpreadSheet = SpreadsheetApp.getActiveSpreadsheet();
var Sheet = SpreadSheet.getSheets()[1];
var FirstRow = 1;
var FirstColumn = 1;
var LastRow = Sheet.getLastRow();
var LastColumn = Sheet.getLastColumn();
var FrozenRows = Sheet.getFrozenRows();
var FrozenColumns = Sheet.getFrozenColumns();
var HeadRange = Sheet.getRange(FirstRow, FirstColumn + FrozenColumns, FrozenRows - FirstRow + 1, LastColumn - FrozenColumns); // A1:C2
var HeadData = HeadRange.getValues(); // [[AB1, , C1], [A2, B2, C2]]
var BodyRange = Sheet.getRange(FirstRow + FrozenRows, FirstColumn + FrozenColumns, LastRow - FrozenRows, LastColumn - FrozenColumns); // A3:C6
var BodyData = BodyRange.getValues(); // [[A3, B3, C3], [A4, B4, C4], [A5, B5, C5], [A6, B6, C6]]
and will end with this:
var OutputData = ContentService.createTextOutput(JSON.stringify(InputData)).setMimeType(ContentService.MimeType.JSON);
return OutputData;
and now my problems :), first problem is, how get value from empty merged cell, when don't know his range, only know other side when know range and want value
for (var i = 0; i < HeadData[0].length; i++) {
var Category = HeadData[0][i];
var CellValue = (RangeCell.isPartOfMerge() ? RangeCell.getMergedRanges()[0].getCell(1,1) : RangeCell).getValue();
Second problem is, how put code together when want start json with number of row data, then category, subcategory and last with item data:
var Obj = {};
for (var i = 1; i <= ItemsRange.getNumRows(); i++) {
var ItemIndex = ItemsRange.getCell(i,1).getRowIndex();
for (var j = 0; j < BodyData.length; j++) {
for (var k = 0; k < BodyData[j].length; k++) {
var ItemCell = BodyData[j][k];
}
}
Obj[ItemIndex] = {};
}
In this case, how about the following flow?
Retrieve values from Spreadsheet.
This is from your script.
Recreate header rows.
Create the result object.
Modification points:
In this modification, at first, the header data is created. The merged ranges can be retrieve by getMergedRanges(). I created the header data using this.
When your sample Spreadsheet is used, HeadData becomes [[AB1, AB1, C1], [A2, B2, C2]] from [[AB1, , C1], [A2, B2, C2]].
In your case, it has already been found that the result object is the nested object with 3 levels. I think that this can be used.
Modified script:
function doGet() {
// 1. Retrieve values from Spreadsheet. This is from your script.
var SpreadSheet = SpreadsheetApp.getActiveSpreadsheet();
var Sheet = SpreadSheet.getSheets()[1];
var FirstRow = 1;
var FirstColumn = 1;
var LastRow = Sheet.getLastRow();
var LastColumn = Sheet.getLastColumn();
var FrozenRows = Sheet.getFrozenRows();
var FrozenColumns = Sheet.getFrozenColumns();
var HeadRange = Sheet.getRange(FirstRow, FirstColumn + FrozenColumns, FrozenRows - FirstRow + 1, LastColumn - FrozenColumns); // A1:C2
var HeadData = HeadRange.getValues(); // [[AB1, , C1], [A2, B2, C2]]
var BodyRange = Sheet.getRange(FirstRow + FrozenRows, FirstColumn + FrozenColumns, LastRow - FrozenRows, LastColumn - FrozenColumns); // A3:C6
var BodyData = BodyRange.getValues(); // [[A3, B3, C3], [A4, B4, C4], [A5, B5, C5], [A6, B6, C6]]
// 2. Recreate header rows.
Sheet.getRange(1, 1, 1, Sheet.getLastColumn()).getMergedRanges().forEach(r => {
let temp = "";
for (let i = r.getColumn(); i <= r.getNumColumns(); i++) {
if (HeadData[0][i - 1].toString() != "") temp = HeadData[0][i - 1];
}
for (let i = r.getColumn(); i <= r.getNumColumns(); i++) {
HeadData[0][i - 1] = temp;
}
});
// 3. Create the result object.
const InputData = BodyData.reduce((o1, r, i) => {
o1[i + FirstRow + FrozenRows] = r.reduce((o2, c, j) => {
const t1 = HeadData[0][j];
const t2 = {[HeadData[1][j]]: c};
return Object.assign(o2, {[t1]: o2[t1] ? Object.assign(o2[t1], t2) : t2});
}, {});
return o1;
}, {});
var OutputData = ContentService.createTextOutput(JSON.stringify(InputData)).setMimeType(ContentService.MimeType.JSON);
return OutputData;
}
Result:
When your sample Spreadsheet is used, the value of InputData is as follows.
{
"3": {
"AB1": {
"A2": "A3",
"B2": "B3"
},
"C1": {
"C2": "C3"
}
},
"4": {
"AB1": {
"A2": "A4",
"B2": "B4"
},
"C1": {
"C2": "C4"
}
},
"5": {
"AB1": {
"A2": "A5",
"B2": "B5"
},
"C1": {
"C2": "C5"
}
},
"6": {
"AB1": {
"A2": "A6",
"B2": "B6"
},
"C1": {
"C2": "C6"
}
}
}
Note:
When you modified the script of Web Apps, please redeploy the Web Apps as new version. By this, the latest script is reflected to the Web Apps. Please be careful this.
When your actual situation is largely different from your sample Spreadsheet in your question, this modified script might not work. So please be careful this.
Please use this modified script with V8.
References:
getMergedRanges()
reduce()
Object.assign()

Adding a timestamp when specific data is entered from another sheet in Google Sheet

I have a Google Sheet containing two sheets, one named Form and the other Data. Information on the Data sheet is usually entered via the Form sheet, where a button click on the Form sheet sends the data over to the bottom row on the Data sheet.
I'm trying to figure out how I can add a timestamp to the appropriate cell in column E on the Data sheet when a cell on the same row in column D receives the word 'CLEANED' either as a submission from the Form sheet or as a direct manual entry on the Data sheet.
This code currently adds the timestamp, but only when I change a value in column D directly on the Data sheet (not when values are added via the Form sheet), and it adds the timestamp for any value that's added.
var ColumnToCheck = 4;
var DateTimeLocation = [0,1];
var sheetName = 'Data'
function onEdit(e) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
if( sheet.getSheetName() == sheetName ) {
var selectedCell = ss.getActiveCell();
if( selectedCell.getColumn() == ColumnToCheck) {
var dateTimeCell = selectedCell.offset(DateTimeLocation[0],DateTimeLocation[1]);
dateTimeCell.setValue(new Date());
}
}
}
I am using this code to transfer data from the Form sheet:
function submitData() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var formSS = ss.getSheetByName("Form");
var dataSheet = ss.getSheetByName("Data");
var values = formSS.getRange("B2:B5").getValues().reduce(function(a, b) {
return a.concat(b)
});
var partNum = values[0];
var row;
dataSheet.getDataRange().getValues().forEach(function(r, i) {
if (r[0] === partNum) {
row = i + 1
}
})
row = row ? row : dataSheet.getLastRow() + 1;
var data = dataSheet.getRange(row, 1, 1, 4).getValues()[0].map(function (el, ind){
return el = values[ind] ? values[ind] : el;
})
dataSheet.getRange(row, 1, 1, 4).setValues([data]);
formSS.getRange("B2:B5").clearContent()
}
What would be the best way to have the date added automatically when only the word 'CLEANED' is entered? The date shouldn't clear if the word 'CLEANED' is removed or changed to a different word.
EDIT - SOLUTION
Thanks to Sourabh Choraria, I was able to change my UPDATE function to this in order to incorporate my needs (my additions to his code are commented):
function submitData() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var formSS = ss.getSheetByName("Form");
var dataSheet = ss.getSheetByName("Data");
var values = formSS.getRange("B3:B6").getValues().reduce(function(a, b) {
return a.concat(b)
});
var partNum = values[0];
var row;
dataSheet.getDataRange().getValues().forEach(function(r, i) {
if (r[0] === partNum) {
row = i + 1
}
})
row = row ? row : dataSheet.getLastRow() + 1;
var data = dataSheet.getRange(row, 1, 1, 4).getValues()[0].map(function (el, ind){
return el = values[ind] ? values[ind] : el;
})
var statusValue = formSS.getRange("B6").getValue(); //added
if (statusValue != 'CLEANED') { //added
dataSheet.getRange(row, 1, 1, 4).setValues([data]); //added
} //added
if (statusValue == 'CLEANED') { //added
var now = [new Date()];
var newData = data.concat(now)
dataSheet.getRange(row, 1, 1, 5).setValues([newData]);
} //added
formSS.getRange("B3:B6").clearContent()
}
Update the submitData() function with the following code -
function submitData() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var formSS = ss.getSheetByName("Form");
var dataSheet = ss.getSheetByName("Data");
var values = formSS.getRange("B2:B5").getValues().reduce(function(a, b) {
return a.concat(b)
});
var partNum = values[0];
var row;
dataSheet.getDataRange().getValues().forEach(function(r, i) {
if (r[0] === partNum) {
row = i + 1
}
})
row = row ? row : dataSheet.getLastRow() + 1;
var data = dataSheet.getRange(row, 1, 1, 4).getValues()[0].map(function (el, ind){
return el = values[ind] ? values[ind] : el;
})
// modification begins here
var now = [new Date()];
var newData = data.concat(now)
dataSheet.getRange(row, 1, 1, 5).setValues([newData]);
// modification ends here
formSS.getRange("B2:B5").clearContent()
}
Basically, I'm declaring a new array variable (now) and concatenating it to the existing data array, thus forming a "newData" variable and then updating the setValues function to accommodate this change.
Hope this helps and thanks for sharing the view access to the sheet - I made a copy of that and tested the solution directly :)
Edit note1
As for updating the sheet only when the dropdown selected is 'CLEANED', kindly modify your onEdit() function to accommodate the following IF condition -
var statusValue = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Form').getRange("B6").getValue();
if (statusValue == 'CLEANED') {
// update timestamp as required
}

Store results of Storyline 2 quiz in google sheet then email me the latest result

Please excuse my compete newness. I am not a coder.
What I need is to store results of quizes taken in some elearning I have made in a google spreadsheet and to email me everytime the sheet gets a new entry ie everytime someone completes the quiz.
From the e-learning heros forum at Articulate i have a code which will perform the task of taking variables from the storyline quiz and writing them to a google sheet.
I also have a bit of code which will gather information from the last row of the sheet and email them to me.
If i test the script in the google editor it sends me the email. It will not send me the email when the sheet is updated by someone completing the quiz. The google sheet does get filled in everytime someone finished the quiz just no email. Here is the code:
var SHEET_NAME = "DATA";
var SCRIPT_PROP = PropertiesService.getScriptProperties();
function doGet(e) {
return handleResponse(e);
}
function doPost(e) {
return handleResponse(e);
}
function handleResponse(e) {
var lock = LockService.getPublicLock();
lock.waitLock(30000); // wait 30 seconds before conceding defeat.
try {
var doc = SpreadsheetApp.openById(SCRIPT_PROP.getProperty("MmzGq0lh9jQjkO-_i8STL2nsLKXLh7K_NHzR8yD5gnk"));
var sheet = doc.getSheetByName(SHEET_NAME);
var headRow = e.parameter.header_row || 1;
var headers = sheet.getRange(1, 1, 1, sheet.getLastColumn()).getValues()[0];
var nextRow = sheet.getLastRow() + 1; // get next row
var row = [];
for (i in headers) {
if (headers[i] == "Timestamp") { // special case if you include a 'Timestamp' column
row.push(new Date());
} else { // else use header name to get data
row.push(e.parameter[headers[i]]);
}
}
sheet.getRange(nextRow, 1, 1, row.length).setValues([row]);
return ContentService
.createTextOutput(JSON.stringify({
"result": "success",
"row": nextRow
}))
.setMimeType(ContentService.MimeType.JSON);
} catch (e) {
return ContentService
.createTextOutput(JSON.stringify({
"result": "error",
"error": e
}))
.setMimeType(ContentService.MimeType.JSON);
} finally {
lock.releaseLock();
var lastRow = sheet.getLastRow();
var range = sheet.getRange(lastRow, 1, lastRow, 10);
var values = range.getValues();
var date = values[0][0]
var formattedDate = Utilities.formatDate(date, "GMT+08:00", "dd/MM/yyyy H:mm a");
var firstname = values[0][2]
var surname = values[0][1]
var score = values[0][3]
var result = values[0][5]
var emailAddress = "My email"
var message = "Name:\t" + firstname + " " + surname + "\n\nDate:\t\t" + formattedDate + "\nScore:\t\t" + score + "%\nStatus:\t" + result;
var subject = "Training " + result;
MailApp.sendEmail(emailAddress, subject, message);
}
}
Any help would be appreciated.
Just to be sure, since you say you're a beginner.. Did you change the email variable with your own email address?
var emailAddress = "My email"

Google Script E-mail Array

I have the following Google Script. It runs through a spreadsheet and imports information into a Google Calendar. However, I also want it to populate an array with the uploaded data and send it in a Google email. Is this possible? Here is what I have so far.
var MAINTENANCE_EXPORTED = "MAINTENANCE_EXPORTED";
var MAINTENANCE_ERROR = "MAINTENANCE_ERROR";
var ss = SpreadsheetApp.getActiveSpreadsheet();
function onOpen() {
var menuEntries = [{name: "Upload CS Maintenance Schedule", functionName: "importCalendarCS"}, {name: "Upload EP Maintenance Schedule", functionName: "importCalendarEP"}];
ss.addMenu("Maintenance Scripts", menuEntries);
}
//
//Coral Street Import Function
//
function importCalendarCS() {
var sheet = ss.getSheetByName('CS');
var startcolumn = 1; // First column of data to process
var numcolumns = sheet.getLastRow(); // Number of columns to process
var dataRange = sheet.getRange(startcolumn, 1, numcolumns, 13) // Fetch values for each column in the Range.
var data = dataRange.getValues();
for (var i = 0; i < data.length; ++i) { // this is a "for loop" that asks the script to run through all rows.
var column = data[i];
var building = column[0]; // 1st column in spreadsheet "BLDG"
var cart = column[1]; // 2nd column in spreadsheet "CART OR LAB"
var room = column[2]; // 3rd column in spreadsheet "LOCATION OF CART OR ROOM"
var deviceType = column[3]; // 4th column in spreadsheet "TYPE OF DEVICES"
var deviceQuantity = column[4]; // 5th column in spreadsheet "# of Devices"
var maintenancePerson = column[5]; // 7th column in spreadsheet "Maintenance Person"
var maintenanceDate = column[6]; // 6th column in spreadsheet "Maint Date"
var maintenanceImported = column[13];
var title = building + " - " + room;
var description = "Building: " + building
+ "\n" + "Room: " + room
+ "\n" + "Cart: " + cart
+ "\n" + "Device Type: " + deviceType
+ "\n" + "Device Quantity: " + deviceQuantity;
var calendarName = "Cart Maint Schedule";
if (maintenancePerson == "Bobby Obvious") {
var email = "example#example.com"
}
else {
var email = "example#example.com"
}
if ((maintenanceImported != MAINTENANCE_EXPORTED) && (maintenanceImported != MAINTENANCE_ERROR) && (building != "BLDG") && (cart != "Cycle 1 Checklist") && (cart != "Cycle 2 Checklist")) { // Prevents importing duplicates
var cal = CalendarApp.openByName(calendarName);
var advancedArgs = {description: description, location: ("Cart: " + cart)};
var itsEmail = "example#example.com";
if
if (maintenanceDate != "") {
cal.createAllDayEvent(title, new Date(maintenanceDate), advancedArgs);
var sheet2 = ss.getSheetByName('CS');
sheet.getRange(startcolumn + i, 14).setValue(MAINTENANCE_EXPORTED);
SpreadsheetApp.flush();
}
else {
var sheet2 = ss.getSheetByName('CS');
sheet.getRange(startcolumn + i, 14).setValue(MAINTENANCE_ERROR);
SpreadsheetApp.flush();
}
}
}
}
Yes it's possible. Use the MailApp class.
https://developers.google.com/apps-script/reference/mail/mail-app
or the GmailApp Class:
https://developers.google.com/apps-script/reference/gmail/gmail-app
Try to use the MailApp.sendEmail method. It accepts an address.