How to diagnose "429 Error" in Google Script - google-apps-script

My script is looping through a list, at each index it is saving a sheet in my workbook as a PDF, then saving it to my google drive folder. There are 7 people in the list. The problem is that my script throws a 429 Error after the 6th PDF is exported. I am trying to figure out how to solve this error but I am quite new to google scripting so I need some help in the right direction.
Error Image
function ToPortrait() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var validation_sheet = ss.getSheetByName('ValidDSM');
var lastRow = validation_sheet.getLastRow();
var inputs = ss.getSheetByName('ValidDSM').getRange('A2:A'+lastRow).getValues();
var sheet2 = ss.getSheetByName('DSM');
var tab = ss.getSheetByName('DSMD');
var url = ss.getUrl().replace(/edit$/,'');
var sheets = ss.getSheets();
var optSheetId = 1123194386;
var options = {
headers: {
'Authorization': 'Bearer ' + ScriptApp.getOAuthToken()
}
}
// Loop through List of 7
for (var i = 0; i < inputs.length; i++){
sheet2.getRange('B3').setValue(inputs[i][0]);
SpreadsheetApp.flush();
Utilities.sleep(500);
// Loop through all sheets, generating PDF files.
//for (var i=0; i<sheets.length; i++) {
//var sheet = sheets[i];
// If provided a optSheetId, only save it.
// if (optSheetId && optSheetId !== sheet.getSheetId()) continue;
//additional parameters for exporting the sheet as a pdf
var url_ext = 'export?exportFormat=pdf&format=pdf' //export as pdf
+ '&gid=' + tab.getSheetId() //the sheet's Id
// following parameters are optional...
+ '&size=letter' // paper size
+ '&portrait=false' // 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
// Get folder containing spreadsheet, for later export
var name = sheet2.getRange('B3').getValue();
var folderID = "1IsffOYYQOHZJKggUzRTntfjmJKN0F6ga"; // Folder id to save in a folder.
var folder = DriveApp.getFolderById(folderID);
var response = UrlFetchApp.fetch(url + url_ext, options)
var blob = response.getBlob().setName(name);
//save the pdf to drive
folder.createFile(blob);
}
}
I expect all 7 PDFs to be exported but only 6 are.

Related

Google Sheets to pdf - combine to one pdf instead of splitting into multiple pdfs

