OnEdit Cell Index not working with multiple inputs - google-apps-script

I'm trying to write a piece of code that whenever someone on our rosters is terminated it will capture their data, put them into a "termed associates" sheet and delete them from the roster.
The code I wrote works fine for single instances of the change (though it is a bit slow), but the main problem is if I change multiple people to "TERM" in quick succession, it breaks and sometimes will delete rows that aren't the row meant to be deleted.
Here's my code:
const ss = SpreadsheetApp.getActiveSpreadsheet();
const termSheet = ss.getSheetByName('Term Tracker');
const check = SpreadsheetApp.getActiveSheet().getActiveCell().getValue();
function deleteTerm() {
if(check == 'TERM'){
//grabs the cell that has just been edited, finds the index of the row
let sheet = ss.getActiveSheet();
let cell = ss.getActiveCell();
let index = cell.getRowIndex();
//grabs data and posts to new sheet
//grabs values to inset into email
let read = sheet.getRange(index,1,1,55).getValues();
let name = sheet.getRange(index, 4).getValue();
let shift = sheet.getRange(index,1).getValue();
termSheet.insertRowBefore(2);
termSheet.getRange(2,1,1,55).setValues(read);
//deletes the index row
sheet.deleteRow(index)
//mails me a notification someone was termed
MailApp.sendEmail({
to: "{myemail}",
subject: "New Term, " + name ,
body: "There is a new term of " + name + ", please confirm the term reason and term date.
They are on the " + shift + " roster"
});
}}
Any ideas on exactly what I'm doing wrong? I'm still very new to coding, so I'm sure that the code isn't very great. Any feedback would be lovely as well. :)

This should work faster
But any expectation of consistently fast response for an onEdit function is a hopeless wish that is not going to be fulfilled. You must be patient and give it time to operate.
function onEdit(e) {
const sh = e.range.getSheet();
const tsh = e.source.getSheetByName('Term Tracker');
if (e.value == 'TERM') {
let vs = sh.getRange(e.range.rowStart, 1, 1, 55).getValues();
let name = vs[0][3];
let shift = vs[0][0];
tsh.insertRowBefore(2);
tsh.getRange(2, 1, 1, 55).setValues(vs);
sh.deleteRow(e.range.rowStart);
MailApp.sendEmail({to: "{myemail}",subject: "New Term, " + name,body: "There is a new term of " + name + ", please confirm the term reason and term date. They are on the " + shift + " roster"});
}
}

Related

Conditional logic and loops: How can I get this working correctly?

I'm trying to only email the PDFs, created from a Google Sheet, in a drive folder that have not yet been emailed. My strategy thus far has been to create a key ("printed" although for simplicity I should probably rename this variable to emailed.) that changes from a blank to 1 when the if statement runs, thus making it skip over it the next time the code runs. My issue at the moment is that the code runs and sends an email for every row in the Sheet, regardless of what is in the "printed" column. I suspect this is an issue with either the variable type or the logical operator as I am very much a novice at JS (my expertise is Python and VB.Net unfortunately.)
I thank you all for your consideration. Let me know if there is any questions I can clear up.
function createBulkPDFs() {
const docFile = DriveApp.getFileById("1zGTNkzUr_ApaYSpqdu_PKcEuDrVm9r9kA_oyqfIRWeI");
const TempFolder = DriveApp.getFolderById("1h8RHp890f0HGsc-dulwEP9Urrpnq7xcw");
const pdfFolder = DriveApp.getFolderById("1boy1E2Ih3Cp3zMTak8nAUtmtc7e34Y1L");
const currentSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("WorkOrders");
const data = currentSheet.getRange(2,1,currentSheet.getLastRow()-1,11).getDisplayValues();
data.forEach((row, i) => {
var printed = SpreadsheetApp.getActiveSheet().getRange(i + 2, 11).getDisplayValue();
console.log(printed)
if (printed !== 1) {
var ID = SpreadsheetApp.getActiveSheet().getRange(i + 2, 11).setValue(getRndInteger(1000,50000));
console.log(ID)
SpreadsheetApp.getActiveSheet().getRange(i + 2, 11).setValue(1); }
createPDF(row[2], row[3], row[0], row[4], row[1], row[5],row[8], row[6], row[9], docFile, TempFolder, pdfFolder);
var ID = row[9]
console.log(ID)
var file = pdfFolder.getFilesByName(ID)
MailApp.sendEmail("fakeEmail#gmail.com","New Work Order", "Please find the Work Order PDF attached to this email. \n\n This is an automated message, please do not respond.", {name: ID, attachments: [file.next().getAs(MimeType.PDF)]});
SpreadsheetApp.getActiveSheet().getRange(i + 2, 11).setValue(1); }
);
Your if statement ends at this line, so sendMail is executed regardless of the value of printed
SpreadsheetApp.getActiveSheet().getRange(i + 2, 11).setValue(1); }
Besides, you should better do batch operations with getValues() and setValues(values)

