Generating PDF Succesfully but I failed when I added Qr Code - google-apps-script

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.

Related

Get multiple URL of attachments from a column in Google Sheet and mail using Appscripts

I have made a program to send mails whenever a user fills in a Google form.
However, while the mail is going, the script is not picking the attachments from the column which are separated using commas.
The column has values like this(sample) - https://drive.google.com/open?id=1JBnVvwYmB1DZp01vP1eeve4yg86KOKmc, https://drive.google.com/open?id=1JBnVvwYmB1DZp01vP1eeve4yg86KOKmc, https://drive.google.com/open?id=1JBnVvwYmB1DZp01vP1eeve4yg86KOKmc
I saw an example that uses YAMM addon and does this, but I'd be glad if someone can offer me the solution as I do not want to rely on the add-on.
Sharing code.
function ifstatement() {
const ss = SpreadsheetApp.getActiveSpreadsheet();
const ws = ss.getSheetByName("Form Responses");
var Avals = ss.getRange("b1:b").getValues();
var lr = Avals.filter(String).length;
Logger.log(lr);
var heading = ws.getRange(lr,17).getValue();
var subheading = ws.getRange(lr,4).getValue();
var body = ws.getRange(lr,11).getValue();
var footer = ws.getRange(lr,12).getValue();
var impfield1 = ws.getRange(lr,5).getValue();
var impfield2 = ws.getRange(lr,7).getValue();
var impfield3 = ws.getRange(lr,9).getValue();
var fieldvalue1 = ws.getRange(lr,6).getValue();
var fieldvalue2 = ws.getRange(lr,8).getValue();
var fieldvalue3 = ws.getRange(lr,10).getValue();
var attach = ws.getRange(lr, 18).getValue();
var file1 = [UrlFetchApp.fetch(attach).getBlob()]
var sub = ws.getRange(lr,3).getValue();
Logger.log(attach)
var mailtemp = ws.getRange(lr,2).getValue();
if(mailtemp=="HTML1"){
const htmlTemplate = HtmlService.createTemplateFromFile("Copy of HTML1");
htmlTemplate.heading = heading;
htmlTemplate.subheading = subheading;
htmlTemplate.body = body;
htmlTemplate.footer = footer;
htmlTemplate.impfield1 = impfield1;
htmlTemplate.impfield2 = impfield2;
htmlTemplate.impfield3 = impfield3;
htmlTemplate.fieldvalue1 = fieldvalue1;
htmlTemplate.fieldvalue2 = fieldvalue2;
htmlTemplate.fieldvalue3 = fieldvalue3;
const htmlforemail = htmlTemplate.evaluate().getContent();
GmailApp.sendEmail("mayank.agarwal#aumcap.com",
"Issue closes tomorrow - Invest in SGB scheme today!",
"Last chance to invest in SGB scheme issue I",
{htmlBody: htmlforemail,
attachments: file1}
) } else if(lr=="HTML2"){
const htmlTemplate = HtmlService.createTemplateFromFile("SGB I");
htmlTemplate.heading = heading;
htmlTemplate.subheading = subheading;
htmlTemplate.body = body;
htmlTemplate.footer = footer;
htmlTemplate.impfield1 = impfield1;
htmlTemplate.impfield2 = impfield2;
htmlTemplate.impfield3 = impfield3;
htmlTemplate.fieldvalue1 = fieldvalue1;
htmlTemplate.fieldvalue2 = fieldvalue2;
htmlTemplate.fieldvalue3 = fieldvalue3;
const htmlforemail = htmlTemplate.evaluate().getContent();
GmailApp.sendEmail("mayank.agarwal#aumcap.com",
"Issue closes tomorrow - Invest in SGB scheme today!",
"Last chance to invest in SGB scheme issue I",
{htmlBody: htmlforemail,
attachments: file1}
)
}
}
I believe your goal as follows.
In your situation, the following URLs are put in one cell of var attach = ws.getRange(lr, 18).getValue(). You want to retrieve the blob data from those files.
https://drive.google.com/open?id=###, https://drive.google.com/open?id=###, https://drive.google.com/open?id=###
In this case, how about the following modification?
From:
var file1 = [UrlFetchApp.fetch(attach).getBlob()]
To:
var file1 = attach.split(",").map(url => DriveApp.getFileById(url.trim().split("=")[1]).getBlob());
In this modification, those URLs separated by , are splitted by , and each blob is retrieved with DriveApp.getFileById().
References:
map()
getFileById(id)

Generating Google doc from template, needing to link within email

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();

Create new document from Google form and add to a new folder

I have a Google script triggered on submission of a form. It creates a new doc based on a template with certain variables in-filled from answers in the form.
I also have a folder created on the form submission.
The trouble I am having is creating the newly created doc within the newly created folder. Looking for some help merging the two scripts that work on their own to acheive this.
Creating a folder on form submission:
function createChannelFolder() {
var ss = SpreadsheetApp.getActive();
var names = ss.getSheetByName("Completed Certifications");
var ChannelName = names.getRange(names.getLastRow(), 2).getValue();
var parentFolder=DriveApp.getFolderById("FOLDERID");
return newFolder=parentFolder.createFolder(ChannelName);
}
Creating a document on form submission
function autoFillGoogleDocFromForm(e) {
//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 = DriveApp.getFolderById('FOLDERID')
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();
}
Explanation:
You need to call createChannelFolder() inside
autoFillGoogleDocFromForm(e).
just return the folder object within createChannelFolder():
return parentFolder.createFolder(ChannelName);
Solution:
Here is autoFillGoogleDocFromForm(e):
function autoFillGoogleDocFromForm(e) {
//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();
}
and here is createChannelFolder():
function createChannelFolder() {
var ss = SpreadsheetApp.getActive();
var names = ss.getSheetByName("Completed Certifications");
var ChannelName = names.getRange(names.getLastRow(), 2).getValue();
var parentFolder=DriveApp.getFolderById("FOLDERID");
return parentFolder.createFolder(ChannelName); // 2nd modification point
}

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)

