Send google forms responses to google calendar - javascript

I have recently began a project to allow communication between separate groups of people to confirm appointments for meetings. The problem is I can't seem to be able to send the response from a form to the google calendar ID that I put in the function.
Could somebody explain what is going wrong with the code or lead me in the right direction to solve this issue?
Here is the code:
//Function records responses and sends them to a google calendar.
function onFormSubmit(e) {
var form = FormApp.getActiveForm(); // opens active form
var usarResponses = form.getResponses(); // collects responses
//Loop creates an array for responses
for(var i = 0; i < usarResponses.length; i++){
var usarResponse = usarResponses[i];
}
//responses are put into variables.
var name = usarResponses[0];
var appointmentName = usarResponses[1];
var appointmentDate = usarResponses[2];
var uDescription = usarResponses[3];
var cal = CalendarApp.getCalendarById('kq14it8fl42i560gl6ueeo4qu8#group.calendar.google.com').createEvent(appointmentName, new Date(appointmentDate), new Date('8:00:00 UTC') , {description: uDescription});
}

This is a tricky one. Here is what worked for me:
function createEvent() {
var form = FormApp.getActiveForm();
var cal = CalendarApp.getDefaultCalendar();
var responses = form.getResponses();
var len = responses.length;
var last = len – 1;
var items = responses[last].getItemResponses();
var email = responses[last].getRespondentEmail();
var name = items[0].getResponse();
var bring = items[1].getResponse();
var date = items[2].getResponse();
Logger.log(date);
var replace = date.replace(/-/g,”/”);
Logger.log(replace);
var start = new Date(replace);
Logger.log(‘start ‘+start);
//Logger.log(newStart.getHours());
var endHours = 2+0+start.getHours();//2 hour event
//Logger.log(start.getDay());
var day = start.getDate();
var minutes = start.getMinutes();
var year = start.getFullYear();
var month = start.getMonth();
var hours = start.getHours();
var d = new Date(year, month, day, endHours, minutes);
Logger.log(d);
var event = cal.createEvent(‘Class Party ‘+name+’ brings ‘+bring, start, d)
.addGuest(email)
.setDescription(name+’ you will be bringing ‘+bring+’ to the party.’);
GmailApp.sendEmail(email, name+’ a Google Calendar invite has been created for you’, name+’ You filled out the Google Form for the date of ‘+start+’. Check your Google Calendar to confirm that you received the invite.\n’);
}

Related

