Saving a specific sheet from the workbook as a PDF - google-apps-script

I have 3 sheets in my workbook and I want to save a specific sheet as a PDF to a specific folder in my Google Drive. I have this code below. However, it is saving the entire workbook as PDF and not that specific sheet.
function checkSheet() {
const ss = SpreadsheetApp.getActive();
const sh = ss.getSheetByName("Tracking");
var fldr = DriveApp.getFolderById("folder id");
if(sh.getRange("C6").getValue() == "Yes") {
var theBlob = ss.getBlob().getAs('application/pdf').setName("mypdf");
fldr.createFile(theBlob);
}
}
Tracking - is the sheet that I want to save as PDF
folder id - is the id taken from the url of the folder where I want to save the PDF file
I tried looking for different syntax for getBlob and I am not able to get that specific sheet saved as a PDF. Here are is a link that I referenced.
Export Single Sheet to PDF in Apps Script

I thought that your referenced thread will be useful. But, from your question, I couldn't understand your tested script. So, in this case, I would like to introduce the modified script using your referenced thread.
Modified script:
function checkSheet() {
const ss = SpreadsheetApp.getActive();
const sh = ss.getSheetByName("Tracking");
var fldr = DriveApp.getFolderById("folder id");
if (sh.getRange("C6").getValue() == "Yes") {
const sheetName = "Sheet1"; // Please set the sheet name you want to export as PDF format.
var sheets = ss.getSheets();
for (var i = 0; i < sheets.length; i++) {
if (sheets[i].getSheetName() !== sheetName) {
sheets[i].hideSheet();
}
}
SpreadsheetApp.flush(); // This might not be required to be used.
var theBlob = ss.getBlob().setName("mypdf");
fldr.createFile(theBlob);
for (var i = 0; i < sheets.length; i++) {
sheets[i].showSheet();
}
}
}
When this script is run, only "Sheet1" is included in the exported PDF file.
By the way, in this case, when the blob is retrieved from Spreadsheet, the Spreadsheet is automatically converted to PDF format. So, in this case, var theBlob = ss.getBlob().getAs('application/pdf').setName("mypdf"); can be replaced with var theBlob = ss.getBlob().setName("mypdf");.
Note:
As another approach, in this case, when the endpoint for exporting the Spreadsheet as PDF format is used, the modified script is as follows.
function checkSheet() {
const ss = SpreadsheetApp.getActive();
const sh = ss.getSheetByName("Tracking");
var fldr = DriveApp.getFolderById("folder id");
if (sh.getRange("C6").getValue() == "Yes") {
const sheetName = "Sheet1"; // Please set the sheet name you want to export as PDF format.
const url = `https://docs.google.com/spreadsheets/d/${ss.getId()}/export?format=pdf&gid=${ss.getSheetByName(sheetName).getSheetId()}`;
const blob = UrlFetchApp.fetch(url, { headers: { authorization: "Bearer " + ScriptApp.getOAuthToken() } }).getBlob();
fldr.createFile(blob.setName("mypdf"));
}
}

Related

Server error when trying to save range of Google sheet cells to PDF in Google Apps Script

I have the following code, running in Google Apps Script. The code attempts to take a range of a spreadsheet and save it as a PDF:
var range = sheet.getRange("A586:K" + lastRow);
// Get the currently active spreadsheet URL (link)
var ss = SpreadsheetApp.getActiveSpreadsheet();
var pdfBlob = DriveApp.getFileById(ss.getId()).getAs('application/pdf');
pdfBlob.setName('test.pdf');
// Save the PDF to your Google Drive.
var folder = DriveApp.getFolderById("1EJIzvW-oOnFfFOopiAAsudhbHsF5FGKz");
var file = folder.createFile(pdfBlob);
When I run the code, it runs for a while, then gives me the error:
We're sorry, a server error occurred. Please wait a bit and try again
Any tips on what might be going on?
I believe your goal is as follows.
You want to export the specific range of a sheet as a PDF format using Google Apps Script.
In your script, range is not used. And, the whole sheet is exported. In this case, I think that your goal can be achieved by the query parameter. Ref When this is reflected in your script, how about the following modification?
Modified script:
function myFunction() {
const sheetName = "Sheet1"; // Please set your sheet name.
const folderId = "###"; // Please set your folder ID.
const ss = SpreadsheetApp.getActiveSpreadsheet();
const sheet = ss.getSheetByName(sheetName);
const range = sheet.getRange("A586:K" + sheet.getLastRow());
const startRow = range.getRow() - 1;
const endRow = startRow + range.getNumRows();
const startCol = range.getColumn() - 1;
const endCol = startCol + range.getNumColumns();
const url = `https://docs.google.com/spreadsheets/d/${ss.getId()}/export?format=pdf&gid=${sheet.getSheetId()}&r1=${startRow}&c1=${startCol}&r2=${endRow}&c2=${endCol}`;
const res = UrlFetchApp.fetch(url, { headers: { authorization: "Bearer " + ScriptApp.getOAuthToken() } });
const folder = DriveApp.getFolderById(folderId);
folder.createFile(res.getBlob().setName("sample.pdf"));
}
References:
fetch(url, params)
Related thread.
How to adjust as custom size margins and paper size in script to save google spreadsheet in PDF?

