Trying to delete named external sheets from a container script - google-apps-script

My first time scripting, I'm trying to create an order sheet for outside sales reps, that they can fill out, and click a button to submit a template file. Sheets 0 & 1 are survey questions that fill in references on sheet 2 (Final Product). Sheets 3 & 4 are data validation fields for sheets 0 & 1 including email addresses for recipients.
I am trying to copy a spreadsheet to a new spreadsheet, --> converting a specific sheet from the copy to text so that I can delete all sheets except the converted sheet and not get reference errors --> email converted sheet via pdf format to contacts on sheet 3. My code does it all except delete the 4 sheets that I want to(0,1,3,4). The script is a container script, so whenever I try to call SpreadsheetApp.getActiveSpreadsheet(); It automatically grabs the container file and deletes the 'template' sheets. I need to know how to delete indexes 0,1,3,4 of an external spreadsheet, in a different folder of my drive.
The code below is a hodgepodge of snippets I have butchered and pieced together.
I hope you can understand all of this.
Here is what I have:
function SubmitOnClicks() {
// Set the Active Spreadsheet so we don't forget
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var orderSheet = ss.getSheetByName("Order Sheet");
var ValidationRef = ss.getSheetByName("Validation References");
orderSheet.activate();
// Set the message to attach to the email.
var message = "Please see attached";
// Get Project Name from Range B3:D3
var projectname = ss.getRange("B3").getValues();
// Get BFS Size from Range C25:E25
var size = ss.getRange("C25:E25").getValues();
// Construct the Subject Line
var subject = projectname + " " + size;
// Get contact details from "Validation References" sheet and construct To: Field
var numRows = ValidationRef.getLastRow();
var emailTo = ValidationRef.getRange(2, 12, 5, 2).getValues();
// Google scripts can't export just one Sheet that I know of
var submittalDate = orderSheet.getRange(17, 2).getValues();
var submittalName = "BFS Submittal"
var folderID = "My Drive Folder ID"; // Folder id to save Copy to: MyDrive/_Sheets/Shared/BFS Exports
var folder = DriveApp.getFolderById(folderID);
var sourceSheet = ss.getSheetByName("Order Sheet");
var sourceRange = sourceSheet.getRange(1,1,sourceSheet.getMaxRows(),sourceSheet.getMaxColumns());
var sourcevalues = sourceRange.getValues();
var destSpreadsheet = SpreadsheetApp.open(DriveApp.getFileById(ss.getId()).makeCopy(submittalName, folder))
var destSheet = destSpreadsheet.getSheets()[2];
var destRange = destSheet.getRange(1, 1, destSheet.getMaxRows(), destSheet.getMaxColumns());
// Replace cell values with text (to avoid broken references)
destRange.setValues(sourcevalues);
var files = DriveApp.searchFiles(
'mimeType = "BFS Submittal' + MimeType.GOOGLE_SHEETS + '"');
while (files.hasNext()) {
var spreadsheet = SpreadsheetApp.open(files.next()); //I'm stuck after this Line
var sheet = spreadsheet.getSheets()[0, 1, 3, 4];
}
// Make the PDF, currently called "BFS Submittal.pdf"
var pdf = DriveApp.getFileById(ss.getId()).getAs('application/pdf').getBytes();
var attach = {fileName:'BFS Submittal',content:pdf, mimeType:'application/pdf'};
// Send the freshly constructed email
MailApp.sendEmail(emailTo, subject, message, {attachments:[attach]});
}

Related

Import CSV data into Google sheet by NAME using Google Script - error Sheet is not defined

