Calculating shipping cost in a form

H

Howard Martin

I have a form at http://www.develop.check.com.au/hh/order.html where
an extended sub-total and then a grand total is calculated as soon as
a quantity is input by a user. I would like to be able to add the
shipping cost to that grand total.

Shipping costs are in the "Postage & handling charges" link and are a
cost per box. If somebody selects "USA, Canada, Middle East" from the
drop down box it should recalculate the shipping cost, otherwise it
should calculate on the default - Australia.

If I post the calculation functions here they'll wrap but they are at
http://www.develop.check.com.au/hh/calculate2.js

Many TIA for your help.
 
A

ASM

Howard said:
I have a form at http://www.develop.check.com.au/hh/order.html where
an extended sub-total and then a grand total is calculated as soon as
a quantity is input by a user. I would like to be able to add the
shipping cost to that grand total.

Shipping costs are in the "Postage & handling charges" link and are a
cost per box. If somebody selects "USA, Canada, Middle East" from the
drop down box it should recalculate the shipping cost, otherwise it
should calculate on the default - Australia.

calculation in caculate2.js :

shipping = new Array('5.00','7.50','8.50','9.50');

function total(what,number) {
var grandTotal = 0;
var quantTotal = 0;
for (var i=0;i<number;i++) {
if (what.elements['price' + i].value == '')
what.elements['price' + i].value = '0.00'; // fix for Opera.

what.elements['subtotal' + i].value=(what.elements['quantity' + i].value
- 0) * (what.elements['price' + i].value - 0);
if (what.elements['quantity' + i].value == "0")
what.elements['subtotal' + i].value = "0.00";

subtotal=what.elements['subtotal' + i].value
grandTotal += (what.elements['price' + i].value - 0) *
(what.elements['quantity' + i].value - 0);

quantTotal += what.elements['quantity'+i].value*1;
}

shippingCost = quantTotal *
shipping[what.elements['location'].selectedIndex];

shippingCost = quantTotal>200? shippingCost*0.8 :
quantTotal>100? shippingCost*0.9 :
quantTotal>50? shippingCost*0.95 :
shippingCost*1;
grandTotal += shippingCost;

subtotal = roundoff(Math.round(subtotal*Math.pow(10,2))/Math.pow(10,2));
what.grandTotal.value =
roundoff(Math.round(grandTotal*Math.pow(10,2))/Math.pow(10,2));

}
If I post the calculation functions here they'll wrap but they are at
http://www.develop.check.com.au/hh/calculate2.js

calculation here :

shipping = new Array('5.00','7.50','8.50','9.50');

function total2(what) {
var quantTotal = 0;
var j=0;
for(var i=0;i<what.length;i++)
if(what.elements.name.substring(0,4)=='quant')
j++;
for (var i=0;i<j;i++)
quantTotal += what.elements['quantity'+i].value*1;
shippingCost = quantTotal *
shipping[what.elements['location'].selectedIndex];
shippingCost = quantTotal>200? shippingCost*0.8 :
quantTotal>100? shippingCost*0.9 :
quantTotal>50? shippingCost*0.95 :
shippingCost*1;
what.grandTotal.value += shippingCost;
what.grandTotal.value=roundoff(Math.round(what.grandTotal.value*Math.pow(10,2))/Math.pow(10,2));
}
 
D

Dr John Stockton

JRS: In article <[email protected]>, dated Tue,
19 Jul 2005 03:59:12, seen in ASM <stephanemo
(e-mail address removed)> posted :
calculation in caculate2.js :
grandTotal += (what.elements['price' + i].value - 0) *
(what.elements['quantity' + i].value - 0);

There is no need to explicitly convert String to Number before
multiplication.

quantTotal += what.elements['quantity'+i].value*1;

There is no need to multiply by 1 to convert String to Number; a unary +
does it more elegantly.


See FAQ.

subtotal = roundoff(Math.round(subtotal*Math.pow(10,2))/Math.pow(10,2));
what.grandTotal.value =
roundoff(Math.round(grandTotal*Math.pow(10,2))/Math.pow(10,2));

Math.pow(10, 2) is *always* 100; there is no need to calculate it every
time, or even once. And roundoff is not defined.
 
A

ASM

Dr said:
JRS: In article <[email protected]>, dated Tue,
19 Jul 2005 03:59:12, seen in ASM <stephanemo
(e-mail address removed)> posted :
grandTotal += (what.elements['price' + i].value - 0) *
(what.elements['quantity' + i].value - 0);

There is no need to explicitly convert String to Number before
multiplication.

who can do more can do less :)
quantTotal += what.elements['quantity'+i].value*1;