How can I overwrite the old file with app script when I save the file?

I have a few pages in google sheet. I'm getting the PDF output of Sheet2 from these pages with the code below. When the pdf prints out, it deletes the old pdf printout and creates a new one instead. When this happens, the links of the pdfs are changed. I don't want the link of the pdf to change. When it creates the new pdf I want it to overwrite the old one. How do I do this?
function checkSheet() {
var sheetName = "Sheet2";
var folderID = "folderid"; // Folder id to save in a folder.
var pdfName = "Catalog";
var sourceSpreadsheet = SpreadsheetApp.getActive();
var sourceSheet = sourceSpreadsheet.getSheetByName(sheetName);
var folder = DriveApp.getFolderById(folderID);
//Copy whole spreadsheet
var destSpreadsheet = SpreadsheetApp.open(DriveApp.getFileById(sourceSpreadsheet.getId()).makeCopy("tmp_convert_to_pdf", folder))
//delete redundant sheets
var sheets = destSpreadsheet.getSheets();
for (i = 0; i < sheets.length; i++) {
if (sheets[i].getSheetName() != sheetName){
destSpreadsheet.deleteSheet(sheets[i]);
}
}
var destSheet = destSpreadsheet.getSheets()[0];
//repace cell values with text (to avoid broken references)
var sourceRange = sourceSheet.getRange(1,1,sourceSheet.getMaxRows(),sourceSheet.getMaxColumns());
var sourcevalues = sourceRange.getValues();
var destRange = destSheet.getRange(1, 1, destSheet.getMaxRows(), destSheet.getMaxColumns());
destRange.setValues(sourcevalues);
//delete old pdf
var files = DriveApp.getFolderById(folderID).getFiles();
while (files.hasNext()) {
var file = files.next();
if(file.getName() == "Catalog"){
DriveApp.getFileById(file.getId()).setTrashed(true);
}
}
//save to pdf
var theBlob = destSpreadsheet.getBlob().getAs('application/pdf').setName(pdfName);
var newFile = folder.createFile(theBlob);
//Delete the temporary sheet
DriveApp.getFileById(destSpreadsheet.getId()).setTrashed(true);
}
Your question contains a lot of unnecessary details. I believe it could be simplified to, "How can one update an existing PDF file on Google Drive?"
To do this, you have to enable Advanced Drive Service which has an update method that will replace an existing PDF file in Google Drive.
function replaceFile(theBlob,theFileId) {
var oldFile = DriveApp.getFileById(theFileId);
Drive.Files.update({title: oldFile.getName(),mimeType:
oldFile.getMimeType()}, theFileId, theBlob);
}
}

Is it possible to export (using Google Scripts) a single sheet to PDF without hiding sheets?

