Comparing Dates in Google Sheets Script Editor - google-apps-script

I am very new to this, so please bear with me. I am trying to get my code to look at each cell in a column, then compare that date to the current date, and if they match send an email. I am aware I will need a loop of some sort to get it to look through the column, but I haven't even gotten that far. I've tried every method I can find online to just get it to compare one cell to the date and send the email.
I tested the email function prior to adjusting it to compare the date, so I know that is working. Put something definitely isn't working...
function sendEmail() {
//Fetch the date
var removalDateRange = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Expirations").getRange("E2");
var removalDate = removalDateRange.getValue();
var currentDateRange = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Alerts").getRange("C2");
var currentDate = new Date();
var ui = SpreadsheetApp.getUi();
//Check Date
if (removalDate == currentDate) {
//Fetch the email address
var emailRange =
SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Alerts").getRange("B2");
var emailAddress = emailRange.getValue();
//Fetch Item Brand
var itemBrandRange =
SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Expirations").getRange("B2");
var itemBrand = itemBrandRange.getValue();
//Fetch Item Name
var itemNameRange =
SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Expirations").getRange("A2");
var itemName = itemNameRange.getValue();
//Fetch Item Location
var itemLocationRange =
SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Expirations").getRange("H2");
var itemLocation = itemLocationRange.getValue();
// Send Alert Email
var message = 'The ' + itemBrand + ' ' + itemName + ' in ' + itemLocation + ' will expire in 2 months. Please use and replace item.';
// Second Column
var subject = 'Pantry Alert';
MailApp.sendEmail(emailAddress, subject, message);
}
}
EDIT
Okay, I had it working late last night and even got it to loop through, and somehow I've broken it again. I've been looking at answers for hours trying to adjust things to make it work. What am I doing wrong?
function emailAlert() {
// today's date information
var today = new Date();
var todayMonth = today.getMonth() + 1;
var todayDay = today.getDate();
var todayYear = today.getFullYear();
// 2 months from now
var oneMonthFromToday = new Date(todayYear, todayMonth, todayDay);
var oneMonthMonth = oneMonthFromToday.getMonth() + 2;
var oneMonthDay = oneMonthFromToday.getDate();
var oneMonthYear = oneMonthFromToday.getYear();
// getting data from spreadsheet
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Exp");
var startRow = 2; // First row of data to process
var numRows = 500; // Number of rows to process
var dataRange = sheet.getRange(startRow, 1, numRows, 999);
var data = dataRange.getValues();
//looping through all of the rows
for (var i = 0; i < data.length; ++i) {
var row = data[i];
var expireDateFormat = Utilities.formatDate(new Date(row[5]),
'ET',
'MM/dd/yyyy'
);
//email Information
var subject = 'Pantry Item Needs Attention!';
var message1 =
row[6] + ' ' + row[3] + ' of ' + row[2] + ' ' + row[1] + ' will expire on ' + expireDateFormat + '. Item can be found in ' + row[7]
+ '. Please Remove and Replace Item.' +
'\n' + 'Thanks Steve!';
var message2 =
row[6] + ' ' + row[3] + ' of ' + row[2] + ' ' + row[1] + ' will expire on ' + expireDateFormat + '. Item can be found in ' + row[7] +
'. Please ensure item has been replaced, removed from the pantry, and deleted from inventory.' +
'\n' + 'Thanks Steve!'
//expiration date information
var expireDateMonth = new Date(row[5]).getMonth() + 1;
var expireDateDay = new Date(row[5]).getDate();
var expireDateYear = new Date(row[5]).getYear();
//checking for today
if (
expireDateMonth === todayMonth &&
expireDateDay === todayDay &&
expireDateYear === todayYear
) {
ui.alert(message1);
}
}
}

Dates can be frustrating to work with, so consider doing the whole thing (loop, if then statement...) with an integer first and then returning to the date part if you're having trouble. That said, try adjusting the top of your code to look like the following:
var ss =SpreadsheetApp.getActiveSpreadsheet();
var removalDateVal = ss.getSheetByName("Expirations").getRange("E2").getValue();
var removalDate = new Date(removalDateVal);
var currentDateVal = ss.getSheetByName("Alerts").getRange("C2").getValue();
var currentDate = new Date(currentDateVal);
That will give you two date objects. But BEWARE! These dates contain time as well as calendar date so they may not equal each other even when they appear to. Use setHours() to zero out the date as seen below.
currentDate.setHours(0,0,0);
removalDate.setHours(0,0,0);
Other notes, it's best practice to set a variable for a spreadsheet and worksheet as shown by Google here. It makes the code much more readable.

