How to send selected cells from google sheets via appscript? - javascript

hello is any one familiar with app scripts?
I'm sending data from unity app to google sheets form then to template, send to a new spreadsheet be converted into pdf with needed data and then send as email,
I'm having trouble with the sheets, I have the where what I want to send should not go pass row 86.
In the email I get all rows of the new spreadsheet which is sending 7 pages, I only need one page to send for this or one range A1:AX86, I've been trying multiple solutions, anyone have a take on this
Thanks,
typefunction sendPdfEmailWithLatestData() {
// Constants
const SPREADSHEET_ID = SpreadsheetApp.getActiveSpreadsheet().getId();
const FORM_RESPONSE_SHEET_NAME = 'FormResponses';
const PERIODONTAL_CHART_SHEET_NAME = 'Periodontal Chart';
const EMAIL_SUBJECT = 'Periodontal Chart';
const EMAIL_BODY = 'Attached is the Periodontal Chart for your review.';
// Get the active spreadsheet and the sheets by their name
const activeSpreadsheet = SpreadsheetApp.getActiveSpreadsheet();
const formResponseSheet = activeSpreadsheet.getSheetByName(FORM_RESPONSE_SHEET_NAME);
const periodontalChartSheet = activeSpreadsheet.getSheetByName(PERIODONTAL_CHART_SHEET_NAME);
// Get the range of all data in the FormResponses sheet, including the header row
const formResponseDataRange = formResponseSheet.getDataRange();
const numRows = formResponseDataRange.getNumRows();
const numColumns = formResponseDataRange.getNumColumns();
const values = formResponseDataRange.getValues();
// Get the values from the latest row in the FormResponses sheet
const headerRow = values[0]; // first row is the header row
const latestRow = values[numRows - 1]; // last row is the latest row
const patientLastName = latestRow[headerRow.indexOf('Last Name')];
const patientFirstName = latestRow[headerRow.indexOf('First Name')];
const patientDateOfBirth = latestRow[headerRow.indexOf('Date of Birth')];
const appointmentDate = latestRow[headerRow.indexOf('Date')];
const appointmentTime = latestRow[headerRow.indexOf('Time')];
const appointmentVisit = latestRow[headerRow.indexOf('Visit')];
const patientEmail = latestRow[headerRow.indexOf('Email')];
// Update the values in the Periodontal Chart sheet
const columnNames = ['E7:L7', 'Q7:X7', 'AC7:AJ7', 'AM7:AO7', 'AR7:AT7', 'AW7:AX7'];
columnNames.forEach(function(columnName) {
// Clear the contents of the cells in the specified column
periodontalChartSheet.getRange(columnName).clearContent();
});
const valuesToSet = [patientLastName, patientFirstName, patientDateOfBirth, appointmentDate, appointmentTime, appointmentVisit];
columnNames.forEach((columnName, index) => {
periodontalChartSheet.getRange(columnName).setValue(valuesToSet[index]);
});
// Convert the active spreadsheet to a PDF file and save it to Google Drive
const pdf = DriveApp.createFile(activeSpreadsheet.getAs('application/pdf'));
pdf.setName('Periodontal Chart.pdf');
// Send the email with the PDF file attached
//GmailApp.sendEmail(patientEmail, EMAIL_SUBJECT, EMAIL_BODY, {attachments: [pdf]});
// Delete the PDF file from Google Drive
pdf.setTrashed(true);
console.log(`Latest row: ${latestRow}`);
copySheetAndSendEmail(SpreadsheetApp.getActiveSpreadsheet(), patientEmail, "Periodontal Chart", "Attached is the Periodontal Chart for your review.",PERIODONTAL_CHART_SHEET_NAME);
}
function copySheetAndSendEmail(sourceSpreadsheet, emailAddress, emailSubject, emailBody, PERIODONTAL_CHART_SHEET_NAME) {
// Get the source sheet
const periodontalChartSheet = sourceSpreadsheet.getSheetByName(PERIODONTAL_CHART_SHEET_NAME);
// Create a new spreadsheet
var newSpreadsheet = SpreadsheetApp.create("Periodontal Chart");
// Copy the sheet to the new spreadsheet, including data and formatting
periodontalChartSheet.copyTo(newSpreadsheet).setName("Periodontal Chart.pdf");
// Get all sheets in the newSpreadsheet
var sheets = newSpreadsheet.getSheets();
// Loop through all sheets
for (var i = 0; i < sheets.length; i++) {
var sheet = sheets[i];
// If the sheet is not the Periodontal Chart sheet, delete it
if (sheet.getName() != "Periodontal Chart.pdf") {
newSpreadsheet.deleteSheet(sheet);
}
}
var sheet = SpreadsheetApp.getActiveSheet();
for(var i=87;i<=sheet.getLastRow();i++){
sheet.hideRow(i);
}
// Convert the specified range of cells to a PDF file and save it to Google Drive
const pdf2 = DriveApp.createFile(newSpreadsheet.getAs('application/pdf'));
// Send the email with the PDF file attached
GmailApp.sendEmail(emailAddress, emailSubject, emailBody, {attachments: [pdf2]});
// Delete the new spreadsheet
pdf2.setTrashed(true);
} here
If I manually goto file download in sheets I will get the export options for the pdf, though I'm not sure how to fully implement via app scripts

