Trying to sort out Google Yearly Time-driven Trigger but failed - google-apps-script

As the Google Apps Script doesn't support yearly triggers, I am trying to run a monthly trigger that runs on a certain date of every month, and if the month is matching my criteria, run the actual function. Here is the code written:
function createYearlyTrigger() {
const sheet=SpreadsheetApp.getActive().getSheetByName("mobile") //<- insert Sheet name
const subjectLine = "Message sent to be Yearly | {{Property}}"; // <-- Insert email draft subject line
sheet.getRange("AH2:AH").setValue("")
ScriptApp.newTrigger("shouldTriggerRun")
.timeBased().onMonthDay(17).atHour(19).create();
}
function shouldTriggerRun() {
var date = new Date();
if (date.getMonth() === 3) {
incrementCell();
}
sendEmails(subjectLine, sheet);
}
Now my target is to run the trigger on 17th day of April. I am also using the following trigger:
But it is not working properly.
Please let me know where I am doing wrong.

Related

Edit a column in google sheets based on a condition

I've a Google sheet which contains two columns first is "Status" column and second is "RegDate" column. I want to update values in the "Status" column if Today's date matches with the RegDate column. Here, I am attaching a sample google sheet for reference.
Basically, I want to write an automated script which will run daily at a certain time and check if the date on which script is running matches with the date present in RegDate column then it should change the corresponding values in "Status" column.
For Eg. If the script is running on 3 Aug 2022 then the row where RegDate is 03-08-2022 should be considered and then "Inactive" value in Status column should be updated to "Active".
I do not have any idea how to automate this, as far as I've researched I need to write a Google AppScript for the same and use a time-driven trigger to run the script daily (Correct me if I am wrong here).
I want to know how can I proceed with this code any help on this would be appreciated. Please also mention any threads which can help me in solving this.
Solution:
Create a daily trigger. You can do this manually (following these steps), or programmatically (executing the function installTrigger below once).
The daily trigger will cause a specific function to execute once daily. On this function, iterate through your range, and for each row, check whether column B date is the same one as today. If that's the case, change column A value to Active.
function updateStatus() {
const now = new Date();
const day = now.getDate();
const month = now.getMonth();
const year = now.getFullYear();
const sheet = SpreadsheetApp.getActive().getSheetByName("Sheet1"); // Change according to your preferences
const range = sheet.getRange("A2:B" + sheet.getLastRow());
const updatedVals = range.getValues().map(row => {
const date = row[1];
if (typeof date.getMonth === 'function' && date.getDate() === day && date.getMonth() === month && date.getFullYear() === year) {
row[0] = "Active";
} else {
// row[0] = "Inactive"; // Uncomment if you want to change status from 'Active' to 'Inactive' if date is not today
}
return row;
});
range.setValues(updatedVals);
}
function installTrigger() {
ScriptApp.newTrigger("updateStatus")
.timeBased()
.everyDays(1)
.create();
}
Note:
I'm unsure whether you want to change status from Active to Inactive if the row date is not today (this was not made explicit on your question). If that's the case, uncomment the corresponding line (row[0] = "Inactive") on the sample above.
Reference:
everyDays(n)

Google Apps Script - Custom Triggers - Just Month + Day - No Year

In short, I have code that I would like to trigger on the first day of a specific month. So, for example, I want to run X-script on Jan 1, but not Feb 1st, March 1st etc. Based on my testing, it seems the atDate function requires the year variable and I'd like the trigger to fire every year on Jan 1, rather than just x year.
This is the version of the timed trigger function I've been working with.
function createTrigger() {
ScriptApp.newTrigger("moveNumbersDecember")
.timeBased()
.atDate(xxxx, 1, 1)
.create();
}
Is there any other function I could use, or workaround for atDate()? My other attempts have been with making the A1 cell on a sheet a clock using today(), then trying to make an if function where if A1 = January 1, then run X script. But I'm very new to coding and haven't been able to make it work.
Any ideas/help extremely appreciated.
GAS do not have yearly trigger, but try this workaround. Create a trigger that runs every month. This runs every month BUT only call the function you want to do if January 1 comes via checking the month of current date.
function createMonthlyTrigger() {
// every month, the trigger created will run checkIfJan1()
ScriptApp.newTrigger("checkIfJan1")
.timeBased()
.onMonthDay(1)
.atHour(0)
.create();
}
function checkIfJan1() {
var date = new Date();
// if jan 1, then run moveNumbersDecember()
if (date.getMonth() === 0) {
moveNumbersDecember();
}
}

Alternative to using triggers to automatically send email for each calendar event created