I would like to be able to export a single specific sheet from a large workbook without having to hide the unrequired sheets. Is that actually possible with Google Scripts?
At the moment I am looping through a list of products, updating a query for each one and then exporting each result to an individual PDF. Basically creating a product "Printout" page for many products.
The code below works quite nicely but it starts by hiding all sheets other than my Printout page. That would be fine except some of the other sheets are protected and not all users that would be using my export functionality have the right to hide sheets.
I've considered adding an unprotect/protect function to my macro but it would be good to know if exporting a single sheet was an option before i went down this route?
The hiding sheets trick was from this post Export Single Sheet to PDF in Apps Script
function exportLoopedSheet(firstRow, lastRow) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheetName = 'Printout'; // update for print sheet name
var productSheetName = 'ProductList'; // update for final product list
var folderName = 'productPDFs';
var main = ss.getSheetByName(sheetName);
var sheets = ss.getSheets();
var productList = ss.getSheetByName(productSheetName);
var lastProductRow = lastRow;
var firstProductRow = firstRow;
// Hide all sheets other than the Print Sheet
for (var i = 0; i < sheets.length; i++) {
if (sheets[i].getSheetName() !== sheetName) {
sheets[i].hideSheet();
}
}
for (var prodNo = firstProductRow; prodNo < lastProductRow + 1; prodNo ++) {
var currentProduct = productList.getRange('A'+ prodNo).getValue();
main.getRange('B9').setValue(currentProduct);
// Ensure all changes are updated
SpreadsheetApp.flush();
// call the export sheet function
exportSheet();
}
// Unhide the sheets
for (i = 0; i < sheets.length; i++) {
sheets[i].showSheet();
}
}
function exportSheet() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheetName = 'Printout';
var main = ss.getSheetByName(sheetName);
var sheets = ss.getSheets();
//Hide All Empty Rows in the Print Sheet
var maxRows = main.getMaxRows();
var lastRow = main.getLastRow();
if (maxRows-lastRow != 0){
main.hideRows(lastRow+1, maxRows-lastRow);
}
// Save pdf version
var folder = 'productPDF';
var parentFolder = DriveApp.getFolderById('1234'); //add this line...
var folder, folders = DriveApp.getFoldersByName(folder);
if (folders.hasNext()) {
folder = folders.next();
} else {
folder = parentFolder.createFolder(folder);
}
var name = main.getRange("B8").getValue();
folder.createFile(ss.getBlob().setName(name));
// Unhide the rows again
var fullSheetRange = main.getRange(1,1,main.getMaxRows(), main.getMaxColumns());
main.unhideRow(fullSheetRange);
}

How to loop data and print each iteration to PDF in a defined Google Drive folder