Please help - I am trying to create a Google script where I can automatically have a csv file that is emailed to me every day be imported into a google sheet by name so that way I can write another script to have a different csv file from a different daily email be imported into the same active google sheet by a different name (i.e. have 2 different sheets by 2 different names in the same Google Active Sheet).
This is my code below but it gives me the ReferenceError: Sheet is not defined for line 8
function importCSVFromGmail() {
var threads = GmailApp.search("Your Aesop Report is Ready (FC Employee Assignment & Demographic)"); // enter search criteria here
var message = threads[0].getMessages()[0];
var attachment = message.getAttachments()[0];
var sheet = SpreadsheetApp.getActiveSpreadsheet(); // runs in the current active sheet
var sheet1 = Sheet.getSheetByName('FC Employee Assignment & Demographic');
var csvData = Utilities.parseCsv(attachment.getDataAsString(), ",");
sheet.clearContents().clearFormats(); // clears target sheet
sheet1.getRange(1, 1, csvData.length, csvData[0].length).setValues(csvData);
GmailApp.markMessagesRead
}
Try this:
function importCSVFromGmail() {
var threads = GmailApp.search("Your Aesop Report is Ready (FC Employee Assignment & Demographic)");
var message = threads[0].getMessages()[0];
var attachment = message.getAttachments()[0];
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet1 = ss.getSheetByName('FC Employee Assignment & Demographic');
var csvData = Utilities.parseCsv(attachment.copyBlob().getDataAsString(), ",");
sheet1.clearContents().clearFormats();
sheet1.getRange(1, 1, csvData.length, csvData[0].length).setValues(csvData);
GmailApp.markMessagesRead(threads[0].getMessages()[0]);
}

Exception: Invalid argument for variable in Google Apps Script

I am trying to link a Google Sheets file with a Google Doc file and replace the text of the Google Docs with some custom items.
Exception: Invalid argument: sheet
autoFillGoogleDocFromForm # Code.gs:5
This error is generated by the following code. I used (name of sheet), (file id inserted), (folder id inserted) instead of showing the actual values.
function autoFillGoogleDocFromForm(e) {
var activateSheet = SpreadsheetApp.getActiveSpreadsheet();
SpreadsheetApp.setActiveSheet(activateSheet.getSheetByName('(name of sheet)'));
var sheet = SpreadsheetApp.getActiveSheet();
var row = e.range.getRowIndex();
var timestamp = sheet.getRange(row, 1).getValues();
var file = DriveApp.getFileById('(file id inserted)');
var folder = DriveApp.getFolderById('(folder id inserted)');
var copy = file.makeCopy('' + timestamp, folder);
var doc = DocumentApp.openById(copy.getId());
var header = doc.getHeader();
header.replaceText('{{TIMESTAMP}}', timestamp);
doc.saveAndClose();
}
You can simplify the way you define a Sheet:
var ss = SpreadsheetApp.getActiveSpreadsheet()
var sheet = ss.getSheetByName('name of the sheet')
Even if you are not going to use the Spreadsheet object any more, you can directly define the Sheet object
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('name of the sheet')
Make sure you write the name of the sheet properly.

Google Sheets Email - Vlookup showing REF value in PDF

