Are if and else if statements bugged in Google Apps Script? - javascript

I'm fairly new to GAS and Javascript in general and have searched far and wide to find an answer to why this isn't working, but haven't found a solution. I was wondering if one of you guys could find the problem. Here's my code:
function maintenanceRequest() {
var findFirstRequest = GmailApp.search("to:censored label:ems-request AND is:unread", 0, 1)[0];
var firstRequest = findFirstRequest.getMessages()[0];
var parseRequest = firstRequest.getPlainBody();
var requestString = String(parseRequest);
if ("Mark archived mail as read" == requestString) {
markArchivedAsRead();
findFirstRequest.moveToArchive();
}
else if ("Cleanup" == requestString) {
weeklyCleanup();
findFirstRequest.moveToArchive();
}
else {
GmailApp.sendEmail("censored", "Failure to parse command", "The EMS has recieved your request but has failed to recognize the command '" + parseRequest + "'. Please try again, using the terms 'Mark archived as read' or 'Cleanup'. If you would like to add an eligible command, please refer to function 'maintenanceRequest'.", {
name: "Email Maintenance Service",
from: "censored"
})
//Add moveToArchive line here after debugging
}
}
The code always skips the if and else if statements and jumps to the else statement, regardless of the email's content. I've tried using both == and === to no avail, and have tried switching the sides that the arguments are on. To no avail. I even created a new var, requestString to convert parseRequest to a string, even though I'm like 99% certain that it already is a string.. so what gives? Where's the problem?

Try adding trim to the string: requestString = requestString.trim()
It's usually a safe bet to use trim on any string you're getting from another service.

Related

What NScriptType: ServerScript to use in NetSuite field value update script

I am looking to update a numeric field for multiple records with arithmetic, not just overriding the current value with a new one. To do this, I plan on uploading a file with the identifier of the item and the new value being added. Parse the file and use custom searches to find the corresponding records, then loading, updating and saving the proper record. However, how to run the script is where I get confused.
I have created previous scripts beforeLoad scripts which run on entering the edit view of an item, but I have not used any server side scripts yet (I read that when accessing files from the filing cabinet, you must use a server side script).
Any information about server script types and when to use them would be appreciated. Thank you.
For this sort of thing a Map/Reduce script is your best bet
You can pass a fileId as a parameter and your getInputData stage can just load and return the file(which, IIRC, sends each line to your map stage). Your map stage has to ignore the header, if present, and any trailing bad lines.
I havent' been able to easily find a script that I've written that does that but I'm pretty sure I have done that.
Normally though I do something like this for processing a file into the map stage:
function getInputData(){
try{
var me = runtime.getCurrentScript();
var targetFileId = <number>me.getParameter({name:'custscript_kotn_att_emp_file'});
var targetFile = file.load({id:targetFileId});
log.audit({title: 'getting data', details:targetFile.name +' ' + targetFile.size});
var empLines = [];
targetFile.lines.iterator().each(line=>{
var parts = line.value.split('|');
if(parts.length >2 && parts.length != expectColumns.length){
throw new Error('Unexpected line length. Had '+ parts.length +' expected '+ expectColumns.length);
}
if(parts.length > 2){
empLines.push(parts);
}
return true;
});
log.audit({title: 'got employee lines', details:empLines.length});
return empLines;
}catch(e){
log.error({
title:"in input stage",
details : (e.message || e.toString()) + (e.getStackTrace ? (' \n \n' + e.getStackTrace().join(' \n')) : '')
});
return null;
}
};
function map(ctx){
const empLine = JSON.parse(ctx.value);
//you have an array of the parsed line
}

How to write (SetValues) to a Google Sheet using a filtered forEach loop?