Related

google sheet email alert if expiry date

I have a table with 8 columns with dates. I need to track them if they are to expire, but for 3 of them I need to alert alert 3 months before and for the remaining columns, 6 months before.
I think that I am on the right track with the code below, but still not doing what it needs to be done.
I start with one month in the beginning. Can somebody help me?
function emailAlert() {
// today's date information
var today = new Date();
var todayMonth = today.getMonth() + 1;
var todayDay = today.getDate();
var todayYear = today.getFullYear();
var newToday = new Date()
var oneMonthFromToday = new Date(newToday.setMonth(newToday.getMonth()+1));
var oneMonthMonth = oneMonthFromToday.getMonth() + 1;
var oneMonthDay = oneMonthFromToday.getDate();
var oneMonthYear = oneMonthFromToday.getFullYear();
var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 2;
var numRows = 100;
var dataRange = sheet.getRange(startRow, 1, numRows, 999);
var data = dataRange.getValues();
//looping through all of the rows
for (var i = 0; i < data.length; ++i) {
var row = data[i];
var expireDateFormat = Utilities.formatDate(
new Date(row[6]),
'ET',
'MM/dd/yyyy'
);
var subject = '';
var message = ' You have expiring pass. ' + '\n';
MailApp.sendEmail('lubomira.petkova88#gmail.com', subject, message);
}
It is not clear on your post but the code below assumed only 1 column needs to be checked. Feel free to adjust the conditions but this should be the main idea of your code.
Code:
function checkPasswordExpiry() {
// today's date information
var today = new Date();
today.setHours(0,0,0,0);
// 3 months before
var prev3Months = new Date();
prev3Months.setMonth(today.getMonth() - 3);
prev3Months.setHours(0,0,0,0);
// 6 months before
var prev6Months = new Date();
prev6Months.setMonth(today.getMonth() - 6);
prev6Months.setHours(0,0,0,0);
var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 2;
// get number of rows/columns in sheet instead of manually setting it
var numRows = sheet.getLastRow();
var numCols = sheet.getLastColumn();
var dataRange = sheet.getRange(startRow, 1, numRows, numCols);
var data = dataRange.getValues();
//looping through all of the rows
for (var i = 0; i < data.length; ++i) {
var row = data[i];
var expireDateFormat = Utilities.formatDate(
new Date(row[6]),
'ET',
'MM/dd/yyyy'
);
var date = new Date(row[6]);
date.setHours(0,0,0,0);
var subject = 'Password Expiry';
var message = 'Hi ' + row[0] + ', \nYour password is expiring';
var email = 'lubomira.petkova88#gmail.com';
if(date.getTime() === prev6Months.getTime()) {
message += " in 6 months. ( " + expireDateFormat + " )";
MailApp.sendEmail(email, subject, message);
}
else if(date.getTime() === prev3Months.getTime()) {
message += " in 3 months. ( " + expireDateFormat + " )";
MailApp.sendEmail(email, subject, message);
}
else if(date.getTime() === today.getTime()) {
message += " today. ( " + expireDateFormat + " )";
MailApp.sendEmail(email, subject, message);
}
}
}
The code above does check column G whether it is already 6 months before today, 3 months before today or exactly the date. If you need to check multiple columns, just replace the conditions inside and it should still work.
Sample email:
Note that the code above should be triggered every day so it can check the data daily.
Code:
function createTimeDrivenTriggers() {
ScriptApp.newTrigger('checkPasswordExpiry')
.timeBased()
.everyDays(1)
.atHour(0)
.create();
}
Function createTimeDrivenTriggers needs to be run just once. Please see reference below.
Reference:
Time driven triggers
everyDays()
If I wasn't able to provide you the answer you are hoping for, I sincerely apologize. Feel free to comment below what are the changes that are needed to be done.

Slack message based on date in Google Spreadsheet

I have a spreadsheet with several payment dates and want to create a slackbot to post a message to Slack when the date in one specific column match today's date. I'm very new to coding and I'm using a code I found to send an email, but can't find nothing about posting it to Slack. Could someone give me a hand, please?
This is the code I'm using to send email:
function emailAlert() {
// today's date information
var today = new Date();
var todayMonth = today.getMonth() + 1;
var todayDay = today.getDate();
var todayYear = today.getFullYear();
// getting data from spreadsheet
var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 2; // First row of data to process
var numRows = 100; // Number of rows to process
var dataRange = sheet.getRange(startRow, 1, numRows, 999);
var data = dataRange.getValues();
//looping through all of the rows
for (var i = 0; i < data.length; ++i) {
var row = data[i];
var expireDateFormat = Utilities.formatDate(
new Date(row[6]),
'ET',
'yyyy/MM/dd'
);
// email information
var subject = '';
var message =
'Hello' +
'\n' +
'\n' +
'These are the due dates for today:' +
'\n' +
'\n' +
' ID number: ' +
row[0] +
'\n' +
' Name: ' +
row[1] +
'\n' +
' Due date: ' +
expireDateFormat;
//expiration date information
var expireDateMonth = new Date(row[6]).getMonth() + 1;
var expireDateDay = new Date(row[6]).getDate();
var expireDateYear = new Date(row[6]).getFullYear();
//checking for today
if (
expireDateYear === todayYear &&
expireDateMonth === todayMonth &&
expireDateDay === todayDay
)
{
var subject =
'Due date ' + row[1] + ' - ' + expireDateFormat;
MailApp.sendEmail('email address here', subject, message);
Logger.log('todayyyy!');
}
}
}
Here is a http post request shows how to send a post to Slack
POST https://slack.com/api/chat.postMessage
Content-type: application/json
Authorization: Bearer xoxb-your-token
{
"channel": "YOUR_CHANNEL_ID",
"text": "Hello world :tada:"
}
Chackout more information from : https://api.slack.com/messaging/sending

Time-driven trigger (daily) not triggering every day

I have the similar issue as described at How to make sure a daily time trigger runs?.
I have a specific script in one of the Google sheets with a daily trigger (time-driven, should trigger every morning, set up through interface, not programmatically). But the script doesn't execute every day. I can see this in the execution report, where there're just successful executions and no failed ones. I can also see if the script executed by checking a cell in the sheet which gets updated with the execution timestamp when the script runs. And I've set up an immediate notification for the failed executions in the trigger settings.
In my specific case, the script should ran every day from Nov 9 - Nov 13, but it ran just on Nov 9, Nov 10, Nov 12. And I didn't get any notification about the failed execution.
The script itself doesn't use any API, it's pretty basic: reading data in one sheet, doing some calculation and writing to another sheet (talking about the sheets in single Google Sheet file).
If I run the main function manually, it always works.
I'd be very glad to get some ideas what could be wrong. Thanks.
EDIT: Code sample (main function and prototype for Array.includes)
function main(){
var date = new Date();
//var date = new Date(2019, 9, 1); // year, month (zero-indexed!!!), day
//var date = new Date(date.getYear(), date.getMonth()-3); // testing
var currentDay = Utilities.formatDate(date, "CET", "d");
Logger.log('currentDate: ' + Utilities.formatDate(date, "CET", "YYYY-MM-dd HH:mm:ss.S") + ' | currentDay: ' + currentDay);
if (currentDay == 1) {
Logger.log('currentDay is 1st of the month');
date = new Date(date.getYear(), date.getMonth() - 1);
var newCurrentDay = Utilities.formatDate(date, "CET", "d");
}
var monthToCheck = Utilities.formatDate(date, "CET", "MMMM").toUpperCase();
var yearToCheck = Utilities.formatDate(date, "CET", "YYYY");
Logger.log('dateToCheck: ' + Utilities.formatDate(date, "CET", "YYYY-MM-dd HH:mm:ss.S") + ' | monthToCheck: ' + monthToCheck + ' | yearToCheck: ' + yearToCheck);
var firstProjectRow = 7; // first row with the project data
var firstProjectCol = 1; // first column with project data - should contain Tool IDs
var numOfProjectRows = 999; // num of project rows to check (counted from and including var firstProjectRow)
var numOfProjectCols = 21; // num of project columns to check (counted from and including var firstProjectCol the last one contains number of hours for the last service)
var firstProjectHoursCol = 7; // first column with data about project hours (usually PM hours)
// ************* DO NOT EDIT BELOW THIS LINE ************* //
//return;
var indexedFirstProjectHoursCol = firstProjectHoursCol - 1;
var ss = SpreadsheetApp.getActiveSpreadsheet();
//var sheet = ss.getSheets()[3];
var sheetName = monthToCheck + ' ' + yearToCheck;
var sheet = ss.getSheetByName(sheetName);
Logger.log('sheet: ' + sheetName);
var range = sheet.getRange(firstProjectRow, firstProjectCol, numOfProjectRows, numOfProjectCols); // getRange(row, column, numRows, numColumns)
var rangeValues = range.getValues();
//Logger.log('rangeValues: "' + rangeValues);
var toolData = new Array();
var toolIds = new Array();
var toolHours = new Array();
//return;
for (var row in rangeValues) {
Logger.log('row: "' + row);
var clientId = rangeValues[row][0];
var projectId = rangeValues[row][1];
var hoursSum = 0;
// we have Tool ID so it's OK to proceed
if (clientId != "" && projectId != "") {
var clientProjectId = clientId + "-" + projectId;
for (var col in rangeValues[row]) {
var cellValue = rangeValues[row][col];
//Logger.log('col: ' + col + ' value: ' + value);
// get hours sum
if (col >= indexedFirstProjectHoursCol)
hoursSum += typeof cellValue == 'number' ? cellValue : 0;
}
//Logger.log('hoursSum: [' + hoursSum + ']');
var record = {id: clientProjectId, hours: hoursSum};
Logger.log("Data: " + record.id + " : " + record.hours);
// don't yet have a record of clientId-projectId
if (!toolIds.includes(clientProjectId)) {
toolData.push(record);
}
else {
recordIdx = toolIds.indexOf(clientProjectId);
toolData[recordIdx].hours += hoursSum;
}
toolIds = [];
toolHours = [];
toolData.forEach(function(item) {
toolIds.push(item.id);
toolHours.push(item.hours);
});
}
//Logger.log(toolData);
//Logger.log('ROW DONE!');
}
Logger.log('ROWS DONE!');
Logger.log('toolData.length: ' + toolData.length);
toolData.forEach(function(item) {
Logger.log('toolData: ' + item.id + " : " + item.hours);
});
Logger.log('DONE!!!');
// fill the table in the sheet with assigned number of hours
fillTheSheet(sheetName, toolData);
}
Apps Script triggers have always been a bit finicky. But of late they have been far more unreliable than usual (there have been several reports of spurious triggers and other maladies).
In this case, you can avoid using them altogether by leveraging an external service such as cron-jobs.org.
You'll have to refactor your app script project and deploy it as a public Web App with a doPost(e) function. You'd then pass the Web App's url to the external service as a web-hook endpoint that is invoked daily.

copy active row From one sheet to another google sheets

I am having trouble copying a single row to a second sheet with google sheets.
I am using Google script editor to send automated email updates which works fine. However I am now trying to log each update from specific columns. I need all the information in the row to move with the cell that is edited.
Each Row is a separate job-site and I will have up to 30 concurrent job-sites going on at one time. So the update may come in in cell "M3" or "M28"
What I am trying to do is capture only the row that is edited not the whole sheet. My current code is copying the whole sheet. I am drawing a blank on how to just define the single row as active and set it to a range.
Here is what I have. I am no java script programmer but searching this site has gotten me this far. Bare with the code is not perfect.
function sendupdate() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var cell = ss.getActiveCell().getA1Notation();
var row = sheet.getActiveRange().getRow();
var cellvalue = ss.getActiveCell().getValue().toString();
var recipients = '';
var message = '';
var techname = '';
var branchname = '';
var city = '';
var state = '';
var technumber = '';
if(cell.indexOf('M')!=-1){
message = sheet.getRange('B'+ sheet.getActiveCell().getRowIndex()).getValue()
techname = sheet.getRange('N'+ sheet.getActiveCell().getRowIndex()).getValue()
branchname = sheet.getRange('H'+ sheet.getActiveCell().getRowIndex()).getValue()
city = sheet.getRange('J'+ sheet.getActiveCell().getRowIndex()).getValue()
state = sheet.getRange('K'+ sheet.getActiveCell().getRowIndex()).getValue()
recipients = "(emailaddress";
var subject = ' Update: ' +techname + ' ' + message + ' ' + city + ' ' + branchname +' ' ;
var body = ': ' + message + ' Technician: « ' + techname + ' » New Update: « ' + cellvalue + ' » has been posted to the Update Sheet Visit ' + ss.getUrl() + ' to view the changes on row: ' + row + '';
MailApp.sendEmail(recipients, subject, body);
var target_sheet = ss.getSheetByName('Log')
var last_row = target_sheet.getLastRow();
target_sheet.insertRowAfter(last_row);
sheet.getRange('A:P').copyTo(target_sheet.getRange('A'+(last_row+1)+':P'+(last_row+1)));
}
debugger
Here is the code I added which made it work
var target_sheet = ss.getSheetByName('Log')
var last_row = target_sheet.getLastRow();
var activeRow = sheet.getRange( row ,1, 1 ,16)
target_sheet.insertRowAfter(last_row);
activeRow.copyTo(target_sheet.getRange('A'+(last_row+1)+':P'+(last_row+1)));
Get the Range of the active row by calling getRange(row, column, numRows). You can then use that range to copy it to the other sheets

Google Script says: You have been creating or deleting too many calendars or calendar events in a short time. Please try again later

I am getting this extremely frustrating error. I am in no way creating or deleting too many calendars - at most I've created about 20 and my script is trying to create just one!
I've narrowed down the problem to event.addGuests(). When I remove this line, the event gets added. When I keep it, this is where Google reports the error to be.
I've tried adding
Utilities.sleep(5000);
before event.addGuest() to see if slowing the script down would work, but this doesn't work either.
Here is the whole script. Note, there is only one item in the spreadsheet now
var ACCEPTED = "ACCEPTED";
var PUBLISHED = "PUBLISHED"
var NOT_PUBLISHED = "NOT_PUBLISHED";
function createCalendarEventsFromSheets(){
// Get Calendar Info
var calId = "privatecalendar#group.calendar.google.com";// use default claendar for tests
var cal = CalendarApp.getCalendarById(calId);
// Get Google Sheet Info
var ss = SpreadsheetApp.openById('privatespreadhseet');
var sheet = ss.getSheets()[0];
var range = sheet.getDataRange();
var rows = range.getValues();
Logger.log("Rows found: " + rows.length);
// Iterate through Google Sheets rows and create events
for (i = 1; i < rows.length; i++){
var row = rows[i];
// Gather variables for row
var eventTitle = row[1];
var date = new Date(row[2]);
var location = row[3];
var shiftStart = row[4];
var shiftEnd = row[5];
var eventStart = row[6];
var eventEnd = row[7];
var numberOfKeys = row[8];
var role = row[9];
var notes = row[10];
var accepted = row[13];
var alreadyPublished = row[14]
// If event has been accepted and wasn't published yet, create event
Logger.log("accepted: " + accepted + ", alreadyPublished " + alreadyPublished);
if (accepted == ACCEPTED && alreadyPublished != PUBLISHED){
Logger.log("**** TRUE ****");
// Set up calendar event
var cal_start = new Date(date.getYear(), date.getMonth(), date.getDate(), shiftStart.getHours(), shiftStart.getMinutes());
Logger.log("cal_start: " + cal_start);
var cal_end = new Date(date.getYear(), date.getMonth(), date.getDate(), shiftEnd.getHours(), shiftEnd.getMinutes());
Logger.log("cal_end: " + cal_end);
var description = "Keys Required: " + numberOfKeys + "\n\nRole: " + role + "\n\nEvent Start Time: " + eventStart.getHours() + ":" + eventStart.getMinutes() + ", Event End Time: " + eventEnd.getHours() + ":" + eventEnd.getMinutes() + "\n\nNotes:\n" + notes;
// CREATE EVENT
var event = cal.createEvent(eventTitle, cal_start, cal_end);
event.setDescription(description);
event.setLocation(location);
//Utilities.sleep(5000); // I've tried this, to no avail
event.addGuest("rap#gmail.com"); //error message details point to here
event.addGuest('e.leg#gmail.com');
event.addGuest('ba#hotmail.com');
event.addGuest('r#hotmail.com');
event.addGuest('js#gmail.com');
event.addGuest('w#gmail.com');
event.addGuest('no.abe#gmail.com');
event.addGuest('esth#gmail.com');
event.addGuest('carolin#gmail.com');
event.addGuest('kalan#gmail.com');
event.addGuest('bob#gmail.com');
event.addGuest('rob#gmail.com');
sheet.getRange(i+1, 15).setValue(PUBLISHED);
Logger.log("Event created, starting at: " + event.getStartTime());
}
}
}