How to loop data and print each iteration to PDF in a defined Google Drive folder - google-apps-script

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
}

Related

On Edit (Google Script)

function onEdit(e)
{
var datum = Utilities.formatDate(new Date(), "GMT+1", "dd.MM.YYYY");
var ss = SpreadsheetApp.getActive();
var newas = SpreadsheetApp.create("Sperren");
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Sperren');
sheet.activate();
var temp = ss.duplicateActiveSheet();
range = temp.getDataRange();
range.copyTo(range, {contentsOnly: true});
temp.copyTo(newas);
ss.deleteSheet(temp);
newas.getSheetByName('Sperren');
newas.deleteActiveSheet();
var folderID = "Sperr Material";
var folderID2 = "Prozess";
var datei = newas.getRange("C3").getValues();
// var dateid = newas.getRange("G6").getValues();
var folder = DriveApp.getFoldersByName(folderID);
var theblob = newas.getBlob().setName(datei +" "+ datum);
var newFile = folder.next().createFolder(folderID2 +" "+ datei + " "+ datum).createFile(theblob);
}
/* #Process Form */
function processForm(formObject)
{
var url = "https://https://docs.google.com/spreadsheets/d/1v03Se_BaW-SqFJpN8TU9oEhT2eSvMRHvqwnh3s14lPY/edit#gid=645028893";
var as = SpreadsheetApp.openByUrl(url);
var ws = as.getSheetByName("Test");
/*ws.appendRow([formObject.material,
formObject.stückzahl,
formObject.label,
formObject.datum,
formObject.grund,
formObject.lgort,
formObject.name,
formObject.sgrund]);*/
ws.getRange("A2").setValue(formObject.material);
ws.getRange("B2").setValue(formObject.stückzahl);
ws.getRange("C2").setValue(formObject.label);
ws.getRange("D2").setValue(formObject.datum);
ws.getRange("E2").setValue(formObject.grund);
ws.getRange("F2").setValue(formObject.lgort);
ws.getRange("G2").setValue(formObject.name);
ws.getRange("H2").setValue(formObject.sgrund);
}
Can anyone help me here, i have Html Formular which sends the values to Google Sheet and Sheet should save on one column.
After that it should be transfer the value to another sheet, where is a specific Table, after that it should be save this table to Drive App with informations.
The first column will be changed by either request and by new change should Google Sheet save a new Datei.
but my OnEdit code will not work
if there is a new change should Google save it to a Folder in Drive APP.
But this onEdit code will not work :)

Export Specific sheet to PDF [duplicate]

This question already has answers here:
Export Single Sheet to PDF in Apps Script
(3 answers)
Closed 2 years ago.
I am aware that similar type of question has being asked earlier under the Using Google Apps Script to save a single sheet from a spreadsheet as pdf in a specific folder
The code that was used is working for me and is mentioned below:
function generatePdf() {
// Get active spreadsheet.
var sourceSpreadsheet = SpreadsheetApp.getActive();
// Get active sheet.
var sheets = sourceSpreadsheet.getSheets();
var sheetName = sourceSpreadsheet.getActiveSheet().getName();
var sourceSheet = sourceSpreadsheet.getSheetByName(sheetName);
// Set the output filename as SheetName.
var pdfName = sheetName;
// Get folder containing spreadsheet to save pdf in.
var parents = DriveApp.getFileById(sourceSpreadsheet.getId()).getParents();
if (parents.hasNext()) {
var folder = parents.next();
} else {
folder = DriveApp.getRootFolder();
}
// 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);
// 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);
}
The problem that I encounter is that my source sheet has a few fields which are auto populated in the sheet using vlookup. These fields are exported in the temp file which is created by this script as I have checked the trash and the field values are present but the PDF generated by the code is missing all the vlookup data.
The sample image of PDF is as below in which the vlookup missing entries are marked in yellow:
While the temp google sheet which is in trash has the values in the respective cells. Screenshot of the same is below the vlookup fields are highlighted in red.
Kindly help me with the solution.
Add the contentOnly: true in line 38. See the code. Hope this solves the problem. This will clear all the formula's. (im not sure the setValues() accept this extra parameter. the copyTo does, so you can make a copy of the sheet to a contentOnly sheet and then use that for the pdf)
function generatePdf() {
// Get active spreadsheet.
var sourceSpreadsheet = SpreadsheetApp.getActive();
// Get active sheet.
var sheets = sourceSpreadsheet.getSheets();
var sheetName = sourceSpreadsheet.getActiveSheet().getName();
var sourceSheet = sourceSpreadsheet.getSheetByName(sheetName);
// Set the output filename as SheetName.
var pdfName = sheetName;
// Get folder containing spreadsheet to save pdf in.
var parents = DriveApp.getFileById(sourceSpreadsheet.getId()).getParents();
if (parents.hasNext()) {
var folder = parents.next();
} else {
folder = DriveApp.getRootFolder();
}
// 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, {contentsOnly: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);
}
Just needed to add a line to flush the app did the work. Updated code:
function generatePdf() {
// Get active spreadsheet.
var sourceSpreadsheet = SpreadsheetApp.getActive();
// Get active sheet.
var sheets = sourceSpreadsheet.getSheets();
var sheetName = sourceSpreadsheet.getActiveSheet().getName();
var sourceSheet = sourceSpreadsheet.getSheetByName(sheetName);
// Set the output filename as SheetName.
var pdfName = sheetName;
// Get folder containing spreadsheet to save pdf in.
var parents = DriveApp.getFileById(sourceSpreadsheet.getId()).getParents();
if (parents.hasNext()) {
var folder = parents.next();
}
else {
folder = DriveApp.getRootFolder();
}
// 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);
SpreadsheetApp.flush();
// 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);
}

