Get value from formula cell to trigger email sending - google-apps-script

I am trying to get an e-mail to be sent when the value in a cell that contains a formula goes below a certain number.
I have achieved this for various other spreadsheets that have the cell value manually entered, but for this specific one sheet where the value on the cell results from a simple SUM formula, the e-mail is not being sent. Now if I enter the value manually into the cell, the e-mail is sent right away.
Below is the code and here is a copy of my spreadsheet:
https://docs.google.com/spreadsheets/d/1gnmJfkmIKHyNqLqTFK-bdOZnh2Ejkia6xo3r_3cjwkk/edit?usp=sharing
function CheckBasketsInventory(e) {
var ss = e.source;
var inventorySheet = ss.getSheetByName("Baskets");
var rowIndex = e.range.getRow();
var columnIndex = e.range.getColumn();
var numCols = 11;
var row = inventorySheet.getRange(rowIndex, 1, 1, numCols).getValues()[0];
var editedInventory = row[10];
var editedMinimum = row[8];
var sheetName = ss.getActiveSheet().getName();
// Checking that: (1) edited cell is an inventory quantity, and (2) Inventory is below minimum
if(editedInventory <= editedMinimum && sheetName == "Baskets" && columnIndex == 11 && rowIndex > 1) {
var inventoryValues = inventorySheet.getDataRange().getValues();
var emailBody = "";
for(var i = 1; i < inventoryValues.length; i++) {
var inventory = inventoryValues[i][10];
var minimum = inventoryValues[i][8];
if(inventory <= minimum) {
var productName = inventoryValues[i][0] + " " + inventoryValues[i][1] + " " + inventoryValues[i][2];
var productUnits = minimum + " " + inventoryValues[i][9];
var messagePart1 = "Inventory for " + productName + " has gone under " + productUnits + ". ";
var messagePart2 = "Organise purchase order. Inventory as of today is: " + inventory + " " + inventoryValues[i][9];
var message = messagePart1.concat(messagePart2);
var newItem = "<p>".concat(message, "</p>");
emailBody += newItem;
}
}
var emailSubject = "Low inventory alert";
var emailAddress = "danielrzg#gmail.com";
// Send Alert Email
if(emailBody != "") {
MailApp.sendEmail({
to: emailAddress,
subject: emailSubject,
htmlBody: emailBody
});
}
}
}
Thank you.

As you can see in the documentation:
Script executions and API requests do not cause triggers to run. For
example, calling FormResponse.submit() to submit a new form response
does not cause the form's submit trigger to run.
This includes values edited by a Sheet Formula not triggering an onEdit trigger.

Related

How do I automate sending gmails row by row when the cells in a specific column have either a yes or no entered

function findTextsendupdate(){
var sheet = SpreadsheetApp.getActiveSheet()
var startRow = 3// First row of data to process
var numRows = 50 // Number of rows to process
// if a yes is entered in column M
var sendUpdateRange = sheet.getRange(startRow, 1, numRows, 14);
// Fetch values for each row in the Range.
var yes = "yes"
var no = "no"
var send = sendUpdateRange.createTextFinder(yes);
send.matchCase(false); //{Boolean} -> match target text's case or not;
send.matchEntireCell(true); //{Boolean} -> check the whole Range or within;
send.ignoreDiacritics(true); //{Boolean} -> ignore diacretic signs during match;
send.matchFormulaText(true); //{Boolean} -> search in formulas (if any) or values;
var dontSend = sendUpdateRange.createTextFinder(no)
dontSend.matchCase(false); //{Boolean} -> match target text's case or not;
dontSend.matchEntireCell(true); //{Boolean} -> check the whole Range or within;
dontSend.ignoreDiacritics(true); //{Boolean} -> ignore diacretic signs during match;
dontSend.matchFormulaText(true); //{Boolean} -> search in formulas (if any) or values;
//invoke search;
var res = send.findNext();
var tes = dontSend.findNext();
{ //do something with result;
if (tes) {
var emailNotSent = "Email Not Sent"
sheet.getRange(startRow, 14, numRows, 1).setValue(emailNotSent)}
if(res) {
var sendEmail = sendUpdateRange.getValues();
var emailSent = "Email Sent";
for (var i = 0; i < sendEmail.length; i++) {
var row = sendEmail[i];
var Name = row[1]
var job = row[2]
var model = row[4]
var info = "Job number: " + job + "\n"
var emailAddress = row[0];
var isEmailSent = row[14]
if (isEmailSent != emailSent && no) {
var message = "Dear " + Name + "\n" + "
var body = info + "\n" + message
var subject = "email";
MailApp.sendEmail(emailAddress, subject, body);
sheet.getRange(startRow, 14, numRows, 1).setValue(emailSent);
} }}}}
I have dedicated column M for the edit trigger. But, every time I enter a yes or a no in the first row, it sends the emails for all the other rows. If I put no on the first row, and yes on the send, it changed from not sending to sending all emails whereas if I put yes on the first row and no on the second, it flips between sending and not sending all emails.
I want to make the script look at column M and decide on a row by row basis on whether to send or not to send an email. This is the part I'm having trouble with and I've exhausted my search options.
Assuming everything you had in there works then this might be close.
function findTextsendupdate(e){
const sh=e.range.getSheet();
if(sh.getName()=="My Email Sheet" && e.range.columnStart==13 && e.value=="TRUE") {
const row=sh.getRange(e.range.rowStart,1,1,sh.getLastColumn()).getValues()[0];
var Name = row[1];
var job = row[2];
var model = row[4];
var info = "Job number: " + job + "\n";
var emailAddress = row[0];
var isEmailSent = row[14];
if (isEmailSent != "EmailSent" && MailApp.getRemainingDailyQuota()>0) {
var message = "Dear " + Name + "\n";
var body = info + "\n" + message;
var subject = "email";
MailApp.sendEmail(emailAddress, subject, body);
sh.getRange(e.range.rowStart,14).setValue('EmailSent');
}
}
}