Fixing a trigger

I need a trigger (or two) and I'm doing something wrong. Or maybe I need to tweak my code.
I want an email to send automatically when I update a line in my spreadsheet. The three columns that update are notes, status, and resolution. Right now, in my test version, it sends an email as soon as I change any one of those columns. Which is fine, if I'm only updating one thing. But if I want to add a note, change the status, and enter a resolution all at once, it sends three separate emails. My first trigger for sending an email upon form submission works great.
Here is my code. Any help would be appreciated
PS: I'm sure there are cleaner ways to do this, but I'm familiar with this from the past. It's just been long enough that I don't remember all of it.
function formSubmitReply(e) {
var userEmail = e.values[3];
var sheet = SpreadsheetApp.getActiveSheet();
var lastRow = sheet.getLastRow();
// Set the status of the new ticket to 'New'.
// Column F is the Status column
sheet.getRange("F" + lastRow).setValue("New");
// Calculate how many other 'New' tickets are ahead of this one
var numNew = 0;
for (var i = 2; i < lastRow; i++) {
if (sheet.getRange("F" + i).getValue() == "New") {
numNew++;
}
}
MailApp.sendEmail(userEmail,
"Helpdesk Ticket #" + lastRow,
"Thanks for submitting your issue. \n\nWe'll start " +
"working on it as soon as possible. You are currently " +
"number " +
(numNew + 1) + " in the queue. \n\nHelp Desk.",
{name:"Help Desk"});
}​
function emailStatusUpdates() {
var sheet = SpreadsheetApp.getActiveSheet();
var row = sheet.getActiveRange().getRowIndex();
var userEmail = sheet.getRange("D" + row).getValue();
var subject = "Helpdesk Ticket #" + row;
var body = "We've updated the status of your ticket.\n\nStatus: " + sheet.getRange("F" +
row).getValue();
body += "\n\nNotes: " + sheet.getRange("E" + row).getValue();
body += "\n\nResolution: " + sheet.getRange("G" + row).getValue();
MailApp.sendEmail(userEmail, subject, body, {name:"Help Desk"});
}
function onOpen() {
var subMenus = [{name:"Send Status Email", functionName: "emailStatusUpdates"},
{name:"Schedule Appointment", functionName: "scheduleAppointment"},
{name:"Push to KB", functionName: "pushToKb"}];
SpreadsheetApp.getActiveSpreadsheet().addMenu("Help Desk Menu", subMenus);
}​
It looks that you are using an on edit trigger to send and email that works OK when you only need to edit one cell but when you need to edit two or more the email should be sent until you ended to edit all the related cells.
One way to achieve the desired behaviour is to add one or more conditions to send the email.
One way to implement the above is to add an auxiliary column to set if the email should be sent inmediately or not. What about calling this "Hold" and add a checkbox?
This is just is a brief example of how to implement the above as an installe on edit trigger
/**
* Columns C,D,E are notes, status and resolution respectively
* Column F is Hold
*/
function sendUpdate(e){
if(e.range.columnStart > 2 && e.range.columnStart < 6 || e.range.columnStart === 6){
var hold = e.range.getSheet().getRange(e.range.rowStart, 6).getValue();
if( hold !== 'TRUE'){
// Call here your send email function
} else {
// Ask if the email should be sent now
}
}
}

Custom Email based on Cell values in google sheets

