Generating Google doc from template, needing to link within email - google-apps-script

I have sections of Google scripts below that I have set to generate a new document from a template with variables added from a Google form.
The new document is then converted to a PDF and emailed as an attachment.
What I now also want to do is include a hyperlink to the Google document itself.
I can see DocumentApp.openByUrl is a possible function but just don't know how to apply it.
autoFillGoogleDocFromForm
//e.values is an array of form values
var Timestamp = e.values[0];
var Channel = e.values[1];
var Name = e.values[2];;
var file = DriveApp.getFileById('FILEID');
var folder = createChannelFolder(); // 1st modification point
var copy = file.makeCopy(Channel + ',' + Name, folder);
var newId = copy.getId();
var doc = DocumentApp.openById(newId);
var body = doc.getBody();
body.replaceText('{{Timestamp}}', Timestamp);
body.replaceText('{{Channel}}', Channel);
body.replaceText('{{Name}}', Name);
doc.saveAndClose();
}
Send html email
//Setup embedded image.
var imgID = "IMAGEID"
var imageURL = "https://drive.google.com/uc?id="+imgID;
var imageBlob = UrlFetchApp
.fetch(imageURL)
.getBlob()
.setName("imageblob");
var body = HtmlService.createTemplateFromFile("html");
body.Name = Name;
body.Channel = Channel;
var Blob = doc.getBlob().getAs('application/pdf');
var Email = Email;
var subject = 'Submitted';
var values = e.values;
GmailApp.sendEmail(Email, subject, body, {htmlBody: body.evaluate().getContent(),
inlineImages:
{
imageblob: imageBlob},
attachments: [{
fileName: Channel + ".pdf",
content: Blob.getBytes(),
mimeType: "application/pdf"}]
});
}

You should use getUrl().
I don't know how those two blocks of code are related or where you want to include the URL, but the example in the link above should be pretty helpful. Something like
var doc = DocumentApp.openById(newId);
var url = doc.getUrl();

Related

Generating PDF Succesfully but I failed when I added Qr Code

