Code is executed in IF statement when condition is not met - javascript

I have a sheet with over 400 calendar events and I am trying to write a script that will take these events from my spreadsheet and create events for them in my Google Calendar. To prevent the script from duplicating events every time it runs, I am setting the eventID as a check in the last column of my spreadsheet. The logic is that if the startTime column and endTime columns are not blank and the EventID column IS blank, then the script should run and create a new event, then log the ID into the last column.
I am finding that the code logs an eventID in the last column all the time, which means it creates an event every time, even when the conditions are not met.
function createCalendarEvent() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('MasterList');
var data = sheet.getSheetValues(3, 1, sheet.getLastRow(), 12);
var calendar = CalendarApp.getCalendarById('*CalendarID*');
for (var i = 0; i <= sheet.getLastRow(); i++) {
var title = data[i][0]; //String
var date = new Date(data[i][1]); //Date
var startTime = new Date(data[i][9]); //DateTime
var endTime = new Date(data[i][10]); //DateTime
var location = data[i][5]; //String
var status = data[i][11]; //String
var allDay = data[i][3]; //String
if (allDay === 'ALL DAY' && status === ''){
var allDayEvent = calendar.createAllDayEvent(title, date, {location: location});
sheet.getRange(i + 3, 12).setValue(allDayEvent.getId());
}
else if (startTime !== '' && endTime !== '' && status === '' ) {
var event = calendar.createEvent(title, startTime, endTime, {location: location});
sheet.getRange(i + 3, 12).setValue(event.getId());
}
else {
Logger.log('\nRow %s is missing start and/or end time or the event has already been created.\n', i + 3);
}
}
}

Based on suggestions in the comments, I determined that the "empty" cells were being treated at the "zero" date of Google Sheets, which is 12/30/1899 0:00:00. So while I could not see a value in the cell, the code was still grabbing that value. Once I set the condition that the endTime had to be greater than the startTime, it worked out (and flushed out a few errors in the spreadsheet where one of the users indeed entered end times that were before the start time).

Related

Checking checkbox for ID depending on value/validation from other sheet

