Syncing Google Sheets to Calendar App Script - google-apps-script

I have the below script and keep getting the error 'Cannot find method createEvent(number,string,string).' I can't figure out what's wrong. Any ideas?
function createCalendarEvent() {
var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 2;
var numRows = sheet.getLastRow();
var numColumns = sheet.getLastColumn();
var dataRange = sheet.getRange(startRow, 1, numRows-1, numColumns);
var data = dataRange.getValues();
var complete = "Done";
for (var i = 0; i < data.length; ++i) {
var row = data[i];
var aname = row[2]; //Agent
var cname = row[3]; //Client Name
var country = row[4]; //Client Country
var phone = row[5]; //Phone Number
var deposit = row[6]; //Type of Deposit
var ewallet = row[7]; //Processor/eWallet
var method = row[8]; //Deposit Method
var amount = row[9]; //Amount/Percent
var date = new Date(row[10]); //Date of Next Contact
var target = row[12]; //Target Amount
var history = row[13]; //Deposit History incl. dates
var currency = row[14]; //Currency
var comments = row[15]; //Comments
var stime = new Date (row[17]);
var etime = new Date (row[18]);
var added = row[19]; //Added to calendar
if (added != complete) {
var currentCell = sheet.getRange(startRow + i, numColumns);
var event = CalendarApp.getDefaultCalendar().createEvent(cname, stime, etime);
currentCell.setValue(complete)};
}
}

This error means that it cannot find that method, probably because you're using wrong arguments to the function createEvent(String,Date,Date) (see documentation here).
You are using function createEvent(number,String,String), which doesn't exist.
Your first variable cname should be transformed to string, and what you are also seing in the error is that 2nd and 3rd parameter are as string, while they should be dates.
The proper solution would be to transform starttime and endtime to date, and that depends on how is the format of your string date.

Related

Issue with onEdit after sending email in google sheets

here is my code in google script:
function Send(){
Browser.msgBox("Send");
}
function myFunction() {
var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 2;
var lr = sheet.getLastRow();
var dataRange = sheet.getRange(startRow, 1, lr-1, 6);
var data = dataRange.getValues();
for (var i = 0; i < data.length; i++) {
var row = data[i];
var name = row[0];
var emailAddress = row[1];
var date = row[2];
var city = row[3];
var status = row[6];
if (emailAddress.match('#') === null){
continue;
};
var subject = row[4];
var message = "Hey " + name + ", welcome in the team " + row[5];
MailApp.sendEmail(emailAddress, subject, message);
sheet.getRange(i+2,7).setValue("Sent");
}
}
Until here everything works fine. I would like then that when "Sent" appears in the 7th column, that the whole row where "Sent" is in, is moved to another tab.
function onEdit(e) {
var ss = e.source;
var s = ss.getActiveSheet();
var r = e.range;
var actionCol = 7;
var nameCol = 7;
var rowIndex = r.getRowIndex();
var colIndex = r.getColumnIndex();
var colNumber = s.getLastColumn()-1;
if (e.value == "Sent" && colIndex == actionCol) {
var targetSheet = s.getRange(rowIndex, nameCol).getValue();
if (ss.getSheetByName("Welcome")) {
var targetSheet = ss.getSheetByName("Done");
var targetRange = targetSheet.getRange(targetSheet.getLastRow()+1, 1, 1, colNumber);
var sourceRange = s.getRange(rowIndex, 1, 1, colNumber);
sourceRange.copyTo(targetRange);
s.deleteRow(rowIndex);
}
}
}
**If I manually write "Sent" in the 7th column, the row is moved to the other sheet. But when I run the first function and that "Sent" appears in that column, the onEdit function doesn't work.
So basically both functions work but not together at the same time.
Does someone know a fix for this?**
Issues:
You are trying to trigger an onEdit function via a script but that's not how triggers work. The official documentation states the following:
The onEdit(e) trigger runs automatically when a user changes the value
of any cell in a spreadsheet.
Namely, onEdit triggers are activated only by user actions, not by scripts nor formulas.
You don't need a separate function to check if the value is Sent and then delete the row with another function. After the email is sent you can move the data and delete the row, all within the same function.
Last but not least, when deleting rows iteratively we change the structure of the sheet and therefore the data input does not match the updated structure. To alleviate this issue, we can store the indexes of the rows we want to delete in an array, and then using that array delete the rows backwards.
Solution:
Assuming your codes work separately, this should also work:
function myFunction() {
var ss = SpreadsheetApp.getActive();
var sheet = ss.getSheetByName("Welcome");
var targetSheet = ss.getSheetByName("Done");
var startRow = 2;
var lr = sheet.getLastRow();
var dataRange = sheet.getRange(startRow, 1, lr-1, 6);
var data = dataRange.getValues();
var colNumber = sheet.getLastColumn()-1;
var delRows = [];
for (var i = 0; i < data.length; i++) {
var row = data[i];
var name = row[0];
var emailAddress = row[1];
var date = row[2];
var city = row[3];
var status = row[6];
if (emailAddress.match('#') === null){
continue;
};
var subject = row[4];
var message = "Hey " + name + ", welcome in the team " + row[5];
MailApp.sendEmail(emailAddress, subject, message);
var targetRange = targetSheet.getRange(targetSheet.getLastRow()+1, 1, 1, colNumber);
var sourceRange = sheet.getRange(i+startRow, 1, 1, colNumber);
sourceRange.copyTo(targetRange);
delRows.push(i+startRow);
}
// delete rows in reverse order
delRows.reverse().forEach(ri=>{sheet.deleteRow(ri)});
}
you don't need the onEdit function anymore so you can delete it.