What is the most efficient way to import event details from Google Calendar to Google Sheets? (Google Apps Script) [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 months ago.
Improve this question
I am working on a script to save Google Calendar events to a Google Sheets file. There were many other posts on the subject, but I needed a single row per event with the guest list split into multiple columns based on criteria and I was unable to find any scripts with this output format. I've built a similar function in a low-code app builder (Appsheet) but I am very new to Javascript.
I've tested the script below and it works well, but I wanted to ask if this was the most efficient way to arrange the for loops to get the information that I need.
function getEventsFromRangeGeneric() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("EventsRange");
var employees = ['test1#email.com','test2#email.com','test3#email.com'];
//Get date range from cells
var start_time = sheet.getRange("A2").getValue();
var end_time = sheet.getRange("B2").getValue();
//Get calendar ID and events
var id_cal = 'workcalendartest#group.calendar.google.com';
var cal = CalendarApp.getCalendarById(id_cal);
var events = cal.getEvents(new Date(start_time), new Date(end_time));
//Create headers and set to fifth row
var header = [["Title","Name","Employee","Client","Start","End","Duration","Location"]]
var range = sheet.getRange(5,1,1,8).setValues(header);
//Loop through each event to get details
var row = 6;
for (var i = 0;i<events.length;i++){
var title = events[i].getTitle();
var start_time = events[i].getStartTime();
var end_time = events[i].getEndTime();
var duration = '';
var loc = events[i].getLocation();
var guestList = events[i].getGuestList();
var guestEmails = [];
var employEmail = [];
var clientEmail = [];
var clientName = '';
//Loop through each guest object to get list of emails
for (var j = 0;j<guestList.length;j++){
guestEmails.push(guestList[j].getEmail());
}
//Loop through each list of emails to determine which is employee and which is client
for (var g = 0;g<guestEmails.length;g++) {
if (employees.includes(guestEmails[g]) === true) {
employEmail.push(guestEmails[g])
} else {
clientEmail.push(guestEmails[g])
}
}
//Use details to fill in corresponding columns
var details = [[title,clientName,employEmail, clientEmail, start_time, end_time, duration, loc]];
var range2 = sheet.getRange(row+i,1,1,8);
range2.setValues(details);
var cell2=sheet.getRange(row+i,7); // go to column 7 (the placeholder) of the output data for duration column
// Calculate the number of hours of the session
cell2.setFormula('=(F' +row+ '-E' +row+ ')');
cell2.setNumberFormat('hh:mm:ss')
}
row=row+i
}
Modification points:
In your script, setValues and setFormula are used in a loop. In this case, the process cost will become high. Ref (Author: me)
In this case, I think that setValues can be used outside of the loop. By this, the process cost can be reduced a little.
The unused variable is included.
for (var j = 0; j < guestList.length; j++) {} and for (var g = 0; g < guestEmails.length; g++) {} can be written by one loop.
I think that var start_time = sheet.getRange("A2").getValue(); and var end_time = sheet.getRange("B2").getValue(); can be written by one request.
In your script, employEmail and clientEmail are an array. In this case, when the value of var details = [[title,clientName,employEmail, clientEmail, start_time, end_time, duration, loc]]; is put to the sheet, the 1st element is used. Please be careful about this.
row=row+i is put outside of the loop. By this, row is always the initial value of var row = 6;.
When these points are reflected in your script, how about the following modification?
Modified script:
function getEventsFromRangeGeneric() {
var employees = ['test1#email.com','test2#email.com','test3#email.com'];
var id_cal = 'workcalendartest#group.calendar.google.com';
var header = ["Title", "Name", "Employee", "Client", "Start", "End", "Duration", "Location"];
var row = 6;
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("EventsRange");
var [start_time, end_time] = sheet.getRange("A2:B2").getValues()[0];
var cal = CalendarApp.getCalendarById(id_cal);
var events = cal.getEvents(new Date(start_time), new Date(end_time));
var values = [header];
for (var i = 0; i < events.length; i++) {
var title = events[i].getTitle();
var start_time = events[i].getStartTime();
var end_time = events[i].getEndTime();
var loc = events[i].getLocation();
var guestList = events[i].getGuestList();
var employEmail = [];
var clientEmail = [];
var clientName = '';
for (var j = 0; j < guestList.length; j++) {
var email = guestList[j].getEmail();
if (employees.includes(email) === true) {
employEmail.push(email);
} else {
clientEmail.push(email);
}
}
values.push([title, clientName, employEmail.join(","), clientEmail.join(","), start_time, end_time, `=F${i + row}-E${i + row}`, loc]);
}
sheet.getRange(row - 1, 1, values.length, values[0].length).setValues(values);
}
References:
Best Practices
Benchmark: Reading and Writing Spreadsheet using Google Apps Script (Author: me)

Auto Move Yesterday's Data from Google Form Response Sheet

