I have 1 select, 2 text inputs & some JSON data in a form:
select input: List of Suppliers
text input 1: Net Amount
text input 2: Gross Amount
JSON Data:contains the rates of various suppliers as JSON in supplier_tax_rates
I am calculating Gross Amount something like this(pseudo code):
grossAmount = NetAmount + ((currently_selected_supplier.tax_percentage_charged / 100) * netAmount)
Here is the complete code:
Calculate total after retriveing tax rate from JSON
Now, this should work but it doesn't. I get NaN(not a number), means something is wrong. But I have trouble find where.
JSfiddle
You have multiple problems in your code. Here is the correct version:
var taxRates = $.parseJSON(supplier_tax_rates);
var getTaxRate = function(id) {
for (var i in taxRates) { // correct loop definition
if (taxRates[i].id == id) { // check you get id correctly
return taxRates[i].tax_percentage_charged; // instead of 'rate'
}
}
};
$('#PurchaseNetAmount').on('change', function(event) {
var taxRatesId = $('#PurchaseSupplierId').val();
var netAmount = parseFloat(this.value);
var grossAmount = netAmount + ((getTaxRate(taxRatesId) / 100) * netAmount);
$('#PurchaseGrossAmount').val(grossAmount);
});
DEMO: http://jsfiddle.net/A9vmg/18/
Your problem is in the look up function.
for(TaxRate in supplier_tax_rates ){
supplier_tax_rates is a string, not a JSON object
Than after you fix that you will have another error
return rate;
What is rate?
Learn to use console.log() or breakpoints so you can step throught your code and debug it.
getTaxRate(taxRatesId) return undefined
Related
I need some assistance figuring out how to sum a column of dynamic totals that could be a positive or negative dollar amount, or an indication of stock shares.
I have a tab-delimited text file of donor contributions for that I am matching up against a CSV file of other related customer data that I am using to create a statement letter which will show a "donation history" of a particular donor. Each donor has a different amount of donations, and to complicate things, the column of data for a particular donation record could show either "$1,000.00" or "($1,000.00)" or "2 Shares APPL". The number with the parentheticals is of course, representing a negative number.
At the end of this column, I need to show a string that will read either "Total: $1,000.00," or if any of the donation history contains a donation record that included shares of stock the returned string will simply read, "$1,000.00 & Stock."
I have been racking my brain trying to come up with the JS rule that can achieve this. I have the JS rule that is generating the donation history correctly, but summing the donation amount column is causing me to go crazy...
Here is the JS for generating my donation history list in the letter (this seems to be working fine):
var contributionList = new ExternalDataFileEx("/~wip/248839 Frontiers/Master Data/Double Data proof.txt", "\t");
var donor_id = Field("Supporter");
var lb = "<br>\n";
var matches = new Array();
for (var i = 0; i <= contributionList.recordCount; i++) {
var idVariable = contributionList.GetFieldValue(i, "Supporter");
var dateVariable = contributionList.GetFieldValue(i, "Donation Date");
var ministryVariable = contributionList.GetFieldValue(i, "Ministry Designation");
var giftVariable = contributionList.GetFieldValue(i, "Donation Amount");
var tsSettings = "<p tabstops=19550,Right,,;29600,Left,,;>";
var ts = "<t>";
if (donor_id == idVariable)
matches.push(tsSettings + dateVariable + ts + giftVariable + ts + ministryVariable);
}
//return matches;
return matches.join(lb);
Now here is the JS code that is not working just fine. I am trying to tally the donation amount column, it only returns "Total: $0.00 & Stock" every time (I have tried to explain my thought process via comments):
var contributionList = new ExternalDataFileEx("/~wip/248839 Frontiers/Master Data/Double Data proof.txt", "\t");
var donor_id = Field("Supporter");
for (var i = 0; i <= contributionList.recordCount; i++) {
var idVariable = contributionList.GetFieldValue(i, "Supporter");
var giftVariable = contributionList.GetFieldValue(i, "Donation Amount");
var sum = 0;
var shares = 0;
var tsSettings = "<p tabstops=19550,Right,,;29600,Left,,;>";
var ts = "<t>";
var totalStr = "Total ";
var stockStr = " & Stock";
var totalFormatted = FormatNumber("$#,###.00", Math.max(0, StringToNumber(sum)));
// Match data from linked file to current Supporter
if (donor_id == idVariable) {
// Look at current record and see if it contains the word "Share(s)"
// or not and act accordingly
if (giftVariable.match(/(^|\W)share($|\W)/i) || giftVariable.match(/(^|\W)shares($|\W)/i)) {
// Turn switch "on" if donation amount is a share or shares so
// we can have the " & Stock" appended to our string.
shares = 1;
// Because this donation is/are shares, we must "zero" this
// amount to make the math work when we sum everything up...
giftVariable = 0;
// This is where we are keeping our running total...
sum += giftVariable[i];
} else {
// This record was not a donation of share(s) so we now have to
// determine whether we are dealing with postive or negative numbers
// and then strip out all of the non-number characters, remove and
// replace the () whis just a "-," leaving us with a number we can
// work with...
// If number has parenthesis, then deal with it...
if (giftVariable.indexOf("(")) {
// Strip out all the ()$, characters...
giftVariable = giftVariable.replace(/[()$,]/g,"")
// Append the minus sign to the number...
giftVariable = "-" + giftVariable;
sum += giftVariable[i];
} else {
giftVariable = giftVariable.replace(/[$,]/g,"");
sum += giftVariable[i];
}
}
}
}
// Return Total...
if (shares == 1) {
return tsSettings + totalStr + ts + totalFormatted + stockStr;
} else {
return tsSettings + totalStr + ts + totalFormatted;
}
Any assistance would be greatly appreciated!
The problem (and code) needs to be broken into smaller, atomic steps. From your description it sounds like you should:
load a text file into memory
for each line in the file
extract: {
donor_id
charity
gift
and store the results in a contributions dictionary
for each item in the contributions dictionary
transform gift string into {
dollarAmount: float with a default of 0.0
stock: name with a default of ""
}
create an empty dictionary called totals
each item will have the shape {
id
dollarAmount as a float
stocks an an array
}
for each item in the contributions dictionary
lookup the id in the totals dictionary
if it exists
totals[id].dolarAmount += item.dollarAmount
totals[id].stocks.push(item.stock)
otherwise
totals[id].dollarAmount = item.dollarAmount
totals[id].stocks = [item.stock]
normalize your charities
for each item in totals dictionary
remove any empty strings from item.charities
create your report
for each item in totals dictionary
write`${item.id} donated `${item.dollarAmont}` ${item.stocks.length > 1 ? 'and stock' : ''
I believe you are trying to do too many things at once. Instead, the goal should be to normalize your data before you attempt to perform any calculations or aggrgrations, then normalize your aggregrations before writing your summaries or reports.
I would also stay away from using any direct string manipulation. You should have a dedicated function whose only purpose is to take a string like "($20.34) and 1 share of APPL" and return either 20.34, -20.34, or 0.0. And a different function whose only purpose is to take the same string and return either true or false is stock was present.
I am making a PDF with a custom calculation script and I want to get the product of 2 fields with the results in the format of currency and for the life of me I cant figure it out. I am relatively new to a lot of this.
Here is the code I currently have:
var QtyRow1 = (this.getField( "QtyRow1").value); // the value of QtyRow1;
var CostRow1 = (this.getField( "CostRow1").value); // the value of CostRow1;
var t1 = QtyRow1 * CostRow1; // the value all TotalRows;
if ( t1 < .01 ) {
// t1 will remain blank if total of CostRow1 * QtyRow are less than 1;
event.value = "";
} else {
// otherwise will calculate total of all TotalRows;
event.value = t1;
}
Additionally here is a link to my PDF I am working on from my google drive. I am trying to take the Quantity and Cost of each row and so a total in the format of Currency from the product of the quantity and cost.
So my problem was I wasn't identifying t1 as a number format with in the JavaScript code so when I would go to the format tab under the form field properties and select that I wanted it to formatted to number and currency it wouldn't work cause it would give me an error saying the "t1" hasn't been properly formatted. So all I did was within the if statement made sure to tell JavaScript that t1 needed to be formatted to a number and did so by doing this: event.value = (Number(t1)) as to where before I just had event.value = t1. That fixed it and now everything works great.
Here is a link to the new PDF with the new code in it:
Click Here
// the value of form field QtyRow1;
var QtyRow1 = (this.getField("QtyRow1").value);
// the value of form field CostRow1;
var CostRow1 = (this.getField("CostRow1").value);
// the product of form fields QtyRow1 and CostRow1;
var t1 = QtyRow1 * CostRow1;
// if statement for results
if( t1 < .01 )
{
// t1 will remain blank if total of form fields CostRow1 * QtyRow are less than .01;
event.value = "";
} else {
// otherwise will caclculate the product of form fields QtyRow1 and CostRow1;
event.value = (Number(t1));
}
Try as I might I CANNOT decipher the problem that I'm having writing new rows to a sheet. I've done this several times and I've debugged this thoroughly using Logger.log, but I just can't solve it. Here's a summary of what I'm doing, a code snippet, and a log:
What I'm doing:
Adding rows to a sheet (below existing rows)
73 new rows are stored stored in array: Grade Rows
When attempt to write the new rows to the sheet, get this error:
Incorrect range width, was 1 should be 26
Here’s the code including some Logger.logs:
var BeginningRow = LastSGRowSheet + 1;
var EndingRow = BeginningRow + SGPushKtr -1;
Logger.log("BeginningRow =>" + BeginningRow + "<=, SGPushKtr =>" + SGPushKtr + "<=, Ending Row =>" + EndingRow + "<=");
var GradesRangeString = 'A' + BeginningRow + ':' + LastStudentGradesColumnLetter + EndingRow;
Logger.log("GradesRangeString =>" + GradesRangeString + "<=");
StudentGradeSheet.getRange(GradesRangeString).setValues(GradeRows);
The error occurs in that last line of code.
Here’s the log:
17-12-31 11:51:15:763 EST] BeginningRow =>364<=, SGPushKtr =>73<=, Ending Row =>436<=
[17-12-31 11:51:15:764 EST] GradesRangeString =>A364:Z436<=
Let's say that your data array is dA then the number of rows in that array is dA.length and assuming its a rectangular array then the number of columns is vA[0].length. So your output command has to be some thing like this.
sheet.getRange(firstRow,firstColumn,dA.length,dA[0].length).setValues(dA);
If you'd like to learn a little more about this problem check this out.
You could also append each row to the current sheet one row at a time in loop.
It's hard to know why GradeRows doesn't match your range without seeing all of your code.
Using Cooper's getRange arguments will likely reveal your problem, and will prevent you from having to update your row and column variables when you make changes to your code. Another issue that gets me sometimes is the fact that the setValues array needs to be exactly the same dimensions as the range. If one row has a different length, it will fail. If the logic I use to create row arrays can result in different lengths, I use the function below to make sure my arrays are symmetric before writing them to a sheet. It is also helpful for debugging.
/**
* Takes a 2D array with element arrays with differing lengths
* and adds empty string elements as necessary to return
* a 2D array with all element arrays of equal length.
* #param {array} ar
* #return {array}
*/
function symmetric2DArray(ar){
var maxLength;
var symetric = true;
if (!Array.isArray(ar)) return [['not an array']];
ar.forEach( function(row){
if (!Array.isArray(row)) return [['not a 2D array']];
if (maxLength && maxLength !== row.length) {
symetric = false;
maxLength = (maxLength > row.length) ? maxLength : row.length;
} else { maxLength = row.length }
});
if (!symetric) {
ar.map(function(row){
while (row.length < maxLength){
row.push('');
}
return row;
});
}
return ar
}
How about using appendRow()? That way you don't need to do lots of calculations about the range. You can loop through your data and add it row by row. Something like this:
myDataArr = [[1,2],[3,4],[5,6]]
myDataArr.forEach(function(arrayItem){
sheet.appendRow([arrayItem[0],arrayItem[1]])
})
// This will output to the sheet in three rows.
// [1][2]
// [3][4]
// [5][6]
I'm still quite new to javascript and was wondering if there's a more efficient way to handle this situation, for example by using an array?
I have an HTML form with 6 fields that let you enter the last six weeks amount of overtime paid. I'm then using javascript to add the six values up, divide by six and multiply by 52 to obtain an annual overtime amount. My fields are named w_ot_1, w_ot_2 up to w_ot_6 and I'm using the code below. It all works fine but I'm finding it's really repetitive and it's not just overtime I need to run this calculation on. I'm sure there's got to be a more efficient way. Does anyone have any ideas that could help?
var weekly_ot_1 = parseFloat(document.getElementById("w_ot_1").value.replace(/[^0-9.]/g, ''));
var weekly_ot_2 = parseFloat(document.getElementById("w_ot_2").value.replace(/[^0-9.]/g, ''));
var weekly_ot_3 = parseFloat(document.getElementById("w_ot_3").value.replace(/[^0-9.]/g, ''));
var weekly_ot_4 = parseFloat(document.getElementById("w_ot_4").value.replace(/[^0-9.]/g, ''));
var weekly_ot_5 = parseFloat(document.getElementById("w_ot_5").value.replace(/[^0-9.]/g, ''));
var weekly_ot_6 = parseFloat(document.getElementById("w_ot_6").value.replace(/[^0-9.]/g, ''));
//weekly annualised overtime values
document.getElementById("w_annual_ot").value= addCommas((((weekly_ot_1 + weekly_ot_2 + weekly_ot_3 + weekly_ot_4 + weekly_ot_5 + weekly_ot_6)/6) * 52).toFixed(2));
This is a situation where you can leverage a simple for loop and string concatenation when calling document.getElementById(). I would suggest creating a function to calculate the overtime paid and have the function take the number of weeks as a parameter so that you can easily change it if you add more fields.
function getOvertimePaid(numberOfWeeks) {
var total = 0;
// Iterate from 1 to the number of weeks and increment the total by
// the parsed value in the field for the current index
for (var i=1; i<=numberOfWeeks; i++) {
total += parseFloat(document.getElementById('w_ot_' + i).value.replace(/[^0-9.]/g, '');
}
// Return the annualized amount as a float for flexibility
return (total / numberOfWeeks) * 52;
}
// Update weekly annualised overtime values and provide formatting at this point
document.getElementById("w_annual_ot").value= addCommas(getOvertimePaid(6).toFixed(2));
Another thing you may want to look at to make the code and the supporting HTML even more flexible is to leverage a class name on your weekly overtime input elements. If you do that and adjust the code slightly you can add or remove fields at will and the function to calculate the annualized overtime will continue to work. As an example:
HTML
<input type="text" id="w_ot_1" class="weekly-overtime" value="0.00" />
<input type="text" id="w_ot_2" class="weekly-overtime" value="0.00" />
<input type="text" id="w_ot_3" class="weekly-overtime" value="0.00" />
JavaScript
function getAnnualizedValue(className) {
// Get all elements with the given class name
var elements = document.getElementsByClassName(className);
// Iterate the elements and keep a running total of their values
var total = 0;
for (var i = 0; i < elements.length; i++) {
total += parseFloat((elements[i].value || '0').replace(/[^0-9.]/g, '');
}
// Return the annualized amount as a float for flexibility
return (total / numberOfWeeks) * 52;
}
// Update weekly annualised overtime values and provide formatting at this point
document.getElementById("w_annual_ot").value= addCommas(getAnnualizedValue('weekly-overtime').toFixed(2));
Ok, I have been working on this for some time, I have some close to getting it to work but not completely. So what I am doing is adding the value from a weekly input form into an array with its key.
There will be no limit on the number of rows as I can (and this works fine) AJAX add a row to the form with a button.
I currently add all the totals for each day together, this works, as all the Mondays have a .Monday class on them (I can post that code it need, please just ask) and each other day.
I have also got an id on each input which as the day of the week and a count, so #Monday0, #Monday1, same for each day and each row ect.
Now what I am doing with the code below, is to add the week up and then display that (console log for now) in that weeks row. So I want to add all the daily ids, Monday though to Sunday that end in 0, then do the same for 1 and so on.
var LoadHourTotals = function() {
$('.TimebreakdownInput').change(function() {
var InputArrays = []; //Array to store all weekly inputs
var Totals = []; //Store Array total for display
GetCurrentID = $(this).attr('id');
CurrentCount = GetCurrentID.charAt(GetCurrentID.length-1)
var WeeklyArray = ["Monday"+CurrentCount,"Tuesday"+CurrentCount,"Wednesday"+CurrentCount,"Thursday"+CurrentCount,"Friday"+CurrentCount,"Saturday"+CurrentCount,"Sunday"+CurrentCount];
$.each(WeeklyArray, function(k, v) {
var values = parseFloat( $('#'+v).val() );
if (isNaN(values)) { values = 0; } //Set value to 0 if its not a number
if (!values) { values = 0; }
InputArrays.push({ key: CurrentCount, hours:values });
});
console.log(InputArrays);
//$('.TimebreakdownTotalHours').html(Totals); //Display / Add total into HTML
});
} //End of LoadHourTotals function
I think I am close with this, each daily input is saved into its own array with a key count and its value for that day. For example, 0:XX 0:XX (this seven times, all for the 1st row). This is then repeated for each row as needed.
If what I have done is not right or there is a better method for doing this, then please let me know.
But now what I need to do is go though each key, take its value, getting a 'grand' total for all seven inputs, then display or save that total into a new array (which is what I was trying to do) then display / console log each weekly total.
I have gone though a number of posts on here but I could not find anything that fits for my problem.
All help very welcome.
If I have not posted some code that is need then please let me know.
Please let me know if I have not explained myself right.
Many Thanks.
Its ok, I have found an answer. I tried this but it did not work,
var total = 0;
$.each(InputArrays,function() {
total += this;
console.log(total);
});
But some playing around with the code, I console loged 'this' and tried the following which now seems to work. Thanks
var total = 0;
$.each(InputArrays,function() {
total += this.hours;
console.log(total);
});