There is no need to multiply by 1 to convert String to Number; a unary +
does it more elegantly.

not understood what is a unary + ?

foo = foo*1
foo = foo+0
or
foo = Number(foo);

see any really better (or elegant) than other one

if I find it back
Math.pow(10, 2) is *always* 100; there is no need to calculate it every
time, or even once. And roundoff is not defined.

I did think this not mine code was debuged ...
and thought it was a hack
in case of famous JS round number = 9.000000000002
 
R

RobG

Dr said:
JRS: In article <[email protected]>, dated Tue,
19 Jul 2005 03:59:12, seen in ASM <stephanemo
(e-mail address removed)> posted :
Howard said:

calculation in caculate2.js :

grandTotal += (what.elements['price' + i].value - 0) *
(what.elements['quantity' + i].value - 0);


There is no need to explicitly convert String to Number before
multiplication.

And all those 'what.elements' statements can modified for simplicity:

var els = what.elements;

and then:

grandTotal += els['price' + i].value * els['quantity' + i].value;
quantTotal += what.elements['quantity'+i].value*1;


There is no need to multiply by 1 to convert String to Number; a unary +
does it more elegantly.


See FAQ.


subtotal = roundoff(Math.round(subtotal*Math.pow(10,2))/Math.pow(10,2));
what.grandTotal.value =
roundoff(Math.round(grandTotal*Math.pow(10,2))/Math.pow(10,2));


Math.pow(10, 2) is *always* 100; there is no need to calculate it every
time, or even once. And roundoff is not defined.

Roundoff was defined (I missed it too initially)

function roundoff(amount) {
return (amount == Math.floor(amount)) ? amount + '.00' : ( (amount*10 ==
Math.floor(amount*10)) ? amount + '0' : amount);
}

All of the rounding and flooring in other places can be removed and
values 'roundoff-ed' just before display using:

function roundoff(amount) {
x = Math.round(x*100) / 100 + '';
var y = x.split('.');
return ( y.length == 1 )? x+'.00' : ( y[1].length == 2 )? x : x+'0' ;
}

and (for example):

<subtotal_field>.value = roundoff( subtotal );
what.grandTotal.value = roundoff( grandTotal );

Maybe the OP is paid by the metre...
 
R

RobG

ASM said:
Dr said:
JRS: In article <[email protected]>, dated Tue,
19 Jul 2005 03:59:12, seen in ASM <stephanemo
(e-mail address removed)> posted :
grandTotal += (what.elements['price' + i].value - 0) *
(what.elements['quantity' + i].value - 0);


There is no need to explicitly convert String to Number before
multiplication.


who can do more can do less :)
quantTotal += what.elements['quantity'+i].value*1;



There is no need to multiply by 1 to convert String to Number; a unary +
does it more elegantly.


not understood what is a unary + ?

foo = '10'; // foo is a string
bar = foo + 6; // => bar = 106 --concatenation
bar = +foo + 6; // => bar = 16 --addition
--------^

The unary + converts foo to a number.
foo = foo*1
foo = foo+0
or
foo = Number(foo);

see any really better (or elegant) than other one



if I find it back



I did think this not mine code was debuged ...
and thought it was a hack
in case of famous JS round number = 9.000000000002

The code appears to be to round to 2 decimal places. There are more
efficient ways of doing it (see the FAQ or post above).

<URL:http://www.merlyn.demon.co.uk/js-round.htm#Round>

When working with currency, it is often better to do all calculation in
the minor unit (in this case cents) and only display in major units
(dollars here) at the end. That way, all internal calculations are
simplified.

The OP could do all calculations in whole cents and do entirely integer
arithmetic (there is no division, only integer multiplication and
addition) then just add the decimal place at the very end.

The result is no rounding or flooring anywhere and the final format
thing can be the one posted earlier or if x is zero or greater and does
not have leading zeros:

function format2d ( x ) {
return (x<10)? '0.0'+x : (x<100)? '0.'+x :
x.substring(0,x.length-2) +'.'+ x.substring(x.length-2);
}
 
H

Howard Martin

I have a form at http://www.develop.check.com.au/hh/order.html

var els = what.elements;
function roundoff(x) {
x = Math.round(x*100) / 100 + '';
var y = x.split('.');
return ( y.length == 1 )? x+'.00' : ( y[1].length == 2 )? x : x+'0' ;
}
Many thanks to all. A combination of the posts has got it working
perfectly though the extended subtotal shows as "50" instead of
"50.00". I've tried to rectify the matter and my feeble attempts are
shown // commented out in
http://www.develop.check.com.au/hh/calculate2.js
and (for example):

