Trigger script on non manual change/edit to cell - google script - google-apps-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.

Related

Running a Google Script from a duplicated speadsheet

I've created a Google spreadsheet that includes some basic script which emails someone when a task to which they are assigned comes due. The script works on the original sheet but when I duplicate the sheet and change nothing but the dates the script no longer works.
I'm not receiving any errors, the emails simply are not being sent.
I'm very new to Google script and wasn't able to find a good answer for this. Does anybody know what the issue might be?
Thanks so much!
function myFunction() {
var date = new Date();
date.setHours(0);
date.setMinutes(0);
date.setSeconds(0);
var FormattedTodayDate = Utilities.formatDate(date,'GMT-0600','MM/dd/yyyy')
//Here we get all the spreadsheets from the spreadsheet app
var spreadSheets = SpreadsheetApp.getActiveSpreadsheet();
//Here we pick out the first spreadsheet. 0 is the first tab of the spreadsheet "Active Sheet"
var currentSheet = spreadSheets.getSheets()[0];
//Here we set up where on the sheet we want to get the data
var startRow = 3;
var numRows = currentSheet.getLastRow()-1;
var numCols = currentSheet.getLastColumn();
//We use those numbers to find a range throughout the table (A2 - H* etc) where we want to grab the data from
var dataRange = currentSheet.getRange(startRow, 1, numRows, numCols);
//Using the data range, grab all the values
var data = dataRange.getValues();
for(i in data){
var row = data[i];
var reminderDate = new Date(row[1]);
var dueDate = new Date(row[3]);
var FormattedReminderDate = Utilities.formatDate(reminderDate,'GMT-0600', 'MM/dd/yyyy')
var FormattedDueDate = Utilities.formatDate(dueDate,'GMT-0600', 'MM/dd/yyyy')
if(row[0] === ''){
// Logger.log(FormattedTodayDate);
//
// Logger.log(FormattedReminderDate);
//
// Logger.log(FormattedReminderDate == FormattedTodayDate);
if(FormattedReminderDate == FormattedTodayDate){
MailApp.sendEmail({
to: row[7],
subject: row[4] + " task due on " + FormattedDueDate,
htmlBody: "The following " + row[4] + " task is coming due on <b>" + FormattedDueDate + "</b> : <br/> <br>" + row[5] + "<br> </br>Go to Google Spreadsheet for more details: https://docs.google.com/spreadsheets/d/1jIBX5By1jhro1V-gHXPPlhIOXDLut6CMvaq92uW5bFw/edit#gid=0&range=" + row[8] + "<br/><br> Please remember to add the word 'done' to the 'done?' column when you complete this task.",
})
}
if(FormattedDueDate == FormattedTodayDate){
MailApp.sendEmail({
to: row[7],
subject: row[4] + " task due TODAY",
htmlBody: "The following " + row[4] + " task has not been completed and is due TODAY: <br/> <br>" + row[5] + "<br> </br>Go to Google Spreadsheet for more details: https://docs.google.com/spreadsheets/d/1jIBX5By1jhro1V-gHXPPlhIOXDLut6CMvaq92uW5bFw/edit#gid=0&range=" + row[8] + "<br/><br> Please remember to add the word 'done' to the 'done?' column when you complete this task.",
})
}
}
}
}
Thanks everyone. Turns out this issue was caused by our spam filter blocking the notifications.

Get value from formula cell to trigger email sending

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.

Automating google sheets via a script to send emails onedit to email on the same row