Related

copyTo Google Sheets Script for Send data workbook

I am very new to Javascript and Apps Script. I want to create a function that updates another sheet based on a date in a certain range of the active sheet. I run and no error but it doesn't transfer value from active sheet to sheet named "Master", in different target url google sheet
data master post
output 1
output 2
output 3
function updateYTD4() {
const ss = SpreadsheetApp.getActiveSpreadsheet();
const sheet = ss.getSheetByName("January");
const targetSheet = ss.getSheetByName("Master");
if (sheet && targetSheet) {
if(sheet.getRange("A2:D32").getValues().length > 0){
sheet.getRange("A2:D32").copyTo(targetSheet.getRange("C"+(targetSheet.getLastRow()+1)),
{contentsOnly:true});
}
}
}
copyTo Google Sheets Script for different workbook how targetSheet change to send data sheet to output 1 , output 2, output 3 ( with a different workbook url )
As another approach, how about the following sample script?
I believe your goal is as follows.
You want to use both the source Spreadsheet and the target Spreadsheet.
The source Spreadsheet is the active Spreadsheet, and the target Spreadsheet is a different Spreadsheet from the source Spreadsheet.
Modification points:
In the current stage, when the source Spreadsheet is different from the target Spreadsheet, copyTo of Class Range cannot be used. When this is used an error like Exception: Target range and source range must be on the same spreadsheet. occurs. Please be careful about this.
In the case of sheet.getRange("A2:D32").getValues().length > 0, even when "A2:D32" are empty, the length is always 31. Please be careful about this.
In your situation, it seems that you want to copy only the values. So, how about using getValues and setValues? When these points are reflected in your script, how about the following modification?
Modified script:
function myFunction1() {
const srcSpreadsheet = SpreadsheetApp.getActiveSpreadsheet();
const dstSpreadsheet = SpreadsheetApp.openById("###"); // Please set your spreadsheet ID.
const srcSheet = srcSpreadsheet.getSheetByName("January");
const targetSheet = dstSpreadsheet.getSheetByName("Master");
if (srcSheet && targetSheet) {
const values = srcSheet.getRange("A2:D32").getValues();
if (values.filter(r => r.join("")).length > 0) {
targetSheet.getRange(targetSheet.getLastRow() + 1, 3, values.length, values[0].length).setValues(values);
}
}
}
If you have multiple Spreadsheet IDs, how about the following sample script?
function myFunction2() {
const spreadsheetIds = ["###", "###", "###"];// Please set your spreadshet IDs.
const srcSpreadsheet = SpreadsheetApp.getActiveSpreadsheet();
const srcSheet = srcSpreadsheet.getSheetByName("January");
if (!srcSheet) return;
const values = srcSheet.getRange("A2:D32").getValues();
if (values.filter(r => r.join("")).length == 0) return;
for (let i = 0; i < spreadsheetIds.length; i++) {
const dstSpreadsheet = SpreadsheetApp.openById(spreadsheetIds[i]);
const targetSheet = dstSpreadsheet.getSheetByName("Master");
if (targetSheet) {
targetSheet.getRange(targetSheet.getLastRow() + 1, 3, values.length, values[0].length).setValues(values);
}
}
}
References:
copyTo(destination, options)
getValues()
setValues(values)
That's because you're handling different workbooks.
const ss = SpreadsheetApp.getActiveSpreadsheet(); will only refer to the workbook from which you run the script.
You should add a new variable for the other sheet:
const newss = SpreadsheetApp.openById("1jQ93ylP0MHzSzxH0myS9_AhTjetdvLQMXvFwg18XFEE")
I've put the ID from the link from the mastersheet, but adapt accordingly to your needs. Then you can use newss.getSheetByName("Sheet you need")
UPDATE
Possible code, if I understand you well:
function updateYTD4() {
const ss = SpreadsheetApp.getActiveSpreadsheet();
const newss = SpreadsheetApp.openById("1jQ93ylP0MHzSzxH0myS9_AhTjetdvLQMXvFwg18XFEE")
const sheet = ss.getSheetByName("January");
const targetSheet = newss.getSheetByName("Master");
if (sheet && targetSheet) {
if(sheet.getRange("A2:D32").getValues().length > 0){
sheet.getRange("A2:D32").copyTo(targetSheet.getRange("C"+(targetSheet.getLastRow()+1)),
{contentsOnly:true});
}
}
}

