Email sender tweaking help needed - email

I've been trying to understand this email on edit function.
I just cannot figure it out.
I need to send informations in Columns A, B, C, F, G, H and J. The email trigger is in column K and would be selected from data validation.
I have the following function which works great. It send the email but I cannot adjust which rows to show here.
What am I doing wrong?
I want body of the Email to appear as follows when I choose email in K101
Headers in A3 : Data in cell A101
Headers in B3 : Data in cell B101
Headers in C3 : Data in cell C101
Headers in F3 : Data in cell F101
Headers in G3 : Data in cell G101
Headers in H3 : Data in cell H101
Headers in J3 : Data in cell J101
Help???
function mailOnEdit(e) {
var sheet = e.source.getActiveSheet();
if (sheet.getName() !== 'Registry Sheet' || e.range.columnStart !== 11 || e.range.rowStart < 4 || !e.value) return;
var h = sheet.getRange(1, 1, 1, 8)
.getValues()[0],
val = sheet.getRange(e.range.rowStart, 1, 1, 8)
.getValues()[0],
i = 0,
body = "",
notCols = [3, 4];
while (i < 7) {
if (notCols.indexOf(i) == -1) {
body += h[i] + ": " + val[i] + "\n";
}
i += 1;
}
body += "\n\n Contact customer within 30 minutes and reply. Thanks";
MailApp.sendEmail(e.value, "New job", body)
}

Seems like your headers are in row three and not in row one. So
Change
var h = sheet.getRange(1, 1, 1, 8).getValues()[0]
to
var h = sheet.getRange(3, 1, 1, 8).getValues()[0]

Related

Dates in my spreadsheets keep getting converted to DateTimes and I want the time component removed as this is handled in a differnt column

