Finally I was able to create function that will automatically update event in a calendar. I tested it and it worked perfectly; it will add new event in the calendar, and when user edits it, it will delete previous event and create new event along with new ID.
The next day however, when I tested it again, it doesn't work, I checked all functions in the code.gs, only this function has problem.
function updateCalendar(request) {
var sheet = SpreadsheetApp.getActiveSheet();
var lastRow = sheet.getLastRow();
var range = sheet.getRange(2,1,lastRow,13);
var values = range.getDisplayValues();
var calendar = CalendarApp.getCalendarById('XXXXXXXXXXXXXXXXXXX#group.calendar.google.com');
var numValues = 0;
for (var i = 0; i < values.length; i++) {
if (values[i][0].length > 0) {
if (values[i][12] == undefined) {
var newEvent = calendar.createEvent("booked", request.date, request.endTime);
var newEventId = newEvent.getId().split('#')[0];
//mark as entered, enter ID
sheet.getRange(i+2,13).setValue('y');
sheet.getRange(i+2,12).setValue(newEventId);
}
else if (values[i][12] == 'y') {
var eventEditId = calendar.getEventSeriesById(values[i][11]);
eventEditId.deleteEventSeries();
var newEvent = calendar.createEvent("booked", request.date, request.endTime);
var newEventId = newEvent.getId().split('#')[0];;
//mark as entered, enter ID
sheet.getRange(i+2,13).setValue('y');
sheet.getRange(i+2,12).setValue(newEventId);
}
}
numValues++;
}
};
I also checked the calendar settings and stuffs, and made sure that I was logged into the admin account. Any help is greatly appreciated, thanks in advance.
I simply changed "undefined" to simply a null string ' ' , it works again. But again, for some reason i am curious why it worked last time with "undefined" command
Related
I am trying to fix a code I found online. My goal is that once the Summary tab, column I is edited with the drop-down "approved" for the sheet to send an email to the person on the name in column D.
The email is found in the range tab though. This is what I have so far...
var admin_email='taniapeche#gmail.com';
function triggerOnEdit(e)
{
sendEmailOnApproval(e);
}
function checkStatusIsApproved(e)
{ var sheet = SpreadsheetApp.getActive().getSheetByName('Summary');
var range = e.range;
if(range.getColumn() <= 9 &&
range.getLastColumn() >=9 )
{
var edited_row = range.getRow();
var status = SpreadsheetApp.getActiveSheet().getSheetName('Summary').getRange(edited_row,9).getValue();
if(status == 'Approved')
{
return edited_row;
}
}
return 0;
}
function sendEmailOnApproval(e)
{ var sheet = SpreadsheetApp.getActive().getSheetByName('Range');
var approved_row = checkStatusIsApproved(e);
if(approved_row <= 0)
{
return;
}
sendEmailByRow(approved_row);
}
function sendEmailByRow(row)
{
var values = SpreadsheetApp.getActiveSheet().getSheetName('Range').getRange(row,1,row,5).getValues();
var row_values = values[0];
var mail = composeApprovedEmail(row_values);
//SpreadsheetApp.getUi().alert(" subject is "+mail.subject+"\n message "+mail.message);
MailApp.sendEmail(admin_email,mail.subject,mail.message);
}
function composeApprovedEmail(row_values)
{
var first_name = row_values[1];
var last_name = row_values[2];
var email = row_values[3];
var message = "The following mileage is approved: "+first_name+" "+last_name+
" email "+email;
var subject = "Mileage approved "+first_name+" "+last_name
return({message:message,subject:subject});
}
This is how to sheet looks:
https://docs.google.com/spreadsheets/d/1lWORvuwAHducEIiL-VVidJ-wjujE344udPbWCZpE1kw/edit?usp=sharing
Thanks for the help :)
First of all, because you want the script to send an email (an action which requires your authorization), you have to install the edit trigger, either manually or programmatically. If you do it programmatically, you can install the trigger by running this function once:
function createTriggerOnEdit(e) {
var ss = SpreadsheetApp.getActive();
ScriptApp.newTrigger("sendEmailOnApproval")
.forSpreadsheet(ss)
.onEdit()
.create();
}
As a result of this, the function sendEmailOnApproval will fire every time the spreadsheet is edited. This function could be something along the following lines (check inline comments for detailed explanation):
function sendEmailOnApproval(e) {
// Get the edited range and sheet using the event object:
var range = e.range;
var editedSheet = range.getSheet();
var textToSearch = "Approved"; // Set which value will cause the email to be sent
// Check that edited cell is in column I, its value is "Approved" and its sheet is "Summary":
if (range.getColumn() === 9 && range.getValue() === textToSearch &&
editedSheet.getName() === "Summary") {
var rowIndex = range.getRow(); // Get index of the edited row
var name = editedSheet.getRange(rowIndex, 4).getValue(); // Get corresponding name in column D
var rangeValues = e.source.getSheetByName("Range").getDataRange().getValues(); // Get values in sheet "Range"
// Iterate through the rows in "Range", looking for the name retrieved from sheet "Summary"
for (var i = 0; i < rangeValues.length; i++) {
var rowValues = rangeValues[i];
if (name === rowValues[0]) { // Check if name matches the one in column D from "Summary"
var mail = composeApprovedEmail(rowValues); // Compose email (your function)
MailApp.sendEmail(admin_email, mail.subject, mail.message); // Send email
return; // End execution so that the script stops iterating through the rows in "Range"
}
}
}
}
Notes:
The function composeApprovedEmail is called in this sample. It's the same as the one you provided. The rest of functions you provided are not used.
Reference:
Installable Triggers
Event Objects: Edit
I'm making an app that adds events to a calendar from a spreadsheet, and then updates the events if the spreadsheet changes. Right now, my code just deletes all the existing events and adds a new one for every entry in the spreadsheet, but sometimes my code errors out because that means I'm adding and deleting too many calendar entries. (Yes, I'm using the sleep utility. Sometimes it crashes anyway.)
It seems like a more efficient way to do this would be to check if the event already exists; if it does, update any changes in the date; and if it doesn't, then create a new event. But I can't quite get my head around how to loop the two lists over each other. If I tell it to loop over all events in the spreadsheet, and inside that to loop over each event in the calendar to look for a match, and if there's no match to make a new event, it seems like it will create a new event for every non-matching item that exists in the calendar for every row of the spreadsheet.
Here's the basic code:
function UpdatePrintCalendar() {
SpreadsheetApp.openByUrl("https://docs.google.com/spreadsheets/d/16U6am5GvgWxh0gcRS8FWf9ws7BxaiJU5KOnSo7kOUlg/edit?usp=sharing&key=AIzaSyBe4KN8M-HhMUbN0UcAao7Xm4rIMgOOC6g")
.getSheetByName("PD Hed List").sort(3).sort(4);
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
var cols = sheet.getLastColumn();
var endofthings = sheet.getLastRow();
var stories = sheet.getRange(1,1, endofthings, cols).getValues();
var rownum = stories.length
var printCal = CalendarApp.getCalendarById("4d1aq2jtt795hfemn7i76cfi30#group.calendar.google.com");
var fromDate = new Date(2019,11,1,0,0,0);
var toDate = new Date(2020,3,31,0,0,0);
var events = printCal.getEvents(fromDate, toDate);
for(var i=0; i<events.length;i++){ /* Clear the calendar. This prevents duplicates. */
var ev = events[i];
ev.deleteEvent();
}
for (x=0; x<stories.length; x++) {
if (x % 10 == 0) { Utilities.sleep(3000); }
var story = stories[x];
var onlinedate = story[1];
var printdate = story[2];
var section = story[5];
var slug = story[6];
var hed = {
'location': section,
'description': slug,
}
if (Boolean(printdate)) {
if (slug) {
printCal.createAllDayEvent(slug, new Date(printdate));
}
}
}
}
}
You can try Array.prototype.filter()
Take a look how to use it on example1 and example2
What I would do in your case:
list all calendar events
find id and title
list titles in Spreadsheet
find what is not match
add missing calendar events
update spreadsheet.
I want onFormSubmit(e) to be my main function trigger and within that I want onEdit(e) to be nested. Basically, no matter, the trigger will run onFormSubmit but it will do others within the onEdit if there is any edit, if there isn't then it will do something else.
I can't see to understand and make it work.
My script triggers shows onFormSubmit as the only function and onEdit is not in the dropdown.
function onFormSubmit(e){
ScriptApp.newTrigger("onEdit").timeBased().after(60000).create();
function onEdit(e){
var ss = SpreadsheetApp.getActiveSpreadsheet().getRange('SpeedVSD');
var sheet = ss.getSheetByName("Responses 1");
var row = ss.range.getRow();
var col = ss.range.getColumn();
if (col >= ss.getColumn() && col <= ss.getLastColumn() && row >= ss.getRow() && row <= ss.getLastRow()){
console.log("You edited a Cell within Range");
}
}
edit: Managed to get my lastRow value. However, I am still looking to get a command that can get the lastRow value for all the columns instead of manually doing it.
edit: Using a FOR Loop helps with collating the values.
//This is to get the Last Row on Column 2 value.
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheets = ss.getSheetByName('FIRST');
var row = sheets.getLastRow();
for(var i = 1; i <= sheets.getLastColumn(); i++){
var myID = sheets.getRange(row, i).getValue();
}
console.log("Row Number: "+row);
console.log("Content of last Row: "+myID);```
If you want the onEdit() to run always, you just create it as a separate function. then you can call it from the onFormSubmit(), like this:
function onFormSubmit(e){
//does something you need...
onEdit();
}
onEdit(e){
//do the onEdit code...
}
The only problem with this is that the event e for onFormSubmit() is different than the one for onEdit(), so working with events might not be the best idea. However, calling one function from the other would fun just like with any other function.
function onFormSubmit(e){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheets = ss.getSheetByName('FIRST');
var row = sheets.getLastRow();
var myIDCol2 = 2;
var myIDCol3 = 3;
var myID2 = sheets.getRange(row, myIDCol2).getValue();
var myID3 = sheets.getRange(row, myIDCol3).getValue();
console.log("Speed Before Trigger Value: "+myID2);
console.log("Voltage Before Trigger Value: "+myID3);
ScriptApp.newTrigger("responsechange").timeBased().after(60000).create();
}
function responsechange(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheets = ss.getSheetByName('FIRST');
var row = sheets.getLastRow();
var myIDCol2 = 2;
var myIDCol3 = 3;
/*for(var i = 1; i <= sheets.getLastColumn(); i++){
console.log("Content of last Row: "+myID);
}*/
var myID2 = sheets.getRange(row, myIDCol2).getValue();
var myID3 = sheets.getRange(row, myIDCol3).getValue();
var template1 = HtmlService.createTemplateFromFile("speed1");
var template2 = HtmlService.createTemplateFromFile("voltage");
template1.speed1 = myID2;
template2.voltage = myID3;
console.log("Speed After Trigger Value: "+myID2);
console.log("Voltage After Trigger Value: "+myID3);
if((myID2 >=100) || (myID2 <= 50)){
MailApp.sendEmail("someone#gmail.com","Out of Range Notification Speed","",{htmlBody: template1.evaluate().getContent()});
}
if((myID3 >=100) || (myID3 <= 50)){
MailApp.sendEmail("someone#gmail.com","Out of Range Notification Voltage","",{htmlBody: template2.evaluate().getContent()});
}
}
With this, I managed make it work whereby on form submit, lets say the values are below 50 and above 100, it will trigger an email after the time-based trigger. I also tried within the time-based trigger, I edited the values to be within the range and it did not send an email. However, the only problems now is, if there are many triggers, it will stop the trigger by saying
This script has too many triggers. Triggers must be deleted from the script before more can be added.
But on the bright side, I managed to get the last value submitted to have it checked if it was edited or not.
Below is all of my code from a function that I have been working on for a while. Essentially I am trying to create a load of class analysis packs (I am a teacher) and print a google sheet as a PDF and then change a drop down (effectively changing the page and data) and then print again until all of the class codes in the drop down have been completed. The function works really well but the issue I have is that it will take longer than 6 mins to run as there are about 150 packs to create. I have looked into triggers and created a time based trigger which should start a few minutes after it has timed out. It seems to successfully create the trigger but the trigger never actually runs. Is this the correct approach? If so can anybody spot why its not working? Any feedback would be amazing as this has been driving me crazy!
function CreateClassPacks() {
SpreadsheetApp.getUi() // Or DocumentApp or FormApp
var startTime= (new Date()).getTime();
var REASONABLE_TIME_TO_WAIT = 100000
var MAX_RUNNING_TIME = 340000
// Getting the date and putting it into the format we want
var d= new Date();
var dateStamp = d.getDate()+"/"+d.getMonth()+"/"+d.getYear();
// Getting a token which will give me the authorisation I need
var request = {
"method": "GET",
"headers":{"Authorization": "Bearer "+ScriptApp.getOAuthToken()},
"muteHttpExceptions": true
};
// This is the key for the spreadsheet I am working on and then it gets fetched
var ss = SpreadsheetApp.getActiveSpreadsheet();
var getKeys = ss.getSheetByName("Settings");
var mainSSKey= getKeys.getRange("B1").getValue();
// Key for the folder we will save the documents into
var folderCPKey = getKeys.getRange("B2").getValue();
var foldersave=DriveApp.getFolderById(folderCPKey);
var fetch='https://docs.google.com/spreadsheets/d/'+mainSSKey+'/export?format=pdf&size=A4&portrait=false'
// This section gets all of the class codes from whichever sheet we choose.
// The first variable will need changing to whichever number sheet holds the codes.
var classCodeSheetNum = 0
var classCodeSheet = SpreadsheetApp.getActiveSpreadsheet().getSheets()[classCodeSheetNum]
var maxRowNum = classCodeSheet.getLastRow()-1;
// This variable must contain the correct column for the class codes
var dataRange = classCodeSheet.getRange(1, 1, maxRowNum, 1);
var data = dataRange.getValues();
Logger.log(data)
// This must be the sheet number for the class analysis packs
var sheetNum = 4
var newTrig = false
// This will loop through my data variable which contains all the class codes
for (var r=0; r<(data.length)-1; r++) {
for (i in data[0]) {
var scriptProperties = PropertiesService.getScriptProperties();
var startRow= scriptProperties.getProperty('start_row');
var currTime = (new Date()).getTime();
if(currTime - startTime >= MAX_RUNNING_TIME) {
if (newTrig == false){
ScriptApp.newTrigger("CreateClassPacks")
.timeBased()
.at(new Date(currTime+REASONABLE_TIME_TO_WAIT))
.create();
newTrig = true
break;
}
} else {
// This sets the value of A2 on the analysis sheet to the value from the data structure
SpreadsheetApp.getActiveSpreadsheet().getSheets()[sheetNum].getRange('O1').setValue(data[r][i]);
var source = SpreadsheetApp.getActiveSpreadsheet();
var sheet = source.getSheets()[sheetNum];
// This gets the value from A2 and sorts out the name of the file
var classCode = data[r][i]
var name = classCode + " " + dateStamp + ".pdf";
// This checks if the file already exists which will hopefully fix any timeout issues
var file = DriveApp.getFilesByName(name)
var chk = file.hasNext()
if (chk === false) {
// This hides all the sheets except for the one I am printing
for(var w=0; w< sheetNum;w++)
{
sheet = source.getSheets()[w];
sheet.hideSheet();
}
// This PDFs the page and has a timeout delaying the access requests so I don't get the annoying errors
var pdf = UrlFetchApp.fetch(fetch, request);
pdf = pdf.getBlob().setName(name);
Utilities.sleep(4000);
var file = foldersave.createFile(pdf)
// This shows all the sheets that I previously hid
for(var q=0; q< sheetNum;q++)
{
sheet = source.getSheets()[q];
sheet.showSheet();
}
}
}
}
}
}
This shows that the trigger seems to be created even though it doesn't run the function again
Maybe I'm missing something here but I think your code could be a lot quicker. For one thing create the var ss=SpreadsheetApp.getActive() and then use ss everywhere else. All create var allSheets=ss.getSheets() and then use allSheets[i] instead of 'ss.getSheets()[i]`. That section for i in data[0] makes no sense to me. The data is one column wide. All I would hide all of the sheets before the loop and then if necessary show the one that I'm printing if you have to. Hiding and showing sheets takes time. Try not to do it. I have gone through the code a bit but admittedly I don't have any context so I doubt that it runs. But I tried to take as much out of the loop as possible and you should too. You may find that you can get it to run in the allotted time.
function CreateClassPacks() {
var dateStamp=Utilities.formatDate(new Date(), Session.getScriptTimeZone(), "dd/MM/yyyy")
var ss=SpreadsheetApp.getActive();
var getKeys=ss.getSheetByName("Settings");
var mainSSKey=getKeys.getRange("B1").getValue();
var folderCPKey=getKeys.getRange("B2").getValue();
var foldersave=DriveApp.getFolderById(folderCPKey);
var fetch='https://docs.google.com/spreadsheets/d/'+mainSSKey+'/export?format=pdf&size=A4&portrait=false'
var classCodeSheetNum=0;
var classCodeSheet=SpreadsheetApp.getActiveSpreadsheet().getSheets()[classCodeSheetNum]
var maxRowNum=classCodeSheet.getLastRow()-1;
var dataRange=classCodeSheet.getRange(1, 1, maxRowNum, 1);
var data=dataRange.getValues();
var sheetNum=4;
var newTrig=false;
var allSheets=ss.getSheets();
for(var i=0;i<allSheets.length;i++){
allSheets[i].hideSheet();
}
var srcrng=allSheets[sheetNum].getRange('O1');
var sheet=allSheets()[sheetNum];
for (var r=0;r<data.length-1;r++){
srcrng.setValue(data[r][0]);
var classCode = data[r][i]
var name=classCode + " " + dateStamp + ".pdf";
var file=DriveApp.getFilesByName(name);
var chk=file.hasNext()
sheet.showSheet();
var pdf = UrlFetchApp.fetch(fetch, request);
pdf = pdf.getBlob().setName(name);
var file = foldersave.createFile(pdf);
sheet.hideSheet();
}
}
I have this function which works but it gets all responses.
function setEditUrl(ss, createDateColumn)
{
var formURL = 'https://docs.google.com/forms/d/101bMiRw9TQaGbdDc4U_tLAD0QzicqejM9qXOEwJPQKU/viewform';
var urlColumn = createDateColumn-2;
var data = ss.getDataRange().getValues();
var form = FormApp.openByUrl(formURL);
for(var i = 2; i < data.length; i++)
{
if(data[i][0] != '' && data[i][urlColumn-1] == '')
{
var timestamp = data[i][0];
var formSubmitted = form.getResponses(timestamp);
if(formSubmitted.length < 1) continue;
var editResponseUrl = formSubmitted[0].getEditResponseUrl();
ss.getRange(i+1, urlColumn).setValue(editResponseUrl);
}//end of if
}//end of for
return;
}// This is the end of the setEditUrl function
As the spreadsheet gets larger I am concerned with performance lag so I want to streamline it and replace the function with one like the one below which just gets the editURL for the last response and only if the sheet cell is empty
function setGoogleFormURL(ss, lastRowInx, createDateColumn)
{
var urlColumn = createDateColumn-2;
if (ss.getRange(lastRowInx, urlColumn).getValue() == "") // so that subsequent edits to Google Form don't overwrite editResponseURL
{
var form = FormApp.openById('101bMiRw9TQaGbdDc4U_tLAD0QzicqejM9qXOEwJPQKU');
var formResponses = form.getResponses();
var lastResponseIndex = form.getResponses.length-1;
var lastResponse = formResponses[lastResponseIndex];
var editResponseUrl = lastResponse.getEditResponseUrl();
var createEditResponseUrl = ss.getRange(lastRowInx, urlColumn);
createEditResponseUrl.setValue(editResponseUrl);
}
else{} //do nothing
however this seems to break on the getEditResponseUrl. I am getting the following error TypeError: Cannot call method "getEditResponseUrl" of undefined. (line 100, file "Code").
I used #SandyGood 's answer to this post as a reference. I wonder though if her observation about the event trigger is why this is borking. This is the onFormSubmit function I am using to call this and other fucntions.
function onFormSubmit(e)
{
var ss = SpreadsheetApp.getActiveSheet();
var lastRowInx = ss.getLastRow(); // Get the row number of the last row with content
var createDateColumn = ss.getMaxColumns(); //CreateDateColumn is currently in AX (Column 50) which is the last/max column position
var createDate = setCreateDate(ss, lastRowInx, createDateColumn);
var trackingNumber = setTrackingNumber(ss, lastRowInx, createDateColumn);
//var editURL = setEditUrl(ss, createDateColumn);
var editResponseURL = setGoogleFormURL(ss, lastRowInx, createDateColumn);
}//This is the end of onFormSubmit
I also found a whole bunch of sources 234where they were looking use the URL to append to an email, were more complex than my use case, or were unanswered. I also found some solutions for getting the EditURL by binding the script to the form but since I want to store the value on the sheet it needs to be bound to the sheet rather than the form.
UPDATE:
Okay so I tried to bind my script to the form instead of the sheet which allowed me to see the URL but now I have the problem in reverse where the form can't find the spreadsheet methods like .getMaxColumns TypeError: Cannot find function getMaxColumns in object Spreadsheet. (line 40, file "Code") AND .getActiveRange Cannot find method getActiveRange(number). (line 48, file "Code").
Here is the code on the form side
function onFormSubmit(e)
{
var form = FormApp.getActiveForm();
var activeFormUrl = form.getEditUrl();
var ss = SpreadsheetApp.openById(form.getDestinationId());
var createDateColumn = ss.getMaxColumns(); //CreateDateColumn is currently in AY (Column 51) which is the last/max column position
var urlColumn = createDateColumn-1; //urlColumn is currently in AX (Column 50) Calculating using it's relative position to createDateColumn Position
Logger.log(activeFormUrl, createDateColumn, urlColumn);
var checkLog1 = Logger.getLog();
Logger.clear();
if (ss.getActiveRange(urlColumn).getValue() == "") // so that subsequent edits to Google Form don't overwrite editResponseURL
{
var editResponseURL = setGoogleFormEditUrl(ss, createDateColumn, activeFormUrl);
var createEditResponseUrl = ss.getActiveRange(urlColumn);
createEditResponseUrl.setValue(activeFormUrl);
}
else
{
if (ss.getActiveRange(urlColumn).getValue() != activeFormUrl)
{
Logger.log("Something went wrong - URL doesn't match")
Logger.log(ss.getActiveRange(urlColumn).getValue());
var checkLog2 = Logger.getLog();
}
else {}//do nothing
}
}//This is the end of the onFormSubmit function
So I am wondering how I can pass a variable between the form and the sheet. Can I somehow read the form log programmically from the sheet? Can I append the value to the form response array (This would mean a few other edits to the referenced columns but could work). Thoughts #Gerneio , #SandyGood , Anyone else?
UPDATE 2:
There seemed to be a conflict with using both the methods from the FormApp and the SpreadsheetApp within the same function.
The solution that worked for me was to modularize the spreadsheet functions out (except the getActiveSheet) and to leave the getEditResponseURL method within the onFormSubmit Function.
The code snippet can be found posted here.
I'd suggest trying to use the onFormSubmit(e) on the form side.
function onFormSubmit(e)
{
var form = e.source;
var response = e.response;
var sheet = SpreadsheetApp.openById(form.getDestinationId());
var editUrl = response.getEditResponseUrl();
Logger.log(editUrl); // check the logger to see what results you are getting now
// Then do whatever operations you need to do...
}
Update:
I'm not so sure why you are having so many problems with this, but I can tell you for sure that it can be done from either side, the Form or Spreadsheet. I just put together a working example with code written on the Spreadsheet side, none what-so-ever on the Form side. Check it out:
function onFormSubmit(e)
{
var rng = e.range;
var ss = SpreadsheetApp.getActiveSpreadsheet();
var fUrl = ss.getFormUrl();
var f = FormApp.openByUrl(fUrl);
var rs = f.getResponses();
var r = rs[rs.length - 1]; // Get last response made
var c = getCellRngByCol(rng, 'Edit Response URL');
c.setValue(r.getEditResponseUrl());
}
// Specific for a form submit trigger
// Pass e.range and the name of the column
// to return a single cell
function getCellRngByCol(rng, col)
{
var aRng = SpreadsheetApp.getActiveSheet().getDataRange();
var hRng = aRng.offset(0, 0, 1, aRng.getNumColumns()).getValues();
var colIndex = hRng[0].indexOf(col);
return SpreadsheetApp.getActiveSheet().getRange(rng.getRow(), colIndex + 1);
}
There were a few small hiccups that I ran into. Firstly, make sure to setup the trigger accordingly. I highly recommend setting up immediate notifications of failures. Secondly, even though the function will rely on the event that is passed, manually run the onFormSubmit(e) method at least once before submitting a form. It will check to see if your script needs any authorization and will request if needed. I'd also recommend that you open up a new form, link a fresh new spreadsheet, and test this code to make sure it works. Then mold the above code to fit your needs.
If you can't get it, then I'll share a working example.
There seemed to be a conflict with using both the methods from the FormApp and the SpreadsheetApp within the same function.
The solution that worked for me was to modularize the spreadsheet functions out (except the getActiveSheet) and to leave the getEditResponseURL method within the onFormSubmit Function.
The code snippet can be found posted here.