Determining the extension of an e-mail attachment automatically (whether it's XLSX or CSV) and applying the right parsing technique

I have two Google Script codes that automate the process of importing email attachments from Gmail (it's automatically labeled) into Google Sheets. So far I managed to make it work for CSV and XLSX files separately. Please see both codes below. My question is: how do I combine those two codes into one, so that it could determine the file extension automatically and apply the right parsing technique when copying the contents of the files in the respective Google Sheet. Thank you!
For XLSX files:
function getXLSX() {
var thread = GmailApp.getUserLabelByName("Invoicing").getThreads(0,1);
/* var message = thread[0].getMessages()[0]; // Get first message */
var messages = thread[0].getMessages();
var len = messages.length;
var message=messages[len-1] //get last message
var attachments = message.getAttachments(); // Get attachment of first message
var xlsxBlob = attachments[0]; // Is supposes that attachments[0] is the blob of xlsx file.
var convertedSpreadsheetId = Drive.Files.insert({mimeType: MimeType.GOOGLE_SHEETS}, xlsxBlob).id;
var sheet = SpreadsheetApp.openById(convertedSpreadsheetId).getSheets()[0]; // There is the data in 1st tab.
var data = sheet.getDataRange().getValues();
Drive.Files.remove(convertedSpreadsheetId); // Remove the converted file.
//var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet_new = SpreadsheetApp.openById("1jRh8sj_jAaZKH4xbdpI9Q4to1tKuGWTTO2MzHlU").getSheetByName("Data drop");
/*for (var i = 0; i > sheet_new.length; i++) {
var range = sheet_new[i].getRange("A:I");
range.clearContents();
}*/
sheet_new.clearContents();
var range = sheet_new.getRange(1,1, data.length,data[0].length);
range.setValues(data);
}
For CSV files:
function getCSV() {
var thread = GmailApp.getUserLabelByName("Invoicing").getThreads(0,1);
/* var message = thread[0].getMessages()[0]; // Get first message */
var messages = thread[0].getMessages();
var len = messages.length;
var message=messages[len-1] //get last message
var attachments = message.getAttachments(); // Get attachment of first message
var csv = attachments[0].getDataAsString();
var data = Utilities.parseCsv(csv);
var a = data.length ;
var b = data[0].length;
//var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = SpreadsheetApp.openById("1jRh8sj_jAaZKH4xbdpI9Q4to1tKuGWTTO2MzHlU").getSheetByName("Data drop");
sheet.getRange("A:J").clear();
var range_final = sheet.getRange(1,1, data.length,data[0].length);
range_final .setValues(data);
}
How about this modification? In this modification, the mimeType is compared and each script is run. Please think of this as just one of several answers.
Modified script:
function myFunction() {
var thread = GmailApp.getUserLabelByName("Invoicing").getThreads(0,1);
var messages = thread[0].getMessages();
var len = messages.length;
var message = messages[len-1]; //get last message
var attachments = message.getAttachments(); // Get attachment of first message
var blob = attachments[0]; // Is supposes that attachments[0] is the blob of xlsx file.
blob.setContentTypeFromExtension();
if (blob.getContentType() == MimeType.MICROSOFT_EXCEL) {
// Process for XLSX
var convertedSpreadsheetId = Drive.Files.insert({mimeType: MimeType.GOOGLE_SHEETS}, blob).id;
var sheet = SpreadsheetApp.openById(convertedSpreadsheetId).getSheets()[0]; // There is the data in 1st tab.
var data = sheet.getDataRange().getValues();
Drive.Files.remove(convertedSpreadsheetId); // Remove the converted file.
var sheet_new = SpreadsheetApp.openById("1jRh8sj_jAaZKH4xbdpI9Q4to1tKuGWTTO2MzHlU").getSheetByName("Data drop");
sheet_new.clearContents();
var range = sheet_new.getRange(1,1, data.length,data[0].length);
range.setValues(data);
} else if (blob.getContentType() == MimeType.CSV) {
// Process for CSV
var csv = blob.getDataAsString();
var data = Utilities.parseCsv(csv);
var a = data.length ;
var b = data[0].length;
var sheet = SpreadsheetApp.openById("1jRh8sj_jAaZKH4xbdpI9Q4to1tKuGWTTO2MzHlU").getSheetByName("Data drop");
sheet.getRange("A:J").clear();
var range_final = sheet.getRange(1,1, data.length,data[0].length);
range_final.setValues(data);
}
}
Note:
This modified script supposes as follows.
The index of 0 of attachment files is the file you need.
The index of 0 of attachment files is XLSX file or CSV file.
Filenames of XLSX and CSV files have the extension of .xlsx and .csv, respectively.
Reference:
setContentTypeFromExtension()
If I misunderstood your question and this was not the result you want, I apologize.

How to Speed Up Function to Save 1 Sheet as PDF to Google Drive Folder in Google Sheets?

The below code works wonderfully to save only the 'PO Template' sheet of my Google Sheet file in PDF format to the designated Google Drive folder, 'Purchase_Orders'. The only issue is the function takes 10+ seconds to run. Is there something within the code that can be condensed to speed up the script run process for this one?
function checkSheet() {
var sheetName = "POTemplate";
var folderID = "Purchase_Orders";
var sourceSpreadsheet = SpreadsheetApp.getActive();
var sourceSheet = sourceSpreadsheet.getSheetByName(sheetName);
var poNo = sourceSheet.getRange("G5").getValue();
var shipTo = sourceSheet.getRange("E9").getValue();
var pdfName = shipTo + " Purchase Order " + poNo;
var folder = DriveApp.getFoldersByName(folderID);
var destSpreadsheet = SpreadsheetApp.open(DriveApp.getFileById(sourceSpreadsheet.getId()).makeCopy(folder));
var source = destSpreadsheet.getSheetByName(sheetName).getDataRange();
source.copyTo(source, {contentsOnly: true});
var sheets = destSpreadsheet.getSheets();
for (i = 0; i < sheets.length; i++) {
if (sheets[i].getSheetName() != sheetName){
destSpreadsheet.deleteSheet(sheets[i])}};
var theBlob =
destSpreadsheet.getBlob().getAs('application/pdf').setName(pdfName);
var newFile = folder.next().createFile(theBlob);
DriveApp.getFileById(destSpreadsheet.getId()).setTrashed(true);
var strUrl = newFile.getUrl()
var html = HtmlService.createTemplateFromFile("NewTab");
html.strUrl = strUrl
SpreadsheetApp.getUi().showModelessDialog(html.evaluate(),
"Congratulations! "+ pdfName + " is now saved.")
}
There is my Execution transcript of your code.
It seems File.makeCopy takes 50% of time. Also Folder.createFile wants 15%.
This means that your optimization will be minimal in the future.

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.