Else if statement executes despite first condition is met - google-apps-script

I have a patch of code that is intended to perform a search across a sheet then assign a variable if found.
Here's the code:
for(i=0;i<values.length; i++)
{
rowvalue = values[i];
for (j=l=1;j<rowvalue.length; j++) {
colvalue = rowvalue[j];
colvalue1 = colvalue.toString();
if(colvalue1.indexOf("search1")>-1 && colvalue1.indexOf("search2")==-1
&& rowvalue[j+5] == "") {
rowp = i+1, colp = j+1;
var itemcode = 9;
}
else if(colvalue1.indexOf("search1")>-1 && colvalue1.indexOf("search2")==-1) {
rowp = i+1, colp = j+1;
var itemcode = 9;
}
When executed, it will always return the value that met the 2nd condition(else if), despite the first condition was met. If I remove the else if statements, then I will get the correct return value.
As far as I know, once if statement was fulfilled, it's supposed to skip else or else if. But for some reason this wasn't the case in my situation. I'm not sure if I'm using the function properly or I'm misunderstanding on how the function work.

Try doing the same function this way:
if(colvalue1.indexOf("search1")>-1 && colvalue1.indexOf("search2")==-1 )
{
if (rowvalue[j+5] == "")
{
rowp = i+1, colp = j+1;
var itemcode = 9;
}else{
rowp = i+1, colp = j+1;
var itemcode = 9;
}
}

If you indent your code correctly it becomes rather obvious where it goes wrong
Your code indented.
for(i=0;i<values.length; i++)
{
rowvalue = values[i];
for (j=l=1;j<rowvalue.length; j++)
{
colvalue = rowvalue[j];
colvalue1 = colvalue.toString();
if(colvalue1.indexOf("search1")>-1 && colvalue1.indexOf("search2")==-1 && rowvalue[j+5] == "")
{
rowp = i+1, colp = j+1;
var itemcode = 9;
else if(colvalue1.indexOf("search1")>-1 && colvalue1.indexOf("search2")==-1)
{
rowp = i+1, colp = j+1;
var itemcode = 9;
}
What you probably meant was to as below, please note the "Added missing closing curly bracket"
for(i=0;i<values.length; i++)
{
rowvalue = values[i];
for (j=l=1;j<rowvalue.length; j++)
{
colvalue = rowvalue[j];
colvalue1 = colvalue.toString();
if(colvalue1.indexOf("search1")>-1 && colvalue1.indexOf("search2")==-1 && rowvalue[j+5] == "")
{
rowp = i+1, colp = j+1;
var itemcode = 9;
} // Added missing closing curly bracket
else if(colvalue1.indexOf("search1")>-1 && colvalue1.indexOf("search2")==-1)
{
rowp = i+1, colp = j+1;
var itemcode = 9;
}
}
}

single closing curly brace before the else statement should resolve the issue.

Related

Exception: The number of rows in the data does not match the number of rows in the range. The data has 1 but the range has 8. Google Script

I am having troubles in
Exception: The number of rows in the data does not match the number of rows in the range. The data has 1 but the range has 8. Google Script
function myFunction() {
var s1 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Staging');
var s2 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Final');
var values1 = s1.getDataRange().getValues();
var values2 = s2.getDataRange().getValues();
var Avals = s2.getRange("A1:A").getValues();
var Alast = Avals.filter(String).length;
var resultArray = [];
for(var n=0; n < values1.length ; n++)
{
var keep = false;
var counter = 0;
for(var p=0; p < values2.length ; p++)
{
if( values1[n][1] == values2[p][1])
{
keep = true;
break ;
}
}
if(keep == false)
{
resultArray.push([values1[n]]);
//s2.appendRow( values1[n] );
s2.getRange(Alast + 1, 1, values1[n].length, values1[n].length).setValues([values1[n]]);
//s2.getRange(s2.getLastRow() + 1, 1, values1.length, values1[0].length).appendRow( values1[n] );
resultArray = [];
keep = false
}
}
}
I believe you are trying to keep appending a new row to the end of the data on "Final". You should revise you script as shown below. Use resultArray to collect all new rows and save it to spreadsheet once.
function myFunction() {
var s1 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Staging');
var s2 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Final');
var values1 = s1.getDataRange().getValues();
var values2 = s2.getDataRange().getValues();
// s2.getDataRange() will get up to the last row of data
var Alast = values2.length;
var resultArray = [];
for(var n=0; n < values1.length ; n++)
{
var keep = false;
var counter = 0;
for(var p=0; p < values2.length ; p++)
{
if( values1[n][1] == values2[p][1])
{
keep = true;
break ;
}
}
if(keep == false)
{
resultArray.push(values1[n]);
keep = false
}
}
if( resultArray.length > 0 ) {
s2.getRange(Alast+1,1,resultArray.length,resultArray[0].length).setValues(resultArray);
}
}

Google Script to hide rows by 2 conditions, One word and one date

This is the first question I have posted on Stack Overflow so I apologize if I am doing this wrong. I have a tracker for work where I am trying to hide rows with a script that meets 2 conditions. 1. If a row contains "rejected" or "withdrew" 2. Date older than the previous quarter (in this case 1/1/2022). I can get the script to hide rows with just the words no problem but I have no clue how to do the date because I think it is a different syntax.
The dates are in column K, M, O, Q, S, U, W.
Here is the code I am currently using:
function Hide() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheets = ss.getSheets();
for (var sheetI = 1; sheetI <= 3; sheetI++) {
var sheet = sheets[sheetI];
sheet.showRows(1, sheet.getMaxRows());
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = ss.getSheetByName("Data Validation");
var v = s.getRange("A2").getValues();
var kk = SpreadsheetApp.getActiveSpreadsheet();
var k = kk.getSheetByName("SM");
var a = k.getRange("K:K").getValue();
var b = k.getRange("M:M").getValue();
var c = k.getRange("O:O").getValue();
var d = k.getRange("Q:Q").getValue();
var e = k.getRange("S:S").getValue();
var f = k.getRange("U:U").getValue();
var g = k.getRange("W:W").getValue();
var colJ = sheet.getRange("J:J").getValues().map(function(row) {return row[0];});
var colL = sheet.getRange("L:L").getValues().map(function(row) {return row[0];});
var colN = sheet.getRange("N:N").getValues().map(function(row) {return row[0];});
var colP = sheet.getRange("P:P").getValues().map(function(row) {return row[0];});
var colR = sheet.getRange("R:R").getValues().map(function(row) {return row[0];});
var colT = sheet.getRange("T:T").getValues().map(function(row) {return row[0];});
var colV = sheet.getRange("V:V").getValues().map(function(row) {return row[0];});
colJ.forEach(function(value, rowI) {
if (value === "rejected" && a < v) {
sheet.hideRows(rowI + 1, 1);
}
else if (value === "withdrew" && a < v) {
sheet.hideRows(rowI + 1, 1);
}
});
colL.forEach(function(value, rowI) {
if (value === "rejected" && b < v) {
sheet.hideRows(rowI + 1, 1);
}
else if (value === "withdrew" && b < v) {
sheet.hideRows(rowI + 1, 1);
}
});
colN.forEach(function(value, rowI)
{
if (value === "rejected" && c < v) {
sheet.hideRows(rowI + 1, 1);
}
else if (value === "withdrew" && c < v) {
sheet.hideRows(rowI + 1, 1);
}
});
colP.forEach(function(value, rowI) {
if (value === "rejected" && d < v) {
sheet.hideRows(rowI + 1, 1);
}
else if (value === "withdrew" && d < v) {
sheet.hideRows(rowI + 1, 1);
}
});
colR.forEach(function(value, rowI) {
if (value === "rejected" && e < v) {
sheet.hideRows(rowI + 1, 1);
}
else if (value === "withdrew" && e < v) {
sheet.hideRows(rowI + 1, 1);
}
});
colT.forEach(function(value, rowI) {
if (value === "rejected" && f < v) {
sheet.hideRows(rowI + 1, 1);
}
else if (value === "withdrew" && f < v) {
sheet.hideRows(rowI + 1, 1);
}
});
colV.forEach(function(value, rowI) {
if (value === "accepted" && g < v) {
sheet.hideRows(rowI + 1, 1);
}
else if (value === "declined" && g < v) {
sheet.hideRows(rowI + 1, 1);
}
else if (value === "didn't extend" && g < v) {
sheet.hideRows(rowI + 1, 1);
}
});
}
}
Original look of sheet
Intended Look of sheet
Since nobody dares to dive deep into this problem (me included) for now, here is the partial solution.
This function returns true if a given date doesn't belong to current quarter:
function is_the_date_old_enough(checked_date) {
// which quarter the date belongs
const get_quarter_of = date => Math.ceil((date.getMonth()+1)/3);
// number of quarters in current date
var cur_date = new Date();
var cur_date_years = cur_date.getFullYear();
var cur_date_quarts = cur_date_years * 4 + get_quarter_of(cur_date);
// number of quarters in checked date
var checked_date_years = checked_date.getFullYear();
var checked_date_quarts = checked_date_years * 4 + get_quarter_of(checked_date);
// if the difference bigger than zero
return (cur_date_quarts - checked_date_quarts) > 0;
}
// tests (current date: 2022-01-14)
console.log(is_the_date_old_enough(new Date())); // false always
console.log(is_the_date_old_enough(new Date('2021-12-20'))); // true
console.log(is_the_date_old_enough(new Date('2021-09-05'))); // true
console.log(is_the_date_old_enough(new Date('2022-01-05'))); // false
console.log(is_the_date_old_enough(new Date('2000-01-05'))); // true
console.log(is_the_date_old_enough(new Date('2030-01-05'))); // false
Beware, the timezones can get you a headache for dates around first and last days of month. If you need to handle timezones it may require a more complicated solution. I suspect the variable cur_date should be defined with '00:00:00.00' time or something like that.

Compiling time takes too long

Here is my code:
function dataValidation()
{
var ss1 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("2019년 출결 정보");
var ss2 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("원생 정보");
var array = [];
for (var c = 0; c <= 1000; c++)
{
array[c] = [];
}
var count = 0;
var lastRow1;
var data1 = ss1.getRange("C:C").getValues();
for (var k = data1.length-1; k >= 0; k--)
{
if (data1[k][0] != null && data1[k][0] != '')
{
lastRow1 = k+1;
break;
}
}
var lastRow2;
var data2 = ss2.getRange("A:A").getValues();
for (var n = data2.length-1; n >=0; n--)
{
if (data2[n][0] != null && data2[n][0] != '')
{
lastRow2 = n+1;
break;
}
}
for (var i = 2; i <= lastRow1; i++)
{
for (var j = 2; j <= lastRow2; j++)
{
if (ss1.getRange(i, 3).getDisplayValue() == ss2.getRange(j, 1).getDisplayValue())
{
array[i-1][count] = ss2.getRange(j, 2).getDisplayValue();
count++;
}
}
var rule = SpreadsheetApp.newDataValidation().requireValueInList(array[i-1], true).setAllowInvalid(false).build();
ss1.getRange(i, 4).setDataValidation(rule);
count = 0;
}
}
I am so concerned because the compile speed takes too long... It takes about a minute to fully execute :(
Execution hint suggests to change from line 71:
for (var i = 2; i <= lastRow1; i++)
{
for (var j = 2; j <= lastRow2; j++)
{
if (ss1.getRange(i, 3).getDisplayValue() == ss2.getRange(j, 1).getDisplayValue())
{
array[i-1][count] = ss2.getRange(j, 2).getDisplayValue();
count++;
}
}
Personally I think this is because of nested loops but I don't have any clever ideas to replace this loops, nor I have much knowledge about google apps script.
What else I can do to decrease compile time?

Google Sheet script getValues and when find the given value, replace the value of the above row

How can I modify the script below to read the values in a column, but only read the values of the specified cells: L9, L10 ... L18, L19 .... L27, L28 .... (two by two jumping eight, to the end of the column L2000) and when find the value "1" in one of those cells, then replace the value that is 4 lines up with "FALSE"?
e.g. if cell L19 is found the number 1, then replace the value of cell L15 with the word "FALSE" ... and if cell L28 is found the number 1, then replace the value of cell L24 with the word "FALSE"
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("ABC");
var lastrow = ss.getLastRow();
var range = ss.getRange(9, 12, lastrow - 1, 1);
var data = range.getValues();
for (var i=0; i < data.length; i++) {
if (data[i][0] == "1") {
data[i][0] = "FALSE";
}
}
range.setValues(data);
Add another counter to loop: Try Modifying
From:
var range = ss.getRange(9, 12, lastrow - 1, 1);
var data = range.getValues();
for (var i=0; i < data.length; i++) {
if (data[i][0] == "1") {
data[i][0] = "FALSE";
}
}
To:
var range = ss.getRange(5, 12, lastrow+5, 1);
var data = range.getValues();
var m= 0;
for (var i=4; i < data.length; ) {
if (data[i][0] == "1") {
data[i-4][0] = "FALSE";
}
m++;
if (m == 2) {
m=0;
i = i + 8;
} else {
i++;
}
}
My take on what the loop should become:
var range = ss.getRange(9, 12, lastrow - 1, 1);
var data = range.getValues();
var i = 4,
// Subtract 1 here because we compare both i and i+1 in the same loop body
len = data.length - 1;
while (i < len) {
// Check the value of the first row in the subset.
if (data[i][0] == 1) {
data[i - 4][0] = "FALSE";
}
// Check the next row in the subset.
if (data[++i][0] == 1) {
data[i - 4][0] = "FALSE";
}
// Advance to the next subset.
i += 8;
}

How to calculate taking input from four fields in yii2 dynamic form

I've five fields- rate, qty. discount, cgst_percent, cgst_amount.
I want to calculate cgst_amount. The formula should be -
cgst_amount = ((rate*qty - (rate*qty*discount)/100)*cgst_percent)/100
To Start with simple steps, I tried cgst_amount = rate*qty
The javascript part is as below -
<?php
/* start getting the cgst */
$script = <<< JS
function getGst(item) {
var index = item.attr("id").replace(/[^0-9.]/g, "");
var qtyvar = ratevar = discvar = cgstpercentvar = cgstvar = 0;
var id = item.attr("id");
var myString = id.split("-").pop();
if (myString == "rate") {
fetch1 = index.concat("-qty");
fetch2 = index.concat("-discount");
fetch3 = index.concat("-cgst_rate");
} else if (myString == "qty") {
fetch1 = index.concat("-rate");
fetch2 = index.concat("-discount");
fetch3 = index.concat("-cgst_rate");
} else if (myString == "discount"){
fetch1 = index.concat("-qty");
fetch2 = index.concat("-rate");
fetch3 = index.concat("-cgst_rate");
} else {
fetch1 = index.concat("-qty");
fetch2 = index.concat("-rate");
fetch3 = index.concat("-discount");
}
temp1 = $("#productsales-"+fetch1+"").val();
temp2 = $("#productsales-"+fetch2+"").val();
temp3 = $("#productsales-"+fetch3+"").val();
//alert (temp2);
if (!isNaN(temp1) && temp1.length != 0) {
ratevar = temp1;
}
if (isNaN(temp2) || temp2.length != 0) {
discvar = temp2;
}
if (isNaN(temp3) || temp3.length != 0) {
cgstpercentvar = temp3;
}
qtyvar = item.val();
if (isNaN(qtyvar) || qtyvar.length == 0) {
qtyvar = 0;
}
//alert (qtyvar);
if (!isNaN(qtyvar) && !isNaN(ratevar) && !isNaN(discvar) && !isNaN(cgstpercentvar)) {
cgstvar = (parseFloat(qtyvar) * parseFloat(ratevar)).toFixed(2);
}
cgstField = "productsales-".concat(index).concat("-cgst_amount");
$("#"+cgstField+"").val(cgstvar);
}
JS;
$this->registerJs($script, View::POS_END);
/* end getting the cgst */
?>
Whn I key in rate and qty I get multiply of them as output in cgst_amount textbox. No problem so far. As soon as I key in anything in discount,the same texts are getting written in cgst_amount as output.
I'm not quite sure about the javascript part.
It is an extension of - Calculate from 3 inputfield in dynamic form yii2 and Calculate 3 fields and display the result in the 4th in yii2 dynamic form
If I work on the full formula, the javascript calculation part becomes - cgstvar = ((((parseFloat(ratevar) * parseFloat(qtyvar)) - (parseFloat(ratevar) * parseFloat(qtyvar) * parseFloat(discvar))/100) * parseFloat(cgstpercentvar))/100).toFixed(2);
And the example is as below image -
The actual result should have been - 5.43. Instead I'm getting -0.00
You meshed up with fields and variables, i have updated a script a bit :
function getGst(item) {
var index = item.attr("id").replace(/[^0-9.]/g, "");
var qtyvar = ratevar = discvar = cgstpercentvar = cgstvar = 0;
var id = item.attr("id");
var myString = id.split("-").pop();
quantity = index.concat("-qty");
rate = index.concat("-rate");
discount = index.concat("-discount");
cgstRate = index.concat("-cgst_rate");
temp1 = $("#productsales-"+quantity+"").val();
temp2 = $("#productsales-"+rate+"").val();
temp3 = $("#productsales-"+discount+"").val();
temp4 = $("#productsales-"+cgstRate+"").val();
if (isNaN(temp1) || temp1.length != 0) {
qtyvar = temp1;
}
if (!isNaN(temp2) && temp2.length != 0) {
ratevar = temp2;
}
if (isNaN(temp3) || temp3.length != 0) {
discvar = temp3;
}
if (isNaN(temp4) || temp4.length != 0) {
cgstpercentvar = temp4;
}
if (!isNaN(qtyvar) && !isNaN(ratevar) && !isNaN(discvar) && !isNaN(cgstpercentvar)) {
cgstvar = ((((parseFloat(ratevar) * parseFloat(qtyvar)) - (parseFloat(ratevar) * parseFloat(qtyvar) * parseFloat(discvar))/100) * parseFloat(cgstpercentvar))/100).toFixed(2);
}
cgstField = "productsales-".concat(index).concat("-cgst_amount");
$("#"+cgstField+"").val(cgstvar);
}