I need help while building a Request Approval Flow in google Forms/Sheets
I have a data response sheet similar to like below, Column A to J headers are
"Timestamp" "EmailAddress" "Name" "Targets" "Account#" "Reason" "Access(Days)" "Approver" "Approved" "CaseID"
I have already setup a form submit email trigger to Approval body through formMule AddOn, Now I want to trigger email when Approval body approve or disapprove the request in Data response sheet.
Everytime when anyone select "Y" or "N" to column "I", script should suppose to trigger an email based on the data present in that row.
I am not an expert but tried to do it with following script and unfortunately not getting desired outcome, I set it up Current project trigger to OnEdit
function sendNotification1(e) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Form Responses 1");
if(e.range.getColumn() == 9 && e.value == "Y")
{
var name = e.range.offset(0,-6).getValue();
var comment = e.range.offset(0,-3).getValue();
var email = e.range.offset(0,-7).getValue();
var case1 = e.range.offset(0,1).getValue();
var approver1 = e.range.offset(0,-1).getValue();
var subject = "Request has been Approved";
var body = "Hi " + name + ", your Change Request number " + case1 + " has been approved by " + approver1 + " with following comments: " + "\n\r" + comment;
MailApp.sendEmail(email, subject, body);
}
if(e.range.getColumn() == 9 && e.value == "N")
{
var name = e.range.offset(0,-6).getValue();
var comment = e.range.offset(0,-3).getValue();
var email = e.range.offset(0,-7).getValue();
var case1 = e.range.offset(0,1).getValue();
var approver1 = e.range.offset(0,-1).getValue();
var subject = "Request has been Disapproved";
var body = "Hi " + name + ", your Change Request number " + case1 + " has been Dis-Approved by " + approver1 + " with following comments: " + "\n\r" + comment;
MailApp.sendEmail(email, subject, body);
}
}
StackDriver logging showed the following error, but couldn't identify where the issue exist while referring the cell addresses.
2018-09-14 08:19:06.336 PKT
The coordinates or dimensions of the range are invalid. at sendNotification1(Code:6)
I am able to trigger an email on any edit event with following code, but no luck with conditional edit event trigger.
function sendNotification1(e) {
MailApp.sendEmail("myemail#companygmail.com", "Sample subject", "Sample body");
}
While debugging the code, I can see the following error
TypeError: Cannot read property "range" from undefined. (line 6, file "Code")
Any help will be highly appreciated
You are likely running into the issue of the code not knowing what range you are referring to, because you never tell it where to look.
Add the following to the top of the function:
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("YOUR SHEET NAME");
And it should work perfectly.
EDIT: Here's the email I sent to myself when I tested it.

Setting Script Property using it in "if" in Google