I am trying to automate certain parts of my workflow for scheduling clients with Google Calendar. I've successfully managed to capture new/edited/deleted events in Google Apps Script using a trigger which detects changes and Calendar.event.list to sync those changes with a spreadsheet.
I create a new row, or edit an existing one, in my spreadsheet of all the clients. What I desire to do is three days before the appointment with the client, automatically generate a custom email with all of their details, to send them as a reminder regarding the appointment.
My plan was every time a new row was created in the Spreadsheet (when a new Calendar event was created), was to make a new email trigger. That trigger would execute code to create an email, with all of the clients info.
function createEmailTrigger(event) {
var today = new Date();
today.setHours(0,0,0,0); // Don't care about time
// Create Email Trigger three days before
const sendDaysBefore = 3;
var daysBefore = new Date(event.start);
daysBefore.setDate(daysBefore.getDate() - sendDaysBefore);
var trigger = ScriptApp.newTrigger('sendEmail')
.timeBased()
.at(daysBefore)
.create();
associateEventWithTrigger(trigger.getUniqueId(), event);
return trigger.getUniqueId();
}
associateEventWithTrigger connects the trigger id with the Calendar event. sendEmail would then create a new email with all of the client's info, which came from the Calendar event. When the trigger is executed, it deletes the trigger since it won't be used again.
All of this was working fine, as I was testing one Calendar event at a time. However, once I decided to sync all of this year's Calendar events, the script very quickly threw this error:
Exception: This script has too many triggers. Triggers must be deleted from the script before more can be added.
Apparently you can only have 20 triggers per user/script. This is very inconvenient, as I was expecting to create hundreds of triggers.
Therefore, I need to rethink how to go about doing this. Any suggestions? I appreciate it.
Proposed workaround
This script is designed to be run on a time-driven trigger that runs daily.
function sendReminderEmails() {
let file = SpreadsheetApp.getActive();
let sheet = file.getSheetByName("Sheet1");
let range = sheet.getDataRange();
let values = range.getValues();
// removing headers
values.shift()
values.forEach(row => {
let name = row[0]
let email = row[1]
let date = row[2]
// Date object representing time now
let now = new Date();
// helper variables
let second = 1000;
let minute = second * 60;
let hour = minute * 60;
let day = hour * 24;
// gets time to appointment in milliseconds
let timeToApp = date.getTime() - now.getTime()
if (timeToApp > 2 * day && timeToApp < 3 * day) {
MailApp.sendEmail(
email,
"Remember Your Appointment",
"Hello " + name + ",\nYou have an appointment coming up soon."
)
}
})
}
This is based on a sample spreadsheet like this:
So you would need to adapt it to your particular format.
Script walkthrough
It is based on the date object.
If your dates are stored as formatted dates in your spreadsheet, when you getValues, Apps Script will automatically pass them as Date object. Alternatively you can cast them as Date objects in Apps Script if needed.
The script starts off by getting all the values in the target sheet.
It initialized a new Date object that represents the time now.
It then goes through each row of the target sheet and gets a value for how long until the appointment.
If the value is between 2 days and 3 days, then an email is sent.
I Think you could make an script to search events every day , events that are 3 days ahead , select then and send email. So it will be just one script that will be triggeres every day, using the date trigger mode.

Copy Sheet to new workbook from template based on date

I have a template sheet inside a workbook that I want to copy to a new workbook that is not yet created. I want this to run on the 29th of each month and do the following:
Take a Spreadsheet names "Template" and the sheet named “Template..2020.”
Create a new Spreadsheet called "December 2020" for example, and rename the first tab to 12.01.20, which I can then copy and rename for every day of the month.
I have tried a few copy functions with time triggers but they have required a blank workbook to be open already.
Example Script
This script
Function createSheetFromTemplate
Uses the date object to get information about today's date and extracts the year, month, day etc.
Gets the template from another sheet using SpreadsheetApp.openById
Creates a new Sheet based on information from today's date.
Copies the template sheet and renames it based on the date.
Function createTrigger
Using ClockTriggerBuilder, creates a trigger to run on the 29th of each month.
Disclaimer: At the moment this script just creates a new Spreadsheet with today's month and a new sheet named with today's date. I understand you may be looking to create a sheet for next month. This problem is probably best served by another question - perhaps look here.
function createSheetFromTemplate() {
// Getting details of today's date
let date = new Date()
let year = date.getFullYear()
let month = date.getMonth() + 1
let monthName = date.toLocaleString('default', { month: 'long' });
let day = date.getDate()
console.log(year, monthName, day)
// Get template based on year
let templateSpread = SpreadsheetApp.openById("1H7GBVxK4f0nmYR5xfZawy6nreDTCZaj76-dKE9eOtUE")
let templateSheet = templateSpread.getSheetByName("Template_" + year)
// Create new Spreadsheet with renamed template
let newSpread = SpreadsheetApp.create(monthName + " " + year)
let newSheet = templateSheet.copyTo(newSpread).setName(year.toString().substring(2,4) + "." + month + "." + day)
let sheetToDelete = newSpread.getSheetByName("Sheet1")
newSpread.deleteSheet(sheetToDelete)
}
// Create trigger to run on 29th of each month.
function createTrigger() {
ScriptApp.newTrigger('createSheetFromTemplate')
.timeBased()
.onMonthDay(29)
.create();
}
References
date object
SpreadsheetApp.openById
ClockTriggerBuilder

How to create a yearly time-driven trigger?

I'm attempting to create a time-based trigger to execute my incrementCell function once a year on a specified date at 1 AM in perpetuity. When attempting to run below
ScriptApp.newTrigger("incrementCell").timeBased().atDate(2018, 1, 4).atHour(1).everyWeeks(52).create();
I received an "Already chosen a specific date time with at() or atDate()." error.
Interestingly, the line immediately below does not error out:
ScriptApp.newTrigger("incrementCell").timeBased().atDate(2018, 1, 4).create();
Google Apps Script doesn't support yearly triggers but you can use a workaround. Create a monthly trigger that runs on the 1st of every month, and if the month is January, run the actual function.
function createYearlyTrigger() {
ScriptApp.newTrigger("shouldTriggerRun")
.timeBased().onMonthDay(1).atHour(1).create();
}
function shouldTriggerRun() {
var date = new Date();
if (date.getMonth() === 0) {
incrementCell();
}
}