Google Sheet to PDF Get Only Active Sheet/Tab - javascript

This script converts pdf in inside the folder which is fine.
There are three tabs on this sheet when the function run.
Merge all the tab in pdf and save in the drive folder with active sheet tab name
var pdfName = "Invoice " + sheetName.getRange("d6").getValue();
What I want
When I run the script only active tab/sheet convert in pdf. and not marge all tab in pdf.
function PDF() {
var sheetName = SpreadsheetApp.getActiveSpreadsheet();
var folderID = "1_gA4D7ybJ60dfgsdfgdsfInqVoo9D769cqmAnJI7g7";
var ss = SpreadsheetApp.openByUrl('https://docs.google.com/spreadsheets/d/1jBl_82etnHsdfgsdfgsdfgsdgcjaCpcTG6VvhKYNNrQQXJMUUOQkFGfORY/edit#gid=1167579479');
var pdfName = "Invoice " + sheetName.getRange("d6").getValue();
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();
//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);
}

Explanation:
Your current solution is not the proper way to create a pdf of a sheet. You need to use getOAuthToken() and Class UrlFetchApp.
Also I improved your script in many different ways. You are defining variables you are not using anywhere. And also you don't need to create a copy of the spreadsheet file and then delete it. You can simply create a pdf file of your source spreadsheet directly.
The following script will create a pdf file of the active sheet. Keep in mind that the active sheet is the sheet selected in the UI.
Solution:
function PDF(){
var sss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = sss.getActiveSheet();
var ssID = sss.getId();
var shID = sheet.getSheetId().toString();
var folderID = "1_gA4D7ybJ60dfgsdfgdsfInqVoo9D769cqmAnJI7g7";
var folder = DriveApp.getFolderById(folderID);
var pdfName = "Invoice " + sheet.getRange("d6").getValue();
var requestData = {"method": "GET", "headers":{"Authorization":"Bearer "+ScriptApp.getOAuthToken()}};
var url = "https://docs.google.com/spreadsheets/d/"+ ssID + "/export?format=pdf&id="+ssID+"&gid="+shID;
var result = UrlFetchApp.fetch(url , requestData);
var newFile = folder.createFile(result.getBlob()).setName(pdfName)
}

Related

Script does not restart after it fails once it does not start up again. I can not find the reason