I have a script that is supposed to mail a chart URL when a metric falls out of X range and Only if someone has entered a new metric. It's mailing everytime I run the script so I know the setProperty is not working and the "if" statement isn't working because it's only supposed to mail if X is TRUE.
The sheet... https://docs.google.com/spreadsheet/ccc?key=0Ai_2YLvaQba0dHN1dWFpY0ZSbGpudWF4cTJYNlFwNHc&usp=sharing
My code...
function myAverages() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var value = ss.getSheetByName("EmailServices").getRange("P2").getValue().toString();
var outside = ss.getSheetByName("EmailServices").getRange("S2").getValue().toString;
var mailed = ss.getSheetByName("EmailServices").getRange("T2").getValue().toString();
var stemiAverage = ss.getSheetByName("EmailServices").getRange("R2").getValue().toString();
var stemiChart = ss.getSheetByName("EmailServices").getRange("U2").getValue().toString();
var last = ScriptProperties.getProperty('last');
//if "value" is not equal to ScriptProperty "last" AND "outside" is TRUE, then mail
if(value =! last, outside = "TRUE")
{
MailApp.sendEmail("dave#mydomain.com", "Metric Warning",
"Yearly STEMI Average has fallen below 65%, it is now: " + stemiAverage + "%" +
"\n\nTo see the current trending chart " + stemiChart + "\n\n The sheet that calculated this is here " + ss.getUrl());
ScriptProperties.setProperty('last','value');
}
}
Thanks for any help you can lend. I'm teaching myself this stuff and feel very much like a newby. I've tried a hundred or more combinations to the script before posting here.
As a complement to Phil's answer and following your comment, there is another error in your script :
ScriptProperties.setProperty("last","value");
should be
ScriptProperties.setProperty({'last':value},true);
The true parameter is optional, see documentation on ScriptProperties, it gives you the possibility to delete all other keys.
So you're complete function with corrections would be :
function myAverages(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var value = ss.getSheetByName("EmailServices").getRange("P2").getValue().toString();
Logger.log('value = '+value)
var outside = ss.getSheetByName("EmailServices").getRange("S2").getValue().toString();
Logger.log('outside='+outside)
var mailed = ss.getSheetByName("EmailServices").getRange("T2").getValue().toString();
Logger.log('mailed = '+mailed)
var stemiAverage = ss.getSheetByName("EmailServices").getRange("R2").getValue().toString();
var stemiChart = ss.getSheetByName("EmailServices").getRange("U2").getValue().toString();
var last = ScriptProperties.getProperty('last');
Logger.log('last='+last)
if(value != last && outside == "true"){
MailApp.sendEmail("me#mydomain.com", "Metric Warning",
"Yearly STEMI Average has fallen below 65%, it is now: " + stemiAverage + "%" +
"\n\nTo see the current trending chart " + stemiChart + "\n\n The sheet that calculated this is here " + ss.getUrl());
ScriptProperties.setProperty({'last':value});
Logger.log('mail sent')
}
}
You need to use the AND operator: &&.
And also, checking for equality requires 2 equals signs: ==.
So be sure you try this:
if (value!=last && outside=="TRUE") {

Set Value on a DIFFERENT Sheet in Google Apps Script

I want to do a variation on the "Sending emails from a Spreadsheet" tutorial on the Google Developers page.
I want to do exactly what they walk me through EXCEPT that when it comes to marking the cell in each row every time the e-mail is sent, I want to mark that on a SEPARATE sheet.
So, on the sheet "NeedReminders", my script finds the e-mail addresses of members to whom the e-mail should be sent in column A (which then becomes variable "emailAddress"). It sends the e-mail to that address.
THEN--and here's where I need help--I want the script to go to the "Master" sheet, find the row where emailAddress is in column X, and--in that same row--set the value of column BT.
Shouldn't be difficult. I just don't necessarily know how to do the "find the row where columm X equals emailAddress and set value of BT to today's date" part.
Who can help? Thanks in advance!
Here's my code so far (I'm always embarrassed to show my code because I'm sure it's terrible juvenile, so be gentle, please!):
function sendDuesReminder() {
var sheet = SpreadsheetApp.openById('___').getSheetByName('NeedReminders');
var startRow = 4; // There are a bunch of headers and other nonsense.
var valueSheet = SpreadsheetApp.openById('___').getSheetByName('Master');
// Determine how many rows to process
var rowRange = sheet.getRange(3,4); // On my sheet, cell D3 counts how many members are on the list of people who need a reminder e-mail.
var rowData = rowRange.getValue();
// End Determine how many rows to process
// Send e-mail
var dataRange = sheet.getRange(startRow, 1, rowData, 2);
var data = dataRange.getValues();
for (i in data) {
var row = data[i];
// var emailAddress = row[0]; //Column A: E-mail Address
var name = row[1]; //Column B: First Name
var subject = "Reminder About Dues for Newcomers & Neighbors";
MailApp.sendEmail("matt#twodoebs.com", subject, "Hi, " + name + ". It's been some time since we received your online registration for Newcomers & Neighbors. But we don't seem to have received your dues payment, yet. So we wanted to drop you a quick line and remind you about it." + "\n\n" + "If you think we should have received your payment by now or there's some kind of a mistake, please let us know by responding to this message." + "\n\n" + "Otherwise, please send a check for __ made payable to ___ to:" + "\n\n" + "___" + "\n" + "___" + "\n" + "___" + "\n" + "___" + "\n\n" + "Thanks! Please don't hesitate to reach out if you have any questions." + "\n" + "___" + "\n" + "___" + "\n\n" + "Best wishes," + "\n\n" + "Kati" + "\n" + "Membership Director",
{name:"___"});
// End Send E-Mail
// Set that an a-(Experimental)
var valueRange = valueSheet.getRange // Here's where I kind of break down . . . I need *something* here that searches the sheet for emailAddress
setValue(today()) //I'm also not sure that this is the right way to set the value as today's date
SpreadsheetApp.flush();
// End Set value
}
Browser.msgBox("OK. Reminder messages have been sent. doebtown rocks the house!")
}
If you're still struggling, try this:
var emails = valueSheet.getRange('X:X').getValues();
var targetRange = valueSheet.getRange('BT:BT');
var dates = targetRange.getValues();
for (var j=0; j<emails.length; ++j) {
if (emails[j][0] == emailAddress) {
dates[j][0] = new Date();
break;
}
}
targetRange.setValues(dates);