Pre-fill date item - javascript

I have been trying to find the right method to pre-fill the start date field in my Google Forms with the current date and time, but I failed to achieve this.
I think the createResponse(hour, minute) would be the best method, however I have absolutely no idea on where to include it in my script:
function book1() {
var form = FormApp.getActiveForm();
var responses = form.getResponses();
var len = responses.length;
var last = len - 1;
var items = responses[last].getItemResponses();
////// var current= items[2].createResponse(10, 00);
var email = responses[last].getRespondentEmail();
var equipment = items[1].getResponse();
var datestart = items[2].getResponse();
var dateend = items[3].getResponse();
var cal = CalendarApp.getCalendarsByName(equipment)[0];
Logger.log('current '+current);
Logger.log(datestart);
Logger.log(dateend);
var start = new Date(datestart);
var end = new Date(dateend);
Logger.log('start '+start);
Logger.log('end '+end);
var allEvents = CalendarApp.getCalendarsByName(equipment)[0].getEvents(start, end);//Returns an array of events
if (allEvents.length < 1) {
var event = cal.createEvent(equipment, start, end)
.addGuest(email);
MailApp.sendEmail({
to: email,
subject: "Equipment " +equipment+ " booking confirmed",
htmlBody: "Equipment " +equipment+ " available, please return it by " +dateend+ " and scan the QR code when returning it.",
});
}
else {
var blob = HtmlService.createHtmlOutputFromFile("calendariframe").getBlob();
MailApp.sendEmail({
to: email,
subject: "Equipment " +equipment+ " not available",
htmlBody: blob.getDataAsString(),
});
};
}
In my latest attempt, I encountered that error;TypeError: items[2].createResponse is not a function
Would you know how to make it work?
Knowing that pre-filling the date and time only simplifies the process of the form users, but that in some cases they will not use the current date and time as a starting time for booking.
Thanks a lot in advance!

Related

MailApp.sendEmail sending email to my inbox even my even not set together to get the email

I have an email script that will send out email to all emails that are in the list of a google sheet. But then, when I run the script, it is also sent to my Inbox instead of only to register into my Sent folder. Before this no issue (after being using the same script for a long time, 1+ year), it just happened a few months back.
I've found similar issue from this post but couldn't get the suggestions work, example:
To replace Mailapp.sendEmail with Gmailapp.sendEmail
Checked if I have any wrong filter in my email
Attached the script as below:
function arrayUnique(arr) {
var tmp = [];
// filter out duplicates
return arr.filter(function(item, index){
var stringItem = item.toString(); // convert row arrays to strings for comparison
tmp.push(stringItem); // push string items into temporary arrays
return tmp.indexOf(stringItem) >= index; // only return the first occurrence of the strings
})}
function sendEmail() {
var sheet = SpreadsheetApp.getActive().getSheetByName("pending list")
var sub = "Error Fix Required"
var data = sheet.getRange(3,1, sheet.getLastRow(), 5).getDisplayValues().filter(function (row){
var date = sheet.getRange(1,2).getDisplayValues()
return row[3] == date
})
var filterunique = arrayUnique(data)
var json = {}
filterunique.forEach(function (item){
if(item[2] || item[2].length > 0){
if(!json[item[2]]){
json[item[2]] = []
}
json[item[2]].push(item[0])
}
})
Object.keys(json).forEach(function(to){
var email = "{{user}}#shopee.com"
email = email.replace(/{{user}}/gi,to)
var sku = "<br><ul><li>" + json[to].join("</li><li>") + "</li></ul>"
var body = "Hi " + to +", <br><br>The following require your kind attention:" + sku + "Please go to this <a href='https://docs.google.com/spreadsheets/d/1nMKeW//'>link</a> to rectify your submissions by today 4pm.<br><br> Thanks."
MailApp.sendEmail({
to: email,
subject: sub,
htmlBody: body
});
})
}
Also attached what I received in my Inbox:
Change this:
MailApp.sendEmail({to: email,subject: sub, htmlBody: body});
to this:
GmailApp.sendEmail(emai,sub,'',{htmlBody:body});

Is there way start a loop in a certain date range