I keep track of trading data in a private spreadsheet and, once a trade is closed, I push a button to run some AppsScript to copy the data across to a publicly visible spreadsheet. It all works well except the following point. I put the dates and times a trade is opened in two different columns and the same with the dates and times trades are closed. When I copy the dates across to the target spreadsheet, instead of "10 Jul 2022" it is showing as "10/07/2022 02:00:00". When I sort the spreadsheet on these date and time columns, this can often produce unwated results. What I want is for the date column to just display as "10 Jul 2022" and for that data to recognized as a date for sorting purposes. Is that possible?
function updatePublicSheet(){
var coinBought;
var dateBought;
var timeBought;
var priceBought;
var dateSold;
var timeSold;
var priceSold;
var sLrIndex;
var tLrIndex;
var sss = SpreadsheetApp.openByUrl("https://docs.google.com/spreadsheets/d/1cBGpD0nUqCGtQqq78svw4fxA4ZgwBqV2yzIbgY1tY2o/edit#gid=1107419239");
var sSheet = sss.getSheetByName('SS Open Trades');
var sRng = sSheet.getRange("H3:J").getValues();
// Find last entry in columns H, I or J in the Open Trades sheet
for (var i = sRng.length-1;i>=0;i--){
var sLrIndex = i;
if (!sRng[i].every(function(c){return c == "";})){
break;
}
}
Logger.log("Last source row is %s", sLrIndex + 3);
// Check that the closed information has been added to all columns
// index 8 = 8th column = H = dateSold
// index 9 = 9th column = I = timeSold
// index 10 = 10th column = J = priceSold
if ((sSheet.getRange((sLrIndex + 3),8).getValue().length) == 0 ||
(sSheet.getRange((sLrIndex + 3),9).getValue().length) == 0 ||
(sSheet.getRange((sLrIndex + 3),10).getValue().length) == 0){
SpreadsheetApp.getUi().alert("You cannot process partially completed entries");
return;
}
// If there is a complete closed entry, copy the values to the variables
if (sLrIndex > 0)
{
coinBought = sSheet.getRange((sLrIndex + 3),2).getValue();
dateBought = toUtcString(sSheet.getRange((sLrIndex + 3),4).getValue());
timeBought = sSheet.getRange((sLrIndex + 3),5).getValue();
priceBought = sSheet.getRange((sLrIndex + 3),6).getValue();
dateSold = toUtcString(sSheet.getRange((sLrIndex + 3),8).getValue());
timeSold = sSheet.getRange((sLrIndex + 3),9).getValue();
priceSold = sSheet.getRange((sLrIndex + 3),10).getValue();
//Logger.log(priceSold);
}
else
{
SpreadsheetApp.getUi().alert("There are no completed entries to process");
return;
}
var tss = SpreadsheetApp.openByUrl("https://docs.google.com/spreadsheets/d/1umkTCr95FZUrZzv0e_ZDD9QZYiiYuH1fJohPYQzNE9Q/edit#gid=1644116137");
var tSheet = tss.getSheetByName('Trade Tracker');
var tRng = tSheet.getRange("B3:J").getValues();
// Create a new row at Row 5 on the Trades Tracker Sheet
tSheet.insertRows(5, 1);//shift all rows down by one from row 5
// Copy values from row 4 to row 5, including the formulae
var tRange = tSheet.getRange(4, 1, 1, 26);
tRange.copyTo(tSheet.getRange(5, 1, 1, 26), {contentsOnly:false});
// Populate row 4, first 7 table columns, from the variables
//Logger.log(coinBought);
tSheet.getRange(4,2).setValue(coinBought);
tSheet.getRange(4,3).setValue(dateBought);
tSheet.getRange(4,4).setValue(timeBought);
tSheet.getRange(4,5).setValue(priceBought);
tSheet.getRange(4,6).setValue(dateSold);
tSheet.getRange(4,7).setValue(timeSold);
tSheet.getRange(4,8).setValue(priceSold);
// Format the cells with dates and times
tSheet.getRange(4,3).setNumberFormat("dd MMM yyyy"); // Short Date
tSheet.getRange(4,4).setNumberFormat("HH:mm"); // Short Time
tSheet.getRange(4,6).setNumberFormat("dd MMM yyyy"); // Short Date
tSheet.getRange(4,7).setNumberFormat("HH:mm"); // Short Time
// Sort the sheet by date/time closed
// Find last entry in Trade Tracker sheet
for (var i = tRng.length-1;i>=0;i--){
var tLrIndex = i;
if (!tRng[i].every(function(c){return c == "";})){
break;
}
}
Logger.log("Last target row is %s", tLrIndex + 4);
var tRange = tSheet.getRange(4, 2, tLrIndex + 4, 8)
tRange.sort([{column: 6, ascending: false}, {column: 7, ascending: false}]);
// On the source sheet, delete the row just copied and add another blank row at the bottom of the table
sSheet.deleteRows(sLrIndex + 3, 1);
var rowLast = sSheet.getLastRow();
sSheet.insertRowAfter(rowLast - 1);
// Copy values from the new last row to the new previous to last row, including the formulae
var sRange = sSheet.getRange(rowLast + 1, 1, 1, 10);
sRange.copyTo(sSheet.getRange(rowLast - 1, 1, 1, 10), {contentsOnly:false});
SpreadsheetApp.getUi().alert("One completed entry processed");
}

Talend - split a string to n rows

I would like to split a string in a column to n rows in Talend.
For example :
column
2aabbccdd
The first number is the "n" which I use to define the row lenght, so the expected result should be :
row 1 = aa
row 2 = bb
row 3 = cc
row 4 = dd
The idea here is to iterate on the string and cut it every 2 characters.
Any idea please ?
I would use a tJavaFlex to split the string, with a trick to have n rows coming out of it.
tJavaFlex's main code:
int n = Integer.parseInt(row1.str.substring(0, 4)); //get n from the first 4 characters
String str2 = row1.str.substring(4); //get the string after n
int nbParts = (str2.length() + 1) / n;
System.out.println("number of parts = " + nbParts);
for (int i = 0; i < nbParts; i++)
{
String part = str2.substring(i * n);
if(part.length() > n)
{
part = part.substring(0, n);
}
row2.str = part;
And tJavaFlex's end code is just a closing brace:
}
The trick is to use a for loop in the main code, but only close it in the end code.
tFixedFlowInput contains just one column holding the input string.

