Good day all:

I have an editable invoice that I have added a sales tax option with a js function doMath(). Prior to my modification with the sales tax option all worked well. the invoice which code is the following:

<textarea id="address" rows="6" cols="38" disabled="true">Website:
Email:
TaxID:
</textarea >
         <div id="vehicleid"><label><strong><u>Vehicle Information</u></strong></label><p>Year: <?php echo $edit_caryear?></p><p>Type: <?php echo $dhtmlgoodies_categoryupdate?></p><p>Make: <?php echo $dhtmlgoodies_subcategoryupdate?></p><p>ClientID# <?php echo $edit_clientID?></p><p>Current Mileage <?php echo $edit_mileage?></p></div>
 
 
        <!--</div>-->
              <!--<div id="logo">
 
              <div id="logoctr">
                <a href="javascript:;" id="change-logo" title="Change logo">Change Logo</a>
                <a href="javascript:;" id="save-logo" title="Save changes">Save</a>
                |
                <a href="javascript:;" id="delete-logo" title="Delete logo">Delete Logo</a>
                <a href="javascript:;" id="cancel-logo" title="Cancel changes">Cancel</a>
              </div>
 
            <div id="logohelp">
                <input id="imageloc" type="text" size="50" value="" /><br />
                (max width: 540px, max height: 100px)
              </div>
              <img id="image" src="images/logo.png" alt="logo" width="280" height="33" />
            </div>-->
 
        </div>
 
        <div style="clear:both"></div>
        <br>
        <div id="customer">
           <?php echo $edit_firstname ?> <?php echo $edit_lastname?><p><?php echo $edit_address?></p><p><?php echo $edit_city?>, <?php echo $edit_state?>, <?php echo $edit_zipcode?></p>
                       </div>
 
<div id=invoicehead>
            <table id="meta">
                <tr>
                    <td class="meta-head">Invoice #</td>
                    <td><textarea style="background: transparent;" name="invoicenum" id="invoicenun" disabled="true"><?php
srand(time());
$random = (rand()%1000000);
print("$random");
?></textarea></td>
                </tr>
                <tr>
 
                    <td class="meta-head">Date</td>
                    <td><textarea name="date" id="date">December 15, 2009</textarea></td>
                </tr>
                <tr>
                    <td class="meta-head">Amount Due</td>
                    <td><div name="due" class="due">$0.00</div></td>
                </tr>
 
            </table>
 
        </div>
 
        <table id="items">
 
          <tr>
              <th>Item</th>
              <th>Description</th>
              <th>Unit Cost</th>
              <th>Quantity</th>
              <th>Price</th>
          </tr>
 
          <tr class="item-row">
              <td class="item-name"><div class="delete-wpr">
                        <!--<label for=\"dhtmlgoodies_category\">Make:</label>-->
                <?php echo $edit_servicearea?><br>
                <!--<SELECT NAME="edit_servicearea">
                        <OPTION>Select One
                        <OPTION>Air Intake
                        <OPTION>Brake
                        <OPTION>Clutch
                        <OPTION>Cooling System
                        <OPTION>Driveshaft & Axle
                        <OPTION>Engine Mechanical
                        <OPTION>Exhaust
                        <OPTION>Steering
                        <OPTION>Suspension
                        <OPTION>Transmission
                        <OPTION>Other
                        </SELECT>-->
<a class="delete" href="javascript:;" title="Remove row">X</a></div></td>
    <td class="description">
 
<textarea name="servicedesc" cols="255" rows="20"><?php echo str_replace('<br/>', "\n", "$inputbox");?></textarea></td>
              <td><textarea name="cost" class="cost">$0.00</textarea></td>
              <td><textarea name="qty" class="qty">1</textarea></td>
              <td><span name="price" class="price">$0.00</span></td>
          </tr>
 
          <tr class="item-row">
              <td class="item-name"><div class="delete-wpr">
                <textarea name="Labor rate" cols="20" rows="3">Labor</textarea><a class="delete" href="javascript:;" title="Remove row">X</a></div></td>
 
              <td class="description" wrap=virtual><textarea>Labor rate for the performance of work --excluding cost for parts.</textarea></td>
              <td><textarea class="cost">$75.00</textarea></td>
              <td><textarea class="qty" rows="2" cols="10">0</textarea></td>
              <td><span class="price">$0.00</span></td>
          </tr>
 
          <tr id="hiderow">
            <td colspan="5"><a id="addrow" href="javascript:;" title="Add a row">Add a row</a></td>
          </tr>
 
          <tr>
              <td colspan="2" class="blank"> </td>
              <td colspan="2" class="total-line">Subtotal</td>
              <td class="total-value"><div id="subtotal">$0.00</div></td>
          </tr>
                       <tr>
                <td colspan="2" class="blank"> </td>
              <td colspan="2" class="tax-line" style="text-align: left" valign="top">INCLUDE TAX? <input type = "checkbox" id = "taxbox" onclick = "doMath()"><br>DC 
                5.576%</td>
               <td class="total-value"><textarea class="tax" id="tax" >$0.00</textarea></td>            </tr>
             <tr>
 
              <td colspan="2" class="blank"> </td>
              <td colspan="2" class="total-line">Total</td>
              <td class="total-value"><div id="total">$0.00</div></td>
          </tr>