I have a sheet that is dynamically updating with leads from my marketing campaign. Currently, it has over 9K rows and will continue to grow.
I need to check values for Col F for leads that came in today; however, when I run a loop, it takes too long since it has 9k+ rows.
I want to run a loop for rows that have today's date only. Is there a way to have my script efficiently look for today's date first (without having to loop through 9k rows), and then start my loop?
Below is what I had originally. The code would start from the top of the sheet and look at Col F values and then email me if a cell had only "az-" instead of a full location value. Content below has been modified for privacy
function Google_Check_Lead_Values() {
var title = "Google | Leads"
var app = SpreadsheetApp;
var Def_url = ("website")
///EDIT ^ URL
var ss = app.openByUrl(Def_url).getSheetByName("Google | Leads");
var last_row = ss.getLastRow();
for (i = 1;i <=last_row; i++) {
var location = ss.getRange(i,6).getValue();
var location_len = location.length;
if (location_len <= 3){
MailApp.sendEmail({
to: "email1",
//cc: "email2",
subject: "Discrepancy found on " + title,
htmlBody:"Hi Team, <br>This is an automated notifcation to let you know that an issue was found on " + title + ". Please take a look at the sheet linked below: <br><br> email"
});//end of email
}//end of if
}//end of for
}//end of function
Try it like this:
function Google_Check_Lead_Values() {
const title = "Google | Leads"
const ss = SpreadsheetApp.openByUrl("url")
const sh = SpreadsheetApp.openByUrl(Def_url).getSheetByName(title);
const dt = new Date();
const dtv = new Date(dt.getFullYear(), dt.getMonth(), dt.getDate()).valueOf();
const vs = sh.getDataRange().getValues();
vs.forEach(r => {
let loc = r[5].toString();
let d = new Date(r[0]);
let dv = new Date(d.getFullYear(),d.getMonth(),d.getDate()).valueOf();
if( dv == dtv && loc.length < 4) {
MailApp.sendEmail({ to: "email1", subject: "Discrepancy found on " + title, htmlBody: "Hi Team, <br>This is an automated notifcation to let you know that an issue was found on " + title + ". Please take a look at the sheet linked below: <br><br> email", })
}
});
}
I believe your goal is as follows.
You want to reduce the process cost of the search of value from a large sheet.
You want to achieve this using Google Apps Script.
In your situation, by searching the values from the columns "A" and "F", you want to send emails.
In order to search the values from a sheet, there are several methods. Using for loop, TextFinder and query language. In my test, when the query language is used, the process cost was the lowest of these 3 patterns. So, in this answer, I would like to propose to search the values using use the query language. Ref
Sample script:
function Google_Check_Lead_Values() {
var title = "Google | Leads"
var Def_url = "###"; // Please use your Spreadsheet URL.
var ss = SpreadsheetApp.openByUrl(Def_url);
const spreadsheetId = ss.getId();
const today = new Date();
const tommorow = new Date();
tommorow.setDate(tommorow.getDate() + 1);
const vToday = Utilities.formatDate(today, Session.getScriptTimeZone(), "yyyy-MM-dd");
const vTommorow = Utilities.formatDate(tommorow, Session.getScriptTimeZone(), "yyyy-MM-dd");
const sheetName = "Google | Leads";
const query = `SELECT * WHERE A >= DATE '${vToday}' AND A < date '${vTommorow}' AND E = 'az-'`;
const url = `https://docs.google.com/spreadsheets/d/${spreadsheetId}/gviz/tq?sheet=${sheetName}&tqx=out:csv&tq=${query}`;
const res = UrlFetchApp.fetch(encodeURI(url), { headers: { authorization: "Bearer " + ScriptApp.getOAuthToken() } });
const [, ...values] = Utilities.parseCsv(res.getContentText());
if (values.length == 0) return;
values.forEach(_ => {
MailApp.sendEmail({
to: "email1",
//cc: "email2",
subject: "Discrepancy found on " + title,
htmlBody: "Hi Team, <br>This is an automated notifcation to let you know that an issue was found on " + title + ". Please take a look at the sheet linked below: <br><br> email"
});
});
}
When this script is run, the today date values are searched from the column "A", and also it searches whether the cell value of column "F" is the value of az-. When the values are found, the emaiil is sent. In this case, from your showing script, for example, when 2 rows are found, 2 emails are sent.
If you know the Spreadsheet ID, you can also directly use it to const spreadsheetId = ss.getId(); like const spreadsheetId = "###SpreadsheetID###";.
In this sample script, about the search of the column "F", it seaches whether the value is az-. But, if you want to search the length of cell value, please modify as follows.
From
const query = `SELECT * WHERE A >= DATE '${vToday}' AND A < date '${vTommorow}' AND E = 'az-'`;
To
const query = `SELECT * WHERE A >= DATE '${vToday}' AND A < date '${vTommorow}' AND E MATCHES '^.{0,3}$'`;
References:
Query Language Reference (Version 0.7)
Related thread.
https://stackoverflow.com/a/56663884

I'm trying to post a Slack message for each new row of a spreadsheet using Google Scripts - but I'm only getting one post. What am I doing wrong?