Hoping you could help me with this, I have created a system that automatically sends the current sheet as an attachment in an email with body and subject text.
I have one problem that I cant seem to solve; the Vlookup used in the sheet generates either a blank column or a REF! on the emailed PDF. And any info directing to another value from a different sheet (eg ='Sheet2'!D2)
Here is the code used on the sheet triggering the PDF attachment :
function mailCCB() {
var originalSpreadsheet = SpreadsheetApp.getActive(); //get active spreadsheet
var message = "Good Day." + "\n\n" + "Please find attached certificate"; //email body
var certNo = originalSpreadsheet.getRange("C7").getValue(); //certificate number
var cust = originalSpreadsheet.getRange("E10").getValues(); //customer name
var subject = "Certificate " + certNo + " | " + cust; //email subject
var emailTo = originalSpreadsheet.getRange("E13").getValue(); //email address
var sheets = originalSpreadsheet.getSheets(); //get all sheets
var sheetName = originalSpreadsheet.getActiveSheet().getName(); //get current sheet name
var sourceSheet = originalSpreadsheet.getSheetByName(sheetName); //source sheet
// Get folder containing spreadsheet to save pdf in.
var parents = DriveApp.getFileById(originalSpreadsheet.getId()).getParents();
if (parents.hasNext()) {
var folder = parents.next();
}
else {
folder = DriveApp.getRootFolder();
}
SpreadsheetApp.getActiveSpreadsheet().toast("Working on it.. 50%", "Busy",12);
// Copy whole spreadsheet.
var destSpreadsheet = SpreadsheetApp.open(DriveApp.getFileById(originalSpreadsheet.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];
var sourceRange = sourceSheet.getRange(1,1,sourceSheet.getMaxRows(),sourceSheet.getMaxColumns());
var sourcevalues = sourceRange.getValues();
SpreadsheetApp.getActiveSpreadsheet().toast("Working on it.. 60%", "Busy",12);
var destRange = destSheet.getRange(1, 1, destSheet.getMaxRows(), destSheet.getMaxColumns());
destRange.setValues(sourcevalues);
var theBlob = destSpreadsheet.getBlob().getAs('application/pdf').setName(subject);
var newFile = folder.createFile(theBlob);
//*****************************
SpreadsheetApp.getActiveSpreadsheet().toast("Working on it.. 75%", "Busy",12);
// Create a new Spreadsheet and copy the current sheet into it.
var newSpreadsheet = SpreadsheetApp.create("Spreadsheet to export");
var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var projectname = SpreadsheetApp.getActiveSpreadsheet();
sheet = originalSpreadsheet.getActiveSheet();
sheet.copyTo(newSpreadsheet);
var pdf = DriveApp.getFileById(originalSpreadsheet.getId()).getAs('application/pdf').getBytes();
var attach = {fileName:'Klerkscale Certificate',content:pdf, mimeType:'application/pdf'};
MailApp.sendEmail(emailTo, subject, message, {attachments:[theBlob]});
DriveApp.getFileById(newSpreadsheet.getId()).setTrashed(true);
originalSpreadsheet.toast("Certificate will be sent shortly to " + emailTo,"Success",20);
}
This is the cropped received email result :
Ok I saw your problem, you're deleting all the sheets which are being referenced by the active sheet in destSpreadsheet thus they will not be available and the results will be #REF! for each cell referencing those deleted sheets. To solve that problem you could use the getDisplayValues() method, which retrieves the current displayed value of the cell instead of getValues() which retrieves the function(VLOOKUP in this case) set in the cell. Change this line:
var sourcevalues = sourceRange.getValues();
For this:
var sourcevalues = sourceRange.getDisplayValues();
Also, don't delete the other sheets which are being referenced until you have copyied the values to destRange in this line:
destRange.setValues(sourcevalues);

How to append data from Gmail in a new column in Google Sheets using Apps Script?

I have a google sheet where sales data is populated every day for the previous day. I want a time series view of the data by appending the data everyday at a specified time.
Current workflow: Data in email label is pasted into a sheet, removing the existing content.
Required workflow: Data in email label is pasted into a new column in the sheet and does not replace the existing content.
I'm pulling data from my email label to sheets via this code:
function fsn_sales_yday() {
var label = GmailApp.getUserLabelByName("Pan India Yesterday Sales");
var threads = label.getThreads();
//var i = threads.length;
//var threads = GmailApp.search('in:inbox from:"bigfoot-reporting#flipkart.com"');
var message = threads[0].getMessages();
message.reverse();
var attachment = message[0].getAttachments()[0];
attachment.setContentType('text/csv');
var ss = SpreadsheetApp.openById("13uCCKnY4_6F1kn54LQsrIBMTb1yeJH_FXlVN2Frd2EU");
SpreadsheetApp.setActiveSpreadsheet(ss);
sheet = SpreadsheetApp.setActiveSheet(ss.getSheets()[0]);
// Is the attachment a CSV file
if (attachment.getContentType() === "text/csv") {
//var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1");
var csvData = Utilities.parseCsv(attachment.getDataAsString(), ",");
// Remember to clear the content of the sheet before importing new data
sheet.clearContents().clearFormats();
sheet.getRange(1, 1, csvData.length, csvData[0].length).setValues(csvData);
//GmailApp.moveMessageToTrash(message[0]);
}
}
How can I achieve the required result?

google script specify active sheet

and thanks for the help. I've got a noob question, and need a noob answer.
Trying to email a specific google sheet as a pdf weekly, but script emails out whatever sheet happens to be open at the time.
Stole various snippets of code, here's what I've got: (And no, I don't think that this block of code was formatted and posted correctly.)
function endOfWK_1 () {
//This script converts all formulas to values in the currently displayed sheet, then converts the currently displayed sheet to a pdf, then emails the
pdf as an attachment to the addresses shown in cell B17 in the "Email" sheet.
//Replace all formulas in range "WK 1!A6:A29" with values
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('WK 1');
var range = sheet.getRange("WK 1!A6:A29");
range.copyTo(range, {contentsOnly: true});
// FOR WK1 ONLY!!!
// Set the Active Spreadsheet so we don't forget
var originalSpreadsheet = SpreadsheetApp.getActive();
// Set the message to attach to the email.
var message = "Please see attached.";
// Get Dates from Email!B5
var period = originalSpreadsheet.getRange("Email!B5").getValues();
// Construct the Subject Line
var subject = period;
// Get contact details from "Email" sheet and construct To: Header
var contacts = originalSpreadsheet.getSheetByName("Email");
var numRows = contacts.getLastRow();
var emailTo = contacts.getRange(17, 2, numRows, 1).getValues();
// Create a new Spreadsheet and copy the current sheet into it.
var newSpreadsheet = SpreadsheetApp.create("Spreadsheet to export");
var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var projectname = SpreadsheetApp.getActiveSpreadsheet();
sheet = originalSpreadsheet.getActiveSheet();
sheet.copyTo(newSpreadsheet);
// Find and delete the default "Sheet1"
newSpreadsheet.getSheetByName('Sheet1').activate();
newSpreadsheet.deleteActiveSheet();
// Create the PDF, currently called "Tracking Sheet.pdf"
var pdf = DriveApp.getFileById(newSpreadsheet.getId()).getAs('application/pdf').getBytes();
var attach = {fileName:'Tracking Sheet.pdf',content:pdf, mimeType:'application/pdf'};
// Send the freshly constructed email
MailApp.sendEmail(emailTo, subject, message, {attachments:[attach]});
// Delete the sheet that was created
DriveApp.getFileById(newSpreadsheet.getId()).setTrashed(true);
// Write the date and time that the script ran
var date = sheet.getRange('Statistics!A1').getValues();
SpreadsheetApp.getActiveSheet().getRange('Analysis!E5').setValues(date);
}
This is a bound script, attached to a google workbook containing 5 sheets. My problem is that my script always emails the sheet that happens to be open at the time.
I want to email one specific sheet, whether the workbook is open or closed. How can I do this? (I hope to install a trigger to make this script run automatically.)
Also, anyone want to critique my code?
Thanks to all.
I've fixed it up a little and added some comments. There were a lot of little things I fixed up biggest thing was that you should reuse variables that you've created.
This hasn't been tested...
function endOfWK_1 () {
//Replace all formulas in range "WK 1!A6:A29" with values
var activeSpreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var sheetWK1 = activeSpreadsheet.getSheetByName('WK 1');
var range = sheetWK1.getRange("WK 1!A6:A29");
range.copyTo(range, {contentsOnly: true});
// FOR WK1 ONLY!!!
// Set the Active Spreadsheet so we don't forget
var originalSpreadsheet = SpreadsheetApp.getActive(); //this should probably be changed depending on what sheet you are trying to access: activeSpreadsheet.getSheetByName('Email')
// Set the message to attach to the email.
var message = "Please see attached.";
// Get Dates from Email!B5
var period = originalSpreadsheet.getRange("Email!B5").getValues();
// Construct the Subject Line
var subject = period;
// Get contact details from "Email" sheet and construct To: Header
var contacts = originalSpreadsheet.getSheetByName("Email");
var numRows = contacts.getLastRow();
var emailTo = contacts.getRange(17, 2, numRows, 1).getValues();
// Create a new Spreadsheet and copy the current sheet into it.
var newSpreadsheet = SpreadsheetApp.create("Spreadsheet to export"); //Create a spreadsheet to copy to
// var originalSheet = activeSpreadsheet.getSheetByName("WK1"); Already defined above as sheetWK1
//var projectname = SpreadsheetApp.getActiveSpreadsheet(); Seems like this is not used.
sheetWK1.copyTo(newSpreadsheet); //Take the original sheet and copy it to the newSpreadsheet
// Find and delete the default "Sheet1"
newSpreadsheet.deleteSheet(newSpreadsheet.getSheetByName("Sheet1")); //We can just call the deleteSheet method.
// Create the PDF, currently called "Tracking Sheet.pdf"
var pdf = newSpreadsheet.getAs('application/pdf').getBytes(); //No need to get the Spreadsheet object again, as we alreat have it!
var attach = {fileName: 'Tracking Sheet.pdf', content: pdf, mimeType: 'application/pdf'};
// Send the freshly constructed email
MailApp.sendEmail(emailTo, subject, message, {attachments:[attach]});
// Delete the sheet that was created
newSpreadsheet.setTrashed(true); //Again no need to find the object. We have it.
// Write the date and time that the script ran
var date = sheet.getRange('Statistics!A1').getValues();
activeSpreadsheet.getRange('Analysis!E5').setValues(date);
}
The main issue was var originalSpreadsheet = SpreadsheetApp.getActive(); you are getting the active sheet and using that to create you pdf.
EDIT: I've cleaned up the whole thing a little and ended up with this. It hasn't been tested.
function endOfWK_1 () {
//Replace all formulas in range "WK 1!A6:A29" with values
var activeSpreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var sheetWK1 = activeSpreadsheet.getSheetByName('WK 1');
var emailSheet = activeSpreadsheet.getSheetByName("Email");
var range = sheetWK1.getRange("WK 1!A6:A29");
range.copyTo(range, {contentsOnly: true});
// FOR WK1 ONLY!!!
// Set the message to attach to the email.
var message = "Please see attached.";
// Get Dates from Email!B5
var period = emailSheet.getRange("Email!B5").getValues();
// Construct the Subject Line
var subject = period;
// Get contact details from "Email" sheet and construct To: Header
var numRows = emailSheet.getLastRow();
var emailTo = emailSheet.getRange(17, 2, numRows, 1).getValues();
// Create a new Spreadsheet and copy the current sheet into it.
var newSpreadsheet = SpreadsheetApp.create("Spreadsheet to export");
sheetWK1.copyTo(newSpreadsheet);
// Find and delete the default "Sheet1"
newSpreadsheet.deleteSheet(newSpreadsheet.getSheetByName("Sheet1"));
// Create the PDF, currently called "Tracking Sheet.pdf"
var pdf = newSpreadsheet.getAs('application/pdf').getBytes();
var attach = {fileName: 'Tracking Sheet.pdf', content: pdf, mimeType: 'application/pdf'};
// Send the freshly constructed email
MailApp.sendEmail(emailTo, subject, message, {attachments:[attach]});
// Delete the sheet that was created
DriveApp.getFileById(newSpreadsheet.getId()).setTrashed(true);
// Write the date and time that the script ran
var date = activeSpreadsheet.getRange('Statistics!A1').getValues();
activeSpreadsheet.getRange('Analysis!E5').setValues(date);
}