<tr>
              <td colspan="2" class="blank"> </td>
              <td colspan="2" class="total-line">Amount Paid</td>
              <td class="total-value"><textarea id="paid">$0.00</textarea></td>
          </tr>
          <tr>
              <td colspan="2" class="blank"> </td>
              <td colspan="2" class="total-line balance">Balance Due</td>
              <td class="total-value balance"><div class="due">$0.00</div></td>
          </tr>
 
        </table>
        </div>
 
 
       </div>
    <div>
<SCRIPT LANGUAGE="JavaScript">
document.write('<form><input type=button value="Refresh" onClick="history.go()"></form>')
</script>
</div><br>
 
    <div id="option">
    <input type="button" id="button" value="Return to Main Menu" onclick="window.location='/andy/addentry.php' " />
    <input type="hidden" name="servicedesc" value="<?php echo $_POST['servicedesc']; ?>">
     <br>
&nbsp;<p> 
     <! I added this button, so that it returns us to the main Menu.> 
     <INPUT TYPE="button" onClick="window.print()" value="Print" /><br>
&nbsp;</p>
    <p><! The above button Clears all the Field's contents ><input type="submit" name="submit" value="Save Changes">
 </div>
</form>

the section of the code higlighted in red is where my problem arises. To achieve the desired results(at least so that I thought), I included the following function in my js function file which is as follows:

function update_total() {
	var total = 0;
  $('.price').each(function(i){
    price = $(this).html().replace("$","");
    if (!isNaN(price)) total += Number(price);
      });
      
  total =roundNumber(total,2);

  $('#subtotal').html("$"+total);
  $('#total').html("$"+total);
  //$('#tax').html("$"+total);

  
  update_balance();
}
var taxRate = .0575;
function doMath(){
     //var subtotal =  0.00;//$('.price').each(function(i);
   var subtotal = $('#subtotal').value;//.html("$"+total);
  if (document.getElementById("taxbox").checked) {
tax = subtotal* taxRate;  //DC 5.576%
tax = roundNumber(tax,2);//the 2 represent the number of digits to round numbers to after decimal point
//tx = " Incl. 5.576%";
}
document.getElementById("tax").value = "$" +tax;
}function update_balance() {
  var due = $("#total").html().replace("$","") - $("#paid").val().replace("$","");
  due = roundNumber(due,2);
  
  $('.due').html("$"+due);
}
function update_price() {
  var row = $(this).parents('.item-row');
  var price = row.find('.cost').val().replace("$","") * row.find('.qty').val();
  price = roundNumber(price,2);
  isNaN(price) ? row.find('.price').html("N/A") : row.find('.price').html("$"+price);
  
  update_total();
}

function bind() {
  $(".cost").blur(update_price);
  $(".qty").blur(update_price);

}

$(document).ready(function() {

  $('input').click(function(){
    $(this).select();
  });
 
  $("#paid").blur(update_balance);
   
  $("#addrow").click(function(){
    $(".item-row:last").after('<tr class="item-row"><td class="item-name"><div class="delete-wpr"><SELECT NAME="edit_servicearea"><option>Select One<option>Air Intake<option>Brakes<option>Clutch<option>Cooling System<option>Driveshaft & Axle<option>Engine Mechanical<option>Exhaust<option>Steering<option>Suspension<option>Transmission<option>Other</select><a class="delete" href="javascript:;" title="Remove row">X</a></div></td><td class="description"><textarea>Description</textarea></td><td><textarea class="cost">$0</textarea></td><td><textarea class="qty">0</textarea></td><td><span class="price">$0</span></td></tr>');
    if ($(".delete").length > 0) $(".delete").show();
    bind();
  });
  
  $(".tax").blur(update_total);//binding tax
  //bind();
    
  bind();
  
.....
  
});