Here is the sample sheet containing the apps script:
https://docs.google.com/spreadsheets/d/1AOzYMVqOqww4bUfSigDWz6gL6tmESfQxuKw4auNS4kU/edit?usp=sharing
I have a master list that tracks if a transaction letter is sent. 3 letters are supposed to be sent after the transaction date - 1st, 3rd, and 6th months after the initial transaction date so there are 3 checkboxes for each ID. If a letter is sent, right now I manually check one checkbox off depending on what letter month it was for. I created a second sheet that will show all the earliest dates for each ID that is not checked and that is before the date on cell B2. My goal is when I run the script, it will check off all the corresponding checkboxes where the Customer ID and Date is matching.
Here is my current apps script code:
function myFunction() {
var sh1 = Sheets.Spreadsheets.Values.get('1AOzYMVqOqww4bUfSigDWz6gL6tmESfQxuKw4auNS4kU','Payment Due by Date!A4:D');
var sh2 = Sheets.Spreadsheets.Values.get('1AOzYMVqOqww4bUfSigDWz6gL6tmESfQxuKw4auNS4kU','Master List!A2:K');
for(var i = 0; i < sh1.values.length; i++){
var sh1Id = sh1.values[i][0]; //sheet1 ID
var sh1DD = sh1.values[i][2]; //sheet1 date
for(var j = 0; j < sh2.values.length; j++){
var sh2Id = sh2.values[j][0]; //sheet2 ID
var sh2m1d = sh2.values[j][3]; //sheet2 month1 date
var sh2m1c = sh2.values[j][4]; //sheet2 month1 checkbox
var sh2m3d = sh2.values[j][5]; //sheet2 month3 date
var sh2m3c = sh2.values[j][6]; //sheet2 month3 checkbox
var sh2m6d = sh2.values[j][7]; //sheet2 month6 date
var sh2m6c = sh2.values[j][8]; //sheet2 month6 checkbox
//Logger.log(sh2m1c);
//compare the ID & month and check the corresponding checkbox
if(sh1Id == sh2Id && sh1DD == sh2m1d)
sh2m1c = "TRUE";
else if(sh1Id == sh2Id && sh1DD == sh2m3d)
sh2m3c = "TRUE";
else if(sh1Id == sh2Id && sh1DD == sh2m6d)
sh2m6c = "TRUE";
}
}
}
When I checked the logger, the loop is I think getting the values(correct me if I'm wrong). I dont know if my loop is incorrectly ran or if how im checking the checkbox is wrong.
EDIT: A specific example in my sheet of what im trying to do:
If in the Payment Due date this row is present
Customer ID
Customer Name
Payment Due Date
Payment Mo Due
1042
Tom, C
6/5/2020
6th Mo Due
When the script runs I want the checkbox under the 6th Mo Due in Master List for ID 1042 to be checked.
Customer ID
Customer Name
Transaction Date
1st Mo Due
1st Mo Sent?
3rd Mo Due
3rd Mo Sent?
6th Mo Due
6th Mo Sent?
Last Unchecked Date (CALCULATED)
Last Date Due (CALCULATED)
1042
Tom, C
12/5/2019
1/5/2020
TRUE
3/5/2020
TRUE
6/5/2020
FALSE
6/5/2020
6th Mo Due
So under the 6th Mo Sent? column, the checkbox will be checked which is now FALSE or unchecked
Try this:
function myFunction() {
var sheet1 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Master List');
var sheet2 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Payment Due By Date');
var spreadsheetId = SpreadsheetApp.getActiveSpreadsheet().getId();
//Use getDisplayValues so the complier won't automatically convert the date based on timezone.
var sheet1_val = sheet1.getRange(2, 1, 12, 11).getDisplayValues();
//get Ids and merge into 1 dimensional array
var sheet1_ids = [].concat(...sheet1.getRange(2, 1, 12, 1).getDisplayValues());
var sheet2_val = sheet2.getRange(4,1,sheet2.getLastRow()-3, 4).getDisplayValues();
for(var i = 0; i < sheet2_val.length; i++){
var customer_id = sheet2_val[i][0];
var pay_due_date = sheet2_val[i][2];
//check if customer id exists in the id list (sheet1_ids)
if (sheet1_ids.indexOf(customer_id) !== -1) {
//get the position/index of the id
var index = sheet1_ids.indexOf(customer_id);
//I used 3 and 8 since we only need the column D-H
for(var j = 3; j < 8; j++){
//Iterate and check each column if match to the pay_due_date
if(pay_due_date == sheet1_val[index][j]){
//assign new value
sheet1_val[index][j+1] = "TRUE";
}
}
}
}
var lastRow = sheet1.getLastRow();
//merge subarrays with same index
var sheet1Transpose = transpose(sheet1_val);
var request = {
'valueInputOption': 'USER_ENTERED',
'data': [
{
'range': 'Master List!E2:E'+lastRow,
'majorDimension': 'COLUMNS',
'values': [sheet1Transpose[4]]
},
{
'range': 'Master List!G2:G'+lastRow,
'majorDimension': 'COLUMNS',
'values': [sheet1Transpose[6]]
},
{
'range': 'Master List!I2:I'+lastRow,
'majorDimension': 'COLUMNS',
'values': [sheet1Transpose[8]]
}
]
};
var response = Sheets.Spreadsheets.Values.batchUpdate(request, spreadsheetId);
}
function transpose(matrix) {
return matrix[0].map((col, i) => matrix.map(row => row[i]));
}
Note: Make sure to add Google Sheets in Services.
Example:
Payment Due Date:
Before:
After:
Reference:
getDisplayValues
Writing to multiple ranges

Trigger email alert based on last row's condition NOT WORKING

I attempted to build a script but there are some issues. The table format are 2 columns which are date and values. These are the needs:
IDEAL STATE
Grab the last filled row (today's date) in the Google Sheets called "test".
Check in that row if the value in column F is greater than 0.5.
If it greater than 0.5, then trigger an email.
In email body, it should state "Results found on [date]."
This was my starting point but it does not produce what I want. These are the issues:
CURRENT STATE
1.The script grabs every row in which column F was greater than 0.5 in the past. I only want to check for today (which would be the last row). It should not look through everything in the past.
2.The email body states: Result found on [row number]". This makes no sense. I want the date to show, not the row number.
This is the current code. Please help.
function readCell() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("test");
var values = sheet.getRange("F3:F").getValues(); //this has the values
var date = sheet.getRange("D3:D").getValues(); // this has the date
var results = [];
for(var i=0;i<values.length;i++){
if(values[i]>=0.5)
{
results.push("Result found on:" +(i+3));
}
}
MailApp.sendEmail('blabla#gmail.com', 'Alert', results.join("\n"));
};
Last Row in this context is Row 217, not 218, assuming sheet.getLastRow() would ignore #DIV/o! values. See screenshot for this.
LATEST UPDATE
The current Error is related "toDateString". I think it may be related that my Google Sheet is one day behind. So, it today is Jan 10, the last row in my Google Sheet is Jan 9th. I think that is why the error happens. Can you confirm? In that case, how do I change it to today-1 day?
See below.
Here's how you can check the last row:
function readCell() {
var sheet = SpreadsheetApp.getActive().getSheetByName('test');
var lastRow = sheet.getLastRow();
var value = sheet.getRange('F' + lastRow).getValue();
var date = sheet.getRange('D' + lastRow).getValue();
if (value >= 0.5) {
var result = 'Result found on: ' + date;
MailApp.sendEmail('blabla#gmail.com', 'Alert', result);
}
};
After seeing your data, I think the code below would suit you better.
function readCell() {
var sheet = SpreadsheetApp.getActive().getSheetByName('test');
var dates = sheet.getRange('D1:D').getValues();
var date = null;
var dateRow = 0;
var dateCount = dates.length;
var yesterday = new Date();
yesterday.setDate(yesterday.getDate() - 1);
var yesterdayString = yesterday.toDateString();
for (dateRow; dateRow < dateCount; ++dateCount) {
date = dates[dateRow];
if (date instanceof Date) {
date = date.toDateString();
if (date === yesterdayString) {
++dateRow;
// To account for zero-based array
break;
}
}
}
var value = sheet.getRange('F' + dateRow).getValue();
if (value >= 0.5) {
var result = 'Result found on: ' + date;
MailApp.sendEmail('blabla#gmail.com', 'Alert', result);
}
};

Google Script does not trigger as expected given row conditions

I have the 2 columns in my table schema:
Column D= Date, i.e. 20180611 [yyymmdd]
Column F= Continuous Value, i.e. 0.1, 0.6, -0.3 etc.
This is what I want to happen:
Check in column D for yesterday's date. Then, take in the corresponding row, and check if column F is greater than 0.5 (for yesterday's date). If TRUE, then send an email alert.
This is the script I have but it does not trigger for some reason. What is wrong with it?
function readCell() {
var sheet = SpreadsheetApp.getActive().getSheetByName('test');
var dates = sheet.getRange('D1:D').getValues();
var date = null;
var dateRow = 0;
var dateCount = dates.length;
var yesterday = new Date();
yesterday.setDate(yesterday.getDate() - 1);
var yesterdayString = yesterday.toDateString();
for (dateRow; dateRow < dateCount; ++dateCount) {
try {
date = dates[dateRow].toDateString();
if (date === yesterdayString) {
++dateRow;
// To account for zero-based array
break;
}
} catch (error) {
Logger.log(error);
}
}
var value = sheet.getRange('F' + dateRow).getValue();
if (value >= 0.5) {
var result = ('Alert found on: ' + date);
MailApp.sendEmail('blabla#gmail.com', 'Alert', result);
}
};
Here is the data
The problem could be due to the use of an open reference D2:D to get values and then use dates.length to set the number of iterations on the for loop because it could be a number too large.
One "quick and dirty" way that could solve the above issue is to replace
var dateCount = dates.length;
by
var dateCount = sheet.getDataRange().getValues().length;