Error when passing a blob file to send it as e-mail attachment

I'm trying to sending a file as e-mail attachment with Google Apps Script, following this rich answer. But instead of a stand alone app, I'm trying to do so within my spreadsheet, using a function like this:
function sendAttachment(){
var activeSheet = ss.getActiveSheet();
ScriptProperties.setProperty('emailRequest', 1);
if(!person_ID) {
person_ID = getCurrentRow();
//if the current line is the Column Headers line then ask the user to specify the ID, very rare case.
if (person_ID == 1) {
var person_ID = Browser.inputBox("Select one name.", "Click in one row:", Browser.Buttons.OK_CANCEL);
}
}
var app = UiApp.createApplication().setHeight(400).setWidth(600);
var panel = app.createVerticalPanel(); // you can embed that in a form panel
var label = app.createLabel("Choose the receiver").setStyleAttribute("fontSize", 18);
app.add(label);
var currentRow = ss.getActiveSelection().getRowIndex();
var personName = activeSheet.getRange(currentRow, 1).getValue();
var personNumber = activeSheet.getRange(currentRow, 5).getValue();
var item1Panel = app.createHorizontalPanel();
var txt = app.createTextBox().setId("item1").setName("item1").setValue(personName);
item1Panel.add(app.createLabel("Person:")).add(txt);
var item2Panel = app.createHorizontalPanel();
var txt = app.createTextBox().setId("item2").setName("item2").setValue(personNumber);
item2Panel.add(app.createLabel("Num:")).add(txt);
var sheet = SpreadsheetApp.openById(letterSpreadsheetId).getSheetByName("emailsDB");
var recipientEmailArray = sheet.getRange(2, 1, sheet.getLastRow(), sheet.getLastColumn()).getValues();
var item3Panel = app.createHorizontalPanel();
item3Panel.add(app.createLabel("Receiver"));
var listBox = app.createListBox().setName('item3');
for(var i = 0; i < (recipientEmailArray.length); i++){
listBox.addItem(recipientEmailArray[i][0] + ": " + recipientEmailArray[i][2]);
}
item3Panel.add(listBox);
var handlerBut = app.createServerHandler("butSendAttachment").addCallbackElement(panel);
var but = app.createButton("submit").setId("submitButton4").addClickHandler(handlerBut);
panel.add(item1Panel)
.add(item2Panel)
.add(item3Panel)
.add(app.createFileUpload().setName('thefile'))
.add(app.createLabel().setId("answer"))
.add(but);
var scroll = app.createScrollPanel().setPixelSize(600, 400).setTitle("My title 1");
scroll.add(panel);
app.add(scroll);
ss.show(app);
// var handlerBut = app.createServerHandler("butSendAttachment").addCallbackElement(panel);
// .add(app.createFileUpload().setName('thefile'));
// var form = app.createFormPanel();
// form.add(panel);
// app.add(form);
;
}
function butSendAttachment(e){
var recipientEmail = e.parameter.item3;
var fileBlob = e.parameter.thefile;
Logger.log("file blob = " + fileBlob);
recipientEmail = recipientEmail.split(':')[1];
var sheet = ss.getActiveSheet();
var person_ID = getCurrentRow();
var columns = getRowAsArray(sheet, 1);
var personData = getRowAsArray(sheet, person_ID);
var sender = actAuthor + " \n " + position;
var name = personData[0];
var motherName = personData[1];
var title = "my title";
var message = my mesage";
var confirm = Browser.msgBox('Send email','Are you sure?', Browser.Buttons.OK_CANCEL);
if(confirm=='ok'){
// MailApp.sendEmail(recipientEmail, title, message, {attachments: [fileBlob]});
MailApp.sendEmail(recipientEmail, title, message, {attachments: [fileBlob]});
var app = UiApp.createApplication().setHeight(150).setWidth(250);
var msg = "An email was sendo to " + recipientEmail;
app.setTitle("E-mail send!");
app.add(app.createVerticalPanel().add(app.createLabel(msg)));
var doc = SpreadsheetApp.getActive();
doc.show(app);
}
else {
return;
}
}
But I get this error: Execution failed: Invalid argument: inlineImages (line 77. Line 77 is this:
MailApp.sendEmail(recipientEmail, title, message, {attachments: [fileBlob]});
I've read the documentation I tried several argument variations. I conclude that fileBlob is Null. Why? How to fix it?
the fileUpload widget works only in a form parent widget and using a doGet/doPost structure.
That's written somewhere in the doc but right now I don't remember exactly where (I'look for it later)
But actually I guess you can build such a structure from within your spreadsheet, just change the names of your functions and use a formPanel as main widget. Don't forget also that you don't need a handler anymore and must use a submitButton widget.
EDIT : how silly I am ! its written in the first line in the widget's doc !!! ;-)