Again, here, my sales tax is highlighted in red. My problem specifically is that I'm unable to:
1.) get the sales tax rate to calculate based on the value of the subtotal, and
2.) on selection for including taxes, to bind the sale tax amount to the total.

I trust someone can provide some guidance!
Mossa

Recommended Answers

All 7 Replies

Mossa,

Here's a bunch of ideas:

First, a couple of utilites that will help keep the volume of code down - add immediately after your jquery script.

<script>
Number.prototype.toCurrency = function() { return "$" + this.toFixed(2); };
String.prototype.fromCurrency = function() { return Number(this.replace("$","")); };
</script>

Next, apply Number.toCurrency() and String.fromCurrency() all through, where you currently either add or strip the "$" symbol and round to to 2 decimal places.

Next, rename the function update_total as update and migrate the code from doMath and update_balance into it. Now modify the migrated code such that it is unnecessary to rediscover known values from the DOM in order to do further maths. Delete functions doMath and update_balance .

Next, in update separate subtotal from total and adjust the total calculation to add in the calculated tax.

Next, change all lines $("#...").xxxx(update_balance) and $("#...").xxxx(update_total) to $("#...").xxxx(update); .

Next, change the tax element from class="tax" to id="tax" (there's only one of them) and make a corresponding change in the javascript.

Next, get rid of the taxbox's onclick="...". Attach update as its event handler in javascript with $("#taxbox").click(update); .

Comment: Several <textbox>s should probably be <input type="text">s.

Putting all this together ....

Javascript:

var taxRate = 0.0575;

function update() {
	var subtotal = 0;
	$('.price').each(function(i) {
		price = $(this).html().fromCurrency();
		if (!isNaN(price)) subtotal += price;
	});
	$('#subtotal').html(subtotal.toCurrency());

	//doMath
	var tax = ($('#taxbox').attr('checked')) ? (subtotal * taxRate) : 0;
	$('#tax').val(tax.toCurrency());

	var total = subtotal + tax;
	$('#total').html(total.toCurrency());

	//update_balance
	var due = total - $('#paid').val().fromCurrency();
	$('.due').html(due.toCurrency());
}

function update_price() {//This could also be migrated into update
	var row = $(this).parents('.item-row');
	var price = row.find('.cost').val().fromCurrency() * Number(row.find('.qty').val());
	isNaN(price) ? row.find('.price').html("N/A") : row.find('.price').html(price.toCurrency());
	update();
}

function bind() {
	$('.cost').blur(update_price);
	$('.cost').keyup(update_price);//added
	$('.qty').blur(update_price);
	$('.qty').keyup(update_price);//added
}

$(document).ready(function() {
	$('input').click(function(){
		$(this).select();
	});
	$('#addrow').click(function(){
		$('.item-row:last').after('<tr class="item-row"><td class="item-name"><div class="delete-wpr"><SELECT NAME="edit_servicearea"><option>Select One<option>Air Intake<option>Brakes<option>Clutch<option>Cooling System<option>Driveshaft & Axle<option>Engine Mechanical<option>Exhaust<option>Steering<option>Suspension<option>Transmission<option>Other</select><a class="delete" href="javascript:;" title="Remove row">X</a></div></td><td class="description"><textarea>Description</textarea></td><td><textarea class="cost">$0</textarea></td><td><textarea class="qty">0</textarea></td><td><span class="price">$0</span></td></tr>');
		if ($('.delete').length > 0) { $('.delete').show(); }//Not sure about the if clause
		bind();
	});
	$('#paid').blur(update);//changed from $("#paid").blur(update_balance)
	$('#paid').keyup(update);//added
	$('#tax').blur(update);//Should the be user-enterable? It's a calculated value.
	$('#taxbox').click(update);
	$('#taxRate').html(taxRate * 100);//Added. This ensures the rate show to the user is the same as the rate used in the calcs
	bind();
//.....
});

HTML:

<textarea id="address" rows="6" cols="38" disabled="true">Website:
Email:
TaxID:
</textarea >
        <div id="vehicleid"><label><strong><u>Vehicle Information</u></strong></label><p>Year: <?php echo $edit_caryear?></p><p>Type: <?php echo $dhtmlgoodies_categoryupdate?></p><p>Make: <?php echo $dhtmlgoodies_subcategoryupdate?></p><p>ClientID# <?php echo $edit_clientID?></p><p>Current Mileage <?php echo $edit_mileage?></p></div>
        </div>
        <div style="clear:both"></div>
        <br>
        <div id="customer">
           <?php echo $edit_firstname ?> <?php echo $edit_lastname?><p><?php echo $edit_address?></p><p><?php echo $edit_city?>, <?php echo $edit_state?>, <?php echo $edit_zipcode?></p>
        </div>
<div id=invoicehead>
            <table id="meta" border>
                <tr>
                    <td class="meta-head">Invoice #</td>
                    <td><textarea style="background: transparent;" name="invoicenum" id="invoicenun" disabled="true"><?php
srand(time());
$random = (rand()%1000000);
print("$random");
?></textarea></td>
                </tr>
                <tr>
                    <td class="meta-head">Date</td>
                    <td><textarea name="date" id="date">December 15, 2009</textarea></td>
                </tr>
                <tr>
                    <td class="meta-head">Amount Due</td>
                    <td><div name="due" class="due">$0.00</div></td>
                </tr>
            </table>
        </div>
        <table id="items" border>
          <tr>
              <th>Item</th>
              <th>Description</th>
              <th>Unit Cost</th>
              <th>Quantity</th>
              <th>Price</th>
          </tr>
          <tr class="item-row">
              <td class="item-name"><div class="delete-wpr">
                        <!--<label for=\"dhtmlgoodies_category\">Make:</label>-->
                <?php echo $edit_servicearea?><br>
                <!--<SELECT NAME="edit_servicearea">
                        <OPTION>Select One
                        <OPTION>Air Intake
                        <OPTION>Brake
                        <OPTION>Clutch
                        <OPTION>Cooling System
                        <OPTION>Driveshaft & Axle
                        <OPTION>Engine Mechanical
                        <OPTION>Exhaust
                        <OPTION>Steering
                        <OPTION>Suspension
                        <OPTION>Transmission
                        <OPTION>Other
                        </SELECT>-->
<a class="delete" href="javascript:;" title="Remove row">X</a></div></td>
    <!--td class="description"><textarea name="servicedesc" cols="255" rows="20"><?php echo str_replace('<br/>', "\n", "$inputbox");?></textarea></td-->
    <td class="description"><textarea name="servicedesc" cols="15" rows="5"><?php echo str_replace('<br/>', "\n", "$inputbox");?></textarea></td><!-- reduced size of textarea to get form on screen-->
              <td><textarea name="cost" class="cost">$0.00</textarea></td>
              <td><textarea name="qty" class="qty">1</textarea></td>
              <td><span name="price" class="price">$0.00</span></td>
          </tr>
 
          <tr class="item-row">
              <td class="item-name"><div class="delete-wpr">
                <textarea name="Labor rate" cols="20" rows="3">Labor</textarea><a class="delete" href="javascript<b></b>:;" title="Remove row">X</a></div></td>
 
              <td class="description" wrap=virtual><textarea>Labor rate for the performance of work --excluding cost for parts.</textarea></td>
              <td><textarea class="cost">$75.00</textarea></td>
              <td><textarea class="qty" rows="2" cols="10">0</textarea></td>
              <td><span class="price">$0.00</span></td>
          </tr>
 
          <tr id="hiderow">
            <td colspan="5"><a id="addrow" href="javascript<b></b>:;" title="Add a row">Add a row</a></td>
          </tr>
 
          <tr>
              <td colspan="2" class="blank"> </td>
              <td colspan="2" class="total-line">Subtotal</td>
              <td class="total-value"><div id="subtotal">$0.00</div></td>
          </tr>
<!--  -->
          <tr>
             <td colspan="2" class="blank"> </td>
             <td colspan="2" class="tax-line" style="text-align: left" valign="top">INCLUDE TAX? <input type="checkbox" id="taxbox"><br><!-- onclick="..." not necessary -->
			 DC <span id="taxRate"></span>%</td>
             <td class="total-value"><textarea id="tax" id="tax">$0.00</textarea></td>
		  </tr>
<!--  -->
             <tr>
              <td colspan="2" class="blank"> </td>
              <td colspan="2" class="total-line">Total</td>
              <td class="total-value"><div id="total">$0.00</div></td>
          </tr>
		  <tr>
              <td colspan="2" class="blank"> </td>
              <td colspan="2" class="total-line">Amount Paid</td>
              <td class="total-value"><textarea id="paid">$0.00</textarea></td>
          </tr>
          <tr>
              <td colspan="2" class="blank"> </td>
              <td colspan="2" class="total-line balance">Balance Due</td>
              <td class="total-value balance"><div class="due">$0.00</div></td>
          </tr>
        </table>
        </div>
      </div>
    <div>
<SCRIPT LANGUAGE="JavaScript">
document.write('<form><input type=button value="Refresh" onClick="history.go()"></form>')
</script>
</div><br>
    <div id="option">
    <input type="button" id="button" value="Return to Main Menu" onclick="window.location='/andy/addentry.php' " />
    <input type="hidden" name="servicedesc" value="<?php echo $_POST['servicedesc']; ?>">
     <br>
&nbsp;<p> 
     <! I added this button, so that it returns us to the main Menu.> 
     <INPUT TYPE="button" onClick="window.print()" value="Print" /><br>
&nbsp;</p>
    <p><! The above button Clears all the Field's contents ><input type="submit" name="submit" value="Save Changes">
 </div>
</form>

Several specifiec comments in code.

I have done limited testing of this in the latest Firefox. Successful as far as it goes.

For updating the calculated values, I think it's important to migrate as much as possible into update and attach this to (almost) anything that can change the calculation (the exception is currently the cost and qty fileds). With a bit of thought you can also migrate update_price , thus making update solely responsible for all calculation. That's certainly what I would do as it removes all uncertainty as to whether everything is up to date when update is called.

You may not want to do all the other changes but note that some are dependant on others (particularly where the HTML is modified and the javascript needs corresponding mod(s)).

Have fun.

Airshow

Airshow, firstly, thank you so very much for the time to expound in great details. I'm getting ready to dig into your suggestions and trust that within, lies the solution to my problem.

Again, thank you very much for your time and expertise in this area. I'll advise of the outcome.

Best,
Mossa

Airshow, you are indeed the Virtuoso, the revision works well -as explained. Now concerning the check box could i still make this option available so that the tax addition to the total is optional. Currently the calculation --including the tax amount is live as the information is typed, which I think is superb and exceed what I had in mind.

You noted in the post to replace the onclick="doMath()"; with click(update); I was assuming that it would still perform the same action. I do need it to perform the same action --of making tax addition to the total optional. Any thoughts on this!

Airshow, please disregard the latter part of my last post --concerning the checkbox. Reading your instructions again made it clear that specific desired task was addressed. Got it working perfectly!

Thanks, again,
Mossa

Glad you like it Mossa.

I've had a few additional thoughts.

1. Migration of update_price into update is actually very simple.

2. As it stands, errors resulting from update_price are ignored in the accrual of subtotal, which is then incorrect without warning the user. For me, it would be better to allow any error to ripple through such that the displayed tax/subtotal/total correctly reflect the error.

3. Your "old" system of reading back data from the document had the advantage that rounding errors in the displayed data were automatically reflected in the calculations. My code maintains accuracy but could give rise to apparant inconsistency at the 1cent level due to rounding. This can be fixed in the code without reading data back from the document.

We can address all these points with fairly minor revisions to update and bind :

function update() {
	var subtotal = 0;
	var errorMsg = "N/A";

	//update_prices and accrue subtotal
	$('.price').each(function(i) {
		var row = $(this).parents('.item-row');
		var price = row.find('.cost').val().fromCurrency() * Number(row.find('.qty').val());
		$(this).html(isNaN(price) ? errorMsg : price.toCurrency());//Display value or 'error' if calculation failed
		subtotal += price.toCurrency().fromCurrency();//"double-shuffle" to ensure the calculation is consistent with the displayed data.
	});

	//subtotal
	$('#subtotal').html(isNaN(subtotal) ? errorMsg : subtotal.toCurrency());//Display value or 'error' if calculation failed

	//doMath (tax)
	var tax = ($('#taxbox').attr('checked')) ? (subtotal * taxRate) : 0;
	$('#tax').val(isNaN(tax) ? errorMsg : tax.toCurrency());//Display value or 'error' if calculation failed

	//total
	var total = subtotal + tax.toCurrency().fromCurrency();//"double-shuffle" to ensure the calculation is consistent with the displayed data.
	$('#total').html(isNaN(total) ? errorMsg : total.toCurrency());//Display value or 'error' if calculation failed

	//update_balance
	var due = total - $('#paid').val().fromCurrency();
	$('.due').html(isNaN(due) ? errorMsg : due.toCurrency());//Display value or 'error' if calculation failed
}

function bind() {
	$('.cost').blur(update);
	$('.cost').keyup(update);//added
	$('.qty').blur(update);
	$('.qty').keyup(update);//added
}

Comments in code explain.

Airshow

Airshow, you have indeed uncomplicated this part of my project --thus alleviating me of much headaches. I can't thank you enough!

I'll make the revision and advise.
The very best,

Mossa

All works well!

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.