For each row in source, if cell of one column isn't empty, copy specific column data from row into specific columns of other sheet. (Apps Scripts)

Context
I'm using Google Apps Scripts to automate some things in Google Sheets. Currently, I can copy the column data for every row without issue. However, I only need to copy rows that aren't empty in a specific column (G) and can't figure out where/how to implement the conditional.
Goal
For each row in the source sheet, check if cell in column G is empty.
If cell is not empty, copy parts of that row to other sheet.
Here is the current script:
function theme_copy_WIP () {
let workbook = SpreadsheetApp.getActiveSpreadsheet(); // get the active sheets workbook
let auditSheet = SpreadsheetApp.getActiveSheet(); // active sheet of workbook to copy from (source)
let auditRangeList = auditSheet.getRangeList(["A2:A", "B2:B", "C2:C", "E2:E", "G2:G", "H2:H"]); //Range of columns to copy data from
let themeSheet = workbook.getSheetByName("Themes"); //themes sheet to paste into (destination)
let destRangeList = themeSheet.getRangeList(["A2:A", "B2:B", "C2:C", "D2:D", "E2:E", "F2:F"]); //Range of destination columns to paste into
for( let i=0; i<auditRangeList.getRanges().length; i++ ) {
let auditRange = auditRangeList.getRanges()[i];
let destRange = destRangeList.getRanges()[i];
auditRange.copyTo(destRange, {contentsOnly: true});
}
}
Copy Values
function myfunk() {
const ss = SpreadsheetApp.getActive();
const ssh = ss.getActiveSheet();
const svs = ssh.getRange(2, 1, ssh.getLastRow() - 1, ssh.getLastColumn()).getValues();
const tsh = ss.getSheetByName("Sheet0");
const tlr = tsh.getLastRow();
if (tlr > 1) {
tsh.getRange(2, 1, tsh.getLastRow() - 1, 6).clearContent();
}
let tvs = svs.map(r => {
if (r[6]) {
return [r[0], r[1], r[2], r[4], r[6], r[7]];
}
}).filter(r => r );
if (tvs && tvs.length > 0) {
tsh.getRange(2, 1, tvs.length, tvs[0].length).setValues(tvs);
}
}
Instead of using rangeList, get the full range, modify it and set back the modified range.
const out = auditSheet
.getRange("A2:H"+auditSheet.getLastRow())
.getValues()
.reduce((acc,[a,b,c,d,e,f,g,h]) => (g && acc.push([a,b,c,e,g,h]),acc),[])
themeSheet
.getRange(2,1,out.length, out[0].length)
.setValues(out)

Get a List of Drive Files Into a Google Sheet

var folder = DriveApp.getFolderById('1_gA4D7dfybJ60IdfgsnqdfdsgVoo9D76fgsdgf9cqmAnJI7g7');
var contents = folder.getFiles();
var file;
var name;
var sheet = SpreadsheetApp.getActiveSheet();
var date;
var size;
sheet.clear();
sheet.appendRow(["Nome", "Data", "Dimensione"]);
while(contents.hasNext()) {
file = contents.next();
name = file.getName();
date = file.getDateCreated();
size = file.getSize();
id = file.getUrl();
data = [name, date, size,id]
sheet.appendRow(data);
}
};
Every time all the data is cleared, after that the data is added from the starting.
sheet.clear();sheet.appendRow(["Nome", "Data", "Dimensione"]);
Is there any way to check the data?
if the same data present Already then the function does not work on the row.
If a new record is added, it should also be added, but the function does not start again from one.
If I have 20 PDFs in my folder, and add one more PDF in folder, then add the function 21 pdf and do not run the function from the beginning.
Explanation:
The logic behind the following script is the following:
We get all the URLs of the files that are currently in column D of the sheet. These are the URLs of the files that have been recorder so far. We can safely assume that the URLs are always unique:
const aURLs = sheet.getRange('D2:D'+sheet.getLastRow()).getValues().flat();
The second step is to iterate through the files as the original script would do and check if the URL of a file is in aURLs. If the file URL is not in aURLs or in other words in column D, then add it to the newFiles array:
if(!uNames.includes(name)){
newFiles.push(data);
}
After we checked all the files, we can add, after the last row of sheet, only the new files:
sheet.getRange(sheet.getLastRow()+1,1,newFiles.length,newFiles[0].length).setValues(newFiles);
Solution:
Manually add the headers in the file for the first time only:
and then execute the script every next time:
function myFunction() {
const folder = DriveApp.getFolderById('1_gA4D7dfybJ60IdfgsnqdfdsgVoo9D76fgsdgf9cqmAnJI7g7');
const contents = folder.getFiles();
const sheet = SpreadsheetApp.getActiveSheet();
const aURLs = sheet.getRange('D2:D'+sheet.getLastRow()).getValues().flat();
const newFiles = [];
while(contents.hasNext()) {
let file = contents.next();
let name = file.getName();
let date = file.getDateCreated();
let size = file.getSize();
let id = file.getUrl();
let data = [name, date, size,id]
if(!aURLs.includes(id)){
newFiles.push(data);
}
}
sheet.getRange(sheet.getLastRow()+1,1,newFiles.length,newFiles[0].length).setValues(newFiles);
}