I have Google form which is linked to Form Response Sheet. I want to Move data from "Discrepancy Report - Outlet" to "Vaishali Nagar - DTR" Sheet on each day. The date is to be used from "Discrepancy Report - Outlet" sheet from Colum J.
The condition is that if I run the script today it should move data of Previous Day. For Ex. If I run script Today i.e. 31/10/2020 then It should only pick data of 30/10/2020. This process goes on each day. For running this script I will use Time Trigger.
I am using script which is mentioned below the Question. The problem I am facing it runs on the basis of today's date.
Link of Spreadsheet is:
https://docs.google.com/spreadsheets/d/1MhCdwFscPqskeeM2Hza-t2VXoVkI6sq3XRCNybMm4NM/edit?usp=sharing
function copyrange() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Discrepancy Report - Outlet'); //source sheet
var testrange = sheet.getRange('J:J');
var testvalue = (testrange.setNumberFormat("#").getValues());
Logger.log(testvalue);
var ds = ss.getSheetByName('Vaishali Nagar - DTR'); //destination sheet
var data = [];
var j =[];
var today = new Date();
var yesterday = new Date(today); yesterday.setDate(yesterday.getDate()-1);
var today = Utilities.formatDate(new Date(), 'GMT-0', 'dd/MM/yyyy')
//Condition to check in J:J, if true, copy the same row to data array
for (i=0;i<testvalue.length;i++) {
if (testvalue[i] == today) {
data.push.apply(data,sheet.getRange(i+1,1,1,9).getValues());
//Copy matched ROW numbers to B
j.push(i);
}
}
//Copy data array to destination sheet
var start_row=ds.getRange('B7:B').getValues().filter(String).length +6; //calculate max row
ds.getRange(start_row+1,1,data.length,data[0].length).setValues(data);
}
Explanation:
The main issue is that your current code compares the dates with the date of today instead of yesterday.
However, your code can be further optimized. Instead of using a for loop to check if an element matches the date of today, you can use filter to get the data only for yesterday and then remove the lst column because you don't need it to be in the destination sheet:
yest_data = data.filter(r=>r[9]==yesterday).map(v=>v.slice(0,-1));
It is a good practice to check if the data has a length higher than 0, otherwise the script will drop an error when setting the values.
Solution:
function copyrange() {
const ss = SpreadsheetApp.getActiveSpreadsheet();
const sheet = ss.getSheetByName('Discrepancy Report - Outlet'); //source sheet
const ds = ss.getSheetByName('Vaishali Nagar - DTR'); //destination sheet
const data = sheet.getRange('A2:J'+ sheet.getLastRow()).getDisplayValues();
var yesterday = new Date();
yesterday.setDate(yesterday.getDate()-1);
var yesterday = Utilities.formatDate(yesterday, ss.getSpreadsheetTimeZone(), 'dd/MM/yyyy');
yest_data = data.filter(r=>r[9]==yesterday).map(v=>v.slice(0,-1));
const start_row=ds.getRange('B7:B').getValues().filter(String).length +6; //calculate max row
if (yest_data.length>0){
ds.getRange(start_row+1,1,yest_data.length,yest_data[0].length).setValues(yest_data);
};
}
When checking date equality, you should use the date value or epoch time. Try this instead, which allows you to pass a specific date as your today value.
function test() {
var now = new Date('October 28, 2020');
var today = new Date(now.setHours(0, 0, 0, 0));
copyYesterday(today);
}
/**
* Copy yesterday's responses from Sheet1 to Sheet2.
* #param {Date} [today] - Optionally include a value to use as "today".
*/
function copyYesterday(today) {
if (today == null) { today = new Date(new Date().setHours(0, 0, 0, 0)); }
var yesterday = (new Date(today)).setDate(today.getDate() - 1);
var ss = SpreadsheetApp.getActive();
var sourceSheet = ss.getSheetByName('Sheet1');
var sourceData = sourceSheet.getDataRange().getValues();
var responses = [];
for (var rowIndex = 0; rowIndex < sourceData.length; rowIndex++) {
var row = sourceData[rowIndex];
var responseDate = row[0];
if (responseDate.valueOf() == yesterday) {
responses.push(row);
}
}
if (responses.length > 0) {
var destination = ss.getSheetByName('Sheet2');
destination.getRange(destination.getLastRow()+1, 1, responses.length, responses[0].length).setValues(responses);
}
}
function copyrange() {
var ss=SpreadsheetApp.getActive();
var sh=ss.getSheetByName('Discrepancy Report - Outlet'); //source sheet
var rg=sh.getRange(1,10,sh.getLastRow(),1);
var vA= rg.setNumberFormat("#").getValues();
var ds = ss.getSheetByName('Vaishali Nagar - DTR'); //destination sheet
var data=[];
var j=[];
var today = new Date().valueOf();
var yesterday = new Date(today.getFullYear(),today.getMonth(),today.getDate()-1).valueOf();
for (var i=0;i<vA.length;i++) {
var dt=new Date(vA[i][0]);
var dtv=new Date(dt.getFullYear(),dt.getMonth(),dt.getDate()).valueOf();
if (dtv==today) {
data.push(sheet.getRange(i+1,1,1,9).getValues());
}
}
ds.getRange(getColumnHeight(ds,2,ss)+1,1,data.length,data[0].length).setValues(data);
}
function getColumnHeight(col,sh,ss){
var ss=ss||SpreadsheetApp.getActive();
var sh=sh||ss.getActiveSheet();
var col=col||sh.getActiveCell().getColumn();
const rcA=sh.getRange(1,col,sh.getLastRow(),1).getValues().reverse()
let s=0;
for(let i=0;i<rcA.length;i++) {
if(rcA[i][0].toString().length==0) {
s++;
}else{
break;
}
}
return rcA.length-s;
}