ag-grid filter not working with formatted number values?

I'm using ag grid with angularjs and the filter does not work with formatted numbers. I use formatted numbers with currency values.
Below is the columndef code:
{ headerName:"GBO", field: "GBO", width: 200, editable:true, cellClass: "number-cell",filter:'agNumberColumnFilter',
cellRenderer : function(params){
if(params.value == "" || params.value == null)
return '-';
else return params.value;
}
}
Before assigning the data to the grid, I format the numbers using :
$scope.formatNumberOnly = function(num,c, d, t){
//console.log(num );
var n = getNumber(num);
//var n = this,
c = isNaN(c = Math.abs(c)) ? 2 : c,
d = d == undefined ? "." : d,
t = t == undefined ? "," : t,
s = n < 0 ? "-" : "",
i = parseInt(n = Math.abs(+n || 0).toFixed(c)) + "",
j = (j = i.length) > 3 ? j % 3 : 0;
return s + (j ? i.substr(0, j) + t : "") + i.substr(j).replace(/(\d{3})(?=\d)/g, "$1" + t) + (c ? d + Math.abs(n - i).toFixed(c).slice(2) : "");
};
});
The problem here is that the filter doesn't work with these formatted numbers and only seems to be working for values upto 999.
Can anyone please help me with a solution to this filtering problem?
If you want the filter to work on these formatted values, you should use a valueGetter instead of a valueFormatter
You should implement the above formatter function as a valueGetter in column Definition.
Also a number filter won't work as in order for your formatted number to be interpreted, it should be a text filter.
Here is an example from official docs.

Google Script: "EMAIL_SENT" value not set in desired column despite email being sent successfully using MailApp.sendEmail

I was wondering if you could please help. I am trying to use the MailApp.sendEmail method to send emails when a date is entered into column M. I currently use a button on the spreadsheet to trigger the sending of emails and this works fine: emails are sent.
I naturally wish for duplicate emails not to be sent and as such I wish for the "EMAIL_SENT" value to entered into Column N at the moment I trigger the sending of emails, but this does not work. This is despite my code pretty much replicating what is shown on google's own page (https://developers.google.com/apps-script/articles/sending_emails) et al.
I also wish it to generate a timestamp into Column O when emails are sent. Again, this does not work, but I can believe my approach is not correct. I'll be honest and say I am new to this!
Please advise me on where the errors are in my code.
var EMAIL_SENT = "EMAIL_SENT";
function SEWEmailReminder() {
var sheet = SpreadsheetApp.getActiveSheet();
var numRows = sheet.getLastRow(); // nothing to change
var startRow = "9"; // put the row number where the formula should start
var range = sheet.getRange(startRow, 1, numRows, 22) // Fetch the range of cells A9:Vx
var data = range.getValues();
for (var i = 0; i < data.length; ++i) {
var row = data[i];
var programmeid = row[0]; // 1st column A
var programmename = row[1]; // 2nd column B
var author = row[2]; // 3rd column C
var authoremail = row[3]; // 4th column D
var comments = row[4]; // 5th column E
var programmestatus = row[5]; // 6th column F
var datadate = row[6]; // 7th column G
var plannedcompletiondate = row[7]; // 8th column H
var completiondate = row[8]; // 9th column I
var presubjointreviewdate = row[9]; // 10th column J
var plannedsubdate = row[10]; // 11th column K
var jvissuedate = row[11]; // 12th column L
var sewresponsedate = row[12]; // 13th column M
var emailsent = row[13]; // 14th column N
var emailtimestamp = row[14]; // 15th column O
var sewreviewdate = row[15]; // 16th column P
var jvreceiveddate = row[16]; // 17th column Q
var difference = row[17]; // 18th column R
var rejectedaccepted = row[18]; // 19th column S
var recipients = row[19]; // 20th column T
var forclientacceptance = row[20]; // 21st column U
var jvreceiveddate = row[21]; // 22nd column V
var subject = "SEW Notification Email";
var message = "Dear " + author + ",\nYou have received this email to notify you that the SEW Response Date is " + sewresponsedate + " for Programme ID " + programmeid + ", titled " + programmename + ".\nKind Regards,\nAdmin"
if (row[12] != "") {
if (emailsent != EMAIL_SENT) { // Prevents sending duplicates
MailApp.sendEmail(authoremail, subject, message);
sheet.getRange(startRow + i, 14).setValue(EMAIL_SENT);
sheet.getRange(startRow + i, 15).setValue(new Date()); // set date & time stamp
// Make sure the cell is updated right away in case the script is interrupted
SpreadsheetApp.flush();
}
}
}
}

