Google Script cell value email notification by current date - javascript

I would like to send automated email notifications from my google spreadsheet if the value in column E is higher than 0. The spreadsheet looks like this. The problem is I cant figure out how to check only values for current days date and then post by email. My code looks like this
var failedOperationRange = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("notif").getRange("E2");
var failedOperation = failedOperationRange.getValue();
var ui = SpreadsheetApp.getUi();
// Check totals sales
if (failedOperation > 0){
// ui.alert('Failed operation occured!');
// Send Alert Email.
var message = failedOperation;
var subject = 'Your Google Spreadsheet Alert';
for(var i in TO) {
MailApp.sendEmail(TO[i], subject, message);
}

Get the value for the corresponding row in column 'H' and compare it with a javascript Date object.
If you need the current date in a string format you can use this:
var today = new Date();
today.toLocaleDateString(); // 3/26/2020
Then you send the email if the two conditions (failed operations > 0 and date = today) are satisfied.

Related

Get Name and Surname from Username in Google Apps Script

I use a script to automatically insert the date and username to fill in the string. Several people fill out the table. How can I modify the script so that the first name and the last name are inserted instead of the username?
function onEdit(e) {
var sheet = e.source.getActiveSheet();
var idCol = e.range.getColumn();
var idRow = e.range.getRow();
if ( idCol == 4 && sheet.getName() =='LIST1' ) {
var Value = e.range.offset(0, -2).getValues();
if ( Value == "" ) {
var vartoday = getDate(); //Gets the current date//
sheet.getRange(idRow, 2).setValue( vartoday ); //Inserts into column 2 of the current row//
var u = Session.getEffectiveUser().getUsername(); //Gets the username of the editor//
sheet.getRange(idRow, 7).setValue(u); //Inserts into column 7 of the current row//
}
}
function getDate() {
var today = new Date();
today.setDate(today.getDate());
return Utilities.formatDate(today, 'GMT+03:00', 'dd/MM/yy');
}
}
Looks like you are storing the username here -
var u = Session.getEffectiveUser().getUsername(); //Gets the username of the editor//
And then inserting the username here -
sheet.getRange(idRow, 7).setValue(u); //Inserts into column 7 of the current row//
You will want to split the name before you store it. Something like this -
var first_name = // Split by your delimeter here and store first name
var last_name = // Split by your delimeter here and store last name
sheet.getRange(idRow, 7).setValue(first_name); //Inserts into column 7 of the current row//
sheet.getRange(idRow, 8).setValue(last_name); //Inserts into column 8 of the current row//
Issue:
getUsername() only gives the email address without the domain part (that is, the content before #). It doesn't provide information on the name or surname, assuming that not every email address is formatted in a distinguishable way, as suggested in other answers (e.g. name.surname).
If you want to access the actual name and surname of a user, you would need to access the Users resource from Directory API. The easiest way to do that is to use the advanced Admin SDK Directory Service on your script.
Important note: This requires the use of Admin SDK, which can only be used by Google Workspace (formerly G Suite) accounts. If you are not a Workspace user, there's no way to retrieve this information.
Workflow:
Enable the advanced Directory Service on your script by clicking Resources > Advanced Google Services..., set the directory_v1 to on and click OK: see example.
Since accessing this API requires authorization, and simple triggers cannot access service that require authorization (see Restrictions), you will have to install the onEdit(e) trigger. First, change the name of your function so that it's not called onEdit. That's a reserved function name, to be used for simple triggers (I called it fireOnEdit on the code sample below).
Install the trigger, either manually (see example settings) or programmatically.
In installed triggers, the effective user is the user who installed the trigger, not the one whose edit triggered the script. Therefore, you would need to use getActiveUser(), or the event object (property e.user) instead.
Using the Advanced service, retrieve the active user properties by calling Users: get.
Retrieve the two desired fields from the API response: first name (User.name.givenName) and family name (User.name.familyName).
Code sample:
function fireOnEdit(e) {
var sheet = e.source.getActiveSheet();
var idCol = e.range.getColumn();
var idRow = e.range.getRow();
if ( idCol == 4 && sheet.getName() =='LIST1' ) {
var Value = e.range.offset(0, -2).getValues();
if ( Value == "" ) {
var vartoday = getDate(); //Gets the current date//
sheet.getRange(idRow, 2).setValue( vartoday ); //Inserts into column 2 of the current row//
var email = e.user.getEmail();
var user = AdminDirectory.Users.get(email);
var name = user.name.givenName;
var surname = user.name.familyName;
//sheet.getRange(idRow, 7).setValue(name + " " + surname); // Name and surname copied to the same cell in G
sheet.getRange(idRow, 7, 1, 2).setValues([[name, surname]]); // Name and surname copied to G and H
}
}
function getDate() {
var today = new Date();
today.setDate(today.getDate());
return Utilities.formatDate(today, 'GMT+03:00', 'dd/MM/yy');
}
}
Notes:
Information on the active user might not always be available (for example, if the user who created the trigger and the one causing the script to run don't belong to the same domain). See this answer, for example.
You would need to install the trigger with an account that has access to the Users resource from Directory API.
I'm unsure whether you want to concatenate both first name and surname in the same cell, or add one to column G and the other to column H. I added both possibilities in the code sample, please comment/uncomment the corresponding lines according to your preferences.
If you're a Gsuite/Google workspace customer, You can use Directory API as mentioned in this answer.
If not, You may be able to leverage the identity token provided by ScriptApp.
★ You need to get explicit permission from each of your editor to get their name. Without getting explicit permission, You will not be able to log their edits programmatically. The built in feature "edit history" would still log them though.
Flow:
Get current script scopes from File > Project properties> Scopes
Add explicit openid, profile and email scopes to the above scopes and add them to the manifest. For eg, the following sample script requires the following scopes:
"oauthScopes":["openid","profile","email",
"https://www.googleapis.com/auth/script.scriptapp",
"https://www.googleapis.com/auth/spreadsheets.currentonly",
"https://www.googleapis.com/auth/script.container.ui"
],
Ask editors to sign up to add them to the edit log by clicking a menu button
Create a installed Edit trigger for them on clicking the menu button.
Use the installable edit trigger to get a identity token. Parse the token to get given name and family name.
Sample script:
function getNameOfCurrentEditor() {
const idToken = ScriptApp.getIdentityToken();
const body = idToken.split('.')[1];
const decoded = Utilities.newBlob(
Utilities.base64Decode(body)
).getDataAsString();
const { given_name: firstName, family_name: lastName } = JSON.parse(decoded);
return { firstName, lastName };
}
/**
* #param{GoogleAppsScript.Events.SheetsOnEdit} e
*/
function installedEditTrigger(e) {
const eUser = e.user.getEmail();
if (eUser === '') return; //no permission=> exit
const { firstName, lastName } = getNameOfCurrentEditor();
e.range.setNote(
`${e.range.getNote()}\n${e.value} added by ${firstName}_${lastName}`
);
}
function onOpen() {
SpreadsheetApp.getUi()
.createMenu('Edit Logger')
.addItem('Sign me up!', 'createEditTrigger')
.addToUi();
}
function createEditTrigger() {
ScriptApp.newTrigger('installedEditTrigger')
.forSpreadsheet(SpreadsheetApp.getActive())
.onEdit()
.create();
}
Note: Multiple edit triggers for all editors, who signed up will run automatically, but only the editor who actually made the edit will be allowed to pass beyond this condition:if (eUser === ''). This works because each editor is unable to get email addresses of other editors. Only a empty string is returned in that case.
Explanation:
Assuming that the username has the format of name.surname then you can use split() to separate the name from the surname by using u.split('.')[0] and u.split('.')[1] respectively.
If the username has a different format then you can change the argument accordingly. For example, if you have name-surname then use u.split('-')[0] and u.split('-')[1].
Solution:
function onEdit(e) {
var sheet = e.source.getActiveSheet();
var idCol = e.range.getColumn();
var idRow = e.range.getRow();
if ( idCol == 4 && sheet.getName() =='LIST1' ) {
var Value = e.range.offset(0, -2).getValues();
if ( Value == "" ) {
var vartoday = getDate(); //Gets the current date//
sheet.getRange(idRow, 2).setValue( vartoday ); //Inserts into column 2 of the current row//
var u = Session.getEffectiveUser().getUsername(); //Gets the username of the editor//
sheet.getRange(idRow, 7).setValue(u.split('.')[0]); //Inserts into column 7 of the current row the firstname of the editor//
sheet.getRange(idRow, 8).setValue(u.split('.')[1]); //Inserts into column 8 of the current row the last of the editor//
}
}
function getDate() {
var today = new Date();
today.setDate(today.getDate());
return Utilities.formatDate(today, 'GMT+03:00', 'dd/MM/yy');
}
}

Google Sheets Calendar

I would like some help in pulling certain data from a google form linked to a spreadsheet and set a certain value in the date of a certain employee. For example if he/she marked as Vacation Leave then the letter V will be marked under the Date. I have attached the link to my calendar to give an example, I have tried searching the net and this is my second time posting here.
I started the Code but I am stuck in actually finding the Cell for a certain date and inserting the letter.
https://docs.google.com/spreadsheets/d/1uFTR2_B7T0QBr7fTflByFffmmiszbNj_RaCvLEfYRCA/edit?usp=sharing
function setData(){
//Spreadsheets
var ss = SpreadsheetApp;
var data = ss.getActiveSpreadsheet().getSheetByName("Data");
var calendar = ss.getActiveSpreadsheet().getSheetByName("Calendar");
//Get last row / Individual Cells from Form
var lRow = data.getLastRow();
var lRowData = data.getRange(lRow,1,1,17).getValues();
var approval = data.getRange(lRow,17,1,1).getValue();
var leave = data.getRange(lRow,9,1,1).getValue();
var agentName = data.getRange(lRow, 5,1,1).getValue();
var dateBefore = data.getRange(lRow, 10,1,1).getValue();
var dateAfter = data.getRange(lRow, 11,1,1).getValue();
//Calander Variable Arrays
var allDates = calendar.getRange("LA1:NJ1").getValues();
var allNames = calendar.getRange("A4:A160").getValues();
for(var i = 0; i<allNames.length; i++){
if (approval === "Approved" && allNames[i][0] === agentName){
//Here I need it to insert the dates under the correct name and date with a value of V H S M U T.
};
};
};
You are building a spreadsheet-based Leave Calendar based on information from a form response. Based on your existing Calendar, you are having problems identifying the relevant leave dates, and then filling calendar cells to indicate proposed leave.
The problem is there are no fields in rows 1,2 or 3 of Calendar that have the same date format as the Start Date and End Date fields on Form. As a result, there's no easy way to search for a match of the form data fields.
The solution, in my view, is to change the format of the date fields in rows 2 and 3 and enable a search to be match.
Row 2
the existing format is "d" - day of the month (Numeric)
change the format to match the Form Start/End dates: "d-MMM-yyyy".
the font colour for this field can be used to "hide" these dates, and the column width reduced also.
Row 3
the existing format is "E" - day of the week (Name)
change the format to combine the existing formats of rows #2 and #3 - "E-d"
Aspects of the script
the form data is retrieved as getDisplayValues(). The purpose of this is to get the date as a string to facilitate the search.
Two sets of Calendar data are obtained
1) the dates row (Row#2)
2) the names column (Col #1). The Javascript map method is used to convert names from a 2D array to a 1D array. This creates an array that can be easily searched.
the Javascript indexOf method is used to find the Column match for the start and end dates, and to match the name in the Calendar Column (which yields the Row)
the script loops through the number of days leave to create a temporary array of "V" values.
using the row number and the start and end column numbers, a range can be defined on calendar and then updated from the values in the temporary array.
Presumably your function would be triggered by onFormSubmit(e).
Form data
Calendar - Before
Calendar - After
function so5871726503(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var form = ss.getSheetByName("Form");
var calendar = ss.getSheetByName("Calander");
//get form data
var formdataRange = form.getRange(6,1,1,9);// test data
var formData = formdataRange.getDisplayValues(); // display values to format date as string
//get the employee name, start date and end date
var formName = formData[0][1];
var formSD = formData[0][3];
var formED = formData[0][4];
// Logger.log("DEBUG: name = "+formName+", start date = "+formSD+", end date = "+formED);
//get Calendar variables
var calLR = calendar.getLastRow();
var calLC = calendar.getLastColumn();
var caldateStart = 9;
var calnameStart=4;
// get Calendar dates
var calDateRange = calendar.getRange(2,caldateStart,1,calLC-caldateStart+1);
var calDateValues = calDateRange.getDisplayValues();
// get Calendar names
var calNameRange = calendar.getRange(calnameStart,1,calLR-calnameStart+1);
var calNameValues = calNameRange.getValues();
var calNames = calNameValues.map(function(e){return e[0];});//[[e],[e],[e]]=>[e,e,e]
// there should be some error checking on indexof results = -1 in case there is a mismatch.
// find form start date in calender
var startdateresult = calDateValues[0].indexOf(formSD);
var startdateresultcol = startdateresult+caldateStart;
// Logger.log("DEBUG: start date result = "+startdateresult+", column = "+startdateresultcol);
// find form end date in calender
var enddateresult = calDateValues[0].indexOf(formED);
var enddateresultcol = enddateresult+caldateStart;
// Logger.log("DEBUG: end date result = "+enddateresult+", column = "+enddateresultcol);
// find form name in calender
var nameresult = calNames.indexOf(formName);
var nameresultrow = nameresult+calnameStart;
// Logger.log("DEBUG: name result = "+nameresult+", row = "+nameresultrow)
// calculate number of days leave
var daysleave = enddateresultcol-startdateresultcol+1
// Logger.log("DEBUG: days leave = "+daysleave)
// create array variable to hold leave data
var leave=[];
// loop to create data to fill Calendar
for (i=0;i<daysleave;i++){
leave.push("V");
}
// Logger.log(leave); // DEBUG
// build leave range
var calLeave = calendar.getRange(nameresultrow,startdateresultcol,1,daysleave);
//Logger.log(calLeave.getA1Notation()); //DEBUG
// Update the leave range
calLeave.setValues([leave]);
}

How to get an updated cell value in google sheets

i want to send an email to myself if my script in python does not run anymore.
I have implemented in python an uptime function. Cell E5 gets updated with the new uptime every 15 seconds. If the uptime does not change my script does not run anymore and i want to get notified via email. For this reason i compare the cell value after 5 minutes.
But uptime_zahl and uptime_new_zahl are always equal the value when i start my apps script function.
How can I get the updated cell value??
function uptimeCheck() {
var ss = SpreadsheetApp.openById("XXX");
var sheet = ss.getSheetByName('Tabellenblatt1');
var uptime_string = sheet.getRange("E5").getValue().toString();
var uptime_zahl = Number(uptime_string.replace(',', "."));
Utilities.sleep(300000);//wait for 5 minutes
var uptime_new_string = sheet.getRange("E5").getValue().toString();
var uptime_new_zahl = Number(uptime_new_string.replace(',', "."));
if (uptime_zahl == uptime_new_zahl)
{
var emailAddress = 'XXX';
var subject = 'The bot does not run';
var message = 'old time: '+uptime_zahl+'new time: '+uptime_new_zahl;
MailApp.sendEmail(emailAddress, subject,message);
}
}
You can store uptime_zahl in Script properties and run your automatically script on a time-driven trigger (e.g. every 5 minutes).
The following sample
sets during the first run the script property 'uptime_zahl' to the actual value in "E5" and the sent status to 0
compares the current value in "E5" against the one stored during the last script run
sends an email if the value is still the same and an email has not been sent yet
sets the script property to the current value and sent to 1, if an email for the current value has been sent already
function uptimeCheck() {
var ss = SpreadsheetApp.openById('XXX');
var sheet = ss.getSheetByName('Tabellenblatt1');
var uptime_string = sheet.getRange("E5").getValue().toString();
var uptime_new_zahl = Number(uptime_string.replace(',', "."));
if(PropertiesService.getScriptProperties().getKeys().length==0){ // first time you run the script
PropertiesService.getScriptProperties().setProperty('uptime_zahl',uptime_new_zahl);
PropertiesService.getScriptProperties().setProperty('sent',0);
}
var sent=parseInt(PropertiesService.getScriptProperties().getProperty('sent'));
var uptime_zahl = PropertiesService.getScriptProperties().getProperty('uptime_zahl');
if (uptime_zahl == uptime_new_zahl&&sent==0)
{
Logger.log('still the same, email sent: '+uptime_zahl);
var emailAddress = 'XXX';
var subject = 'The bot does not run';
var message = 'old time: '+uptime_zahl+'new time: '+uptime_new_zahl;
MailApp.sendEmail(emailAddress, subject,message);
sent=1;
}else if(uptime_zahl != uptime_new_zahl){
sent=0;
Logger.log('value changed');
}else{
Logger.log('value did not change, but email has been sent already');
}
PropertiesService.getScriptProperties().setProperty('uptime_zahl',uptime_new_zahl);
PropertiesService.getScriptProperties().setProperty('sent',sent);
}
To set up a time-driven trigger:

If/Else Statement not working to send different emails

I am trying to write a script in google sheets that will send one of two different emails based on the response to a multiple choice question. I can get my if/else statement to send either one or the other of the emails but it will not recognize the text of the multiple choice answer and send the correct email.
Here is the full script:
function sendEmails() {
var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 2; // First row of data to process
var numRows = 1;
// Fetch the range of cells A2:B3
var dataRange = sheet.getRange(startRow, 1, numRows, 8)
// 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[1]; // First column
var startDate = row[3]; // Second column
var endDate = row[4];
var description = row[2];
var location = row[6];
var eventImport = row[5];
var emailAddress = row[7];
var multchoice = row[8];
if (multchoice == "Part Time") {
var subject = "New Hire Part Time Email - " + startDate;
var emailBody = "Congradulations"
var htmlBody = "Congradulations! Part time person"
MailApp.sendEmail (emailAddress, subject, emailBody);
} else {
var subject = "New Hire Appointment - " + startDate;
var emailBody = "Congratulations! We are excited"
var htmlBody = "Congratulation! </i><br/> <br/> We are excited"
MailApp.sendEmail(emailAddress, subject, emailBody);
}
}
}
I believe the problem is here:
if (multchoice == "Part Time")
Any help is greatly appreciated! I am a novice
It looks like you are assigning your variables starting with '1' I stead of '0'. Start assigning them with 0 and counting up.
Without an example sheet to use, I won't be able to do a whole lot of debugging for you.
However, Apps Script comes with it's own debugger. Select the function you wish you debug and click the Little bug icon beside the play button.
Click on the sidebar where you want to set a breakpoint, where the code will stop executing.
Once it hits that breakpoint you can see all the variables currently within your scope. So the array, value, and i variables are visible to you.
Use this to your advantage and debug your code to find out where the issue is. Alternatively, you can use Logger.log() to log values at certain points within your code and then read back through the logs to try and determine where the problem lies.
The problem is not with your if/else statement. The problem is with how you are assigning your variables from your row[] array. While you use regular numbers in the getRange() function, the range that is returned is an array of those cells. Arrays always start with an index of [0]. Change var multchoice = row[8] to var multchoice = row[7] and your if/else statement will work (you'll want to change all of your other references, too).

Combine a Date & a Time Column in Google Sheets for a createEvent() function [duplicate]

This question already has an answer here:
How to merge date and time as a datetime in Google Apps Spreadsheet script?
(1 answer)
Closed 7 years ago.
I need to combine two columns into one dateTime column that can be reading by a createEvent function for startDate.
Column F is the date (mm-dd-yyyy) & Column G is the time (HH:mm PM/AM). I am currently combine them in Column H with the following code:
function conCat() {
var sheet = SpreadsheetApp.getActiveSheet();
var numberOfRows = sheet.getLastRow().toString();
var range = sheet.getRange(2,1,numberOfRows,12);
var values = range.getValues();
var consultedAlreadyFlag = sheet.getRange(2,10,numberOfRows,12);
var sheetName = sheet.getSheetName();
//show updating message
consultedAlreadyFlag.setFontColor('red');
var numValues = 0;
for (var row = 2; row < values.length.toString(); row++) {
//check to see if name and type are filled out - date is left off because length is "undefined"
if (values[row][3].length > 0) {
currentStatus = values[row][1];
//check if it's been entered before
if (values[row][9] != 'EMAIL_SENT'){
sheet.getRange(row+2,8,1,1).setValue('=F' +(row+2)+ '+G' +(row+2));
}
else{
//sheet.getRange(row+2,10,1,1).setValue('EMAIL_SENT');
}
numValues++;
}
//hide updating message
consultedAlreadyFlag.setFontColor('green');
}
}
This code isn't working because when someone submits the form, and the code combines the columns, I cannot get the format to come out as "mm-dd-yyyy HH:mm:ss" which I feel I need in order for my createEvent function to work.
How can I get it to combine the two columns to get the format I need?
I wouldn't bother trying to combine the two columns. There's no point in adding another column, I don't think. You can use JavaScript methods like setHours():
function fncAddToCalender() {
var theEventDate = //To Do - Get the Date
var startMin = value from sheet cell
theEventDate.setHours(15); //Sets event date to 3pm
theEventDate.setMinutes(startMin);
var cal = CalendarApp.getDefaultCalendar();
var event = cal.createEvent(calndrTitle, theEventDate, endDate, {
description : theDescrptn,
location : theLocation,
guests : guestToInvite,
sendInvites : true
});
};
The format in the spreadsheet is probably set to "date". And getting the values with Apps Script will probably return a value that's already in a date format. If you have the columns formatted as text, you'd need to change the values to a date.

Categories