I amu sing the script below to send emails to email addresses inputted into specific columns when yes is inputted into a specific column.
One of the issues that I am having with this code is that i am not sure how I can send emails to more than two recepients at a time.
Furthermore this script does not work on sheets linked to google forms. After doing research i have found that the reason the script does not work is beacuse the script won`t run on onedit triggers but wil only run on timed triggers when linked to google Forms.
Please could someone accomplish the above.
EmailScript() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Repairs");
// Sets "range" from A2 (2,1) to Bottom right cell of sheet (MaxRow,MaxColumn)
var range = sheet.getRange(2,1,sheet.getMaxRows()-1,sheet.getMaxColumns());
var data = range.getValues()
var activeRng,activeCell,columnToCheck,editedColumn,editedRow,newValue,sh,ss,valueToTestFor;//Define variables without assigning a value
//USER INPUT
columnToCheck = 9 ;//Column A is 1
valueToTestFor = "Y"
//END OF USER INPUT
ss = SpreadsheetApp.getActiveSpreadsheet();//Get the active spreadsheet
sh = ss.getActiveSheet();//Get the active sheet tab
activeRng = SpreadsheetApp.getActiveRange();//Get the active range
activeCell = activeRng.getCell(1, 1);//Get the first cell in the active range
newValue = activeCell.getValue();//Get the new value in the cell that was just edited
editedColumn = activeCell.getColumn();//Get the column of the cell that was just edited
editedRow = activeCell.getRow();//Get the row of the cell that was just edited
if (editedColumn !== columnToCheck) {//Only run the code if the column to monitor is the correct one
return;
}
// Loops through data, 0 to the "length" of the data, set above (dictated by range), with i to be each row number with each loop, and row[X] representing Column X for row i.
for (var i = 0; i < data.length; ++i) {
// Setting all variables for email messages
// Column A = row[0], Column B = row[1],C2,D3,E4,F5,G6,H7,I8,J9,K10,L11,M12,N13,O14,P15,Q16,R17,S18,T19,U20,V21,W22,X23
var row = data[i];
var firstname = row[0];
var email = row[1];
var email2 = row [2];
var email3 = row [4];
var emailstatus = row[13]
var emailPattern = /^[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*#(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+(?:[A-Z]{2}|aero|asia|biz|com|coop|edu|gov|info|int|jobs|mil|mobi|name|museum|name|net|org|pro|tel|travel)\b/;
var validEmailAddress = emailPattern.test(email);
if (newValue === valueToTestFor && emailstatus != "EMAIL_SENT") {
var message = "<HTML><BODY>"
+ "<P>Dear " + firstname + ","
+ "<br /><br />"
+" Your device has been repaired"
+ "<br /><br />"
+ "Regards"
+ "<br /><br />"
+ "Test"
+ "<br /><br />"
+ "</HTML></BODY>";
MailApp.sendEmail({
to:email,
cc:email2,
bbc:email3,
subject:"Device Repair",
htmlBody: message});
sheet.getRange(i+2,10).setValue("EMAIL_SENT");
}
}
}
Thank you in advance for your help.

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.

Send Email when value changes in Google Spreadsheet

I am trying to figure out, how do the following in Google Spreadsheet.
Send email when a value changes in a cell. (Value = Completed).
Compile that rows data into the email. See format in code below.
Prompt user for confirmation of info.
If YES, send email to active user as well as the preset users in the code below.
This is optional: Update sheet in row on column (P) 16 with Email Sent + timestamp.
Hi Serge,
Try to implement the code you provided, but I could not make heads or tails on what to modify to fit what I needed done.
Let me explain it again with below workflow.
Send an email when the value changes for column K.
Partial Sample code to watch column K
var sheetNameToWatch = "Active Discs";
var columnNumberToWatch = 14; // column A = 1, B = 2, etc.
var valueToWatch1 = "Completed";
var valueToWatch2 = "in progress";
try{
var ss = e.source;
var sheet = ss.getActiveSheet();
var range = e.range;
if (sheet.getName() == sheetNameToWatch && range.columnStart ==
columnNumberToWatch && e.value == valueToWatch)
var confirm = Browser.msgBox
('Email will be sent Team X. Do you want to sent this email?', Browser.Buttons.YES_NO);
if(confirm!='yes'){return};
// if user click NO then exit the function, else move data
The email will contain the specified values of that specific row. Ex. Values in columns A, B, C, D, E, F, G, H, I, J.
//Email to be sent if **Inprogess** value is a match:
Var sendEmailTeamA(){
var ProjectName = e.values[0];
var ProjectId = e.values[1];
var ProjectManager = e.values[3];
var Sales = e.values[4];
var Client = e.values[5];
var DiscType = e.values[6];
var DVDFlash = e.values[7];
var Phase = e.values[8];
var Encryption = e.values[9];
var Qty = e.values[11];
var DueDate = e.values[12];
var SpecialInstructions = e.values[13];
var emailAddress = '';
var subject = "DVD Request - " + ProjectName + " " + ProjectId;
var emailBody = "Hi Venue Colombo Team,"
"\n\nThe following data room(s) will need a disc creation. Please begin bulk save data room and create ISO to upload to the FTP site: " +
"\nProject Name: " + ProjectName +
"\nProject ID: " + ProjectId +
"\nProject Manager: " + ProjectManager +
"\nPhase: " + Phase +
"\nDisc Type: " + DiscType +
"\nEncryption: " + Encryption +
"\nQuantity: " + Qty +
"\nClient Due Date: " + DueDate +
"\nSpecialInstructions: " + SpecialInstructions;
var htmlBody = "Thank you for your <b>Club Ambassador Program</b> report submitted on <i>" + timestamp +
"</i><br/> <br/>Person Show Submitted this email: " +
"<br/><font color=\"red\">Your Name:</font> " + activeSessionuser +
"<br/>Your Email: " + toAddress;
var optAdvancedArgs = {name: "Club Ambassador Program", htmlBody: htmlBody};
MailApp.sendEmail(emailAddress, subject, emailBody, optAdvancedArgs);
}
//Email to be sent if **“Completed”** value is a match:
Var sendEmailTeamB() {
var ProjectName = e.values[0];
var ProjectId = e.values[1];
var ProjectManager = e.values[3];
var Sales = e.values[4];
var Client = e.values[5];
var DiscType = e.values[6];
var DVDFlash = e.values[7];
var Phase = e.values[8];
var Encryption = e.values[9];
var Qty = e.values[11];
var DueDate = e.values[12];
var SpecialInstructions = e.values[13];
var emailAddress = '';
var subject = "DVD Request - " + ProjectName + " " + ProjectId;
var emailBody = "Hi Venue Colombo Team,"
"\n\nThe following data room(s) will need a disc creation. Please begin bulk save data room and create ISO to upload to the FTP site: " +
"\nProject Name: " + ProjectName +
"\nProject ID: " + ProjectId +
"\nProject Manager: " + ProjectManager +
"\nPhase: " + Phase +
"\nDisc Type: " + DiscType +
"\nEncryption: " + Encryption +
"\nQuantity: " + Qty +
"\nClient Due Date: " + DueDate +
"\nSpecialInstructions: " + SpecialInstructions;
var htmlBody = "Thank you for your <b>Club Ambassador Program</b> report submitted on <i>" + timestamp +
"</i><br/> <br/>Person Show Submitted this email: " +
"<br/><font color=\"red\">Your Name:</font> " + activeSessionuser +
"<br/>Your Email: " + toAddress;
var optAdvancedArgs = {name: "Club Ambassador Program", htmlBody: htmlBody};
MailApp.sendEmail(emailAddress, subject, emailBody, optAdvancedArgs);
}
This workflow will apply to columns K, L, M, N, O. Email will be sent to the preset email addresses in the code. I hope this explains it a little bit better. I thank you again for your time and help.
I can get you started:
Add a trigger in Resources>Current project's triggers that triggers sendEmail() "on edit".
...
I just wrote a script that does that kind of thing but I wanted it to keep an eye on all the changes in the sheet but send a message only once every hour to avoid spamming my mailBox.
The script has 2 functions, one that collects the changes and stores them in text format and a second that sends email if any change occurred in the last hour.
The first function is called grabData and must be triggered by an onEdit installable trigger and goes like this :
function grabData(e){
Logger.log(JSON.stringify(e));
var cell = e.range.getA1Notation();
var user = e.user.email;
var time = Utilities.formatDate(new Date(),Session.getScriptTimeZone(),'dd-MM-yyyy')+' à '+Utilities.formatDate(new Date(),Session.getScriptTimeZone(),'hh:mm');;
if(user!='email1#email.com'&&cell!='A1'){
var dataUser1 = PropertiesService.getScriptProperties().getProperty('contentUser1');
if(dataUser1==null){dataUser1=''};
dataUser1+='\nCellule '+cell+' modifiée le '+time+' par '+user+' (nouvelle valeur = '+e.range.getValue()+')';
PropertiesService.getScriptProperties().setProperty('contentUser1',dataUser1);
}
if(user!='email2#email.com'&&cell!='A1'){
var dataUser2 = PropertiesService.getScriptProperties().getProperty('contentUser2');
if(dataUser2==null){dataUser2=''};
dataUser2+='\nCellule '+cell+' modifiée le '+time+' par '+user+' (nouvelle valeur = '+e.range.getValue()+')';
PropertiesService.getScriptProperties().setProperty('contentUser2',dataUser2);
}
}
The other function has a timer trigger, I set it to fire every hour but you can change it to your best fit.
function sendReport(){
var dataUser1 = PropertiesService.getScriptProperties().getProperty('contentUser1');
var dataUser2 = PropertiesService.getScriptProperties().getProperty('contentUser2');
if(dataUser1.length>1){
MailApp.sendEmail('email2#email.com', 'Modification dans le planning FFE', dataUser1);
PropertiesService.getScriptProperties().setProperty('contentUser1','');
}
if(dataUser2.length>1){
MailApp.sendEmail('email1#email.com', 'Modification dans le planning FFE', dataUser2);
PropertiesService.getScriptProperties().setProperty('contentUser2','');
}
}
after a mail has been sent, the stored data is deleted. No mail is sent if no change was recorded.
You can also notice that I have 2 different users and 2 different storage places so that each of them can see what the other does without being notified for his own modifications.
Since both function use installable triggers, this will run on your account so beware not to explode your quotas if you set the timer to a very short period.