Change sheet cells color onEdit

I figured out how to compare dates in Google Sheets but when I try to enter more dates for some reason all the cells that were green and red become all red. Also how can I make two cells red if only one cell has a date?
Example: In cell D18 the Due date is 4-18-2014 and in cell E18 the cell is blank. I want to make both cells red so I would know that I should find out why is that cell red.
This is the code I have so far:
function onEdit() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = ss.getSheetByName('Copy of Project Sheet 1');
var values1Rule1 = s.getRange('E2:E1000').getValues();
var values2Rule1 = s.getRange('D2:D1000').getValues();
var range3Rule1 = s.getRange('D2:E2');
var color1 = 'Red';
var color2 = 'Green';
for (var row in values1Rule1) {
for (var col in values1Rule1[row]) {
if (values1Rule1[row][col] > values2Rule1[row][col]) s.getRange(s.getRange('D2').offset(row, col, 1, 2).getA1Notation()).setBackgroundColor(color1);
else if (values1Rule1[row][col] < values2Rule1[row][col]) s.getRange(s.getRange('D2').offset(row, col, 1, 2).getA1Notation()).setBackgroundColor(color2);
else s.getRange(s.getRange('D2').offset(row, col, 1, 2).getA1Notation()).setBackgroundColor('white'); }}
};
All you need to do is add this condition as an OR clause in your red condition, e.g.
if (values1Rule1[row][col] > values2Rule1[row][col] || values1Rule1[row][col] === '')
But there's lots of "minor" problems with your code. First of all, you're doing way too many API calls unnecessarily. This is a big performance issue. For example, when you offset, you already have the new range, there's no need to getA1Notation then get the range again, you could do:
s.getRange('D2').offset(row, col, 1, 2).setBackgroundColor(color1);
But that's still two calls, getting D2, then offseting. You could get the desired range at once:
s.getRange(row+1, 4, 1, 2).setBackgroundColor(color1);
I'd go even further and build a matrix of colors and set it all at once after the loop:
s.getRange('D2:E1000').setBackgroundColors(colors);
But even better, inside an onEdit you should only work on what has just being edited, instead of triggering a full recalculation of your colors because the user edited something on another column or another sheet entirely.
I think your code should be something like this:
function onEdit(e) {
var ss = e.source;
var s = ss.getActiveSheet();
if( s.getName() !== 'Copy of Project Sheet 1' ) return; //only interested in one sheet
var r = s.getActiveRange();
var c = r.getColumn();
if( c !== 4 && c !== 5 ) return; //only interested in changes on columns D or E
r = r.offset(0, c === 4 ? 0 : -1, 1, 2);
var v = r.getValues()[0];
r.setBackgroundColor(v[1] === '' || v[1] > v[0] ? 'red' : v[1] < v[0] ? 'green' : 'white');
}
--edit
You can not run this function manually directly, because it needs a parameter that is passed only when it runs automatically. But you can emulate it with a test function, like this:
function testEdit() { onEdit({source:SpreadsheetApp.getActive()}); }