The if condition in Google Apps Script to send an email from Google sheets doesn't work

The aim of the script below is to send an email from a Google sheet, BUT I only want it to send if a condition is met.
In my spreadsheet in column M (row 12), the value is either TRUE or FALSE. The cell shows TRUE or FALSE based on an AND script that runs inside the cell. For example, one condition for TRUE is that column P is empty (rather than showing EMAIL_SENT). The AND statement works fine.
But when I run the script, it just sends emails regardless of this condition. So something is wrong with the condition...
I based it on this tutorial here... but I just ran it like that and the original doesn't seem to work for me either, which doesn't help I guess!
// Create a date object for the current date and time.
var now = new Date();
// This constant is written in column C for rows for which an email
// has been sent successfully.
var EMAIL_SENT = "EMAIL_SENT";
var SENDYESNO = "FALSE";
function sendEmails2() {
var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 2; // First row of data to process
var numRows = 2; // Number of rows to process
// Fetch the range of cells A2:B3
var dataRange = sheet.getRange(startRow, 1, numRows, 16)
// Fetch values for each row in the Range.
var data = dataRange.getValues();
for (var i = 0; i < data.length; ++i) {
var row = data[i];
var title = row[0];
var name = row[2];
var link = row[9];
var emailAddress = row[10]; // First column
var message = row[14]; // Second column
var emailSent = row[16]; // Third column
var date = row[17];
var yesNo = row[12];
if (yesNo != SENDYESNO) { // Prevents sending duplicates
var subject = "Sending emails from a Spreadsheet";
GmailApp.sendEmail(emailAddress, subject, "Dear " + title + " " + name + ", \n\nThis is an email report of your link. \n\nYour link is " + link + " \n\nKind regards,\nName ", {
from: "my#email.com",
name: "My name"});
sheet.getRange(startRow + i, 16).setValue(EMAIL_SENT);
sheet.getRange(startRow + i, 17).setValue(now);
// Make sure the cell is updated right away in case the script is interrupted
SpreadsheetApp.flush();
}
}
}
I would guess your value is Column M is a boolean true/false and not a text string. You are comparing it to a text string. Try changing
var SENDYESNO = "FALSE";
to
var SENDYESNO = false;
to test against the boolean. I would also change the logic to test for true and then change the if test from != to ===
var SENDYESNO = true;
//more code...
if (yesNo === SENDYESNO) { //continue with your code...

Google Apps Script: Email Reminder Have Time Pulled from Column Values

I'm trying to create a Google Sheets setup with a script that will create calendar events and set reminder times for those events.
I have everything working with one exception: I want to be able to have a column "Reminder Time" where each cell in that column can have a different reminder time to correspond to a given calendar entry (So for example, for Type A, a calendar event will be created with a reminder 3 days in advance, but for Type B, the calendar event will be created 6 days in advance, so in the "Reminder Time" column, the first cell would be 4320 and the second cell would be 8640 (times in minutes)).
My problem is that Type A and Type B are both being assigned the first value in the "Reminder Time" column (The reminder time column is column 8).
function pushToCalendar() {
var sheet = SpreadsheetApp.getActiveSheet();
//Define reminder, THIS IS WHERE MY PROBLEM SEEMS TO LIE
var reminder = sheet.getRange(2, 8).getValue();
var lastRow = sheet.getLastRow();
var range = sheet.getRange(2, 1, lastRow, 5);
var values = range.getValues();
var calendar = CalendarApp.getCalendarById('joncodle9gk4#group.calendar.google.com')
var numValues = 0;
for (var i = 0; i < values.length; i++) {
if ((values[i][0].length > 0) && (values[i][3].length > 0)) {
if (values[i][4] != 'y') {
var newEventTitle = 'Note Due: ' + values[i][0] + ' - ' + values[i][3];
var newEvent = calendar.createAllDayEvent(newEventTitle, values[i][2]);
newEvent.addEmailReminder(reminder);
var newEventId = newEvent.getId();
sheet.getRange(i + 2, 5).setValue('y');
sheet.getRange(i + 2, 6).setValue(newEventId);
}
}
numValues++;
}
}
Your "reminder" is only ever read from H2, rather the row for that event. So you need to move your
var reminder = sheet.getRange(2,8).getValue();
into your row loop:
var reminder = sheet.getRange(i+1,8).getValue();

Categories

Resources