Need help on simplifying this script. I still need to add more clusters in while loops.
function Files() {
var ss = SpreadsheetApp.getActive();
var names = ss.getSheetByName("AME");
var SupplierName = names.getRange(names.getLastRow(),5).getValue();
var Cluster = names.getRange(names.getLastRow(),3).getValue();
if (Cluster == 'US'){
var ClusterID = DriveApp.getFolderById("1z2R");
var newFolderID = ClusterID.createFolder(SupplierName);
var sourceFolder = DriveApp.getFoldersByName("US").next();
var files = sourceFolder.getFiles();
var destFolder = DriveApp.getFoldersByName(SupplierName).next();
while(files.hasNext()){
var file = files.next();
file.moveTo(destFolder);
}
return newFolderID.getId();
SUGGESTION:
We are still kind of lurking in the dark here but here are some opportunities I have identified on the provided script above.
/** Can be a global variable */
var ss = SpreadsheetApp.getActive();
var names = ss.getSheetByName("AME");
var SupplierName = names.getRange(names.getLastRow(),5).getValue();
var Cluster = names.getRange(names.getLastRow(),3).getValue();
function Files() {
if(Cluster == 'US') {
var ClusterID = DriveApp.getFolderById("SET FOLDER ID");
var folders = ClusterID.getFoldersByName(SupplierName).hasNext();
if(folders !== true){
ClusterID.createFolder(SupplierName);
moveFolders(SupplierName);
}
else {
moveFolders(SupplierName);
}
}
else {
Logger.log('Cluster is ' + Cluster);
}
}
function moveFolders() {
var sourceFolder = DriveApp.getFoldersByName("US").next();
var files = sourceFolder.getFiles();
Logger.log(files);
var destFolder = DriveApp.getFoldersByName(SupplierName).next();
while(files.hasNext()){
var file = files.next();
file.moveTo(destFolder);
}
}
Created a separate function moveFolders() to move files to the created folder ClusterID.createFolder(SupplierName); if Cluster 'US' was checked on the last row of the sheet. I assumed that your data is from a response that came from a Google Form that is why the last row is only being checked.
Sample Data:
Source parent folder for Cluster Folder and US Folder:
Files inside the "US" Folder:
After the script is run, created the SupplierName folder containing the files moved from the US Folder:
Now I haven't worked on dynamically adjusting the script to manually define the cluster name as of the moment due to lack of clarity of the question, but I'll modify my answer once questions are addressed.

App Script + Forms: How to move upload files

I have a Form bound to a Sheet. That works fine. I need to move the uploads to the newFolder and delete them from the temp holding folder.
I have it split into 2 functions. They work independently but I can not get them to work together. I think I just don't know enough.
So I could use some help sorting this out.
Thanks
//this part works great
function autoFillForm(e) {
var timestamp = e.values[0];
var firstName = e.values[1];
var lastName = e.values[2];
var title = e.values[3];
//create new folder
var parentFolder = DriveApp.getFolderById('My Parent Folder ID');
var newFolder = parentFolder.createFolder(lastName + ' - ' + firstName);
//Get template
var file = DriveApp.getFileById('My Template ID');
//Copy template, name it, save to new folder
var copy = file.makeCopy(lastName + ',' + firstName + ' - ' + 'Template Name', newFolder);
//Open copied file
var doc = DocumentApp.openById(copy.getId());
//Get Template body
var body = doc.getBody();
//Replace text in template
body.replaceText('{{fName}}', firstName);
body.replaceText('{{lName}}', lastName);
body.replaceText('{{title}}', title);
//Save and close
doc.saveAndClose();
}
UPDATE
I was able to get this working and it moves the files but only in a stand alone script. I have been trying for hours to get it to work with the main scripts and I'm at a loss.
function movingFiles (e){
//get file names from source folder
var files = DriveApp.getFolderById(ID for Source Folder).getFiles();
while(files.hasNext())
{
var file = files.next();
}
//get file ID
var fileId = file.getId();
//move file, clean source folder
DriveApp.getFolderById(newFolder).addFile(file);
file
.getParents()
.next()
.removeFile(file);
}
TLDR:
this: DriveApp.getFolderById(newFolder).addFile(file);
to this: DriveApp.getFolderById(newFolder.getId()).addFile(file);
this: (newFolder)
to this: (newFolder.getId())
I feel kind of stupid because this was an easy answer in the end.
I am able to to do everything in the one function. No need for seperate functions of Global Variables.
//this part works great
function autoFillForm(e) {
var timestamp = e.values[0];
var firstName = e.values[1];
var lastName = e.values[2];
var title = e.values[3];
//create new folder
var parentFolder = DriveApp.getFolderById('My Parent Folder ID');
var newFolder = parentFolder.createFolder(lastName + ' - ' + firstName);
//Get template
var file = DriveApp.getFileById('My Template ID');
//Copy template, name it, save to new folder
var copy = file.makeCopy(lastName + ',' + firstName + ' - ' + 'Template Name',
newFolder);
//Open copied file
var doc = DocumentApp.openById(copy.getId());
//Get Template body
var body = doc.getBody();
//Replace text in template
body.replaceText('{{fName}}', firstName);
body.replaceText('{{lName}}', lastName);
body.replaceText('{{title}}', title);
//Save and close
doc.saveAndClose();
//get file names from source folder
var files = DriveApp.getFolderById(ID for Source Folder).getFiles();
while(files.hasNext())
{
var file = files.next();
}
//get file ID
var fileId = file.getId();
//error here
//move file, clean source folder
DriveApp.getFolderById(newFolder).addFile(file);
file
.getParents()
.next()
.removeFile(file);
//this is where I was making a mistake
//this: DriveApp.getFolderById(newFolder).addFile(file);
//to this: DriveApp.getFolderById(newFolder.getId()).addFile(file);
//I was failing to understand I needed to define the function to the var again
}

How to change name new creating folder with the subfolders

i want creating new folder with new name from cell in the sheet, and i want copy to this folder files and folders with the sourcedestiny.
Could you help me to solve my problem.
It is possible change name newFolder witout change name folders and subfolders- after his creating?
function copyFolderass() {
const sourceFolder = DriveApp.getFolderById('');
const destinyFolder = DriveApp.getFolderById('');
copyFolder(sourceFolder, destinyFolder);
}
function copyFolderContents(source, target) {
const filesIterator = source.getFiles();
while (filesIterator.hasNext()) {
const file = filesIterator.next();
file.makeCopy(file.getName(), target);
}
}
function copyFolder(sourceFolder, destinyFolder) {
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("nameFile");
var name = ss.getRange("F4").getValue();
const newFolder = destinyFolder.createFolder(sourceFolder.getName());
copyFolderContents(sourceFolder, newFolder);
const foldersIterator = sourceFolder.getFolders();
while (foldersIterator.hasNext()) {
const folder = foldersIterator.next();
copyFolder(folder, newFolder);
}
}
Create Folders and Copy Files
Reads a sheet to obtain FilesFolder Id FolderFolder Id and new FolderName
It creates the new folder and copies all of the files from the Files Folder to the newly created folder.
It records the new folder id in FolderId Column.
It records all of the file ids in the FileIds column.
It put the date in the created column.
It doesn't do anything for rows that have content in Created
//FilesFolder FolderFolder FolderName FolderId FileIds Created
function createFolderAndCopyFiles() {
const ss = SpreadsheetApp.getActive();
const sh = ss.getSheetByName("Sheet0");
const shsr = 2;
let [hA, ...vs] = sh.getDataRange().getValues();
let idx = {};
let col = {};
hA.forEach((h, i) => { idx[h] = i; col[h] = i + 1; });
vs.forEach((r, i) => {
if (!r[idx["Created"]]) {
let dfldr = DriveApp.getFolderById(r[idx["FolderFolder"]]);
let fldr = dfldr.createFolder(r[idx["FolderName"]]);
let fldrid = fldr.getId();
sh.getRange(i + shsr, col["FolderId"]).setValue(fldrid);
let files = DriveApp.getFolderById(r[idx["FilesFolder"]]).getFiles();
let ids = [];
while (files.hasNext()) {
let file = files.next();
let fid = file.getId();
file.makeCopy(file.getName(), fldr);
ids.push(fid);
}
sh.getRange(i + shsr, col["FileIds"]).setValue(ids.join('\n'));
sh.getRange(i + shsr, col["Created"]).setValue(new Date());
}
});
}
Spreadsheet
You fill in the stuff in yellow the program fills in the rest and it won't make folders again if the Created Column not empty.
Thx Cooper for the answer,
but this is not that what i want to do.
on google drive i have a template of structure od catalogs.
my code is one of the part code of my main code. main code working like this
i click send email and then run my code with creating folder from temtlace
when is creating a have name of the template folder but i want just change one part of this line of my code.
instead of this line
const newFolder = destinyFolder.createFolder(sourceFolder.getName());
i want to just like this - the name of the creating folder is from cell F4.
the remaining names of the folders may stays like from template.
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("nameFile");
var name = ss.getRange("F4").getValue();
const newFolder = destinyFolder.createFolder(sourceFolder.setName(name));
but this line change ale name in subfolders i all structure catalog when is creating.

app script, after file.makeCopy create a new file, how to access this new file

I'm trying to get attachment from Gmail to Google Drive. After create a new file into the folder, I have encountered a problem accessing the new file that script created.
same as the makeCopy Function
err: Exception: The document is inaccessible. Please try again later. at myFunction(Code:21:37)
Appreciated any help and suggestions. Thank you!
function myFunction() {
const files = DriveApp.getFolderById("xxxxxxxxxxxxxxxxxxx").getFiles();
while (files.hasNext()){
var file = files.next();
var filename = file.getName();
const aname = "xxxx.docx"
if (filename == aname){
var oldid = file.getId();
var copyfile = file.makeCopy().setName("COPYYYYY");
var newid = copyfile.getId();
}
}
var body = DocumentApp.openById(newid).getBody();
Logger.log(oldid);
Logger.log(newid);
Logger.log(body);
}
Modification points:
In your script, I think that when file of var copyfile = file.makeCopy().setName("COPYYYYY"); is Google Document, the script works. But from your error message and const aname = "xxxx.docx", I thought that you might try to have directly opened the DOCX file using DocumentApp.openById. If it's so, the reason of your issue is this.
In order to open the DOCX file using DocumentApp.openById, in the current stage, it is required to convert the DOCX file to Google Document.
When above points are reflected to your script, it becomes as follows.
Modified script:
Before you use this script, please enable Drive API at Advanced Google services.
function myFunction() {
const files = DriveApp.getFolderById("xxxxxxxxxxxxxxxxxxx").getFiles();
var newid = "";
while (files.hasNext()){
var file = files.next();
var filename = file.getName();
const aname = "xxxx.docx";
if (filename == aname){
var oldid = file.getId();
if (file.getMimeType() == MimeType.MICROSOFT_WORD) {
var copyfile = Drive.Files.copy({title: "COPYYYYY"}, oldid, {convert: true});
newid = copyfile.id;
}
}
}
if (newid) {
var body = DocumentApp.openById(newid).getBody();
Logger.log(oldid);
Logger.log(newid);
Logger.log(body);
}
}
In this modified script, the DOCX file is converted by the method of "Files: copy" of Drive API.
Reference:
Files: copy

email Google Doc as PDF attachment

abc#example.comAfter struggling for a while with this I am calling for help from the crowd.
I am trying to attach 2 Google Docs to an email as PDFs. I see many examples in regard to Google Sheets and have successfully been able to email copies of sheets as PDF, but I have not been able to port this over to Docs.
In multiple different scenarios, the PDF attachments are either a copy of my original template Doc or an image capture of "One Account. All of Google" sign in page. When I look at the links that are generated (Logger.log) and use them, a copy of the correct Doc is downloaded.
Below is an example of my scenario in which I am trying to create the email attachments. See function emailDocAsPDF() towards the bottom
Thanks in advance for any guidance on this issue.
function myFunctionUpdated() {
var testTemplateId = searchDriveFile('Test Template');
Logger.log('test template id = ' + testTemplateId);
var fileName = 'Copy of Test Template'
Logger.log(fileName);
DriveApp.getFileById(testTemplateId).makeCopy(fileName);
var ss = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var range = ss.getRange(1, 1, 3, 2).getValues();
var copyNewTemplateId = searchDriveFile(fileName);
var copyTemplate = DocumentApp.openById(copyNewTemplateId);
var copyTemplateBody = copyTemplate.getBody().editAsText();
for (i=0; i<range.length; i++) {
copyTemplateBody.replaceText(range[i][0], range[i][1]);
}
copyTemplate.saveAndClose();
emailDocAsPDF(fileName)
}
// Searched Google Drive for a file name and returns the file ID.
function searchDriveFile(fileName) {
var files = DriveApp.searchFiles(
'title = "'+ fileName +'"');
while (files.hasNext()) {
var file = files.next();
var id = file.getId();
return id;
}
}
// Send document in an email as PDF
function emailDocAsPDF(fileName) {
var staticDoc = 'FILE-ID';
var attachmentDoc = UrlFetchApp.fetch("https://docs.google.com/document/d/" + copyTemplateId + "/export?format=pdf");
Logger.log("https://docs.google.com/document/d/" + copyTemplateId + "/export?format=pdf");
var attachmentStaticDoc = UrlFetchApp.fetch("https://docs.google.com/document/d/" + staticDoc + "/export?format=pdf");
Logger.log("https://docs.google.com/document/d/" + staticDoc + "/export?format=pdf");
var fileBlob = [];
fileBlob[0] = attachmentDoc.getBlob().getAs('application/pdf');
fileBlob[1] = attachmentStaticDoc.getBlob().getAs('application/pdf');
var body = "Bird is the WORD!! <br>" +
"<a href='http://www.example.com'>Visit Example</a>";
if (MailApp.getRemainingDailyQuota() > 0)
GmailApp.sendEmail("email#example.com", "Test Documents Email", body, {
htmlBody: body,
attachments:[fileBlob[0],fileBlob[1]]
});
}
EDIT -- Successful Updates with code provided by Sandwich.
// Send document in an email as PDF
function emailDocAsPDF(fileName) {
var staticDoc = 'FILE-ID';
var copyTemplateId = searchDriveFile(fileName);
var blobs = [];
var doc = DriveApp.getFileById(copyTemplateId);
blobs[0] = doc.getBlob().getAs('application/pdf').setName('MyAttachment1.pdf');
var doc = DriveApp.getFileById(staticDoc);
blobs[1] = doc.getBlob().getAs('application/pdf').setName('MyAttachment2.pdf');
var zipBlob = Utilities.zip(blobs).setName('Documents.zip');
var recipient = 'abc#example.com';
var subject = 'Test Email';
var body = 'Bird is the WORD';
MailApp.sendEmail(recipient, subject, body, {attachments: [zipBlob]});
}
To attach any kind of document as a PDF, call getBlob on the file, specify content type as with .getAs('application/pdf') and optionally set a name with setName. That's all:
var doc = DriveApp.getFileById('ID_HERE');
var blob = doc.getBlob().getAs('application/pdf').setName('MyAttachment.pdf');
var recipient = 'user#example.com';
var subject = 'Email subject';
var body = 'Text here';
MailApp.sendEmail(recipient, subject, body, {attachments: [blob]});
You were trying to use "export as PDF via URL query", which is a poorly documented feature that is sometimes useful for Sheets (setting the boundaries of exported region), but is unnecessary for Docs, if it even exists for them. The above method should work for any kind of content stored in Google Drive.
By the way, it is preferable to use MailApp instead of GmailApp when sending email, because it keeps the level of authorization to what you need: sending emails. With GmailApp, the script is also granted permission to access and delete all of your existing emails, which is unadvisable for scripts composed by trial, error, and copying code from the Internet.

Categories