I've been trying for hours to make the following Google Apps Script work. What it needs to do, is send emails (from an html-template) to anyone that:
has a complete Event Schedule (which is completed if they have been
assigned to at least 4 events, which is counted in column Q);
has NOT been sent an email earlier (which is kept track of in column
R);
The script keeps track of errors in column S, i.e. if there's no email address provided.
It appears it only works:
if I comment out
data = data.filter(function(r){ return r[17] == true & r[16] > 3});
or if I comment out
ws.getRange("S3:S" + ws.getLastRow()).setValues(errors);
ws.getRange("R3:R" + ws.getLastRow()).setValues(mailSucces);
How can I get this script to work properly?
A copy of the Google Sheet I'm referring to is this one:
https://docs.google.com/spreadsheets/d/1sbOlvLVVfiQMWxNZmtCLuizci2cQB9Kfd8tYz64gjP0/edit?usp=sharing
This is my code so far:
function SendEmail(){
var voornaam = 3;
var achternaam = 4;
var email = 5;
var event1 = 9;
var event2 = 10;
var event3 = 11;
var event4 = 12;
var event5 = 13;
var event6 = 14;
var event7 = 15;
var emailTemp = HtmlService.createTemplateFromFile("email");
var ws = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Events Day 1");
var datum = ws.getRange(1,3).getValue();
var spreker = ws.getRange(1,6).getValue();
var data = ws.getRange("A3:R" + ws.getLastRow()).getValues();
data = data.filter(function(r){ return r[17] == false && r[16] > 3}); //Either this needs to be commented out...
let errors = [];
let mailSucces = [];
data.forEach(function(row){
try{
emailTemp.voornaam = row[voornaam];
emailTemp.email = row[email];
emailTemp.datum = datum;
emailTemp.spreker = spreker;
emailTemp.event1 = row[event1];
emailTemp.event2 = row[event2];
emailTemp.event3 = row[event3];
emailTemp.event4 = row[event4];
emailTemp.event5 = row[event5];
emailTemp.event6 = row[event6];
emailTemp.event7 = row[event7];
var htmlMessage = emailTemp.evaluate().getContent();
GmailApp.sendEmail(
row[email],
"Here you go! Your personal schedule for the event of " + datum,
"Your emailprogramm doesn't support html.",
{
name: "Event Organisation Team", htmlBody: htmlMessage, replyTo: "info#fakeemail.com"
});
errors.push([""]);
mailSucces.push(["TRUE"]);
}
catch(err){
errors.push(["Error: no message sent."]);
mailSucces.push(["False"]);
}
}); //close forEach
ws.getRange("S3:S" + ws.getLastRow()).setValues(errors); //or this and the next line need to be commented out.
ws.getRange("R3:R" + ws.getLastRow()).setValues(mailSucces);
}
Edit I have been trying and thinking en trying... but still haven't found out how to make it work. But I also got understanding of why it's not working; I just don't know how to get it fixed.
Let me elaborate on the problem a bit more:
The problem is, that within the forEach loop the range is a filtered variant of the data, pulled from the spreadsheet with getValues. Therefore, writing data back with ws.getRange("R3:R" + ws.getLastRow()).setValues(mailSucces); results in mismatched checkmarks in te spreadsheet.
So, somehow I need to put the range of the previous used filter data = data.filter(function(r){ return r[17] == false & r[16] > 3}); in a variable...? I guess?
Furthermore, I don't think it's wise to use setValue within the loop, because (from what I understand from my searching on the topic) this results in a slow script, because every loop the script makes an API call to write in the spreadsheet. Hence the errors.push and mailSucces.push, and my attempt to do a setValue at the end, after the loop is finished.
Can someone help me to finish this problem?
The problem is different size of the range you write to and data you are writing in.
Try replacing:
ws.getRange("S3:S" + ws.getLastRow()).setValues(errors);
ws.getRange("R3:R" + ws.getLastRow()).setValues(mailSucces);
With:
ws.getRange(3, 19, errors.length, 1).setValues(errors);
ws.getRange(3, 18, mailSucces.length, 1).setValues(mailSucces);
You should use this variation of getRange
https://developers.google.com/apps-script/reference/spreadsheet/sheet#getrangerow,-column,-numrows,-numcolumns
Your data has non-fixed number of rows and fixed number of columns (1). In general case your data will be matrix of X rows and Y columns. For that purpose you can make it completely dynamic:
sheet.getRange(startRow, startColumn, data.length, data[0].length)
Just make sure data.length is > 0 before you do this, otherwise data[0].length will break.
Edit:
I started writing a comment but it got too long. There are couple of things that may go wrong with sending emails. First thing I noticed is that you use & in filter, but in AppsScript/JavaScript/C-like-languages, you should use && for logical AND. Now the email: you only detect the code break with the catch block. At this point you don't know why the code breaks it could be anything. With GmailApp I recommend you to use createDraft while developing, then when all ok replace it with sendEmail for the final version, both functions have the exact same parameters, thank you Google devs ;-).
To find out the exact problem you should get the error message on break and display it. err.stack should tell you pretty much everything:
catch(err){
Logger.log(err.stack); // Added
errors.push(["Error: no message sent."]);
mailSucces.push(["False"]);
}
Run the sendEmail function from the code editor and you should see the Log for each catch(err) pass.

Replace function in javascript is not replacing correct index of regex match