I found a script here that does everything I want however for some reason it is splitting the document into several pdf's. I would like to keep everything as it is however just create one single pdf.
Edit: My Google sheets have 5 worksheets and each worksheet at the moment becomes a seperate pdf so I end up with 5 different pdfs. I would like it to just come out as 1 pdf with 5 pages inside.
function savePDFs( optSSId, optSheetId ) {
var ss = (optSSId) ? SpreadsheetApp.openById(optSSId) : SpreadsheetApp.getActiveSpreadsheet();
var url = ss.getUrl().replace(/edit$/,'');
var parents = DriveApp.getFileById(ss.getId()).getParents();
var folders = DriveApp.getFoldersByName('Invoices'); // Modified
var folder = folders.hasNext() ? folders.next() : parents.next(); // Modified
var sheets = ss.getSheets();
for (var i=0; i<sheets.length; i++) {
var sheet = sheets[i];
if (optSheetId && optSheetId !== sheet.getSheetId()) continue;
var url_ext = 'export?exportFormat=pdf&format=pdf' //export as pdf
+ '&gid=' + sheet.getSheetId() //the sheet's Id
// 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 + url_ext, options);
var valor = sheet.getRange('D5').getValue(); // Modified
var blob = response.getBlob().setName(valor + '.pdf');
folder.createFile(blob);
}
}
The reason you are getting 5 PDF files is that, you are iterating between each page of the sheet and creating a PDF from there; instead of calling the entire sheet. I ran a test with the following code, and it exported the Google sheet as a 1 PDF.
Note: I made some changes to the first part of the code since I didn't have access to the other functions been call.
I remove this part:
var sheets = ss.getSheets();
for (var i=0; i<sheets.length; i++) {
var sheet = sheets[i];
if (optSheetId && optSheetId !== sheet.getSheetId()) continue;
var url_ext = 'export?exportFormat=pdf&format=pdf' //export as pdf
+ '&gid=' + sheet.getSheetId() //the sheet's Id
+ '&size=letter' // paper size
And modify it like this:
// I didn't have access to the optSSId or optSheetId so for my test I added the URL and the active sheet link to the apps script
// you can keep this part as you had it before
var url = "https://docs.google.com/spreadsheets/d/<spreadsheet_ID>/";
var sheet = SpreadsheetApp.getActiveSpreadsheet();
// From the URL_ext I remove + '&gid=' + sheet.getSheetId() since we want the complete sheet
var url_ext = '/export?exportFormat=pdf&format=pdf' //export as pdf
+ '&size=letter' // paper size
So basically you form this URL:
https://docs.google.com/spreadsheets/d/<SPREADSHEETID>//export?exportFormat=pdf&format=pdf&size=letter&portrait=true&fitw=true&sheetnames=false&printtitle=false&pagenumbers=false&gridlines=false&fzr=false
Update:
function savePDFs( optSSId, optSheetId ) {
//var ss = (optSSId) ? SpreadsheetApp.openById(optSSId) : SpreadsheetApp.getActiveSpreadsheet();
//var url = ss.getUrl().replace(/edit$/,'');
//var parents = DriveApp.getFileById(ss.getId()).getParents();
var url = "https://docs.google.com/spreadsheets/d/<Sheet_ID>/";
var folders = DriveApp.getFolderById("<Folder_ID>"); // Modified
//var folder = folders.hasNext() ? folders.next() : parents.next(); // Modified
// I didn't have access to the optSSId or optSheetId so my test I added the URL and the active sheet link to the apps script
var sheet = SpreadsheetApp.getActiveSpreadsheet();
var url_ext = 'export?exportFormat=pdf&format=pdf' //export as pdf
+ '&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 + url_ext, options);
// var valor = sheet.getRange('D5').getValue(); // Modified
var blob = response.getBlob().setName("test" + '.pdf');
folders.createFile(blob);
}
Replace <Sheet_ID> with the ID of the Google Sheet and <Folder_ID> with the ID of the folder where the PDF file will be store.

Is there a way to auto next ( to the next item) the in cell data validation dropdown list after running a script in google sheet?

I am currently new to the google sheet script. I'm doing a simple report generator in google sheet using script. I already have a script that saves a generated pdf file to the google drive. In my google sheet there is a cell referenced to the main data source with dropdown data validation selecting the email of the person and will generate the other details (it a reference also based from that email in the same sheet). what I want is, when I run the script to save pdf file, it should automatically generate pdf file for each item in the dropdown validation list. Is this possible? Anyone who know this please.
this is my code that generate pdf file to the drive (i got this also from the net and made some changes)... thank you so much in advance.
var ss = SpreadsheetApp.getActiveSpreadsheet()
var sheet2 = ss.getSheetByName('ID');
var gdid1 = sheet2.getRange('B1').getValue();
var gdid2 = sheet2.getRange('B4').getValue();
function onOpen() {
var ui = SpreadsheetApp.getUi()
ui.createMenu('ExportGDrive')
.addItem('Export BasicED', 'exportBasicED')
.addItem('Export College', 'exportCollege')
.addToUi()
}
function _exportBasic(blob, fileName, spreadsheet) {
blob = blob.setName(fileName)
var folder = DriveApp.getFolderById(gdid1)
var pdfFile = folder.createFile(blob)
// Display a modal dialog box with custom HtmlService content.
const htmlOutput = HtmlService
.createHtmlOutput('<p>Click to open ' + fileName + '</p>')
.setWidth(300)
.setHeight(80)
SpreadsheetApp.getUi().showModalDialog(htmlOutput, 'Export Successful')
}
function _exportCollege(blob, fileName, spreadsheet) {
blob = blob.setName(fileName)
var folder = DriveApp.getFolderById(gdid2)
var pdfFile = folder.createFile(blob)
// Display a modal dialog box with custom HtmlService content.
const htmlOutput = HtmlService
.createHtmlOutput('<p>Click to open ' + fileName + '</p>')
.setWidth(300)
.setHeight(80)
SpreadsheetApp.getUi().showModalDialog(htmlOutput, 'Export Successful')
}
function exportAsPDF() {
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet()
var blob = _getAsBlob(spreadsheet.getUrl())
_exportBlob(blob, spreadsheet.getName(), spreadsheet)
}
function _getAsBlob(url, sheet, range) {
var rangeParam = ''
var sheetParam = ''
if (range) {
rangeParam =
'&r1=' + (range.getRow() - 1)
+ '&r2=' + range.getLastRow()
+ '&c1=' + (range.getColumn() - 1)
+ '&c2=' + range.getLastColumn()
}
if (sheet) {
sheetParam = '&gid=' + sheet.getSheetId()
}
// A credit to https://gist.github.com/Spencer-Easton/78f9867a691e549c9c70
// these parameters are reverse-engineered (not officially documented by Google)
// they may break overtime.
var exportUrl = url.replace(/\/edit.*$/, '')
+ '/export?exportFormat=pdf&format=pdf'
+ '&size=LETTER'
+ '&portrait=true'
+ '&fitw=true'
+ '&top_margin=0.75'
+ '&bottom_margin=0.75'
+ '&left_margin=0.7'
+ '&right_margin=0.7'
+ '&sheetnames=false&printtitle=false'
+ '&pagenum=UNDEFINED' // change it to CENTER to print page numbers
+ '&gridlines=FALSE'
+ '&fzr=FALSE'
+ sheetParam
+ rangeParam
Logger.log('exportUrl=' + exportUrl)
var response
var i = 0
for (; i < 5; i += 1) {
response = UrlFetchApp.fetch(exportUrl, {
muteHttpExceptions: true,
headers: {
Authorization: 'Bearer ' + ScriptApp.getOAuthToken(),
},
})
if (response.getResponseCode() === 429) {
// printing too fast, retrying
Utilities.sleep(3000)
} else {
break
}
}
if (i === 5) {
throw new Error('Printing failed. Too many sheets to print.')
}
return response.getBlob()
}
function exportCurrentSheetAsPDF() {
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet()
var currentSheet = SpreadsheetApp.getActiveSheet()
// Change the Cell for the name of the file (example: B3 for current sheet)
var blob = _getAsBlob(spreadsheet.getUrl(), currentSheet)
_exportBlob(blob, SpreadsheetApp.getActiveSheet().getRange('B3').getValue(), spreadsheet)
}
function exportBasicED() {
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet()
var sheet1 = spreadsheet.getSheetByName('Generate-Basic Ed');
var name = sheet1.getRange('B3').getValue();
// Change the Cell for the name of the file (example: B3 for current sheet)
var blob = _getAsBlob(spreadsheet.getUrl(), sheet1)
_exportBasic(blob, name, spreadsheet)
}
function exportCollege() {
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet()
var sheet1 = spreadsheet.getSheetByName('Generate-College');
var name = sheet1.getRange('B3').getValue();
// Change the Cell for the name of the file (example: B3 for current sheet)
var blob = _getAsBlob(spreadsheet.getUrl(), sheet1)
_exportCollege(blob, name, spreadsheet)
}
Try
function nextItem() {
var sh = SpreadsheetApp.getActive();
var data = sh.getRange('myValidationList').getValues();
for (var i = 0; i < data.length; i++) {
sh.getRange('A2').setValue(data[i][0]);
SpreadsheetApp.flush();
// here you can call the script to send pdf
Utilities.sleep(1000);
}
};
assuming that myValidationList is the list of valid data, avd A2 the cell in wich the validation applies.

Export PDf while iterating over a set of values

I'm fairly new to the world of aumating sheets with scripts and ma still firmly in the 'cobble other peoples code together' phase of writing scripts.
I have a schedule in Google Sheets that display's different department overviews based on the contents of a cell ('B1'). I'm attempting to iterate a list of values through that cell and in each instance export the resulting sheet to pdf.
So far I've got it working, my next hurdle is getting it to export the pdf in landscape rather than portrait. I can see implementations using url export but I'm not confident enough (read keep breaking everything) to implement that in to the script below.
Any help greatly appreciated!
function PrintPDF(){
var df = DriveApp.getFolderById("folderID");
var arr = new Array();
var files = df.getFiles();
while( files.hasNext() ) {
var f = files.next();
arr.push( [ [ f.getId() ] , [ f.getLastUpdated() ] ] );
}
arr.sort( sortFunction );
function sortFunction( a , b ) {
var aDate = new Date(a[1]);
var bDate = new Date(b[1]);
if ( aDate === bDate ) return 0;
else if ( aDate < bDate ) return 1;
else return -1;
};
for( var i=0 ; i<arr.length ; i++ )
DriveApp.getFileById( arr[i][0] ).setTrashed( true );
//Create array of show codes
var Dss = SpreadsheetApp.getActive().getSheetByName('Value Lists')
var Tss = SpreadsheetApp.getActive().getSheetByName('PrintSheet')
var Shows = Dss.getRange('K3:K11').getValues()
var Count = Shows.length
var Code = Tss.getRange('B1')
Logger.log(Count)
Logger.log(Shows)
for (i=0;i<Count;i++){
Code.setValue(Shows[i])
HideBlankRows ()
const folderName = `foldername`;
var ss =SpreadsheetApp.getActiveSpreadsheet()
var name = "Department - "+ss.getRange('B1').getValue()
Logger.log(name)
DriveApp.getFoldersByName(folderName)
.next()
.createFile(ss
.getBlob()
.getAs(`application/pdf`)
.setName(name)
);
}
Code.setValue('')
}
function HideBlankRows() {
var ss = SpreadsheetApp.getActive();
var sheets = ss.getSheets(); // array of all sheet objects in ss
var numSheets = ss.getNumSheets(); // count of sheets
for(sheet in sheets) {
if(sheets[sheet].getSheetName() == "AA") continue;
//show all the rows
sheets[sheet].showRows(1, sheets[sheet].getMaxRows());
//get data from column A
var data = sheets[sheet].getRange('A:A').getValues();
Logger.log(data)
//iterate over all rows
for(var i=0; i< data.length; i++){
//compare column, if no, then hide row
if(data[i][0] == 'Yes'){
sheets[sheet].hideRows(i+1);
}
}
}
}
Your code looks a bit cryptic to me. I don't understand why do you need the arr array if you nowhere use it. Etc.
But whatever. Suppose the code works fine and all you need is to save a PDF file with landscape orientation. In this case you need to replace these lines in your code:
DriveApp.getFoldersByName(folderName)
.next()
.createFile(ss
.getBlob()
.getAs(`application/pdf`)
.setName(name)
);
With this:
savePDFs(name);
And add at the end of your script the function savePDFs():
function savePDFs(name) {
SpreadsheetApp.flush();
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var url = ss.getUrl();
//remove the trailing 'edit' from the url
url = url.replace(/edit$/, '');
//additional parameters for exporting the sheet as a pdf
var url_ext = 'export?exportFormat=pdf&format=pdf' + //export as pdf
//below parameters are optional...
'&size=a4' + //paper size
'&portrait=false' + //orientation, false for landscape, true for portrait
'&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
'&gid=' + sheet.getSheetId(); //the sheet's Id
var token = ScriptApp.getOAuthToken();
var response = UrlFetchApp.fetch(url + url_ext, {
headers: { 'Authorization': 'Bearer ' + token }
});
var blob = response.getBlob().setName(name + '.pdf');
DriveApp.createFile(blob);
}
This function was taken from here: Change document orientation when exporting to PDF

Overwrite existing file in a specific Google Drive folder

I need the var file = dir.createFile(blob).setContent('Stores_Month.pdf'); to every time, overwrite the existing Stores_Month.pdf file in the specified Google Drive folder.
function runCBUEBUquarterly() {
var file = DriveApp.getFilesByName("Data_Stores_Quarter.csv").next();
var csvData = Utilities.parseCsv(file.getBlob().getDataAsString());
var sheet = SpreadsheetApp.getActive().getSheetByName('Data_Month');
sheet.getRange(1, 1, csvData.length, csvData[0].length).setValues(csvData);
/* Highlight all sort range and sort by AS - Okanagan */
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = SpreadsheetApp.getActive().getSheetByName('Stores_Month');
var range = sheet.getRange("A5:AS10");
// Sorts by the values in column (AS)
range.sort({column: 45, ascending: false});
/* Highlight all sort range and sort by AS - LM & Whistler */
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = SpreadsheetApp.getActive().getSheetByName('Stores_Month');
var range = sheet.getRange("A13:AS24");
// Sorts by the values in column (AS)
range.sort({column: 45, ascending: false});
/* Save as PDF to Google Drive */
SpreadsheetApp.flush();
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = SpreadsheetApp.getActive().getSheetByName('Stores_Month');
var url = ss.getUrl();
//remove the trailing 'edit' from the url
url = url.replace(/edit$/,'');
//additional parameters for exporting the sheet as a pdf
var url_ext = 'export?exportFormat=pdf&format=pdf' + //export as pdf
//below parameters are optional...
'&size=letter' + //paper size
'&portrait=false' + //orientation, false for landscape
'&fitw=false' + //fit to width, false for actual size
'&pagenumbers=true' + //fit to width, false for actual size
'&sheetnames=false&printtitle=false' + //hide optional headers and footers
'&gridlines=false' + //hide gridlines
'&fzr=true' + //do not repeat row headers (frozen rows) on each page
'&gid=' + sheet.getSheetId(); //the sheet's Id
var token = ScriptApp.getOAuthToken();
var response = UrlFetchApp.fetch(url + url_ext, {
headers: {
'Authorization': 'Bearer ' + token
}
});
var blob = response.getBlob().setName(sheet.getName() + '.pdf');
//from here you should be able to use and manipulate the blob to send and email or create a file per usual.
//In this example, I save the pdf to drive
var dir = DriveApp.getFoldersByName('CBU & EBU - Quarterly Tracker').next();
var file = dir.createFile(blob).setContent('Stores_Month.pdf');
}
You'll probably need to use something like the following code. I haven't tested it, but try it out, and see what happens:
var dir, file, newContent;
//dir = DriveApp.getFoldersByName('CBU & EBU - Quarterly Tracker').next();
dir = DriveApp.getFolderById('put the folder ID here');//Get folder by ID
file = dir.getFilesByName('Stores_Month.pdf').next();
if (file) {//There is an existing file by that name
newContent = blob.getDataAsString();
Logger.log('blob: ' + blob);
Logger.log('blob.getDataAsString(): ' + blob.getDataAsString());
file.setContent(newContent);//The new content must be a string
} else {//no file by that name was found
file = dir.createFile(blob).setName('Stores_Month.pdf');
}

Run script across multiple spreadsheets (googlesheet)

I'm currently running a script that takes a sheet, converts it into PDF and emails it out to an email address nightly. I am doing this across three separate spreadsheets. Instead of it running separately on each spreadsheet, I wanted to see if there was a to call each spreadsheet, and run the script once and attach all the PDFs into one email. It works great by itself, but I feel like it would make sense if I can have one spreadsheet run the function once and incorporate the other spreadsheets as well. Any direction would be helpful Thank you!
The script I am using is as follows
function PDFtoEmail() {
var email = "email#gmail.com";
var ss = SpreadsheetApp.getActiveSpreadsheet();
SpreadsheetApp.setActiveSheet(ss.getSheetByName('Schedule 1'));
var sheet = ss.getActiveSheet();
var subject = "Nightly Scheduled PDF";
var body = "";
var url = "https://docs.google.com/spreadsheets/d/SS_ID/export?".replace("SS_ID", ss.getId());
var url_ext = 'exportFormat=pdf&format=pdf'
+ '&size=letter'
+ '&portrait=true'
+ '&fitw=true&source=labnol'
+ '&sheetnames=false&printtitle=false'
+ '&pagenumbers=false&gridlines=false'
+ '&fzr=true'
+ '&gid=';
var token = ScriptApp.getOAuthToken();
var sheets = ss.getSheets();
var PDFtoEmail = [];
for(var i = 0; i < 3; i++){
var response = UrlFetchApp.fetch(url + url_ext + sheets[i].getSheetId(), {
headers: {
'Authorization': 'Bearer ' + token
}
});
PDFtoEmail[i] = response.getBlob().setName("Schedule.pdf");
}
if (MailApp.getRemainingDailyQuota() > 0)
GmailApp.sendEmail(email, subject, body, {
attachments:PDFtoEmail,
});
}
SpreadsheetApp.openByUrl() can open (for use by the script, they don't open in browser window) spreadsheets other than the one that is currently active. openByID is equally valid.
var sheets = [firstsheeturl, secondsheeturl,thirdsheeturl];
for(var i = 0; i < sheets.length; i++){
var ss = SpreadsheetApp.openByUrl(sheets[i]);
//code to do on all three sheets
}