How to debug why a Google Script is not reading information from rows?

I am attempting to write a script to email employees account details after they have been hired. The script finally sends an email. and does not send duplicates. However it is not reading the information as expected across each row. I have no idea what is going on. I am also truly lost over the line
sheet.getRange(startRow + i-18,1).setValue(EMAIL_SENT);
at the bottom and why I had to put in the -18 in order to get the EMAIL_SENT written to the correct row in the sheet.
Here is the script:
var EMAIL_SENT = 'EMAIL_SENT';
function sendEmails() {
var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 2; // First row of data to process
var numRows = 55; // Number of rows to process
var dataRange = sheet.getRange(startRow, 1, numRows, 9);
// Fetch values for each row in the Range.
var data = dataRange.getValues();
var subject = "MCS Account Info";
for (i in data) {
// clear variables between loops
var email1 = "";
var ccs = "";
var message = "";
var row = data[i];
var email1 = row[4];
if(row[4] !== "") var ccs = row[4];
if(row[5] !== "") var ccs = ccs + ", " + row[5];
if(row[6] !== "") var ccs = ccs + ", " + row[6];
if(row[7] !== "") var ccs = ccs + ", " + row[7];
var message = row[8];
// just so I can see what is in each variable will be removed when working
Logger.log("email - ",row[3],"subject - ",subject,"message - ",message,"bcc - ",ccs);
if (row[0] !== EMAIL_SENT) {
if(row[2] !== "") {
MailApp.sendEmail(row[3], subject, message, {
bcc: ccs
});
sheet.getRange(startRow + i-18,1).setValue(EMAIL_SENT);
SpreadsheetApp.flush();
}
}
}
}
and a link to the test sheet I am using: https://docs.google.com/spreadsheets/d/1CzrMlsgwvkzp_w4IjZcOkSl7rU9T8qnBYBYi2luwWkg/edit?usp=sharing
In case the link does not work this is a sheet with 9 columns.
A - EMAIL_SENT message
B - # to look up info from another sheet
C - Username
D - User's Email address
E - H Additional Email Addresses for BCC
G - Message to send
Sheet will have several hundred entries as the year progresses right now I am looking at the first 56 rows even though my sheet only has 2 entries in it.
Try this:
function sendEmails() {
var sheet=SpreadsheetApp.getActiveSheet();
var startRow=2;
var numRows=55;
var dataRange=sheet.getRange(startRow,1,numRows,9);
var data=dataRange.getValues();
var subject="MCS Account Info";
for (var i=0;i<data.length;i++) {
var ccs="";
var row=data[i];
var email1=row[4];
if(row[4]!="") var ccs=row[4];
if(row[5]!="") var ccs=ccs + ", " + row[5];
if(row[6]!="") var ccs=ccs + ", " + row[6];
if(row[7]!="") var ccs=ccs + ", " + row[7];
var message=row[8];
if (row[0]!='EMAIL_SENT' && row[2]!="") {
MailApp.sendEmail(row[3], subject, message, {bcc: ccs});
sheet.getRange(i+startRow,1).setValue('EMAIL_SENT');
}
}
}

Trigger script on non manual change/edit to cell - google script

