Print Google Spreadsheet Range using Cloud Print - google-apps-script

I'm trying to sent a print job to one of my printers in Cloud Print.
The information I would like to print is the current range the user is selecting inside a Spreadsheet.
For this I have used this guide:
https://www.labnol.org/code/20061-google-cloud-print-with-apps-script in order to set up the printer with GAS.
Step 1: Get the information you want to print
Source: How to Print sheet/range using .gs script in Google Sheets?
Explanation: carlesgg97's solution opens a modal window that will show our spreadsheet range exported as a PDF. From that point the user would need to manually print the job.
However, the information is sent to the Html via script.
Code adapted:
var PRINT_OPTIONS = {
'size': 7, // paper size. 0=letter, 1=tabloid, 2=Legal, 3=statement, 4=executive, 5=folio, 6=A3, 7=A4, 8=A5, 9=B4, 10=B
'fzr': false, // repeat row headers
'portrait': false, // false=landscape
'fitw': true, // fit window or actual size
'gridlines': false, // show gridlines
'printtitle': false,
'sheetnames': false,
'pagenum': 'UNDEFINED', // CENTER = show page numbers / UNDEFINED = do not show
'attachment': false
}
var PDF_OPTS = objectToQueryString(PRINT_OPTIONS);
function printSelectedRange() {
SpreadsheetApp.flush();
var ss = SpreadsheetApp.getActiveSpreadsheet(); //Our Spreadsheet
var sheet = ss.getActiveSheet(); //Our Active Sheet
var range = sheet.getActiveRange(); // Our Active Range
var gid = sheet.getSheetId();
var printRange = objectToQueryString({
'c1': range.getColumn() - 1,
'r1': range.getRow() - 1,
'c2': range.getColumn() + range.getWidth() - 1,
'r2': range.getRow() + range.getHeight() - 1
});
//Here is variable that we will send to the htmlTemplate
//We will build the HtmlTemplate using this url
var url = ss.getUrl().replace(/edit$/, '') + 'export?format=pdf' +
PDF_OPTS + printRange + "&gid=" + gid;
var htmlTemplate = HtmlService.createTemplateFromFile('js');
//Here I'm wrongly trying to get the content from the Html.
//What I'll get is the content of js.html and not the info from the url
var pdf_html = htmlTemplate.evaluate().getContent();
//The blob needs to be build using an object.
//However I don't know how to access the pdf I'm exporting inside the url var
var blob = Utilities.newBlob(pdf_html, MimeType.HTML, 'temp').getAs(MimeType.PDF);
//random printer ID
var printerID = 'b71f9cd2-3e3e-qweq-12asd-aogt5keoqoa2';
printGoogleDocument(blob, printerID, 1);
}
function objectToQueryString(obj) {
return Object.keys(obj).map(function(key) {
return Utilities.formatString('&%s=%s', key, obj[key]);
}).join('');
}
js.html:
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<script>
window.open('<?=url?>', '_blank', 'width=800, height=600');
google.script.host.close();
</script>
</body>
</html>
Step 2: Print the Job
function printGoogleDocument(docBlob, printerID, docName) {
var ticket = {
version: "1.0",
print: {
color: {
type: "STANDARD_COLOR",
vendor_id: "Color"
},
duplex: {
type: "NO_DUPLEX"
}
}
};
var payload = {
"printerid" : printerID,
"title" : docName,
"content" : docBlob,
"contentType": "application/pdf",
"ticket" : JSON.stringify(ticket)
};
var response = UrlFetchApp.fetch('https://www.google.com/cloudprint/submit', {
method: "POST",
payload: payload,
headers: {
Authorization: 'Bearer ' + getCloudPrintService().getAccessToken()
},
"muteHttpExceptions": true
});
response = JSON.parse(response);
if (response.success) {
Logger.log("%s", response.message);
} else {
Logger.log("Error Code: %s %s", response.errorCode, response.message);
}
}
I believe that what I need to modify is how the HtmlTemplate is build so that I can create a correct BLOB and send it to the printer.
EDIT
Applying Tanaike recommendation it works just fine when I call the function directly from the Script Editor.
Although in the scenario where we want to call this function printSelectedRange() using another function I got the following error:
Exception: Request failed for https://docs.google.com returned code 500.
Truncated server response: <!DOCTYPE html><html lang="en"><head>
<metaname="description" content="Web word processing, presentations and
spreadsheets"><meta name="viewport" c... (use muteHttpExceptions option to`
examine full response)`
The error points out to this line of code
var blob = UrlFetchApp.fetch(url, {headers: {authorization: "Bearer " +
ScriptApp.getOAuthToken()}}).getBlob();
In order to avoid this I updated the parameters for the UrlFetchApp:
var htmlTemplate = HtmlService.createTemplateFromFile('js');
htmlTemplate.url = url;
var params = {
headers: {authorization: "Bearer " + ScriptApp.getOAuthToken()},
muteHttpExceptions: true
};
var blob = UrlFetchApp.fetch(url, params).getBlob();
var printerID = 'randomprinterID';
printGoogleDocument(blob, printerID, 1);

How about this modification?
In this modification, blob is directly retrieved from url as the PDF data.
From:
var url = ss.getUrl().replace(/edit$/, '') + 'export?format=pdf' +
PDF_OPTS + printRange + "&gid=" + gid;
var htmlTemplate = HtmlService.createTemplateFromFile('js');
//Here I'm wrongly trying to get the content from the Html.
//What I'll get is the content of js.html and not the info from the url
var pdf_html = htmlTemplate.evaluate().getContent();
//The blob needs to be build using an object.
//However I don't know how to access the pdf I'm exporting inside the url var
var blob = Utilities.newBlob(pdf_html, MimeType.HTML, 'temp').getAs(MimeType.PDF);
//random printer ID
var printerID = 'b71f9cd2-3e3e-qweq-12asd-aogt5keoqoa2';
printGoogleDocument(blob, printerID, 1);
To:
var url = ss.getUrl().replace(/edit$/, '') + 'export?format=pdf' + PDF_OPTS + printRange + "&gid=" + gid;
var blob = UrlFetchApp.fetch(url, {headers: {authorization: "Bearer " + ScriptApp.getOAuthToken()}}).getBlob();
var printerID = 'b71f9cd2-3e3e-qweq-12asd-aogt5keoqoa2';
printGoogleDocument(blob, printerID, 1);

Related

Google Sheets App Script failed email send Exception: Request failed for https://docs.google.com returned code 401. Truncated server

I have 5 google sheets all with the same code below and only 1 of them is having this error Exception: Request failed for https://docs.google.com returned code 401. Truncated server
//Get active sheets
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
// Base URL this is used to send to the API
var url = "https://docs.google.com/spreadsheets/d/SS_ID/export?".replace("SS_ID", ss.getId());
//Format PDF settig up styling
var url_ext = 'exportFormat=pdf&format=pdf' // export as pdf / csv / xls / xlsx
+ '&size=A4' // paper size legal / letter / A4
+ '&portrait=true' // orientation, false for landscape
+ '&fitw=true&source=labnol' // fit to page width, false for actual size
+ '&sheetnames=false&printtitle=false' // hide optional headers and footers
+ '&pagenumbers=false&gridlines=false' // hide page numbers and gridlines
+ '&fzr=false' // do not repeat row headers (frozen rows) on each page
+ '&gid='; // the sheet's Id
//API to fetch PFD of google sheet
var token = ScriptApp.getOAuthToken();
var response = UrlFetchApp.fetch(url + url_ext + sheet.getSheetId(), {
headers : {
'Authorization' : 'Bearer ' + token
}
}).getBlob().setName(sheet.getName() + ".pdf");
sheet_as_pdf_blob_document=response;
// Define your variables here
var beerOrderrecipient="test#test.com";
var beerOrdersubject=SpreadsheetApp.getActiveSpreadsheet().getName();
var beerOrderbody="Hello,\n\nNew items have been added to your Ordered Beer List. Attached is a printable copy of the most up to date list. \n- Have a great day!";
var nameOfSender="Operations";
function sendOrderedSheet() {
var message = {
to: beerOrderrecipient,
subject:beerOrdersubject,
body: beerOrderbody,
name: nameOfSender,
attachments: [sheet_as_pdf_blob_document]
}
MailApp.sendEmail(message);
SpreadsheetApp.getUi().alert("The email has been sent thank you!");
}
I'm not sure what makes this one different. If I need to include anything else let me know!
UPDATE
I was able to fix the problem. So apparently there was a trigger from a long time ago calling a different function but it never succeeded it automatically went off every day and failed, so I deleted the trigger and its connecting function and everything started to work again!
I ran it this way:
function sendOrderedSheet() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var url = "https://docs.google.com/spreadsheets/d/SS_ID/export?".replace("SS_ID", ss.getId());
var url_ext = 'exportFormat=pdf&format=pdf' + '&size=A4' + '&portrait=true' + '&fitw=true&source=labnol' + '&sheetnames=false&printtitle=false' + '&pagenumbers=false&gridlines=false' + '&fzr=false' + '&gid=';
var token = ScriptApp.getOAuthToken();
var response = UrlFetchApp.fetch(url + url_ext + sheet.getSheetId(), {
headers: {
'Authorization': 'Bearer ' + token
}
}).getBlob().setName(sheet.getName() + ".pdf");
const sheet_as_pdf_blob_document = response;
var beerOrderrecipient = "myemail";
var beerOrdersubject = SpreadsheetApp.getActiveSpreadsheet().getName();
var beerOrderbody = "Hello,\n\nNew items have been added to your Ordered Beer List. Attached is a printable copy of the most up to date list. \n- Have a great day!";
var nameOfSender = "Operations";
var message = {
to: beerOrderrecipient,
subject: beerOrdersubject,
body: beerOrderbody,
name: nameOfSender,
attachments: [sheet_as_pdf_blob_document]
}
MailApp.sendEmail(message);
//SpreadsheetApp.getUi().alert("The email has been sent thank you!");
}

Google sheet script suddenly stops working and fails to send email attachment due to attachment authentication failure

Software: Google Sheets & Google App Script
Hi all,
I have been sending test emails to myself with attachments from my google sheet. They have been going great. Then I hop on one day and start receiving authentication errors. I have tried several different fixes but I'm still stuck. I'm not sure why it broke if I didn't change anything. Anyways, I'm changing stuff now to try and fix it.
It will let me send plain emails, but when I try to attach pdf's or xsls files, it fails. This was working great until it stopped working... Setting 'muteHttpExceptions' : true, allows the email to send, but the attachments are empty / corrupt.
Do you know of a better way to send specific sheets via email as pdf's or perhaps a way to fix this?
Code:
function SampleEmail() {
var ss = SpreadsheetApp.getActiveSpreadsheet()
var ssID = ss.getId();
var sheetgId = ss.getActiveSheet().getSheetId();
var sheetName = ss.getName();
var email = "test#gmail.com";
var subject = "Important Info!";
var body = "Test email.";
var url = "https://docs.google.com/spreadsheets/d/" + ssID + "/export?" + "format=pdf" + "&gid=" + sheetgId + "&portrait=true" + "&exportFormat=pdf";
var token = ScriptApp.getOAuthToken();
var result = UrlFetchApp.fetch(url, {
headers: {
'Authorization': 'Bearer ' + token
},
'muteHttpExceptions': false
});
var contents = result.getContent();
GmailApp.sendEmail(email, subject, body, { attachments: [{ fileName: sheetName + ".pdf", content: contents, mimeType: "application//pdf" }] });
}
Error message:
5:58:33 AM Error
Exception: Request failed for https://docs.google.com returned code 401. Truncated server response: <HTML>
<HEAD>
<TITLE>Unauthorized</TITLE>
</HEAD>
<BODY BGCOLOR="#FFFFFF" TEXT="#000000">
<H1>Unauthorized</H1>
<H2>Error 401</H2>
</BODY>
</HTML>
(use muteHttpExceptions option to examine full response)
SampleEmail # code.gs:108
SOLUTION: (Thank you #Amit_Singh for the advice.)
Try running this function to send your google sheet as a pdf to your google drive. This cleared the cache or something with the getOAuthToken() for me and allowed the original script to authenticate and send email attachments properly. Here is the function:
function convertSheetToPDF() {
var ss = SpreadsheetApp.getActiveSpreadsheet()
var ssID = ss.getId();
var sheetgId = ss.getActiveSheet().getSheetId();
var sheetId = sheetgId; // "2SqIXLiic6-gjI2KwQ6OIgb-erbl3xqzohRgE06bfj2c";
var spreadsheetName = "My Spreadsheet";
var destination = DriveApp.createFolder('new folder');
//var destination = DriveApp.getFolderById("1vFL98cgKdMHLNLSc542pUt4FMRTthUvL");
//var url = "https://docs.google.com/feeds/download/spreadsheets/Export?key=" + sheetId + "&exportFormat=xlsx";
var url = "https://docs.google.com/spreadsheets/d/" + ssID + "/export?" + "format=pdf" + "&gid=" + sheetgId + "&portrait=true" + "&exportFormat=pdf";
var params = {
method: "get",
headers: { "Authorization": "Bearer " + ScriptApp.getOAuthToken() },
muteHttpExceptions: false
};
var blob = UrlFetchApp.fetch(url, params).getBlob();
blob.setName(spreadsheetName + ".xlsx");
destination.createFile(blob);
}

Problem sending data from a newly created PDF file to my website

I create a PDF and then send its information to my website so that this PDF is converted to an image file and published:
SpreadsheetApp.flush();
var theurl = 'https://docs.google.com/a/mydomain.org/spreadsheets/d/' +
'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' +
'/export?format=pdf' +
'&size=0' +
'&portrait=true' +
'&fitw=true' +
'&top_margin=0' +
'&bottom_margin=0' +
'&left_margin=0' +
'&right_margin=0' +
'&sheetnames=false&printtitle=false' +
'&pagenum=false' +
'&gridlines=false' +
'&fzr=FALSE' +
'&gid=' +
'aaaaaaaaaaa';
var token = ScriptApp.getOAuthToken();
var docurl = UrlFetchApp.fetch(theurl, { headers: { 'Authorization': 'Bearer ' + token } });
var pdfBlob = docurl.getBlob();
//...get token and Blob (do not create the file);
var fileName = ss.getSheetByName("General").getRange("H2").getValue();
//Access or create the 'Archives' folder;
var folder;
var folders = DriveApp.getFoldersByName("Archives");
if(folders.hasNext()) {
folder = folders.next();
}else {
folder = DriveApp.createFolder("Archives");
}
//Remove duplicate file with the same name;
var existing = folder.getFilesByName(fileName);
if(existing.hasNext()) {
var duplicate = existing.next();
if (duplicate.getOwner().getEmail() == Session.getActiveUser().getEmail()) {
var durl = 'https://www.googleapis.com/drive/v3/files/'+duplicate.getId();
var dres = UrlFetchApp.fetch(durl,{
method: 'delete',
muteHttpExceptions: true,
headers: {'Authorization': 'Bearer '+token}
});
var status = dres.getResponseCode();
if (status >=400) {
} else if (status == 204) {
folder.createFile(pdfBlob.setName(fileName));
}
}
} else {
folder.createFile(pdfBlob.setName(fileName));
}
Utilities.sleep(5000);
createPostByFileName(folder, fileName);
function createPostByFileName(folder, fileName) {
var fileIterator = folder.getFilesByName(fileName);
if(fileIterator.hasNext()) {
var file = fileIterator.next()
file.setSharing(DriveApp.Access.ANYONE_WITH_LINK, DriveApp.Permission.VIEW)
name = file.getName();
league = name.split(' ')[0];
title = name.split(league)[1].split('.pdf')[0];
link = file.getUrl();
shareable = link.split('/view')[0];
id = file.getId();
var data = {
'api_league_name': league,
'title': title,
'google_drive_id': id,
'google_drive_url': shareable,
'pass': 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
};
var options = {
'method' : 'post',
'contentType': 'application/json',
'payload' : JSON.stringify(data)
};
UrlFetchApp.fetch('https://www.xxx.com.br/api/posts', options);
}
}
For some reason I am forced to put Utilities.sleep(5000); before calling the function that sends the PDF data to my website, because if I don't, when the website tries to convert the PDF to an image, an problem happens as if the PDF is not yet available in the folder or it generates a big slowdown until can access the file.
Obviously putting this sleep is not a professional way to solve the case, because then I can't even know why this happens.
Anyone who has had this experience, can tell me how I should proceed in a professional way?
From the discussions in the comment, when Drive API is used for your script, it becomes as follows. Before you use this, please enable Drive API at Advanced Google services.
Modified script:
function sample() {
const createFile = (filename, blob, folderId) => Drive.Files.insert({ title: filename, parents: [{ id: folderId }] }, blob);
SpreadsheetApp.flush();
var theurl = 'https://docs.google.com/a/mydomain.org/spreadsheets/d/' +
'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' +
'/export?format=pdf' +
'&size=0' +
'&portrait=true' +
'&fitw=true' +
'&top_margin=0' +
'&bottom_margin=0' +
'&left_margin=0' +
'&right_margin=0' +
'&sheetnames=false&printtitle=false' +
'&pagenum=false' +
'&gridlines=false' +
'&fzr=FALSE' +
'&gid=' +
'aaaaaaaaaaa';
var token = ScriptApp.getOAuthToken();
var docurl = UrlFetchApp.fetch(theurl, { headers: { 'Authorization': 'Bearer ' + token } });
var pdfBlob = docurl.getBlob();
var fileName = ss.getSheetByName("General").getRange("H2").getValue();
var folder;
var folders = DriveApp.getFoldersByName("Archives");
if (folders.hasNext()) {
folder = folders.next();
} else {
folder = DriveApp.createFolder("Archives");
}
var existing = folder.getFilesByName(fileName);
var pdfFileId = "";
if (existing.hasNext()) {
var duplicate = existing.next();
if (duplicate.getOwner().getEmail() == Session.getActiveUser().getEmail()) {
var durl = 'https://www.googleapis.com/drive/v3/files/' + duplicate.getId();
var dres = UrlFetchApp.fetch(durl, {
method: 'delete',
muteHttpExceptions: true,
headers: { 'Authorization': 'Bearer ' + token }
});
var status = dres.getResponseCode();
if (status >= 400) {
} else if (status == 204) {
var obj = createFile(fileName, pdfBlob, folder.getId());
pdfFileId = obj.id;
}
}
} else {
var obj = createFile(fileName, pdfBlob, folder.getId());
pdfFileId = obj.id;
}
// Utilities.sleep(5000);
Drive.Permissions.insert({ role: "reader", type: "anyone" }, pdfFileId);
league = fileName.split(' ')[0];
title = fileName.split(league)[1].split('.pdf')[0];
shareable = "https://drive.google.com/file/d/" + pdfFileId;
id = pdfFileId;
var data = {
'api_league_name': league,
'title': title,
'google_drive_id': id,
'google_drive_url': shareable,
'pass': 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
};
var options = {
'method': 'post',
'contentType': 'application/json',
'payload': JSON.stringify(data)
};
UrlFetchApp.fetch('https://www.xxx.com.br/api/posts', options);
}
Note:
This is a sample script for testing whether Utilities.sleep(5000) can be removed.

Google Script timeouts

Problem:
The import function importXLSXtoGsheet() times out before it can process all 52 XLSX files, I received the error:
Exception: Time-out: https://www.googleapis.com/batch/drive/v3 at [unknown function](Code:63) at Do(Code:8) at importXLSXtoGsheet(Code:71)
If I run the function with 1 file in the importXLS folder, it works correctly.
Script explained:
I've got 52 folders, each containing one spreadsheet file.
Each folder is shared with different colleagues.
During the day, people make changes to the files.
At the end of the day, all files are collected in one folder (gsheetFolder) and converted to XLSX files, using the function collectAndExportXLS.
These files are copied to a local server in the evening (using batch script and drive sync) which updates other information in the file and are copied back to the importXLSXfolder.
In the morning the importXLSXtoGsheet function runs and converts all XLSX files in the importXLSXfolder folder to Gsheet files in the gsheetFolder.
After that sortGsheetFiles runs, sorting and moving every Gsheet file in one of the 52 folders (using an array list from the current spreadsheet).
Other actions include cleaning the folders with the deleteFolder function.
Script:
var gsheetFolder = '###';
var XLSXfolder = '###';
var importXLSXfolder = '###';
// Modified
function deleteFolder(folderId) {
var url = "https://www.googleapis.com/drive/v3/files?q='" + folderId + "'+in+parents+and+trashed%3Dfalse&fields=files%2Fid&access_token=" + ScriptApp.getOAuthToken();
var res = UrlFetchApp.fetch(url);
var obj = JSON.parse(res.getContentText());
var reqs = obj.files.map(function(e) {return {method: "DELETE", endpoint: "https://www.googleapis.com/drive/v3/files/" + e.id}});
var requests = {batchPath: "batch/drive/v3", requests: reqs};
if (requests.requests.length > 0) BatchRequest.Do(requests);
}
// Added
function deleteFiles(files) {
var reqs = files.map(function(e) {return {method: "DELETE", endpoint: "https://www.googleapis.com/drive/v3/files/" + e.id}});
var requests = {batchPath: "batch/drive/v3", requests: reqs};
if (requests.requests.length > 0) BatchRequest.Do(requests);
}
// Added
function getValuesFromSpreadsheet() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
return sheet.getRange("A2:B53").getValues();
}
// Modified
function sortGsheetFiles() {
var url = "https://www.googleapis.com/drive/v3/files?q='" + gsheetFolder + "'+in+parents+and+mimeType%3D'" + MimeType.GOOGLE_SHEETS + "'+and+trashed%3Dfalse&fields=files(id%2Cname)&access_token=" + ScriptApp.getOAuthToken();
var res = UrlFetchApp.fetch(url);
var obj = JSON.parse(res.getContentText());
var values = getValuesFromSpreadsheet();
var reqs = values.reduce(function(ar, e) {
for (var i = 0; i < obj.files.length; i++) {
if (obj.files[i].name == e[0]) {
ar.push({
method: "PATCH",
endpoint: "https://www.googleapis.com/drive/v3/files/" + obj.files[i].id + "?addParents=" + e[1] + "&removeParents=" + gsheetFolder,
});
break;
}
}
return ar;
}, []);
var requests = {batchPath: "batch/drive/v3", requests: reqs};
if (requests.requests.length > 0) BatchRequest.Do(requests);
deleteFolder(importXLSXfolder);
}
// Modified
function importXLSXtoGsheet(){
deleteFolder(XLSXfolder);
var url = "https://www.googleapis.com/drive/v3/files?q='" + importXLSXfolder + "'+in+parents+and+mimeType%3D'" + MimeType.MICROSOFT_EXCEL + "'+and+trashed%3Dfalse&fields=files(id%2Cname)&access_token=" + ScriptApp.getOAuthToken();
var res = UrlFetchApp.fetch(url);
var obj = JSON.parse(res.getContentText());
var reqs = obj.files.map(function(e) {return {
method: "POST",
endpoint: "https://www.googleapis.com/drive/v3/files/" + e.id + "/copy",
requestBody: {mimeType: MimeType.GOOGLE_SHEETS, name: e.name + ".xlsx", parents: [gsheetFolder]},
}
});
var requests = {batchPath: "batch/drive/v3", requests: reqs};
if (requests.requests.length > 0) BatchRequest.Do(requests);
deleteFolder(importXLSXfolder);
}
// Modified
function ConvertBackToXLS(fileList) {
var token = ScriptApp.getOAuthToken();
var reqs1 = fileList.map(function(e) {return {
method: "GET",
url: "https://docs.google.com/spreadsheets/export?id=" + e.id + "&exportFormat=xlsx&access_token=" + token,
}
});
var res = UrlFetchApp.fetchAll(reqs1);
var reqs2 = res.map(function(e, i) {
var metadata = {name: fileList[i].name, parents: [XLSXfolder]};
var form = FetchApp.createFormData(); // Create form data
form.append("metadata", Utilities.newBlob(JSON.stringify(metadata), "application/json"));
form.append("file", e.getBlob());
var url = "https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart";
return {url: url, method: "POST", headers: {Authorization: "Bearer " + token}, body: form};
});
FetchApp.fetchAll(reqs2);
}
// Modified
function collectAndExportXLS() {
deleteFolder(gsheetFolder);
var values = getValuesFromSpreadsheet();
var reqs1 = values.reduce(function(ar, e) {
if (e[0] && e[1]) {
ar.push({
method: "GET",
endpoint: "https://www.googleapis.com/drive/v3/files?q='" + e[1] + "'+in+parents+and+trashed%3Dfalse&fields=files(id%2Cname)",
});
}
return ar;
}, []);
var resForReq1 = BatchRequest.Do({batchPath: "batch/drive/v3", requests: reqs1});
var temp = resForReq1.getContentText().split("--batch");
var files = temp.slice(1, temp.length - 1).map(function(e) {return JSON.parse(e.match(/{[\S\s]+}/g)[0])});
var fileList = files.reduce(function(ar, e) {return ar.concat(e.files.map(function(f) {return f}))}, []);
ConvertBackToXLS(fileList);
deleteFiles(fileList);
}
About your question, I could understand like below.
When importXLSXtoGsheet() is run with 52 files, the error occurs.
When importXLSXtoGsheet() is run with less than 13 files, no error occurs.
Other functions except for importXLSXtoGsheet() works fine.
If my understanding is correct, as one workaround, it decides the maximum number for processing the files once. When this is reflect to importXLSXtoGsheet() of your script, the modified script is as follows.
Modified script:
function importXLSXtoGsheet(){
deleteFolder(XLSXfolder);
var url = "https://www.googleapis.com/drive/v3/files?q='" + importXLSXfolder + "'+in+parents+and+mimeType%3D'" + MimeType.MICROSOFT_EXCEL + "'+and+trashed%3Dfalse&fields=files(id%2Cname)&access_token=" + ScriptApp.getOAuthToken();
var res = UrlFetchApp.fetch(url);
var obj = JSON.parse(res.getContentText());
// I modified below script.
var n = 10; // Maximum number.
var files = [];
var len = obj.files.length;
for (var i = 0; i < len; i++) {
files.push(obj.files.splice(0, n));
len -= n - 1;
}
files.forEach(function(f) {
var reqs = f.map(function(e) {return {
method: "POST",
endpoint: "https://www.googleapis.com/drive/v3/files/" + e.id + "/copy",
requestBody: {mimeType: MimeType.GOOGLE_SHEETS, name: e.name + ".xlsx", parents: [gsheetFolder]},
}
});
var requests = {batchPath: "batch/drive/v3", requests: reqs};
if (requests.requests.length > 0) BatchRequest.Do(requests);
});
deleteFolder(importXLSXfolder);
}
Note:
In this sample script, 10 files are processed every batch request. If you want to change this, please modify var n = 10;.

Export multiple sheets in a single PDF

Just wondering how I would be able to export a PDF file to contain multiple sheets, but not all in the workbook. I've been only been able to send single sheets as separate PDF attachments. Any insight on this would be great.
var url = ss.getUrl(); //gets url
url = url.replace(/edit/,'');
var url_ext = 'export?exportFormat=pdf&format=pdf' +
'&size=letter' +
'&portrait=false' +
'&fitw=true' +
'&sheetnames=false&printtitle=false' +
'&pagenumbers=true&gridlines=false' +
'&fzr=true' +
'&gid=GID'
var token = ScriptApp.getOAuthToken();
var response = UrlFetchApp.fetch(url + url_ext, {
headers: {
'Authorization': 'Bearer ' + token
}
});
var blob = response.getBlob().setName(sheet.getName() + '.pdf');
A guide has been written about this in this blog post by Andrew Roberts, the source code from that post is as follows:
function convertSpreadsheetToPdf(email, spreadsheetId, sheetName, pdfName) {
var spreadsheet = spreadsheetId ? SpreadsheetApp.openById(spreadsheetId) : SpreadsheetApp.getActiveSpreadsheet();
spreadsheetId = spreadsheetId ? spreadsheetId : spreadsheet.getId()
var sheetId = sheetName ? spreadsheet.getSheetByName(sheetName).getSheetId() : null;
var pdfName = pdfName ? pdfName : spreadsheet.getName();
var parents = DriveApp.getFileById(spreadsheetId).getParents();
var folder = parents.hasNext() ? parents.next() : DriveApp.getRootFolder();
var url_base = spreadsheet.getUrl().replace(/edit$/,'');
var url_ext = 'export?exportFormat=pdf&format=pdf' //export as pdf
// Print either the entire Spreadsheet or the specified sheet if optSheetId is provided
+ (sheetId ? ('&gid=' + sheetId) : ('&id=' + spreadsheetId))
// following parameters are optional...
+ '&size=letter' // paper size
+ '&portrait=true' // orientation, false for landscape
+ '&fitw=true' // fit to width, false for actual size
+ '&sheetnames=false&printtitle=false&pagenumbers=false' //hide optional headers and footers
+ '&gridlines=false' // hide gridlines
+ '&fzr=false'; // do not repeat row headers (frozen rows) on each page
var options = {
headers: {
'Authorization': 'Bearer ' + ScriptApp.getOAuthToken(),
}
}
var response = UrlFetchApp.fetch(url_base + url_ext, options);
var blob = response.getBlob().setName(pdfName + '.pdf');
folder.createFile(blob);
if (email) {
var mailOptions = {
attachments:blob
}
MailApp.sendEmail(
email,
"Here is a file named " + pdfName,
"Please let me know if you have any questions or comments.",
mailOptions);
}
} // convertSpreadsheetToPdf()
function test() {
var TEST_EMAIL = 'your email address'
// Create a PDF containing all the tabs in the active spreadsheet, name it
// after the spreadsheet, and email it
convertSpreadsheetToPdf(TEST_EMAIL)
// Create a PDF containing all the tabs in the spreadsheet specified, name it
// after the spreadsheet, and email it
convertSpreadsheetToPdf(TEST_EMAIL, '1r9INcnsyvSQmeduJWVYAvznOOYei9jeAjsy0acA3G1k')
// Create a PDF just containing the tab 'Sheet2' in the active spreadsheet, specify a name, and email it
convertSpreadsheetToPdf(TEST_EMAIL, null, 'Sheet2', 'PDF 3')
}