function arrayMail(){
var ss=SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Sheet1');
var startRow = 2;
var lastRow = sheet.getLastRow();
var lastColumn = sheet.getLastColumn();
var range = sheet.getRange(startRow,1,lastRow,lastColumn);
var data = range.getValues();
var array = [];
for(var i=0;i<data.length;++i){
var row = data[i];
var rowTemp=[]; //create a blank array that will hold only the desired columns in this row
for (var j=0; j<row.length; j++)//iterates through columns
{
if(j==4||j==3||j==1||j==5){continue;}
rowTemp.push(row[j])
}
var emailPos = row[3];
var date = row[2];
if(emailPos =='example4#gmail.com'&& date == 0){
array.push(rowTemp);
}
}
GmailApp.sendEmail('example1#gmail.com','This is a test',array.join('\n\n'));
}
Above script I used for me sending email when date count is 0 and the email become the reference who to email. I wanted to make the array (which is in plain text if using script above) become a table format. I'm stuck with the table formatting. The question is, how do I make it in table format here? Beginner level in scripting
After reading from book/examples, I came up with below script. But it doesn't work as intended;
function arrayMail(){
var ss=SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Sheet1');
var startRow = 2;
var lastRow = sheet.getLastRow();
var lastColumn = sheet.getLastColumn();
var range = sheet.getRange(startRow,1,lastRow,lastColumn);
var data = range.getValues();
var tableStart = "<table border=\"1\"><tr>";
var tableEnd = "</tr></table>";
var array = [];
for(var i=0;i<data.length;++i){
var row = data[i];
var rowTemp=[]; //create a blank array that will hold only the desired columns in this row
for (var j=0; j<row.length; j++)//iterates through columns
{
if(j==4||j==3||j==1||j==5){continue;}
rowTemp.push('<td>'+row[j]+'</td>');
}
var emailPos = row[3];
var date = row[2];
if(emailPos =='example4#gmail.com'&& date == 0){
array.push(rowTemp);
}
}
var HTMLbody = tableStart +array.join('')+tableEnd;
GmailApp.sendEmail('example#gmail.com','This is a test',HTMLbody,{htmlBody:HTMLbody});
}
Result:
What I wanted to be is like;
Infusion Pump 0
Infusion Pump 0
This is not a full answer but the code below translates the array to the string you asked about in your Google+ post...
var array = [
['Infusion Pump', 'B', 'C', 'D', 'E', 'F'],
['Another Pump', 'B', 'C', 'D', 'E', 'F'],
['Defib', 'B', 'C', 'D', 'E', 'F']
];
var str = '';
for (var i = 0; i < array.length; i++) {
str = str + '<tr>';
for (var j = 0; j < array[i].length; j++) {
str = str + '<td>' + array[i][j] + '</td>';
}
str = str + '</tr>';
}
console.log(str);
Based on SamScholefield's answer I did modified his code a bit to suit my need and here is the final code:
function arrayMail(){
var ss=SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Sheet1');
var startRow = 2;
var lastRow = sheet.getLastRow();
var lastColumn = sheet.getLastColumn();
var range = sheet.getRange(startRow,1,lastRow,lastColumn);
var data = range.getValues();
var array = [];
for(var i=0;i<data.length;++i){
var row = data[i];
var rowTemp=[]; //create a blank array that will hold only the desired columns in this row
for (var j=0; j<row.length; j++){ //iterates through columns
if(j==4){continue;}
rowTemp.push(row[j]);
}
var emailPos = row[3];
var date = row[2];
if(emailPos =='example1#gmail.com'&& date == -28){
array.push(rowTemp);
}
}
var str = '';
var bodyEnd = '</table>';
var header = '<table border =1><tr><th>Message</th><th>Date Remind</th><th>Days Left</th><th>Email Address</th><th>Status</th></tr>';
for (var k = 0; k < array.length; k++) {
str = str + '<tr>';
for (var l = 0; l < array[k].length; l++) {
str = str + '<td>' + array[k][l] + '</td>';
}
str = str + '</tr>';
var msg = header+str+bodyEnd;
}
GmailApp.sendEmail(Session.getActiveUser().getEmail(),'This is a test',msg, {htmlBody:msg});
};
Result
Related
In a google sheets table, I use a script that allows me to count the cells in color in a column that displays dates as values. Each date over 11 days is colored in red, and my script works very well.
In another column, I indicate the name of each salesman.
What I would like is to be able to count the number of red cells that belong to each salesman.
The date column is column "G" and the salesman column is column "F" (In my script it doesn't matter because I indicate in which column to count).
My Sheet:
https://docs.google.com/spreadsheets/d/1BFd57xpFOJMOAjuRaiO6_cLCMMxQKDwi_TB6dOCDb9A/edit#gid=0
The formula for my script is:
=CompteCouleurs($G6:$G;C4)
"$G6:$G" is the range to count
"C4" is the sample of the color to search
My script is:
function SommeCouleurs(plage,couleur) {
var activeRange = SpreadsheetApp.getActiveRange();
var activeSheet = activeRange.getSheet();
var formule = activeRange.getFormula();
var laplage = formule.match(/\((.*)\;/).pop();
var range = activeSheet.getRange(laplage);
var bg = range.getBackgrounds();
var values = range.getValues();
var lacouleur = formule.match(/\;(.*)\)/).pop();
var colorCell = activeSheet.getRange(lacouleur);
var color = colorCell.getBackground();
var total = 0;
for(var i=0;i<bg.length;i++)
for(var j=0;j<bg[0].length;j++)
if( bg[i][j] == color )
total=total+(values[i][j]*1);
return total;
};
function CompteCouleurs(plage,couleur) {
var activeRange = SpreadsheetApp.getActiveRange();
var activeSheet = activeRange.getSheet();
var formule = activeRange.getFormula();
var laplage = formule.match(/\((.*)\;/).pop();
var range = activeSheet.getRange(laplage);
var bg = range.getBackgrounds();
var values = range.getValues();
var lacouleur = formule.match(/\;(.*)\)/).pop();
var colorCell = activeSheet.getRange(lacouleur);
var color = colorCell.getBackground();
var count = 0;
for(var i=0;i<bg.length;i++)
for(var j=0;j<bg[0].length;j++)
if( bg[i][j] == color )
count=count+1;
return count;
};
First, expand your area to G and F =CompteCouleurs($F6:$G;C4)
Then as you only take column G into account, you can omit for(var j=0;j<bg[0].length;j++)
Therefore you can check color in G and salesman in F as follows if( bg[i][1] == color && values[i][0] == salesman )
If you want to include the salesman as parameter, you will have to change the regex as follows to retrieve each argument (args will be an array)
var args = formule.match(/\(.*\)/g)[0].match(/[A-Z0-9:]+/g)
I recommand also to add a dummy parameter (checkbox) to update the calculation
Correction of your script:
function compteCouleursSi(plage, couleur, vendeur) {
var activeRange = SpreadsheetApp.getActiveRange();
var activeSheet = activeRange.getSheet();
var formule = activeRange.getFormula();
// array of arguments
var args = formule.match(/(?<=\().*(?=\))/g)[0].split(/[;|,]/)
var laplage = args[0];
if (laplage.includes('!')) {
var range = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(laplage.split('!')[0].replace(/'/g,'')).getRange(laplage.split('!')[1].trim());
}else{
var range = activeSheet.getRange(laplage);
}
var bg = range.getBackgrounds();
var values = range.getValues();
var lacouleur = args[1];
var color = activeSheet.getRange(lacouleur).getBackground();
var salesman = args[2];
var who = activeSheet.getRange(salesman).getValue()
var total = 0;
for (var i = 0; i < bg.length; i++)
if (bg[i][1] == color && values[i][0] == who)
total += 1;
return total;
};
function sommeCouleursSi(plage, couleur, vendeur) {
var activeRange = SpreadsheetApp.getActiveRange();
var activeSheet = activeRange.getSheet();
var formule = activeRange.getFormula();
// array of arguments
var args = formule.match(/(?<=\().*(?=\))/g)[0].split(/[;|,]/)
var laplage = args[0];
if (laplage.includes('!')) {
var range = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(laplage.split('!')[0].replace(/'/g,'')).getRange(laplage.split('!')[1].trim());
}else{
var range = activeSheet.getRange(laplage);
}
var bg = range.getBackgrounds();
var values = range.getValues();
var lacouleur = args[1];
var color = activeSheet.getRange(lacouleur).getBackground();
var salesman = args[2];
var who = activeSheet.getRange(salesman).getValue()
var total = 0;
for (var i = 0; i < bg.length; i++)
if (bg[i][1] == color && values[i][0] == who)
total += values[i][1];
return total;
};
Just started learning Javascript/Google Apps Script, so please be patient with me.
My goal is to create an automated email script that emails a reminder when the inventory stock has dipped below a certain level.
To start, I have a Google Sheet with 3 tabs: ContactSheet, ReorderSheet, and EmailSheet. These tabs have columns, respectively: person's name and email address; item name, number, manufacturer, current stock, and threshold for reorder; subject line and message.
Code below. No runtime errors, but the emails either do not send or they send out for only the first or last item in the spreadsheet. (Should be sending out exactly 5 emails for 5 different items.) I think the issue is with the if statement --- I'm assuming that the variables are not able to call on their respective indices, if that makes sense. I've tried converting the variables to arrays with no success. This version works best according to the logger, and only breaks down at the last block.
Thanks in advance.
function sendEmail() {
var Spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var ContactSheet = Spreadsheet.getSheetByName('ContactSheet');
var ReorderSheet = Spreadsheet.getSheetByName('ReorderSheet');
var EmailSheet = Spreadsheet.getSheetByName('EmailSheet');
var SubjectLine = EmailSheet.getRange(2,1).getValue();
var Message = EmailSheet.getRange(2,2).getValue();
var N = ReorderSheet.getLastRow();
for(var i = 2; i < N+1; i++) {
var ItemName = ReorderSheet.getRange(i,1).getValue();
var ItemNumber = ReorderSheet.getRange(i,2).getValue();
var ItemManufacturer = ReorderSheet.getRange(i,3).getValue();
var ItemStock = ReorderSheet.getRange(i,4).getValue();
var ItemReorder = ReorderSheet.getRange(i,5).getValue();}
var M = ContactSheet.getLastRow();
for(var j = 2; j < M+1; j++) {
var Name = ContactSheet.getRange(j,1).getValue();
var EmailAddress = ContactSheet.getRange(j,2).getValue();}
if (ItemStock < ItemReorder) {
SubjectLine = SubjectLine.replace("<item>",ItemName);
Message = Message.replace("<name>",Name).replace("<item>",ItemName).replace("<itemnumber>",ItemNumber).replace("<manufacturer>",ItemManufacturer);
MailApp.sendEmail(EmailAddress, SubjectLine, Message);}
}
This for loop does not contain the sendEmail method:
for (var i = 2; i < N + 1; i++) {
var ItemName = rsh.getRange(i, 1).getValue();
var ItemNumber = rsh.getRange(i, 2).getValue();
var ItemManufacturer = rsh.getRange(i, 3).getValue();
var ItemStock = rsh.getRange(i, 4).getValue();
var ItemReorder = rsh.getRange(i, 5).getValue();
}
So your always only dealing with the data on the last row
Same with this one:
for (var j = 2; j < M + 1; j++) {
var Name = csh.getRange(j, 1).getValue();
var EmailAddress = csh.getRange(j, 2).getValue();
}
This structure will send emails to every email address:
function sendEmail() {
var ss = SpreadsheetApp.getActive();
var csh = ss.getSheetByName('ContactSheet');
var rsh = ss.getSheetByName('ReorderSheet');
var esh = ss.getSheetByName('EmailSheet');
var subject = esh.getRange(2, 1).getValue();
var message = esh.getRange(2, 2).getValue();
var N = rsh.getLastRow();
var M = csh.getLastRow();
for (var j = 2; j < M + 1; j++) {
var Name = csh.getRange(j, 1).getValue();
var EmailAddress = csh.getRange(j, 2).getValue();
for (var i = 2; i < N + 1; i++) {
var ItemName = rsh.getRange(i, 1).getValue();
var ItemNumber = rsh.getRange(i, 2).getValue();
var ItemManufacturer = rsh.getRange(i, 3).getValue();
var ItemStock = rsh.getRange(i, 4).getValue();
var ItemReorder = rsh.getRange(i, 5).getValue();
if (ItemStock < ItemReorder) {
subject = subject.replace("<item>", ItemName);
message = message.replace("<name>", Name).replace("<item>", ItemName).replace("<itemnumber>", ItemNumber).replace("<manufacturer>", ItemManufacturer);
MailApp.sendEmail(EmailAddress, subject, message);
}
}
}
}
function myFunction() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('data');
var data = sheet.getDataRange().getValues();
var range = sheet.getRange("A1:L" + data.length);
range.sort(1);
const people = {};
for(var i = 0; i < data.length; i++) {
var name = data[i][0] + data[i][1];
console.log(i);
if (!people.name) {people.name = {rows: [i]};} else {people.name.rows.push(i)}
}
Logger.log(people);
}
What should I be doing differently? At the end, it logs {name={rows=[0.0, 1.0, 2.0, ...]}} instead of having an object for each name...?
In the sheet there's just a first name and last name on columns A and B, for around 80 rows.
Use the bracket syntax if you want to use dynamic names for properties: https://riptutorial.com/javascript/example/2321/dynamic---variable-property-names
In your case:
function myFunction() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('data');
var data = sheet.getDataRange().getValues();
var range = sheet.getRange("A1:L" + data.length);
range.sort(1);
const people = {};
for(var i = 0; i < data.length; i++) {
var name = data[i][0] + data[i][1];
console.log(i);
if (!people[name]) {people[name] = {rows: [i]};} else {people[name].rows.push(i)}
}
Logger.log(people);
}
I want to get sums of numeric values for each separate column in the range. What I do wrong?
function countNutrients(){
var sh = SpreadsheetApp.getActiveSheet();
var lastcol = sh.getLastColumn(); //Get last column
var lastcolval = sh.getRange(1, 1, 1, lastcol).getValues();
var lastrowval = sh.getRange("C1:C").getValues(); //Trick to get last row
var lastrow = lastrowval.filter(String).length; //
var sumvalues = sh.getRange(2, 14, lastrow, lastcol).getValues();
(typeof sumvalues === 'number' ? "" : sumvalues);
Logger.log(sumvalues);
for (var j = 13; j < lastcolval.length ; j++) {
var sumcolumnval = sh.getRange(2, [j], lastrow);
var sum = 0;
for (var i in sumcolumnval[0]) {
var sum = sumvalues[0][i] + sum;
}
return sum
Logger.log(sum);
}
return sumcolumnval
}
Columns on the screenshot and 65 more
enter link description here
CSV example
Sum of Columns With a Script
function sumOfCols() {
var ss=SpreadsheetApp.getActive();
var sh=ss.getSheetByName('Sheet14');
var hA=sh.getRange(1,1,1,sh.getLastColumn()).getValues()[0];
var sum={};
hA.forEach(function(h,i){sum[h]=0;});
var rg=sh.getRange(2,1,sh.getLastRow()-1,sh.getLastColumn());
var v=rg.getValues();
v.forEach(function(r,i){r.forEach(function(c,j){sum[hA[j]]+=c;});});
var html='';
hA.forEach(function(h,i){html+=Utilities.formatString('<br />%s(sum): %s',h,sum[h]);});
var ui=HtmlService.createHtmlOutput(html);
SpreadsheetApp.getUi().showModelessDialog(ui, "Column Sums")
}
Spreadsheet:
Output Dialog:
Data(csv):
COL1,COL2,COL3,COL4,COL5,COL6,COL7,COL8,COL9,COL10
1,2,3,4,5,6,7,8,9,10
2,3,4,5,6,7,8,9,10,11
3,4,5,6,7,8,9,10,11,12
4,5,6,7,8,9,10,11,12,13
5,6,7,8,9,10,11,12,13,14
6,7,8,9,10,11,12,13,14,15
7,8,9,10,11,12,13,14,15,16
A function for your particular Application
This will sum just the six columns that you selected
function countNutrients(){
var sh=SpreadsheetApp.getActiveSheet();
var hA=sh.getRange(1,14,1,6).getValues()[0];
var sum={};
hA.forEach(function(h,i){sum[h]=0;})
var vA=sh.getRange(2,14,sh.getLastRow()-1,6).getValues();
vA.forEach(function(r,i){
r.forEach(function(c,j){
if(!isNaN(c)) {
sum[hA[j]]+=c;
}
});
});
var html="";
var keys=Object.keys(sum);
keys.forEach(function(k,i){
html+=Utilities.formatString('<br />sum[%s]=%s',k,sum[k]);
})
var ui=HtmlService.createHtmlOutput(html);
SpreadsheetApp.getUi().showModelessDialog(ui,'Sums of Cols N through S')
}
I need some fresh eyes on what I'm trying to do. I'm working on making our inventory spreadsheet more accurate and email a person when we get low on something. I got most of the code done, there's one part that I'm having issues with and it's where we add a number to certain parts of the spreadsheet. To be more exact, I'm trying to have a menu with multiple text areas for each part, and each text area will relate to the number that we just bought of that part.
My current code for this section has an array that will create and add the textarea to the panel and the part that is labeled in the spreadsheet. A button that will add the text area to the spreadsheet.
My issue that I'm having is correctly setting up the .addCallbackElement() with an array and get whats in the text area to the spreadsheet.
Can anyone see where I am making the mistake, or possible recommendation at something better that I could do?
Thanks for any help that is given
function addBit() {
var ss = SpreadsheetApp.getActive();
var sheet0 = ss.getSheetByName('Inventory');
var lastrow0 = sheet0.getLastRow();
//var ui = SpreadsheetApp.getUi();
//data for each column that we need
var datarange0 = sheet0.getRange('D2:D'+lastrow0);
var datarange1 = sheet0.getRange('E2:E'+lastrow0);
var datarange2 = sheet0.getRange('F2:F'+lastrow0);
var datarange3 = sheet0.getRange('K2:K'+lastrow0);
var datarange4 = sheet0.getRange('I2:I'+lastrow0);
var data0 = datarange0.getValues();// Column D
var data1 = datarange1.getValues();// Column E
var data2 = datarange2.getValues();// Column F
var data3 = datarange3.getValues();// Column K
var data4 = datarange4.getValues();// Column I
var app = UiApp.createApplication();
app.setHeight(500).setWidth(500);
var scroll = app.createScrollPanel().setPixelSize(500,500);
var vpanel0 = app.createVerticalPanel();
var vpanel1 = app.createVerticalPanel();
var hpanel0 = app.createHorizontalPanel();
var apanel = app.createAbsolutePanel();
var text = new Array(lastrow0-1);
//creating labels and text areas for each part for the first column in the menu
for (var i = 0; i <= Math.round((lastrow0 - 2)/2); i++) {
var hpanel = app.createHorizontalPanel();
var label = app.createLabel(data0[i]+ ' ' + data1[i] + 'mm ('+ Math.round(data2[i]) + 'mil)');
text[i] = app.createTextArea().setName('text'+i).setSize(50,20).setValue(0);//.setId('text'+i);
hpanel.add(text[i]);
hpanel.add(label);
vpanel0.add(hpanel);
}
//creating labels and text areas for each part for the second column in the menu
for (var i = Math.round((lastrow0 - 2)/2) + 1; i <= lastrow0 - 2; i++) {
var hpanel = app.createHorizontalPanel();
var label = app.createLabel(data0[i]+ ' ' + data1[i] + 'mm ('+ Math.round(data2[i]) + 'mil)');
text[i] = app.createTextArea().setName('text'+i).setSize(50,20).setValue(0);//.setId('text'+i);
hpanel.add(text[i]);
hpanel.add(label);
vpanel1.add(hpanel);
}
//Creating handlers for the text areas
var thandler = app.createServerHandler('addition');
for (var j = 0; j <= lastrow0 - 2; j++) {
thandler.addCallbackElement(text[j]).setId('text'+i);
}
//when button is hit, the function 'addition' will run
var addButton = app.createButton("Add", thandler);
hpanel0.add(vpanel0);
hpanel0.add(vpanel1);
apanel.add(hpanel0);
apanel.add(addButton);
scroll.add(apanel);
app.add(scroll);
return app;
}
function addition(e){
var app = UiApp.getActiveApplication();
var ss = SpreadsheetApp.getActive();
var sheet0 = ss.getSheetByName('Inventory');
var lastrow0 = sheet0.getLastRow();
//data for each column
var datarange3 = sheet0.getRange('K2:K'+lastrow0);
var datarange4 = sheet0.getRange('I2:I'+lastrow0);
var data3 = datarange3.getValues();// Column K
var data4 = datarange4.getValues();// Column I
var text0 = new Array(lastrow0-1);
//text0[] will have what was in each text area
for (var i = 0; i <= lastrow0 - 2; i++) {
text0[i] = e.parameter.('text' + 1);
}
//for loop will add what was in the text area to columns 'Qty Acq' and 'Current Stock'
for (var j = 0; j <= lastrow0-2; j++) {
var k = j+2;
var v = data3[j] + text0[j];
var x = data4[j] + text0[j]
sheet0.getRange('M' + k).setValue(v);
sheet0.getRange('N' + k).setValue(x);
}
app.close();
}
Use the highest level panel (scrollpanel I guess) as a single callbackElement, it will automatically include all the child widgets.