Prevent duplicate calendar events from Apps Script

I've read through a number of posts on SO and elsewhere as to how to prevent a script from continuing to add duplicate calendar events each time it's run. I've been unsuccessful so far in stopping the duplicates.
Here's my code:
function onOpen() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var menuEntries = [ {name: "Push to Calendar", functionName: "sendCalendarEvents"} ];
ss.addMenu("Custom Menu", menuEntries);
}
function sendCalendarEvents() {
var spreadsheet = SpreadsheetApp.getActiveSheet();
var calendarId = spreadsheet.getRange('G1').getValue();
var eventCal = CalendarApp.getCalendarById(calendarId);
var lastRow = spreadsheet.getLastRow();
var count = spreadsheet.getRange("A3:E"+lastRow+"").getValues();//five columns
var minutesBefore = 462
for (x=0; x<count.length; x++) {
var row = count[x];
var title = row[0];
var startTime = row[1];
var endTime = row[2];
var guests = row[3];
var description = row[4];
var location = row[5];
var id = row[7];no row[7]
var options = {
'location': location,
'description': description,
'guests':guests +',',
'sendInvites': 'True',
}
if(!id) {
var event = eventCal.createAllDayEvent(title, startTime, options);
var newEventId = event.getId();
spreadsheet.getRange(x+3,7).setValue('yes');
spreadsheet.getRange(x+3,8).setValue(newEventId);
event.addEmailReminder(minutesBefore);
Logger.log('Event ID: ' + event.getId());
and here's my spreadsheet (with 'test' data)
I've also tried variations of the 'if' statement (like if (row[x][7] != 'yes')...create the event) but that hasn't worked either.
Any help? After the duplicate issue is resolved, I then want to be able to have a user edit the date or title or such of an event in the spreadsheet and have the existing event deleted and then a new event (with the updated title/date) be created...if that's possible.
Thanks for any help you can provide!
You only have five columns in your data. There is no row[7]
var count = spreadsheet.getRange("A3:E"+lastRow+"").getValues();//only five columns in your data
var minutesBefore = 462
for (x=0; x<count.length; x++) {
var row = count[x];
var title = row[0];
var startTime = row[1];
var endTime = row[2];
var guests = row[3];
var description = row[4];
var location = row[5];
var id = row[7];//Problem is right here...there is no row[7];

Setting value in Google Script doesn't work when try to put using variable row and fixed column number

This is my code, in the last line I am trying to put "Yes" in the column J. I am using row number as variable i since the row count will be different always. If I provide cell value directly like J1 then it works. Can someone please help ?
function myFunction() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Form Responses 1");
var rowCount = sheet.getRange('A:A').getLastRow();
var PTOEmail = "lssnihit#gmail.com";
for(var i=2; i<rowCount; i++)
{
if(sheet.getRange(i,1).getValue() != "" && sheet.getRange(i,10).getValue() != "Yes")
{
var requesterName = sheet.getRange(i, 2).getValue();
var requesterEmail = sheet.getRange(i,3).getValue();
var startDate = sheet.getRange(i, 4).getValue();
var endDate = sheet.getRange(i, 5).getValue();
var sickHours = sheet.getRange(i, 6).getValue();
var vacationHours = sheet.getRange(i, 7).getValue();
var approverEmail = sheet.getRange(i, 8).getValue();
var comStatus = sheet.getRange(i, 9).getValue();
var mailSubject = "Leave Information for "+requesterName;
}
}
var mailBodyOK = "Hi, "+requesterName+" has requested for leave starting from "+startDate+" to "+endDate+". It contains "+sickHours+" sick hours and "+vacationHours+" vacation hours. \n"+requesterName+" has stated that communication with onsite FB manager is done and manager is fine with the leave.";
if ( comStatus == "Informed - OK with leave")
{
MailApp.sendEmail( {
to: approverEmail,
cc: PTOEmail,
subject: mailSubject,
htmlBody: "<p> "+mailBodyOK+"</p>"
})
}
sheet.getRange(i, 10).setValue("Yes"); //indicates that mail is sent
}
It seems to me that var i is not known at the line setting the value (outside the loop). If you need to use it this way, declare it before the loop.
I believe this will work for you:
function myFunction() {
var ss = SpreadsheetApp.getActive();
var sheet = ss.getSheetByName("Form Responses 1");
var range = sh.getDataRange();
var vA=range.getValues();
var rowCount = sheet.getLastRow();
var PTOEmail = "lssnihit#gmail.com";
for(var i=1;i<vA.length;i++) {
var requesterName = vA[i][1];
var requesterEmail = vA[i][2];
var startDate = vA[i][3];
var endDate = vA[i][4];
var sickHours = vA[i][5];
var vacationHours = vA[i][6]
var approverEmail = vA[i][7];
var comStatus = vA[i][8];
var mailSubject = "Leave Information for "+requesterName;
var mailBodyOK = "<p>Hi, "+requesterName+" has requested for leave starting from "+startDate+" to "+endDate+". It contains "+sickHours+" sick hours and "+vacationHours+" vacation hours. \n"+requesterName+" has stated that communication with onsite FB manager is done and manager is fine with the leave.</p>";var mailBodyOK = "<p>Hi, "+requesterName+" has requested for leave starting from "+startDate+" to "+endDate+". It contains "+sickHours+" sick hours and "+vacationHours+" vacation hours. \n"+requesterName+" has stated that communication with onsite FB manager is done and manager is fine with the leave.</p>";
if ( comStatus == "Informed - OK with leave")
{
MailApp.sendEmail(approverEmail,mailSubject,null, {cc: PTOEmail, htmlBody: mailBodyOK})
}
sheet.getRange(i+1,10).setValue("Yes"); //indicates that mail is sent
}
}

Google script google sheet to calendar TypeError: Cannot find function createEvent in object Calendar. (line 18, file "Code")

I have attempted to create a google script that will create calendar events based on information within cells in google sheets. I have gotten to the point where everything is labeled and marked, but an error is occuring that states:
TypeError: Cannot find function createEvent in object Calendar. (line 18, file "Code")
Here is the code I have written:
function calInsert() {
var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 2; // First row of data to process
var numRows = 25; // Number of rows to process
var dataRange = sheet.getRange(startRow, 2, numRows, 9);
var data = dataRange.getValues();
var cal = CalendarApp.getCalendarsByName( "EC Calendar" );
for (i in data) {
var row = data[i];
var title = row[1]; // First column
var tstart = row[2]; // Second column
var tstop = row[3];
var desc = row[4];
var loc = row[5];
var cmmail = row[6];
var leamail = row[7];
var event = cal.createEvent(title, new Date(tstart), new Date(tstop), {description:desc,location:loc,guests:cmmail,guests:leamail});
}
}
Any help you can provide would be appreciated.
var cal = CalendarApp.getCalendarsByName("EC Calendar");
This gives you an array of calendars with that name. Change this to:
var cal = CalendarApp.getCalendarsByName("EC Calendar")[0]; //Gets the correct calendar
This gives you the first Calendar with the name. I tried the below code:
function calInsert() {
var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 2; // First row of data to process
var numRows = 2; // Number of rows to process
var dataRange = sheet.getRange(startRow, 1, numRows, 5);
var data = dataRange.getValues();
var cal = CalendarApp.getCalendarsByName( "calendar ID" )[0];
for (i in data) {
var row = data[i];
var title = row[0]; // First column
var tstart = row[2]; // Second column
var tstop = row[3];
Logger.log(tstop);
var desc = row[1];
var loc = row[4];
//var cmmail = row[6];
//var leamail = row[7];
cal.createEvent(title, new Date(tstart), new Date(tstop), {description:desc,location:loc});
}
}
I am able to create event in my calendar. If needed, you can send cmmail and leamail to createEvent.

How to loop command using the .getRowIndex() in Google Sheets?

function getColIndexByName(colName) {
var sheet = SpreadsheetApp.getActiveSheet();
var numColumns = sheet.getLastColumn();
var row = sheet.getRange(1, 1, 1, numColumns).getValues();
for (i in row[0]) {
var name = row[0][i];
if (name == colName) {
return parseInt(i) + 1;
}
}
return -1;
}
function sendtoContacts () {
var source = SpreadsheetApp.getActiveSpreadsheet();
var ss = source.getActiveSheet();
var row = ss.getActiveRange().getRowIndex();
var group = ContactsApp.getContactGroup('From Googlesheet');
var givenName = ss.getRange(row, getColIndexByName("First")).getValue();
var familyName = ss.getRange(row, getColIndexByName("Last")).getValue();
var email = ss.getRange(row, getColIndexByName("Work Gmail")).getValue();
var Homeemail = ss.getRange(row, getColIndexByName("Personal Email")).getValue();
var company = ss.getRange(row, getColIndexByName("Company")).getValue();
var title = ss.getRange(row, getColIndexByName("Title")).getValue();
var phone = ss.getRange(row, getColIndexByName("Phone")).getValue();
var mobile = ss.getRange(row, getColIndexByName("Mobile")).getValue();
var newContact = ContactsApp.createContact(givenName, familyName, email);
var contactid = newContact.getId();
var addy = ss.getRange(row, getColIndexByName("Address")).getValue();
var city = ss.getRange(row, getColIndexByName("City")).getValue();
var prov = ss.getRange(row, getColIndexByName("Prov")).getValue();
var pc = ss.getRange(row, getColIndexByName("Postal Code")).getValue();
var address = addy + ", " + city + ", " + prov + ", " + pc
var AltContact = ss.getRange(row, getColIndexByName("Alt Contact Name")).getValue();
var AltRelation = ss.getRange(row, getColIndexByName("Alt ContactRelation")).getValue();
var AltPhone = ss.getRange(row, getColIndexByName("Alt Contact Phone")).getValue();
var AltWork = ss.getRange(row, getColIndexByName("Alt Contact Wk No")).getValue();
var AltMobile = ss.getRange(row, getColIndexByName("Alt Contact Mobile")).getValue();
newContact.addToGroup(group);
newContact.addAddress("Home", address);
newContact.addCompany(company, title);
newContact.addEmail("Home", Homeemail);
newContact.addCustomField("Emergency Contact", AltContact);
newContact.addCustomField("Emergency Contact Relation", AltRelation);
newContact.addCustomField("Emergency Contact Work", AltWork);
newContact.addCustomField("Emergency Contact Mobile", AltMobile);
for ( var i = 0; i < phone.length ; i++){
if (phone[i][3] != ''){ newContact.addPhone("HOME", phone); return}};
for ( var i = 0; i < mobile.length ; i++){
if (mobile[i][44] != ''){ newContact.addPhone("Mobile", mobile); return}};
}
function MakeAllContacts() {
var source = SpreadsheetApp.getActiveSpreadsheet();
var ss = source.getActiveSheet();
var startRow = 2; // First row of data to process
var numRows = 100; // Number of rows to process
for (row = 2; row < 6; row++)
{
sendtoContacts();
}
return
}
Here I am duplicating the entries with MakeAllContacts() but I want to make the RowIndex change to every row in the sheet so it add all the contacts in the sheet. Here is at Video I made explaining it Video and here is a link to my actual sheet Google Sheet. I have a fair bit of code I would like to start sharing if I could just get my head are around looping instead of the one row to be All the rows in the sheet. Thanks for any help is appreciated.
Your sendtoContacts () function is using ss.getActiveRange().getRowIndex(); to determine which row to use but nowhere in your script you set any row to active so you keep using the same data all the way through the main loop in MakeAllContacts().
There are 2 possible solutions :
use activate() in the MakeAllContacts() function loop so that the active row changes for each iteration (ss.getRange(row,1).activate())
use a rowIndex parameter in the sendtoContacts () function like below :
function MakeAllContacts() {
var source = SpreadsheetApp.getActiveSpreadsheet();
var ss = source.getActiveSheet();
var startRow = 2; // First row of data to process
var numRows = 100; // Number of rows to process
for (row = 2; row < numRows; row++){
sendtoContacts(row);
}
}
and then change the function sendtoContacts () function like this:
function sendtoContacts (row) { // row as parameter
var source = SpreadsheetApp.getActiveSpreadsheet();
var ss = source.getActiveSheet();
...
That said, this approach is not very efficient since each data is read in the spreadsheet using a single getRange/getValue which is particularly slow... please read the best practice to get inspiration on how to handle your data more efficiently using a single getValues() and iterate the array content instead.