I have google form with response as in table (spreadsheet) below.
This script can't generate qr code. QR code formula in header so it is automatically generate qr code in spreadsheet in column B with data from column D.I don't know how to solve it.
var docTemplate = "doc ID";
var docName = "Vehicle check with images";
function onFormSubmit(e) {
var replaceTextToImage = function(body, searchText, fileId) {
var width = 300; // Please set this.
var blob = DriveApp.getFileById(fileId).getBlob();
var r = body.findText(searchText).getElement();
r.asText().setText("");
var img = r.getParent().asParagraph().insertInlineImage(0, blob);
var w = img.getWidth();
var h = img.getHeight();
img.setWidth(width);
img.setHeight(width * h / w);
}
//Get information from form and set as variables
var email_address = "myemailaddress#here.com";
var qrCode = e.values[1].split("=")[3];//I want to try
var empName = e.values[2];
var empId = e.values[3];
var photo = e.values[4].split("=")[1];
// Get document template, copy it as a new temp doc, and save the Doc’s id
var copyId = DriveApp.getFileById(docTemplate)
.makeCopy(docName+' for '+empName)
.getId();
// Open the temporary document
var copyDoc = DocumentApp.openById(copyId);
// Get the document’s body section
var copyBody = copyDoc.getBody();
replaceTextToImage(copyBody, 'qrcode', qrCode);//problem could not be generated
copyBody.replaceText('name', empName);
copyBody.replaceText('id', empId);
replaceTextToImage(copyBody, 'photo', photo);
copyDoc.saveAndClose();
var pdf = DriveApp.getFileById(copyId).getAs("application/pdf");
var subject = "sample attachment file";
var body = "sample text: " + empName + "";
MailApp.sendEmail(email_address, subject, body, {htmlBody: body, attachments: pdf});
DriveApp.getFileById(copyId).setTrashed(true);
}
Timestamp
={"QR CODE";ARRAYFORMULA(IF(D2:D<>"";IMAGE("https://chart.googleapis.com/chart?chs=300x300&cht=qr&chl="&D2:D);))}
Name
Id
Photo
10/07/2021 8:35:24
QR CODE
Robert
1234
https://drive.google.com/open?id=14SAL5EK8tqOESgZyAayScbTqhSEE89Wa
I didn't manage to reproduce the problem. I repeated all the steps more or less and it works as intended. Here is the minimal reproducible example.
const doc_template_ID = 'template ID';
const ss_ID = 'spreadsheet ID';
const email_address = 'mail#gmail.com';
function make_doc_and_send_it_as_pdf() {
// get data from spreadsheet
const sheet = SpreadsheetApp.openById(ss_ID).getSheets()[0];
const QR_text = sheet.getRange('B1').getValue();
// make copy of the template and make changes in the doc
const doc_file = DriveApp.getFileById(doc_template_ID).makeCopy('QR_code');
const doc_ID = doc_file.getId()
const doc = DocumentApp.openById(doc_ID);
var body = doc.getBody();
body = body.replaceText('{{text}}', QR_text);
// insert a pic of the QR code
const url = "https://chart.googleapis.com/chart?chs=300x300&cht=qr&chl=" + QR_text;
const resp = UrlFetchApp.fetch(url);
const image = resp.getBlob();
replaceTextToImage(body, '{{QR}}', image);
doc.saveAndClose();
// send the doc via email as pdf
var pdf = doc_file.getAs("application/pdf");
var subject = "QR pdf";
var body = "sample text";
MailApp.sendEmail(email_address, subject, body, {htmlBody: body, attachments: pdf});
doc_file.setTrashed(true);
}
// modified Tataike's function from here
// https://tanaikech.github.io/2018/08/20/replacing-text-to-image-for-google-document-using-google-apps-script/
// now it takes image (blob) instead of fileId
function replaceTextToImage(body, searchText, image) {
var next = body.findText(searchText);
if (!next) return;
var r = next.getElement();
r.asText().setText('');
r.getParent().asParagraph().insertInlineImage(0, image);
return next;
};
My spreadsheet looks like this:
My doc template looks like this:
The PDF in email look like this:
It gets data from spreadsheet, makes a copy of doc template, changes text in the doc, inserts image of QR code in the doc (it replaces all the paragraph that contains '{{QR}}', I left it as it was, probably it can replace just a word in the paragraph)), and sends the doc via mail as PDF.
In your code, probably you need to change the function replaceTextToImage() this way:
var replaceTextToImage = function(body, searchText, blob) {
var width = 300; // Please set this.
var r = body.findText(searchText).getElement();
r.asText().setText("");
var img = r.getParent().asParagraph().insertInlineImage(0, blob);
var w = img.getWidth();
var h = img.getHeight();
img.setWidth(width);
img.setHeight(width * h / w);
}
It makes the function to take a blob instead of a fileId.
And to change these two lines:
var qrCode = e.values[3].split("=")[1];
var photo = e.values[4].split("=")[1];
with this:
var qrCode = UrlFetchApp.fetch(e.values[3].split("=")[1]).getBlob();
var photo = DriveApp.getFileById(e.values[4].split("=")[1]).getBlob();
I suppose that e.values[3].split("=")[1] contains a text of QR code, and e.values[4].split("=")[1] contains file ID. But I can be wrong.

Adding editor with script throws 'Invalid email' and stops script

I'm using Apps Script to generate a document including responses from a Google form and store this in a new folder. I also enable the user submitting the form editor access based on the email they provide.
.addEditor(email);
This seems to work for Google domains or company domains using g-suite.
When the email is not Google based however, the script breaks.
'Invalid email: email#example.com'
Looking for a means of skipping past this error and having the script complete.
function autoFillGoogleDocFromForm(e) {
var Timestamp = e.values[0];
var email = e.values[1];
var file = DriveApp.getFileById('FILEID');
var folder = createfolder();
var copy = file.makeCopy(Name + ' - Document', folder);
var newId = copy.getId();
var doc = DocumentApp.openById(newId).addEditor(email);
var body = doc.getBody();
body.replaceText('{{Timestamp}}', Timestamp);
body.replaceText('{{Email}}', Email);
doc.saveAndClose();
}
Looking for a means of skipping past this error and having the script
complete.
If you are looking for a solution to skip the error, then you can always use try...catch:
function autoFillGoogleDocFromForm(e) {
var Timestamp = e.values[0];
var email = e.values[1];
var file = DriveApp.getFileById('FILEID');
var folder = createfolder();
var copy = file.makeCopy(Name + ' - Document', folder);
var newId = copy.getId();
try{
var doc = DocumentApp.openById(newId).addEditor(email);
}
catch(error){
var doc = DocumentApp.openById(newId);
}
var body = doc.getBody();
body.replaceText('{{Timestamp}}', Timestamp);
body.replaceText('{{Email}}', Email);
doc.saveAndClose();
}
This snippet will try to execute var doc = DocumentApp.openById(newId).addEditor(email);.
If the latter fails, then it will just open the document var doc = DocumentApp.openById(newId); and continue with the rest of the code.