I'm using the following script to send an email every time a "No" changes to "Yes" in a particular column.
However this only happens if the cell is manually changed to "Yes", typed into a cell. And triggers based on the on edit UI trigger.
But the cell updates based on a formula that references to another sheet where it takes the "No" and "Yes" from, so there is no manual editing/updating on the cell in this sheet.
How can I get it to send the email without any manual change to cells, only on the change from "No" to "Yes"
Any help would be appreciated.
function sendNotification(e){
var s = SpreadsheetApp.getActiveSpreadsheet();
var ss = s.getSheetByName("Order Details")
if(e.range.getColumn()==3 && e.value=='Yes'){
var cell = ss.getActiveCell();
var row = cell.getRow();
var ordernumber = ss.getRange(row,4).getValue(); //Column D
var sku = [{}]; sku = ordernumber.toString().split("-")
var sizewidth = ss.getRange(row,5).getValue(); //Column E
var sizeheight = ss.getRange(row,6).getValue(); //Column F
var qty = ss.getRange(row,8).getValue(); //Column H
var country = ss.getRange(row,10).getValue(); //Column J
var tube = ss.getRange(row,9).getValue(); //Column I
var paintingimage = ss.getRange(row,7).getValue(); //Column G
var orderlink = ('http://testly/Km345TS');
MailApp.sendEmail({
to: "xxx#gmail.com",
subject: country + " New Order No. " + ordernumber, // note the spaces between the quotes...
//attachment: [file,blob],
htmlBody: "Hello XYZ, <br><br>"+
"Please find order details below. <br><br>"+
sku[1] + "<br><br>" +
"Size - Width: " + sizewidth + " x " + "Height: " + sizeheight + "<br><br>"+
"Quantity - " + qty + "<br><br>"+
"- It needs to be tube rolled"+ "<br>" +
"- Shipment to " + country + "<br>" +
"- Order image is " + paintingimage + "<br><br>" +
"Please fill in cost and delivery details at this link " + orderlink + "<br><br>" +
"The order is for a customer from " + country + "<br><br>" +
"Thanking you, <br>" +
"ABC",
})
}
}
Update: Solution - a big thank you to Ron.
function sendNotification2(){
var sSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet 1");
var data = sSheet.getRange(2, 1, sSheet.getLastRow(), sSheet.getLastColumn()).getValues(); //get the values of your table, without the header
var EMAIL_SENT = 'EMAIL_SENT';
for (var i = 0; i < data.length; i++) {
var row = data[i];
var send = row[16]; //Column Q
var emailSent = row[17]; //Column R
var ordernumber = row[4]; //Column E
var country = row[10]; //Column K
var orderlink = ('http:/testly/Khghgy');
var shipaddress = row[18]; //Column S
if (send == "Yes"){
if (emailSent != EMAIL_SENT) { // Prevents sending duplicates
MailApp.sendEmail({
to: "xx#gmail.com",
subject: country + " Ship Order No. " + ordernumber, // note the spaces between the quotes...
htmlBody: "Hello XYZ, <br><br>"+
"Thanking you, <br>" +
"ABC",
})
sSheet.getRange(i+2, 18).setValue(EMAIL_SENT);
}
}
}
}
If you want to have the email triggered on the edit change, you could create a separate function that watches for the edit on the other sheet, and then call the above function to send the email.
Something like:
function onEdit(){
var s = SpreadsheetApp.getActiveSpreadsheet();
var ss = s.getSheetByName("Other Sheet Name");
if(e.range.getColumn()==3 && e.value=='Yes'){ //change this if the data setup is different on the other sheet
sendNotification();
}
}
The issue is that this setup will then send an email to every 'Yes' on the email sheet. This can be rectified using an 'Email_Sent' indicator (you can look that up - lots of examples available).
**Another option, as I mentioned in the last question, would be to have the sendNotification function triggered every minute, 5 minutes, 10 minutes, or ??? This won't provide immediate emails, but it would be nearly so.

Script won't stop sending emails

Below is my script. It sends emails, as its suppose to, but it continues to send emails even when the refereed cell already says "Sent". Can anyone show me where I went wrong?
function sendEmails() {
var sheet = SpreadsheetApp.getActiveSheet();
var lastRow = sheet.getLastRow();
var range = sheet.getRange(2,1,lastRow,13);
var data = range.getValues();
for (i=0;i<data.length;i++){
var employeeName = data [i][6];
var startDate = data [i][2];
var endDate = data [i][3];
var oHours = data [i][4];
var email = data [i][14];
var emailAd = data [i][1];
var response = data [i][9];
if (response == "Approved" && email != "Sent"){
var subject = "Overtime Request";
var message = "Your request for overtime for " + employeeName + " has been " + response + ". This overtime should occur between " + startDate + " to " + endDate + " and should not exceed " + oHours + " hours.";
MailApp.sendEmail(emailAd,subject,message);
sheet.getRange(i+2,14).setValue("Sent");}
else if(response=="Declined" && email != "Sent"){
var subject = "Overtime Request";
var message = "Your request for overtime for " + employeeName + " has been " + response + ".";
MailApp.sendEmail(emailAd,subject,message);
sheet.getRange(i+2,14).setValue("Sent");}
else if(email == "Sent"){return;}
}}
Right now the email is undefined and email != "Sent" will always evaluate to true.
At this line:
var range = sheet.getRange(2,1,lastRow,13);
The getRange() method is getting the the columns A to M, and then at this line:
var email = data [i][14];
You're trying to get the value of the column O.
Remember that while a range index starts at 1, 1, the JavaScript array
will be indexed from [0][0].
You just need to change your sheet.getRange(2,1,lastRow,13); to sheet.getRange(2,1,lastRow,15); so you can get the value where you're setting the value "Sent" and evaluate it in your if() statement.

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.