I'm trying to build a simple app to post a message to Slack for every new row in a Google Spreadsheet. I can get the info from the sheet and post it to the logger, and I can post to Slack, but I can only seem to get this to work with the first row in the loop (whereas the logger will receive all values for all rows). I'm probably just messing up the way the loops work (new to this) but having stared at it for a few hours now I can't see it. My intention is to set this to trigger on edit (it's populated from a Google Form), so I've added a column to mark when a Slack message has been sent, just to avoid a mad loop of endless messages for whatever reason.
I've tried logging the output and can get all values there. Putting the post to Slack part of the code in the same place only results in one post, though.
//Set up a variable to show when we've sent a message to Slack
var slackSentText = "Yes";
//This is hte Slack hook
var url = "https://hooks.slack.com/services/tokens!";
function getNewInfo() {
var sheetname = "Info"
var myspreadsheet = SpreadsheetApp.openById('secretID!');
var sheet = myspreadsheet.getSheetByName(sheetname);
// set rows until work out how to do more elegantly...
var startRow = 8; // First row of data to process
var numRows = 5; // Number of rows to process
var dataRange = sheet.getRange(startRow, 1, numRows, 11);
var data = dataRange.getValues();
// iterate and make variables for Slack
for (var i = 0; i < data.length; ++i) {
var row = data[i];
var idNumber = row[0];
var projectType=row[6];
var supplierName=row[2];
var projectName=row[3];
var projectDescription=row[4];
var projectStatus=row[1];
var projectDate=row[5];
var slackSent = row[10];
// check if column is marked with Slack sent note and if so ignore. If not send Slack
if (slackSent !== slackSentText) {
// Slack bit
var slackMessage = {
"channel": "ID-number-bot",
"username": "ID-bot",
"text": "\n :white_check_mark:" +
"\n *New Project:* " + idNumber +
"\n *Project Name:* " + projectName +
"\n *Supplier:* " + supplierName +
"\n *Project Status:* " + "["+projectStatus+"]" +
"\n *Project Description:* " + "_"+projectDescription+"_" +
"\n *Project Type:* " + projectType +
"\n *Estimated Delivery Date:* " + projectDate +
"\n"+ slackSent +
"\n Job folder string: \n" + "RCM "+jobNumber+" "+projectName +
"\n \n"
};
var options = {
"method": "post",
"contentType": "application/json",
"payload": JSON.stringify(slackMessage)
};
return UrlFetchApp.fetch(url,options);
sheet.getRange(startRow + i, 11).setValue(slackSentText);
Logger.log("jobNumber:"+jobNumber)
Logger.log("projectType:"+projectType)
Logger.log("supplierName:"+supplierName)
Logger.log("projectName:"+projectName)
Logger.log("projectDescription:"+projectDescription)
Logger.log("projectStatus:"+projectStatus)
Logger.log("projectDate:"+projectDate)
}
}
// SpreadsheetApp.flush();
}
Thanks very much everyone. Hopefully I've given enough info.
As #Tanaike proposed, your problem should be fixed by changing:
return UrlFetchApp.fetch(url,options);
To this:
UrlFetchApp.fetch(url,options)
The return keyword gets you out of the loop. The code finds return in the first iteration, so it doesn't go on with the following rows, and that's why you are only getting the first row sent.

Google Scripts: Pull Google Document Based on User ID / Email

Good Morning Stack!
I was looking for some advice for some expanded functionality on a Google Script that helps me track and process absence requests. The process is as follows:
A user submits their form responses
The form responses are stored on a spreadsheet
A google doc, pre-created, is pulled and the values from the spreadsheet are implanted in the document.
The document is converted to a PDF
That PDF is automatically emailed to me.
However, some work policies have changed and I now need this form to have a signature that is unique to the person filling the form. In the past we simply printed the resulting PDF and had the person sign off on it.
I know I do not have the technicality to add on any sort of Electronic Signature functionality, nor is emailing that PDF to them an option as it doesn't create a fillable PDF (and my users don't really know how to digitally sign items anyways)
So what I was thinking is to create a form unique to each of the 15-20 users of this process and instead of a getFileByID, have the script check the Google Users account / email and pull the file created for them and stored in my drive instead.
As follows is my current, functional, script. How could I make this work?
function onFormSubmit(e) {
var Last_Name = e.values[2];
var First_Name = e.values[3];
var Middle_Initial = e.values[4];
var Work_Location = e.values[5];
var Job_Title = e.values[6];
var Contact_Number = e.values[7];
var Start = e.values[8];
var End = e.values[9];
var Time = e.values[10];
var Reason = e.values[11];
var D = new Date();
var copyId = DriveApp
.getFileById("1sdfjlsdf55asdfnk565enasdfnsnsd2")
.makeCopy("AbsenceRequest" + Last_Name + Start).getId();
var copyDoc = DocumentApp.openById(copyId)
var copyBody = copyDoc.getActiveSection();
copyBody.replaceText('keyLastName', Last_Name);
copyBody.replaceText('keyFirstName', First_Name);
copyBody.replaceText('keyMiddleInitial', Middle_Initial);
copyBody.replaceText('keyWorkLocation', Work_Location);
copyBody.replaceText('keyJobTitle', Job_Title);
copyBody.replaceText('keyContactNumber',Contact_Number);
copyBody.replaceText('keyStart', Start);
copyBody.replaceText('keyEnd', End);
copyBody.replaceText('keyTime', Time);
copyBody.replaceText('keyDate', D);
copyDoc.saveAndClose();
var pdf = DriveApp.getFileById(copyId).getAs("application/pdf");
var Email = "email#email.org" + "," + "email#email.org";
var Subject = "Absence Request"
var Body = "This is an absence request"
MailApp.sendEmail(Email, Subject, Body, {attachments: pdf});
DriveApp.getFileById(copyId).setTrashed(true);
}