Attach multiple files - Google Sheets/Gmail/Drive

I currently have a script to create draft emails and also attach a file to them. Currently, the script does not work for multiple file attachments and also does not work if there are no attachments.
Any tips on how to get (1) and (2) [below]
Updated for more info:
Main objective is to add a multiple file names in Col[3] and attaching the files to the draft using the files names provided in Col[3]. Example: if I type the following into Col[3]: "test.pdf, test2.pdf"
it will attach the files "test.pdf" & "test2.pdf" for that particular draft.
At the moment, the script does attach a single file to a draft, but if I enter multiple file names separated by comas it does not create a draft at all.
I've attach a screenshot of how the spreadsheet looks like below when I run the script (I currently cannot embed pictures):
https://imgur.com/a/sVoHO3Q
When I run the script using the info from the screenshot, the 2nd row does not create a draft at all, the 3rd row creates a draft with the attachment and the 4th row does not create a draft at all.
Would it be possible to create a draft and attach multiple files using filenames separated by comas and also create drafts when some cells in Col[3] is empty?
TLDR:
How to attach multiple files to individual drafts
How to create a draft without any attachments
function SaveDrafts() {
var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 2;
var rows = 1000;
var dataRange = sheet.getRange(startRow, 1, rows, 5);
var data = dataRange.getValues();
for (i in data) {
var row = data[i];
var emailAddress = row[0];
var subject = row[1];
var message = row[2];
var pdfName = row[3];
var cc = row[4];
var list = DriveApp.getFilesByName(pdfName);
if (list.hasNext()) {
var File = list.next();
GmailApp.createDraft(emailAddress, subject, message, {
cc: cc,
attachments: [File]
});
}
}
}
Update:
First off, I performed a split() on the values of the pdfName cell so I could search for and add one file at a time.
The draft creation would only run if there were files because it was inside the list if statement, no files meant it would not run.
I pulled it out of that and created an interator for list and a files array that can be given to the createDraft() function. The iterator allows multiple Files to be added to the files array if the DriveApp.getFilesByName(pdfName) returns multiple Files.
function SaveDrafts() {
var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 2;
var rows = 1000;
var dataRange = sheet.getRange(startRow, 1, rows, 5);
var data = dataRange.getValues();
for (i in data) {
var row = data[i];
var emailAddress = row[0];
var subject = row[1];
var message = row[2];
var pdfName = row[3].split(','); //split the values taken from cell into array
var cc = row[4];
var files = []; //initialize files as empty array.
for(var j in pdfName){ //run through cell values and perform search
var results = DriveApp.getFilesByName(pdfName[j]); //Perform the search,results is a FileIterator
while(results.hasNext()) { //Interate through files found and add to attachment results
files.push(results.next()); //Add files to array
}
}
GmailApp.createDraft(emailAddress, subject, message, {
cc: cc,
attachments: files //the attachments option takes our files array
});
}
}

If matching content move to new sheet

I am writing a script that looks through a list of suppliers, then needs to create a new sheet for each of them and import the information for that supplier into that sheet.
So far, I have the following:
function getData() {
var masterSS = SpreadsheetApp.getActiveSpreadsheet() || SpreadsheetApp.openById("xxx");
var supSS = masterSS.getSheetByName("Suppliers");
masterSS.setActiveSheet(supSS)
var supSR = 2;
var supNoRows = supSS.getLastRow() - 1;
var supRange = supSS.getRange(supSR, 1, supNoRows, masterSS.getLastColumn());
var supData = supRange.getValues();
var orderSS = masterSS.getSheetByName("Orders");
var orderData = orderSS.getRange("A2:AB").getValues();
var templateSS = masterSS.getSheetByName("Template");
supData.forEach(function(name) {
var newSheet = masterSS.insertSheet(name, {template: templateSS});
console.log(name)
});
}
This is working as intended and is creating a sheet for each supplier listed on the Supplier sheet. I then need it to look through a range on a sheet called Orders, and if A2:A matches the supplier name used to create the new sheet, import that row to the newly created sheet.
I can't figure out quite how to get this working, as I would need to do it as each sheet is created. Anyone able to point me in the right direction?

Categories