I have a String and I am detecting some 'urls' and 'closing anchor tags' using regex expression. firstly I am using match function which is returning the list of 'urls' and 'closing anchor tags'. further if my first url is matching with the second url then I dont need to do anything and if it is not matching then I need to replace the closing anchor tag with the same urls. here is the string:-
"This message was sent to ${EmailAddress} because you asked us to keep you up to date with the latest news and offers from the company. If you do not wish to receive these emails, please unsubscribe ${optout()}. You can also change your email preferences on our website logging in at 'a tag' class="footer-link" href="https://sample-website">https://sample-website 'closing a tag'. Please do not reply to this email, as we are unable to respond from this email address. If you need support, please visit the Sample Help Center 'closing a tag'.
var regex3 = new RegExp(/<\/a.?>/gm);
var regex4 = new RegExp(/(?:(?:https?|ftp|file):\/\/|www\.|ftp\.)(?:\([-A-Z0-9+&##\/%=~_|$?!:,.]*\)|[-A-Z0-9+&##\/%=~_|$?!:,.])*(?:\([-A-Z0-9+&##\/%=~_|$?!:,.]*\)|[A-Z0-9+&##\/%=~_|$])/igm);
var closingATag = footerContentPlainText.match(regex3);
var URLList = footerContentPlainText.match(regex4);
if(URLList != null){
for(var j =0,k=0; j<URLList.length; j++,k++){
if(j+1 != URLList.length) {
if(URLList[j] != URLList[j+1]){
footerContentPlainText =
footerContentPlainText.replace(closingATag[j],"<" + URLList[j] + ">");
}
else if(URLList[j] == URLList[j+1]){
j++;
}
}
else{
if(URLaTags != null){
footerContentPlainText = footerContentPlainText.replace(closingATag[k],"<" + URLList[j] + ">");
}
}
}
}
Although I am handing different scenarios for different type of strings but this is the scenario where I am stuck.
I expect the output, where last 'closing a tag' should be replaced by 3rd url i.e "https://support.samplewebsite.com/samplename".
Here I am not able to write a tag in actual format so I have used just text in place of the same
please help

Running script function from editor doesn't work as expected

So, I never ever programmed JavaScript and never did anything with Google Script before either. I have a fairly good understanding of Visual Basic and macros in Excel and Word. Trying to make a fairly basic program: Plow through a list of variables in a spreadsheet, make a new sheet for each value, insert a formula in this new sheet, cell (1,1).
Debug accepts my program, no issues - however, nothing at all is happening when I run the program:
function kraft() {
var rightHere =
SpreadsheetApp.getActiveSpreadsheet().getActiveSheet().getRange("A1:A131");
var loopy;
var goshDarn = "";
for (loopy = 1; loopy < 132; loopy++) {
celly = rightHere.getCell(loopy,1);
vaerdi = celly.getValue();
fed = celly.getTextStyle();
console.log(vaerdi & " - " & fed);
if (vaerdi != "" && fed.isBold == false) {
SpreadsheetApp.getActiveSpreadsheet().insertSheet(vaerdi);
var thisOne = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(vaerdi);
thisOne.deleteRows(500,500);
thisOne.deleteColumns(5, 23);
thisOne.getRange(1,1).setFormula("=ArrayFormula(FILTER('Individuelle varer'!A16:D30015,'Individuelle varer'!A16:A30015=" & Char(34) & vaerdi & Char(34) & ")))");
}
}
}
activeSheet could be called by name, so could activeSpreadsheet, I guess. But range A1:A131 has a ton of variables - some times there are empty lines and new headers (new headers are bold). But basically I want around 120 new sheets to appear in my spreadsheet, named like the lines here. But nothing happens. I tried to throw in a log thingy, but I cannot read those values anywhere.
I must be missing the most total basic thing of how to get script connected to a spreadsheet, I assume...
EDIT: I have tried to update code according to tips from here and other places, and it still does a wonderful nothing, but now looks like this:
function kraft() {
var rightHere = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet().getRange("A1:A131");
var loopy;
var goshDarn = "";
for (loopy = 1; loopy < 132; loopy++) {
celly = rightHere.getCell(loopy,1);
vaerdi = celly.getValue();
fed = celly.getFontWeight();
console.log(vaerdi & " - " & fed);
if (vaerdi != "" && fed.isBold == false) {
SpreadsheetApp.getActiveSpreadsheet().insertSheet(vaerdi);
var thisOne = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(vaerdi);
thisOne.deleteRows(500,500);
thisOne.deleteColumns(5, 23);
thisOne.getRange(1,1).setFormula("=ArrayFormula(FILTER('Individuelle varer'!A16:D30015,'Individuelle varer'!A16:A30015=" + "\"" + vaerdi + "\"" + ")))");
}
}
}
EDIT2: Thanks to exactly the advice I needed, the problem is now solved, with this code:
function kraft() {
var rightHere = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet().getRange("A1:A131");
var loopy;
for (loopy = 1; loopy < 132; loopy++) {
celly = rightHere.getCell(loopy,1);
vaerdi = celly.getValue();
fed = celly.getFontWeight()
console.log(vaerdi & " - " & fed);
if (vaerdi != "" && fed != "bold") {
SpreadsheetApp.getActiveSpreadsheet().insertSheet(vaerdi);
var thisOne = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(vaerdi);
thisOne.deleteRows(500,499);
thisOne.deleteColumns(5, 20);
thisOne.getRange(1,1).setFormula("=ArrayFormula(FILTER('Individuelle varer'!A16:D30015;'Individuelle varer'!A16:A30015=" + "\"" + vaerdi + "\"" + "))");
}
}
}
There are multiple issues with your script, but the main one is that you never actually call the isBold() function in your 'if' statement.
if (value && format.isBold() == false) {
//do something
}
Because you omitted the parentheses in 'fed.isBold', the expression never evaluates to 'true'. 'isBold' (without the parentheses) is of type Object as it's a function.
There are other issues that prevent the script from running properly:
Not using the 'var' keyword to declare variables and polluting the global scope. As a result, all variables you declare within your 'for' loop are not private to your function. Instead, they are attached to the global object and are accessible outside the function. https://prntscr.com/kjd8s5
Not using the built-in debugger. Running the function is not debugging. You should set the breakpoints and click the debug button to execute your function step-by-step and examine all values as it's being executed.
Deleting the non-existent columns. When you create the new sheet, you call the deleteColums(). There are 26 columns in total. The 1st parameter is the starting column while the 2nd one specifies how many columns must be deleted. Starting from column 5 and telling the script to remove 23 columns will throw an exception. Always refer to the documentation to avoid such errors.
console.log doesn't exist within the context of the Script Editor. You are NOT executing the scripts inside your browser, so Browser object model is not available. Use Logger.log(). Again, this is detailed in the documentation.
Your formula is not formatted properly.
JS is a dynamically typed language that's not easy to get used to. If you don't do at least some research prior to writing code, you'll be in for a lot of pain.

Google Script maker to format a spreadsheet

This is my first time posting so bear with me if I leave any crucial details out.
Anyway, to summarize the problem: I have been trying to get a script to work on Google Script maker to format a spreadsheet which is hooked up to a form, to go straight to my email.
So basically User Form --> Spreadsheet --> My Email
The questions are pretty Standard:
What's the problem?
Where are you located
However the one question I'd like to use is "What is the priority of this problem?" High or low. I have it under multiple choice format so its a simple choice.
Psuedocode for what I want:
if (priority = low) put #priority low onto the email
Simple enough, however I can't seem to get it to work, here's my code:
function sendFormByEmail(e)
{
// Remember to replace XYZ with your own email address
var email = "email";
var subject = "Help Desk Form Submitted";
var s = SpreadsheetApp.getActiveSheet();
var headers = s.getRange(1,1,1,s.getLastColumn()).getValues()[0];
var message = "";
var priority = "";
if(message.indexOf("What is the priority of this problem? = Low")){
priority += "#priority low";
}
else
priority == "GFHHFFHAHFH ";
for(var i in headers){
message += headers[i] + ' = \t \t'+ e.namedValues[headers[i]].toString() + "\n\n"; }
if (message.indexOf("What is the priority of this problem? = Low"))
message += "This is a test";
else
message += "This is not a test";
MailApp.sendEmail(email, subject, message);
}
Let's look at the first instance of if(message.indexOf().... It's got some problems:
A few lines earlier, message was set to an empty string... so you won't find the "priority" string in it.
The if statement is treating the return of indexOf() as a Boolean. However, the return code from .indexOf() is -1 when an item is not found, which is "true-ish". If the string IS found, and is located at the start of the search subject, the return will be 0, which is "false-ish". If it is found at any other location, the value will be `>0', also "true-ish".
In the else, there's a typo. The comparison == should be assignment =, or += if you prefer.
Looking at the surrounding code, this piece looks like it was left-over from a previous version, and can be deleted.
Now look at the second instance.
The message should now be populated. However, the comparison is still using an incorrect Boolean interpretation of .indexOf().
The search string contains a batch of spaces... but the previous code that looped through responses used tabs to separate the "header" from the "value", so the search will always return '-1' (which will be interpreted as true).
There are a couple of other tidy-up items. You probably need:
function sendFormByEmail(e)
{
Logger.log(JSON.stringify(e));
var email = Session.getEffectiveUser().getEmail();
var subject = "Help Desk Form Submitted";
var message = "";
var s = e.range.getSheet(); // Sheet that received form response
var headers = s.getDataRange().getValues()[0];
for (var question in headers) {
message += headers[question] + ' = \t\t' + e.values[question] + '\n\n';
}
// Add text relative to the priority of the reported issue.
if (e.namedValues["What is the priority of this problem?"].toString() === "Low")
message += "This is a test";
else
message += "This is not a test";
Logger.log(message);
MailApp.sendEmail(email, subject, message);
}
PS: You can see why it would be advisable to keep form questions short, like "Priority", and leave the explanatory sentence to be helper text!

Categories