How to retrieve data from columns dependent upon date

I have a rota (a fixed order of rotation (as of persons or duties)) that I've already had help with this week. It's up & running as is, but for simpler reading I'd like to transpose it.
You can see the transposed sheet as I'd like it here
The current script is for the pre-transposed table.
It would search Column 0 for the date. If it was was 7 days away it would retrieve the name from Column 1 & match it with e-mail address in separate sheet etc.
What I'd like to do is instead have the Date in Row 0 & then subsequent names in Row 1 etc etc
I've tried various things. I've stepped through the code & can see what it's doing, & I've done some reading through about 2 dimensional arrays, but I can't seem to find a way of getting the code to work down through columns, instead of across the rows.
Here's the code:
function sendEmails() {
var ss1 = SpreadsheetApp.getActiveSpreadsheet();
var sh1 = ss1.getSheetByName("Rota")
ss1.setActiveSheet(sh1);
var rotalink = "https://docs.google.com/spreadsheets/d/1LgzUWSAGA2kbpar8r5nosU1bSHF7nrtvtUiHS3nB_e8";
var sheet = SpreadsheetApp.getActiveSheet();
// Fetch the range
var dataRange = sheet.getRange("B3:G50")
// Fetch values for each row in the Range.
var data = dataRange.getValues();
for (i in data) {
var row = data[i];
var today=new Date();
var timecell = new Date(row[0]);
var timediff = new Date();
var one_day=1000*60*60*24;
var daystogo = Math.ceil((timecell.getTime()-today.getTime())/(one_day));
if (daystogo==7) {//only e-mail people with one week to go. To change that alter the "7" to the number of days you want
var subject = "Rota reminder!";
var emailAddress = [];
var message;
message = "Hello \n\n"+
"You are down to help at Youth Café this week. \n\n" +
"Please see the below rota for your role \n\n" +
"If you have any questions or problems let us know at thameyouthcafe#gmail.com \n\n" +
"Remember, you can check the rota anytime by clicking on the link below: \n\n"+
rotalink
for (var x = 1; x < 5; x++) { // 5 because emails are till col4
// var emailAddress = []; // Start by collecting the non-blank emails in an array
if (getEmailFromName(row[x]) != "") {
emailAddress.push(getEmailFromName(row[x]))
}
}
emailAddress = emailAddress.join(); // Join the array to get a comma separated string
MailApp.sendEmail(emailAddress, subject, message);
}
}
}
and here's the getEmailFromName function that matches with SKey (which I presume comes from the "i" variable in the first function?
function getEmailFromName(sKey) {
// to use this function, don’t put anything in the first column (A) or row (1).
// Put the name (i.e. the key, or what we’re looking for) in column B.
// Put what we want to return in column C.
var columnToSearch = 1; //column B
// Set the active sheet to our email lookup
var ss1 = SpreadsheetApp.getActiveSpreadsheet();
var sh1 = ss1.getSheetByName("EmailContactList")
ss1.setActiveSheet(sh1);
var data = SpreadsheetApp.getActiveSheet().getDataRange().getValues();
var line = -1;
for( var i = 0; i < data.length; i++ ) {
if( data[i][columnToSearch] == sKey ) {
line = i;
break;
}
}
if( line != -1 ) {
//do what you want with the data on "line"
return data[line][2]; //value on column C of the matched line
}
else {
return "";
// if criteria is not found
}
}
Try it this way:
function sendEmails() {
var ss1 = SpreadsheetApp.getActive();
var sh1 = ss1.getSheetByName("Rota")
ss1.setActiveSheet(sh1);
var rotalink = "https://docs.google.com/spreadsheets/d/1LgzUWSAGA2kbpar8r5nosU1bSHF7nrtvtUiHS3nB_e8";
var sheet = SpreadsheetApp.getActiveSheet();
var dataRange = sheet.getRange("B3:G50")
var data = dataRange.getValues();
for (var i=0;i<dataRange.length;i++) {
var row = data[i];
var today=new Date();
var timecell = new Date(row[0]);
var timediff = new Date();
var one_day=1000*60*60*24;
var daystogo = Math.ceil((timecell.getTime()-today.getTime())/(one_day));
if (daystogo==7) {
var subject = "Rota reminder!";
var emailAddress = [];
var message = Utilities.formatString('Hello\n\nYou are down to help at Youth Café this week.\n\n Please see the below rota for your role \n\nIf you have any questions or problems let us know at thameyouthcafe#gmail.com \n\nRemember, you can check the rota anytime by clicking on the link below: \n\n%s',rotalink);
for (var x=1;x<5;x++) {
if(data[i][x]) {
emailAddress.push(data[i][x]);
}
}
MailApp.sendEmail(emailAddress.join(), subject, message);
}
}
}
Managed to solve it - thank you for your contributions. Turned out it was incredibly simple.
Just had to change this line:
var timecell = new Date(data[0])
to this:
var timecell = new Date(data[0][i])
so it iterates through the first row of each column.