Returning future weekday excluding holidays

I should preface by saying I know nothing about scripting. I found this script online that fit my needs, so I was able to re-purpose it for my project. Anyway, this script takes Google form submissions, populates a Google doc template, that template gets copied, converted to PDF, and placed in a specific folder on my Google Drive.
So my question is, I have a simple line that pulls the current date when the script gets run, but I also need some code that can calculate the current date plus 5 weekdays (which should exclude weekends), but I also need it to exclude defined holidays. Any help would be greatly appreciated.
// Work Order
// Get template from Google Docs and name it
var docTemplate = ""; // *** replace with your template ID ***
var docName = "Work Order";
// When Form Gets submitted
function onFormSubmit(e) {
//Get information from form and set as variables
var email_address = "";
var job_name = e.values[1];
var ship_to = e.values[11];
var address = e.values[12];
var order_count = e.values[7];
var program = e.values[2];
var workspace = e.values[3];
var offer = e.values[4];
var sort_1 = e.values[5];
var sort_2 = e.values[6];
var print_services = e.values[10];
var priority = e.values[13];
var notes = e.values[14];
var formattedDate = Utilities.formatDate(new Date(), "EDT", "MM/dd/yyyy");
// Get document template, copy it as a new temp doc, and save the Doc's id
var copyId = DriveApp.getFileById(docTemplate)
.makeCopy(docName + ' for ' + job_name)
.getId();
// Open the temporary document
var copyDoc = DocumentApp.openById(copyId);
// Get the document's body section
var copyBody = copyDoc.getActiveSection();
// Replace place holder keys,in our google doc template
copyBody.replaceText('keyJobName', job_name);
copyBody.replaceText('keyShipTo', ship_to);
copyBody.replaceText('keyAddress', address);
copyBody.replaceText('keyOrderCount', order_count);
copyBody.replaceText('keyProgram', program);
copyBody.replaceText('keyWorkspace', workspace);
copyBody.replaceText('keyOffer', offer);
copyBody.replaceText('keySort1', sort_1);
copyBody.replaceText('keySort2', sort_2);
copyBody.replaceText('keyPrintServices', print_services);
copyBody.replaceText('keyPriority', priority);
copyBody.replaceText('keyNotes', notes);
copyBody.replaceText('keyDate', formattedDate);
copyBody.replaceText('keyDue', expirationDate);
// Save and close the temporary document
copyDoc.saveAndClose();
// Convert temporary document to PDF by using the getAs blob conversion
var pdf = DriveApp.getFileById(copyId).getAs("application/pdf");
// Attach PDF and send the email
var subject = "New Job Submission";
var body = "Here is the work order for " + job_name + "";
MailApp.sendEmail(email_address, subject, body, {
htmlBody: body,
attachments: pdf
});
// Move file to folder
var file = DriveApp.getFileById(copyId);
DriveApp.getFolderById("").addFile(file);
file.getParents().next().removeFile(file);
}
You can use the below function to get future date which excludes weekends and if any holiday declared in the array.
function addDates() {
var date = new Date(); // yor form date
var hodiday = ["08/09/2017","08/15/2017"]; //Define holiday dates in MM/dd/yyyy
var days = 5; //No of days you want to add
date.setDate(date.getDate());
var counter = 0;
if(days > 0 ){
while (counter < days) {
date.setDate(date.getDate() + 1 );
var check = date.getDay();
var holidayCheck = hodiday.indexOf(Utilities.formatDate(date, "GMT", "MM/dd/yyyy"));
if (check != 0 && check != 6 && holidayCheck == -1) {
counter++;
}
}
}
Logger.log(date) //for this example will give 08/16/2017
return date;
}

Categories

Resources