<subtotal_field>.value = roundoff( subtotal );
what.grandTotal.value = roundoff( grandTotal );

Maybe the OP is paid by the metre...

Heheh. I wish! The OP is a php bloke who sometimes has to struggle
with JS.

Howard
 
R

RobG

Howard said:
I have a form at http://www.develop.check.com.au/hh/order.html

var els = what.elements;

function roundoff(x) {
x = Math.round(x*100) / 100 + '';
var y = x.split('.');
return ( y.length == 1 )? x+'.00' : ( y[1].length == 2 )? x : x+'0' ;
}

Many thanks to all. A combination of the posts has got it working
perfectly though the extended subtotal shows as "50" instead of
"50.00". I've tried to rectify the matter and my feeble attempts are
shown // commented out in
http://www.develop.check.com.au/hh/calculate2.js

Comments below...
Heheh. I wish! The OP is a php bloke who sometimes has to struggle
with JS.

Ahh, say no more! ;-p

Your script (I've added quote marks manually):

Ditch the HTML comments, they are completely unnecessary and possibly
harmful in HTML - and should never be used in a .js file.
function roundoff(amount) {
return (amount == Math.floor(amount)) ? amount + '.00' : ( (amount*10
== Math.floor(amount*10)) ? amount + '0' : amount);
}

Replace this with (one of) the suggested alternatives.


Here is your total() function with the suggested modifications applied.
Using shorter form control names would help too:

function total( what, number ) {

var grandTotal = 0;
var subtotal = 0; // Declare subtotal here
var el = what.elements; // New variable for shorter code

for ( var i=0; i<number; i++ ) {
if ( el['price' + i].value == '') {
el['price' + i].value = '0.00'; // fix for Opera.
}
subtotal = el['quantity'+i].value * el['price'+i].value;
el['subtotal'+i].value = roundoff( subtotal );

grandTotal += subtotal;
}

what.grandTotal.value = roundoff( grandTotal );
}

You don't appear to be doing any input validation (you should be
checking that all input is appropriate numbers). Search the group
archives or read the FAQ, there are plenty of examples.

You should also make all inputs other than quantity 'readonly' so only
the quantity can be changed by the user ( <input type="text" .....
readonly> ) unless you want them messing with the price, etc.

I hope you are validating all input back at the server - your users
could be entering anything and can modify readonly inputs if they want
(most aren't that clever, but they aren't the ones you should be worried
about).

Finally, you should have a 'rest' button on the form - users are much
happier if they can clear all the values if they don't want to continue
with the order.
 
H

Howard Martin

You don't appear to be doing any input validation (you should be
checking that all input is appropriate numbers). Search the group
archives or read the FAQ, there are plenty of examples.

You should also make all inputs other than quantity 'readonly' so only
the quantity can be changed by the user ( <input type="text" .....
readonly> ) unless you want them messing with the price, etc.

I hope you are validating all input back at the server - your users
could be entering anything and can modify readonly inputs if they want
(most aren't that clever, but they aren't the ones you should be worried
about).
Many thanks, Rob. The input validation has been fixed and, yes,
everything will be validated server-side. The URL is now
http://www.develop.check.com.au/hh/order.html
and the JS functions are at
http://www.develop.check.com.au/hh/calculate.js

The lines "I will pay by: Credit card online..." are in fact <SUBMIT>
buttons disguised by the magic of CSS though they don't actually do
anything yet.

Howard
 
L

Lasse Reichstein Nielsen

ASM said:
not understood what is a unary + ?

An unary operator that expects a number and gives the same number
back. It is the dual of the unary negation operator used in, e.g.,
bar = -(a * n + 4);
Like the negation operator, it has the side effect of converting
its argument to a number before acting on it.
foo = foo*1

The multiplication operator converts both its arguments to numbers
before acting on them, so this converts the value of "foo" to a
number and the multiplies it by 1, giving that number.
foo = foo+0

This does not work to convert a string to a numerical value. The
plus operator works both as addition of numbers and concatenation
of strings, and if "foo" contains a string, it will do string
concatenation.
foo = Number(foo);

This is the most direct way of converting a value to a number.
The unary plus opeator would do the same as:

foo = +foo;

Personally, I prefer using the Number function. It might be a
tiny bit slower and a few bytes longer, but it is far more
directly readable, especially to people not as familiar with
Javascript.

I wouldn't worry a miniscule difference in effectivity for
something like string to number conversion. It's not something
that should happen inside a tight loop anyway.

/L
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,904
Latest member
HealthyVisionsCBDPrice

Latest Threads

Top