Google scripts copy range from one spreadsheet to another based on date

I am currently trying to automatically archive responses from a Google form. I have a script which runs every time the form is submitted and does some processing of the last submit.
What I want to do is on the first submit of the month, create a separate spreadsheet with just last months entries.
I am doing this by getting the date from last month, creating a new spreadsheet with last months name and year as the name of the file.
What I now need to do is select a range based on dates. So in column A is a timestamp (e.g. 31/12/2014 22:21:31) - I would want to select all rows between for example 1/12/2014 00:00:00 and 31/12/2014 23:59:59.
Using this example I know its possible to copy a range but it's finding the correct range I need help with:
var ss = SpreadsheetApp.getActiveSpreadsheet();
var target = SpreadsheetApp.openById("0Aqv8.....");
var source_sheet = ss.getSheetByName("Form Responses");
var target_sheet = target.getSheetByName("Sheet1");
var source_range = source_sheet.getRange("A2:A");
var target_range = target_sheet.getRange("A2:A");
var values = source_range.getValues();
target_range.setValues(values);
I am using the following to get the start time, and end time of the month:
var x = new Date();
var d = new Date();
// Start Time:
x.setDate(1);
x.setHours(0);
x.setMinutes(0);
x.setSeconds(0);
x.setMonth(x.getMonth()-1);
// Finish Time:
d.setDate(0);
d.setHours(23);
d.setMinutes(59);
d.setSeconds(59);
Ok so this probably isn't the best answer, but hey it seems to work for me:
var x = new Date();
var d = new Date();
// Start Time:
x.setDate(1);
x.setHours(0);
x.setMinutes(0);
x.setSeconds(0);
x.setMonth(x.getMonth()-1);
// Finish Time:
d.setDate(0);
d.setHours(23);
d.setMinutes(59);
d.setSeconds(59);
// Create a blank spreadsheet:
var root = DocsList.getRootFolder()
var newFileId = SpreadsheetApp.create(archiveName).getId();
var newFile = DocsList.getFileById(newFileId);
newFile.addToFolder(destFolder);
newFile.removeFromFolder(root);
// Get the spreadsheets:
var ss = SpreadsheetApp.getActiveSpreadsheet();
var target = SpreadsheetApp.openById(newFileId);
var sheet = ss.getSheetByName("Form Responses");
var target_sheet = target.getSheetByName("Sheet1");
// Record the range:
var firstRow = 1;
var lastRow = 1;
var width = sheet.getDataRange().getWidth();
// Get all the current data:
var numRows = sheet.getDataRange().getNumRows();
var data = sheet.getDataRange().getValues();
// Get the first entry:
for(var i=0; i<numRows; i++){
var tmp = new Date(data[i][0]);
if (tmp > x) {
firstRow = i+1;
Logger.log(i + " - is the first row");
i = numRows;
}
}
// Get the last entry:
for(var i=0; i<numRows; i++){
var tmp = new Date(data[i][0]);
if (tmp > d) {
lastRow = i;
Logger.log(i + " - is the last row");
i = numRows;
}
}
// Copy the title:
var source_range = sheet.getRange(1,1,1,width);
var target_range = target_sheet.getRange(1,1,1,width);
var values = source_range.getValues();
var formats = source_range.getNumberFormats();
target_range.setValues(values);
target_range.setNumberFormats(formats);
target_sheet.setFrozenRows(1);
// Copy the last months values:
var source_range = sheet.getRange(firstRow,1,lastRow-firstRow+1,width);
var target_range = target_sheet.getRange(2,1,lastRow-firstRow+1,width);
var values = source_range.getValues();
target_range.setValues(values);