I'm a novice at GAS, so please bear with me.
I'd like to create a script for a Google Sheet that will loop through a series of values, pause at each value, and print a specific tab from the sheet to a defined location in Google Drive (creating a new folder with a date within the parent folder). Below is what I have so far, which achieves looping and printing, but I can't figure out how to get it to save the PDF files to a specific folder. Grateful for any help! Thank you.
Link to dummy spreadsheet with script here, and target Google Drive folder here.
function loop() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var validation_sheet = ss.getSheetByName('Validation');
var lastRow = validation_sheet.getLastRow();
var inputs = ss.getSheetByName('Validation').getRange('A2:A'+lastRow).getValues();
var sheet2 = ss.getSheetByName('Loadout');
var tab = ss.getSheetByName('Loadout');
var formattedDate = Utilities.formatDate(new Date(), "GMT+5", "yyyy-MM-dd hh:mm");
//Create Folder for PDFs
var fld = DriveApp.createFolder(formattedDate);
fld.addFile(DriveApp.getFileById(ss.getId()));
for (var i = 0; i < inputs.length; i++) {
sheet2.getRange('A1').setValue(inputs[i][0]);
SpreadsheetApp.flush();
Utilities.sleep(5000);
//Print PDFs
var name = tab.getRange(1, 1).getValue();
fld.createFile(ss.getAs('application/pdf')).setName(name);
}
DriveApp.getRootFolder().removeFile(DriveApp.getFileById(ss.getId()));
}
You want to create PDF files to "target Google Drive folder". https://drive.google.com/drive/u/1/folders/1QmjXLyssyCGU16ApLQ4Anj_kir0uuQS8
If my understanding is correct, how about this modification?
Modification points:
Retrieve the target folder using DriveApp.getFolderById().
When PDF file is created, it creates the file to the target folder.
Modified script:
function loop() {
var targetFolderId = "1QmjXLyssyCGU16ApLQ4Anj_kir0uuQS8"; // Added
var targetFolder = DriveApp.getFolderById(targetFolderId); // Added
var ss = SpreadsheetApp.getActiveSpreadsheet();
var validation_sheet = ss.getSheetByName('Validation');
var lastRow = validation_sheet.getLastRow();
var inputs = ss.getSheetByName('Validation').getRange('A2:A'+lastRow).getValues();
var sheet2 = ss.getSheetByName('Loadout');
var tab = ss.getSheetByName('Loadout');
// var formattedDate = Utilities.formatDate(new Date(), "GMT+5", "yyyy-MM-dd hh:mm"); // Removed
//Create Folder for PDFs
// var fld = DriveApp.createFolder(formattedDate); // Removed
// fld.addFile(DriveApp.getFileById(ss.getId())); // Removed
for (var i = 0; i < inputs.length; i++) {
sheet2.getRange('A1').setValue(inputs[i][0]);
SpreadsheetApp.flush();
Utilities.sleep(5000);
//Print PDFs
var name = tab.getRange(1, 1).getValue();
targetFolder.createFile(ss.getAs('application/pdf')).setName(name); // Modified
}
// DriveApp.getRootFolder().removeFile(DriveApp.getFileById(ss.getId())); // Removed
}
Note:
In your script, the active spreadsheet is also moved to a created new folder. About this, how do you want to do?
References:
getFolderById(id)
If I misunderstand your question, please tell me. I would like to modify it.
Edit:
When you run the script, at first, you want to create new folder in the target folder. Then, you want to create PDF files in the created folder.
About the active spreadsheet, do nothing.
I understood like above. If my understanding is correct, how about this modification?
Modified script:
function loop() {
var targetFolderId = "1QmjXLyssyCGU16ApLQ4Anj_kir0uuQS8"; // Added
var targetFolder = DriveApp.getFolderById(targetFolderId); // Added
var ss = SpreadsheetApp.getActiveSpreadsheet();
var validation_sheet = ss.getSheetByName('Validation');
var lastRow = validation_sheet.getLastRow();
var inputs = ss.getSheetByName('Validation').getRange('A2:A'+lastRow).getValues();
var sheet2 = ss.getSheetByName('Loadout');
var tab = ss.getSheetByName('Loadout');
var formattedDate = Utilities.formatDate(new Date(), "GMT+5", "yyyy-MM-dd hh:mm");
//Create Folder for PDFs
var fld = targetFolder.createFolder(formattedDate); // Modified
// fld.addFile(DriveApp.getFileById(ss.getId())); // Removed
for (var i = 0; i < inputs.length; i++) {
sheet2.getRange('A1').setValue(inputs[i][0]);
SpreadsheetApp.flush();
Utilities.sleep(5000);
//Print PDFs
var name = tab.getRange(1, 1).getValue();
fld.createFile(ss.getAs('application/pdf')).setName(name); // Modified
}
// DriveApp.getRootFolder().removeFile(DriveApp.getFileById(ss.getId())); // Removed
}

How can I make my script save the copy to a specific folder?

I am using the below script to make a copy of my google worksheet (values and formatting only). However, this script is placing the new file in my main google drive and I want the file to be saved to an archive folder. How can I edit my script to do this?
function copySheetValuesV4(){
var sourceSpreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var sourceSheets = sourceSpreadsheet.getSheets();
var destination = SpreadsheetApp.create('03_'+sourceSpreadsheet.getName()+' _December 2017');
for (var i = 0; i < sourceSheets.length; i++){
var sourceSheet = sourceSheets[i];
if (!sourceSheet.isSheetHidden()) {
var sourceSheetName = sourceSheet.getSheetName();
var sValues = sourceSheet.getDataRange().getValues();
sourceSheet.copyTo(destination)
var destinationSheet = destination.getSheetByName('Copy of '+sourceSheetName).setName(sourceSheetName);
destinationSheet.getRange(1,1,sValues.length,sValues[0].length).setValues(sValues);// overwrite all formulas that the copyTo preserved */
}
destination.getSheetByName("sheet1").hideSheet() // Remove the default "sheet1" */
}
}
Use DriveApp.getFolderById(folder_id).addFile(DriveApp.getFileById(destination.getId())). This gets the spreadsheet ID and then adds the spreadsheet to a folder.