Adding save pdf option GAS

A year ago with the help of another user I was able to use google app script to take the form responses and email a pdf (code below)
I now need to save the pdf to a specific folder
I also need to add a link to the saved pdf within the google sheet. Is this possible?
var docTemplate = "doc ID";
var docName = "Vehicle check with images";
function onFormSubmit(e) {
var replaceTextToImage = function(body, searchText, fileId) {
var width = 300; // Please set this.
var blob = DriveApp.getFileById(fileId).getBlob();
var r = body.findText(searchText).getElement();
r.asText().setText("");
var img = r.getParent().asParagraph().insertInlineImage(0, blob);
var w = img.getWidth();
var h = img.getHeight();
img.setWidth(width);
img.setHeight(width * h / w);
}
//Get information from form and set as variables
var email_address = "myemailaddress#here.com";
var vehicle_vrn = e.values[1];
var front_desc = e.values[2];
var front_image = e.values[3].split("=")[1];
var rear_desc = e.values[4];
var rear_image = e.values[5].split("=")[1];
var driver_desc = e.values[6];
var driver_image = e.values[7].split("=")[1];
var passenger_desc = e.values[8];
var passenger_image = e.values[9].split("=")[1];
// Get document template, copy it as a new temp doc, and save the Doc’s id
var copyId = DriveApp.getFileById(docTemplate)
.makeCopy(docName+' for '+vehicle_vrn)
.getId();
// Open the temporary document
var copyDoc = DocumentApp.openById(copyId);
// Get the document’s body section
var copyBody = copyDoc.getBody();
copyBody.replaceText('keyVrn', vehicle_vrn);
copyBody.replaceText('keyFrontdesc', front_desc);
replaceTextToImage(copyBody, 'keyFrontimage', front_image);
copyBody.replaceText('keyReardesc', rear_desc);
replaceTextToImage(copyBody, 'keyRearimage', rear_image);
copyBody.replaceText('keyDriversdesc', driver_desc);
replaceTextToImage(copyBody, 'keyDriversimage', driver_image);
copyBody.replaceText('keyPassdesc', passenger_desc);
replaceTextToImage(copyBody, 'keyPassimage', passenger_image);
copyDoc.saveAndClose();
var pdf = DriveApp.getFileById(copyId).getAs("application/pdf");
var subject = "sample attachment file";
var body = "sample text: " + vehicle_vrn + "";
MailApp.sendEmail(email_address, subject, body, {htmlBody: body, attachments: pdf});
DriveApp.getFileById(copyId).setTrashed(true);
}```
I believe your goal as follows.
You want to save the PDF data to the specific folder as a file.
You want to retrieve the URL of the saved PDF file and put it to the specific column of the Spreadsheet.
Modification points:
In order to save the PDF data (in your case, it's a blob.) to the specific folder, you can use DriveApp.getFolderById("folderId").createFile(pdf).
In order to retrieve the URL of the created file, you can use getUrl().
In order to put the URL to the specific column of the Spreadsheet.
You want to put the value to the next column of the last row.
Modified script:
Please modify your script as follows. Before you use this modified script, please set the folder ID, Spreadsheet ID and sheet name.
From:
copyDoc.saveAndClose();
var pdf = DriveApp.getFileById(copyId).getAs("application/pdf");
To:
copyDoc.saveAndClose();
var pdf = DriveApp.getFileById(copyId).getAs("application/pdf");
var url = DriveApp.getFolderById("###folderId###").createFile(pdf).getUrl();
var sheet = SpreadsheetApp.openById("###spreadsheetId###").getSheetByName("###sheetName###");
sheet.getRange(sheet.getLastRow(), sheet.getLastColumn() + 1).setValue(url);
When you run the script, pdf is created to the folder ###folderId### as a file, and url is put to the next column of the last row of the sheet ###sheetName### on the Spreadsheet ###spreadsheetId###.
Note:
If you want to give the filename of PDF file, please modify as follows.
From
var pdf = DriveApp.getFileById(copyId).getAs("application/pdf");
To
var pdf = DriveApp.getFileById(copyId).getAs("application/pdf").setName("###filename###");
References:
getFolderById(id)
getUrl()
getRange(row, column)

In Google sheets, I need a script to run on a form submit, but reference a separate sheet other than "form responses"

I am trying to get a script to look at a named sheet in the workbook when a form is submitted. I used this script for a while and now need to add some calculations to the data that gets submitted. I have the form response data going to a sheet to add some calculations, then gets put in a doc and emailed out. The email doc function works great, just can not got the script to look at the data on the "Output" sheet vs. the "Form_Responses" sheet.
This is the script as it has been, I have tried several things but no luck, always pulls from "Form_Responses". I removed my trial code for clarity.
Any thoughts?
Thanks!
My code :
var docTemplate = "1oeUqdaesyHM-WzUTFIlzHFzAqIm1DN4OiiGywgs622w"; // template ID
var docName = "Service Invoice";
function onFormSubmit(e) {
var email_address = "<>";
var email_address2 = "<>";
var job_number = e.values[1];
var date = e.values[2];
var tech_name = e.values[7];
var customer_name = e.values[3];
var customer_email = e.values[6];
var address = e.values[4];
var phone = e.values[5];
var work_description = e.values[9];
var project_manager = e.values[8];
var project_manager_email = "<>";
var known_issues = e.values[10];
var hours = e.values[11];
var labor_total = e.values[21];
var material_total = e.values[20];
var total = e.values[22];
var paid = e.values[15];
var type = e.values[16];
var check_num = e.values[17];
var copyId = DriveApp.getFileById(docTemplate)
.makeCopy(docName + ' for ' + job_number)
.getId();
var copyDoc = DocumentApp.openById(copyId);
var copyBody = copyDoc.getActiveSection();
copyBody.replaceText('keydate:', date);
copyBody.replaceText('keyjobnumber:', job_number);
copyBody.replaceText('keycustomername:', customer_name);
copyBody.replaceText('keyaddress:', address);
copyBody.replaceText('keyphonenumber:', phone);
copyBody.replaceText('keycustomeremailaddress:', customer_email);
copyBody.replaceText('keyemployeename:', tech_name);
copyBody.replaceText('keyworkdescription:', work_description);
copyBody.replaceText('keyprojectmanager:', project_manager);
copyBody.replaceText('keyfollowup:', known_issues);
copyBody.replaceText('keyhours:', hours);
copyBody.replaceText('keylabortotal:', labor_total);
copyBody.replaceText('keymaterialtotal:', material_total);
copyBody.replaceText('keytotal:', total);
copyBody.replaceText('keypaid:', paid);
copyBody.replaceText('keypaymenttype:', type);
copyBody.replaceText('keycheck:', check_num);
copyDoc.saveAndClose();
var pdf = DriveApp.getFileById(copyId).getAs("application/pdf");
var subject = "ESCON Group Service Invoice";
var body = "Please find attached your invoice for the service work performed by ESCON Group.";
MailApp.sendEmail(customer_email, subject, body, {
htmlBody: body,
attachments: pdf
});
var subject = "ESCON Group Service Invoice" + job_number;
var body = "Here is the Service Invoice for: " + job_number + "";
MailApp.sendEmail(project_manager_email, subject, body, {
htmlBody: body,
attachments: pdf
});
var subject = "ESCON Group Service Invoice" + job_number;
var body = "Here is the Service Invoice for: " + job_number + " -Please contact Trevor Gross with any questions.";
MailApp.sendEmail(email_address, subject, body, {
htmlBody: body,
attachments: pdf
});
var subject = "ESCON Group Service Invoice" + job_number;
var body = "Here is the Service Invoice for " + job_number + "";
MailApp.sendEmail(email_address2, subject, body, {
htmlBody: body,
attachments: pdf
});
DriveApp.getFileById(copyId).setTrashed(true);
}
To get a value from a specific sheet, you need to get the spreadsheet (e.source), the sheet (getSheetByName()), the range (getRange()), and then the value (getValue()).
For example:
function onFormSubmit(e) {
var outputSheet = e.source.getSheetByName("Output");
var outputColumnA = outputSheet.getRange("A:A").getValues();
var outputA1 = outputColumnA[0][0];
console.log(outputA1);
}

Modifying a Google doc template and then sending it as a docx in an email whenever a google form is filled in

I'm trying to modify a template document with pertinent information from a google form submission and then send an email with the filled in document as a word doc to the person who filled the form in. I can manage to update the template and I can even get as far as attaching it as a pdf, but it needs to be editable by the receiver so that isn't really an option. Here is my code:
//Set template variables
var docTemplate = "1_l4T-MVXYXWPvirgE9aE25hKOejTqf9AcfHCKRC67Fk";
var docName = "Editorial Briefing Form";
//Get pertinent info from form
function onFormSubmit(e) {
var timeStamp = e.values[1];
var RequestorName = e.values[2];
var Account = e.values[3];
var JobNumber = e.values[4];
var Files = e.values[6];
var StartDate = e.values[7];
var BudgetHours = e.values[8];
var ActualDeadline = e.values[10];
var Email = e.values[11];
// Get template and save a copy with a new name
var copyId = DriveApp.getFileById(docTemplate)
.makeCopy(docName+' for '+RequestorName)
.getId();
var copyDoc = DocumentApp.openById(copyId);
var copyBody = copyDoc.getActiveSection();
//replace tags with form info
copyBody.replaceText('keyAccount', Account);
copyBody.replaceText('keyJobNumber', JobNumber);
copyBody.replaceText('keyStartDate', StartDate);
copyBody.replaceText('keyRequestorName', RequestorName);
copyBody.replaceText('KeyFiles', Files);
copyBody.replaceText('KeyBudgetHours',BudgetHours);
copyBody.replaceText('KeyActualDeadline', ActualDeadline);
copyDoc.saveAndClose()
MailApp.sendEmail(Email, 'test', 'see attachment', {attachments:[copyDoc]});
}
The only thing I've seen online involves Google OAuth, but I have no idea about that.
Any help would be hugely appreciated.
Thanks
Tom
I just figured out something similar. I couldn't get it to work from onFormSubmit(e), but I set it to run as a trigger from spreadsheet on form submit, and then told it to grab the last row of data, because forms submit puts that data in the last row (unless you have another script sorting things). So, my code looked like this:
function FormSubmitEmail(){
var templateid = "your template id here";
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var row = sheet.getLastRow();
var data = sheet.getRange(5,1,sheet.getLastRow()-1,sheet.getLastColumn()).getValues();
var today = Utilities.formatDate(new Date(), "CST", "MM/dd/yy");
var firstname = sheet.getRange("B"+row).getValues();
var lastname = sheet.getRange("C"+row).getValues();
var docname = (lastname+", "+firstname+" "+today);
var folder = DriveApp.getFolderById("I have mine saving a copy also to a folder, your folder ID here");
var docid = DriveApp.getFileById(templateid).makeCopy(docname, folder).getId();
Logger.log(docid);
var doc = DocumentApp.openById(docid);
var body = doc.getActiveSection();
body.replaceText("%DateCreated%",(sheet.getRange("A"+row).getValues()));
body.replaceText("%FirstName%",(sheet.getRange("B"+row).getValues()));
body.replaceText("%LastName%",(sheet.getRange("C"+row).getValues()));
body.replaceText("%EmailAddress%",(sheet.getRange("M"+row).getValues())); //etc.
doc.saveAndClose();
var message = "See attached, or find in folder: https://drive.google.com/drive/folders/[your folder id here]"; // Customize message
var emailTo = "email2#gmail.com, email1#gmail.com" // replace with your email
var subject = "A form has been submitted!."; // customize subject
var pdf = DriveApp.getFileById(docid).getAs('application/pdf').getBytes();
var attach = {fileName:'Autogenerated template.pdf',content:pdf, mimeType:'application/pdf'}; // customize file name: "Autogenerated template"
MailApp.sendEmail(emailTo, subject, message, {attachments:[attach]});
}