Insert more than 250 items in sharepoint list using javascript

I am not able to add 365 days( date format: 01/01/2014) of year in a sharepoint list using javascript.
but it is updating list when I enter range of 'for' loop = 250.
Please refer below code.
function DateIncrement() {
var siteUrl = '/sites/..';
var clientContext = new SP.ClientContext(siteUrl);
var oList = clientContext.get_web().get_lists().getByTitle('Student');
var itemCreateInfo = new SP.ListItemCreationInformation();
for (i = 1; i < 365; i++) {
var myDate = new Date("01/01/2014");
myDate.setDate(myDate.getDate() + i);
var str = myDate;
this.oListItem = oList.addItem(itemCreateInfo);
oListItem.set_item('Date', str);
oListItem.update();
}
clientContext.load(oListItem);
clientContext.executeQueryAsync(onSucceededCallback, onFailedCallback);
function onSucceededCallback(sender, args) {
alert("Complete");
}
function onFailedCallback(sender, args) {
alert("Failed");
}
}
The date must be specially formatted. In SharepointPlus I created a function that converts a JavaScript Date to the Sharepoint format.
The format should be: "year-month-day hours:minutes:seconds". So, for "31/Oct/2012" it must be "2012-10-31 00:00:00".
The function toSPDate looks like that:
function toSPDate(oDate) {
var pad = function(p_str){
if(p_str.toString().length==1){p_str = '0' + p_str;}
return p_str;
};
var month = pad(oDate.getMonth()+1);
var day = pad(oDate.getDate());
var year = oDate.getFullYear();
var hours = pad(oDate.getHours());
var minutes = pad(oDate.getMinutes());
var seconds = pad(oDate.getSeconds());
return year+"-"+month+"-"+day+" "+hours+":"+minutes+":"+seconds;
}
Note: SharepointPlus uses the Sharepoint web services. I'm not sure if you need to do the same with the Microsoft native functions.
Note 2: I read again your question but I'm not sure I understood correctly... If not, please try to explain again your issue.

Categories

Resources