Jump to content
  • Checkout
  • Login
  • Get in touch

osCommerce

The e-commerce.

jQuery/Ajax Advanced Order Handler for osCommerce 2.3.3


Recommended Posts

This is such a great addition, and a reason I had recently been contemplating moving on from osCommerce. Why it doesn't exist in the core is beyond me, it seems like such a no-brainer. THANK YOU.

 

As for the graphs, mine have also disappeared. I've done all the modifications to the download in this thread, and installed the jQuery Flot 0.8.3 as you suggested. They are still not there. I do have 2 errors in developer tools

 

Error: Time mode requires the flot.time plugin.

ReferenceError: Can't find variable: goonload

 

Thanks,

jim

 

 

UPDATE: this is on my local environment . . . I'm uploading it now to my server, let me confirm before you spend any time thinking about this.

Edited by jimlongo
Link to comment
Share on other sites

well it looks great BUT!

I install it from the instractions and i made the corrections posted above the problems seams to be a lot!

 

1. If i add a field with a discount in an order it not subtracked the value from the total value sometimes it sums to the total sometime it stays unchange

2. the buck button returns a blank page

3.if i am inside an order and append a new comment it returns with a blank comment and if you go to the orders_hander.php the order is deleted!!!

4. As for the graphs, mine have also disappeared.

 

for now its a great looking contr!!!!

after alot of updates something like this will be a must have for the osc users

 

lazaros

sorry for my english

Edited by Larry21

regards

Lazaros

Link to comment
Share on other sites

I've uploaded everything now. The graphs are not displaying. In case it was any modifications I've done to those 2 files d_total_revenue.php and d_total_customers.php I uploaded fresh copies from the 2.3.3.4 package.

 

Error: Time mode requires the flot.time plugin.

ReferenceError: Can't find variable: goonload

 

osCommerce 2.3.3.4 PHP 5.4.27

Link to comment
Share on other sites

Could you open the "Network" tab in Chrome Developer Tools, go to the Edit Order Page. Then clear the view by pressing the small icon to the top left under the Network Tab.

 

Now, try again to either add a product or change the amount. Press Filter and select XHR. There should be two rows, press the top one, the one that makes the request to orders_ajax.php.

 

Then Copy the Request URL and Post it back here. It should look something like this:

 

Request URL:https://[YOUR_SERVER]/admin/orders_ajax.php?action=update_product&pID=303&order=318&field=products_quantity&new_value=2

 

I am also getting no action on delete or changes, etc.,

When I do as you requested on an edit to my product model# I get the url -> https://register.mydomain.com/admin/orders_ajax.php?action=update_product&pID=&order=4352&field=products_model&new_value=CT.1Mk

 

On clicking the Delete icon I get -> https://register.mydomain.com/admin/orders_ajax.php?action=eliminate&pID=&order=4352&new_value=0

However, if I click the Delete button at the top of the page, I get a window which when I click Delete actually deletes the order.

 

On clicking the Duplicate Order button in the top row I get the following url -> https://register.mydomain.com/admin/ajax_handler.php?page=1&get_order=4352&cID=&action=duplicate_order

And the notification I get is ->

Error: Not a Numeric Customer ID

Edited by jimlongo
Link to comment
Share on other sites

I've uploaded everything now. The graphs are not displaying. In case it was any modifications I've done to those 2 files d_total_revenue.php and d_total_customers.php I uploaded fresh copies from the 2.3.3.4 package.

 

Error: Time mode requires the flot.time plugin.

ReferenceError: Can't find variable: goonload

 

osCommerce 2.3.3.4 PHP 5.4.27

 

To install the new jQuery flot, replace the files from the new version with the ones you have in ./ext/flot/./, then in ./admin/includes/template_top.php find this code:

<script type="text/javascript" src="<?php echo tep_catalog_href_link('ext/flot/jquery.flot.js'); ?>"></script>

Replace with

<script type="text/javascript" src="<?php echo tep_catalog_href_link('ext/flot/jquery.flot.js'); ?>"></script>
<script type="text/javascript" src="<?php echo tep_catalog_href_link('ext/flot/jquery.flot.time.min.js'); ?>"></script>

 

Done.

 

 

On clicking the Delete icon I get -> https://register.mydomain.com/admin/orders_ajax.php?action=eliminate&pID=&order=4352&new_value=0

However, if I click the Delete button at the top of the page, I get a window which when I click Delete actually deletes the order.

 

It looks like there is a problem retrieving the products_id. Make sure that the delete link with the ajaxLinkProduct class has a attribute called data-product with the ID of the product you want to remove. If it isn't there, then you need to search in order_handler.php and ajax_handler.php to see why data-product doesn't exist/doesn't have correct value.

 

I have fixed a lot of bugs already and introduced some new features to the update that I will publish when I'm done with it. The entire order_handler.js is rewritten to only use jQuery instead of mixed jQuery/Javascript. This should help for compatibility issues.

 

I finally managed to get a real progress bar working, displaying the real amount of orders updated/mail sent to customers when batch updating, using the new HTML5 ProgressEvent interface or AJAX 2. Not that it helps that much to speed up order handling, but it's a nice feature to have. :)

 

I have experimented a lot with the MySQLi prepared statements to see what's possible to do to speed things up and it's really surprising how some situations can benefit from prepared queries and multi queries, especially those that are made in a loop.

 

So, now all queries will be prepared statements instead. Perhaps not all will yield performance increases, but some definitely will and it seems to be the right way to do it.

 

I'm thinking on adding, later on, more Comet and AJAX 2 features, e.g. some nice auto hiding modal/control panel to get an update of currently logged in customers. Perhaps a way to send instant messages to logged in customers. Would that be helpful, perhaps? I don't know.

 

Personally, I have also added features to my own shop to automatically send tracking numbers to my customers. I think that is something that is appreciated A LOT.

And since I did that I don't get those time consuming "What's my tracking number?" E-Mails. It gives the customer a scence that order handling in your shop is really fast and if it's something most online customers like, it's speed.

 

Getting an E-Mail confirmation 5 minutes after the customer have completed their order with tracking information and that estimated delivery is no more than 18 h away has gived me lots of positive feedback. (w00t)

Too many E-Commerce shops are incomprehensible slow in the order processing..

 

Anyway, since there are so many shipping solutions available I don't really know of a way to solve this so everyone can adapt it to their situation.

If you have templates on how your XML/CSV/Text shipping label import/export should look like, you can upload/post them here if you like so that I, maybe, can solve it.

 

I have replaced the search for Add a Product function to use jQuery Autocomplete instead.

 

The Comet function has been improved by removing one of the steps, so now there will only be one request to stream.php and when new orders have been added it will return them instantly instead of having two different script doing all of that.

 

It's now possible to sort the orders Ascending/Descending by pressing on the the respective table heading column, the Sort by number of products in order function now works as it should.

 

I have improved the jQuery code to use Asynchronous requests together with jQuery.deferred. This will speed up the Ajax requests and make handling appear in a more linear soft kind of way (No page locks).

 

There will now be a lot more Growl Notifications when you update orders etc. I have tried to include JSON Error/Success callbacks from most functions to make Order Handling more like a real Application.

 

More tool tips have been added as requested.

 

I don't know, there's probably more things added/replaced in the code. I feel like I need to get away from it a while and work on something else soon since it's starting to get to my head, ha ha. :rolleyes:

 

But I must say I really liked how the new "AJAX 2" handles responses and how useful Comet can be. This really opens up for a lot of ideas on a further development on this and more..

 

 

I'll try to finish this update as soon as I feel like it, that's better then to spend time searching possible bugs in the "old" code, here's one quick fix however:

 

To fix the Back button, find this code in ./admin/js/order_handler.js around line 433

return $( this ).ajaxLink(link + '?ajax=1', 'orderTable' );

Replace with:

return $( this ).ajaxLink(link + '&ajax=1', 'orderTable' );

 

Good night.

Link to comment
Share on other sites

Hello Eric!

 

h

 

Oh, sorry about that, I forgot to include the new files for jQuery flot. You can easily download and replace the ones you have in ./ext/flot/*

Press here to download jQuery Flot 0.8.3 or Click here to visit their website.

 

After that, you can remove your code modification to template_top.php.

 

If your tabbed mod doesn't work, then open the console in Chrome and reply with the error messages that it shows and also expand the error and look at what code it's complaining about, it's the one that's not in the jQuery.js or jQuery-ui.js files. It's usually an easy fix to mod the code to be compatible with the newer versions of jQuery.

 

 

Could you upload a screenshot of the layout?

 

Regarding the database error, I need to see the track trace

 

Could you also go to Admin => Tools => Server Info and check which MySQL driver you're using. At least in the next update I will upload, it will be require to use the MySQL native driver (mysqlnd). This is the preffered driver which gives the best performance increase for PHP and is required when using mysqli_stmt::get_result.

 

So make sure that you can find both "Mysqli Support" and the "mysqlnd" section in your server info.

 

In order to solve the warning you get you need to enable backtraces on your webserver so I can see where the the function has been called. Line 167 in database.php, is that the mysqli_prepared_query function?

 

If you can't enable backtraces, then you can temporarily replace the mysqli_prepared_query function to this:

function mysqli_prepared_query($sql, $typeDef = FALSE, $params = FALSE, $link = "db_link") {
global $$link;
if($stmt = mysqli_prepare($$link,$sql)){
 if(count($params) == count($params,1)){
 $params = array($params);
 $multiQuery = FALSE;
 } else {
 $multiQuery = TRUE;
 }
 if($typeDef){
 $bindParams = array();
 $bindParamsReferences = array();
 $bindParams = array_pad($bindParams,(count($params,1)-count($params))/count($params),"");		
 foreach($bindParams as $key => $value){
	 $bindParamsReferences[$key] = &$bindParams[$key];
 }
 array_unshift($bindParamsReferences,$typeDef);
 $bindParamsMethod = new ReflectionMethod('mysqli_stmt', 'bind_param');
 $bindParamsMethod->invokeArgs($stmt,$bindParamsReferences);
 }
 $result = array();
 foreach($params as $queryKey => $query){
 foreach($bindParams as $paramKey => $value){
	 $bindParams[$paramKey] = $query[$paramKey];
 }
 $queryResult = array();
 if(mysqli_stmt_execute($stmt)){
	 $resultMetaData = mysqli_stmt_result_metadata($stmt);
	 if($resultMetaData){																			
	 $stmtRow = array();
	 $rowReferences = array();
	 while ($field = mysqli_fetch_field($resultMetaData)) {
		 $rowReferences[] = &$stmtRow[$field->name];
	 }							
	 mysqli_free_result($resultMetaData);
	 $bindResultMethod = new ReflectionMethod('mysqli_stmt', 'bind_result');
	 $bindResultMethod->invokeArgs($stmt, $rowReferences);
	 while(mysqli_stmt_fetch($stmt)){
		 $row = array();
		 foreach($stmtRow as $key => $value){
		 $row[$key] = $value;		
		 }
		 $queryResult[] = $row;
	 }
	 mysqli_stmt_free_result($stmt);
	 } else {
	 $queryResult[] = mysqli_stmt_affected_rows($stmt);
	 }
 } else {
	 $queryResult[] = FALSE;
 }
 $result[$queryKey] = $queryResult;
 }
 mysqli_stmt_close($stmt);
} else {
 $result = FALSE;
}
var_dump(debug_backtrace());
debug_print_backtrace();
if($multiQuery){
 return $result;
} else {
 return $result[0];
}
}

 

And then try to find where the function has been called where you get the warning.

 

Also, make sure that the "Add a Product" form has a display:none; CSS attribute to it in stylesheet.css under .addProduct.

 

 

Make sure that the following section in stylesheet.css has the correct path to the fontawesome files:

@font-face {
font-family: 'FontAwesome';
src: url('../css/fonts/fontawesome-webfont.eot?v=4.0.3');
src: url('../css/fonts/fontawesome-webfont.eot?#iefix&v=4.0.3') format('embedded-opentype'), url('../css/fonts/fontawesome-webfont.woff?v=4.0.3') format('woff'), url('../css/fonts/fontawesome-webfont.ttf?v=4.0.3') format('truetype'), url('../css/fonts/fontawesome-webfont.svg?v=4.0.3#fontawesomeregular') format('svg');
font-weight: normal;
font-style: normal;
}

 

 

 

No, you can remove it in order_handler.php, remove this:

<?php
$heading = array();
$contents = array();
switch ($action) {
case 'delete':
 $heading[] = array('text' => '<b>' . TEXT_INFO_HEADING_DELETE_ORDER . '</b>');
 $contents = array('form' => tep_draw_form('orders', FILENAME_ORDERS_HANDLER, tep_get_all_get_params(array('oID', 'action', 'ajax')) . 'oID=' . $oInfo->orders_id . '&action=deleteconfirm'));
 $contents[] = array('text' => TEXT_INFO_DELETE_INTRO . '<br><br><b>' . $oInfo->customers_name . '</b>');
 $contents[] = array('text' => '<br>' . tep_draw_checkbox_field('restock') . ' ' . TEXT_INFO_RESTOCK_PRODUCT_QUANTITY);
 $contents[] = array('align' => 'center', 'text' => '<br>' . tep_draw_button(IMAGE_DELETE, 'trash') . tep_draw_button(IMAGE_CANCEL, 'close', tep_href_link(FILENAME_ORDERS_HANDLER, tep_get_all_get_params(array('oID', 'action')) . 'oID=' . $oInfo->orders_id)));
 break;
default:
 if (isset($oInfo) && is_object($oInfo)) {
 $heading[] = array('text' => '<b>[' . $oInfo->orders_id . ']  ' . tep_datetime_short($oInfo->date_purchased) . '</b>');
 $contents[] = array('align' => 'center', 'text' => tep_draw_button(IMAGE_EDIT, 'document', tep_href_link(FILENAME_ORDERS_HANDLER, tep_get_all_get_params(array('oID', 'action')) . 'oID=' . $oInfo->orders_id . '&action=edit'), 'secondary', array('params' => 'class="ajax_disable"')) . tep_draw_button(IMAGE_DELETE, 'trash', tep_href_link(FILENAME_ORDERS_HANDLER, tep_get_all_get_params(array('oID', 'action', 'ajax')) . 'oID=' . $oInfo->orders_id . '&action=delete'), 'secondary', array('params' => 'class="ajax_disable"')));
 $contents[] = array('align' => 'center', 'text' => tep_draw_button(IMAGE_ORDERS_INVOICE, 'document', tep_href_link(FILENAME_ORDERS_INVOICE, 'oID=' . $oInfo->orders_id), null, array('newwindow' => true), 'secondary', array('params' => 'class="ajax_disable"')) . tep_draw_button(IMAGE_ORDERS_PACKINGSLIP, 'document', tep_href_link(FILENAME_ORDERS_PACKINGSLIP, 'oID=' . $oInfo->orders_id), null, array('newwindow' => true)) . tep_draw_button(IMAGE_CREATE_ORDER, 'document', tep_href_link(FILENAME_CREATE_ORDER, 'Customer=' . $oInfo->customers_id), 'secondary', array('params' => 'class="ajax_disable"')));
 $contents[] = array('text' => '<br />' . TEXT_DATE_ORDER_CREATED . ' ' . tep_date_short($oInfo->date_purchased));
 if (tep_not_null($oInfo->last_modified)) $contents[] = array('text' => TEXT_DATE_ORDER_LAST_MODIFIED . ' ' . tep_date_short($oInfo->last_modified));
 $contents[] = array('text' => '<br />' . ' ' . $oInfo->payment_method);
 }
 break;
}
if ( (tep_not_null($heading)) && (tep_not_null($contents)) ) {
echo '		 <td width="20%" valign="top" id="defaultMenu">' . "\n";
$box = new box;
echo $box->infoBox($heading, $contents);
echo '		 </td>' . "\n";
//tep_exit();
} else {
echo '		 <td id="defaultMenu"></td>';
}
?>

 

And this in ajax_handler.php

<?php
switch ($action) {
case 'delete':
 $heading[] = array('text' => '<b>' . TEXT_INFO_HEADING_DELETE_ORDER . '</b>');
 $contents = array('form' => tep_draw_form('orders', FILENAME_ORDERS_HANDLER, tep_get_all_get_params(array('oID', 'action', 'cID', 'ajax')) . 'oID=' . (int)$oID . '&action=deleteconfirm'));
 $contents[] = array('text' => TEXT_INFO_DELETE_INTRO . '<br><br><b>' . $order->customer['name'] . '</b>');
 $contents[] = array('text' => '<br>' . tep_draw_checkbox_field('restock') . ' ' . TEXT_INFO_RESTOCK_PRODUCT_QUANTITY);
 $contents[] = array('align' => 'center', 'text' => '<br>' . tep_draw_button(IMAGE_DELETE, 'trash') . tep_draw_button(IMAGE_CANCEL, 'close', tep_href_link(FILENAME_ORDERS_HANDLER, tep_get_all_get_params(array('oID', 'action')) . 'oID=' . (int)$oID)));
 break;
default:
if (isset($oID)) {
 $heading[] = array('text' => '<b>[' . $oID . ']  ' . tep_datetime_short($orders['date_purchased']) . '</b>');
 $contents[] = array('align' => 'center', 'text' => tep_draw_button(IMAGE_EDIT, 'document', tep_href_link(FILENAME_ORDERS_HANDLER, tep_get_all_get_params(array('oID', 'action')) . 'oID=' . $oID . '&action=edit'), 'secondary', array('params' => 'class="ajax_disable"')) . tep_draw_button(IMAGE_DELETE, 'trash', tep_href_link(FILENAME_ORDERS_HANDLER, tep_get_all_get_params(array('oID', 'action', 'ajax')) . 'oID=' . (int)$oID . '&action=delete'), 'secondary', array('params' => 'class="ajax_disable"')));
 $contents[] = array('align' => 'center', 'text' => tep_draw_button(IMAGE_ORDERS_INVOICE, 'document', tep_href_link(FILENAME_ORDERS_INVOICE, 'oID=' . (int)$oID), null, array('newwindow' => true), 'secondary', array('params' => 'class="ajax_disable"')) . tep_draw_button(IMAGE_ORDERS_PACKINGSLIP, 'document', tep_href_link(FILENAME_ORDERS_PACKINGSLIP, 'oID=' . (int)$oID), null, array('newwindow' => true)) . tep_draw_button(IMAGE_CREATE_ORDER, 'document', tep_href_link(FILENAME_CREATE_ORDER, 'Customer=' . $orders['customers_id']), 'secondary', array('params' => 'class="ajax_disable"')));
 $contents[] = array('text' => '<br />' . TEXT_DATE_ORDER_CREATED . ' ' . tep_date_short($orders['date_purchased']));
 if (tep_not_null($orders['last_modified'])) $contents[] = array('text' => TEXT_DATE_ORDER_LAST_MODIFIED . ' ' . tep_date_short($orders['last_modified']));
 $contents[] = array('text' => '<br />' . ' ' . $orders['payment_method']);
}
break;
}
if ( (tep_not_null($heading)) && (tep_not_null($contents)) ) {
echo '		 <td width="20%" valign="top" id="defaultMenu">' . "\n";
$box = new box;
echo $box->infoBox($heading, $contents);
echo '		 </td>' . "\n";
tep_exit();
}
?>

 

 

 

It sounds like order_handler.js isn't loaded correctly, check in Chrome Developer Tools under the tab "Sources" that you can find admin/js/order_handler.js and also make sure that there are no error messages in the console.

 

Ok,

 

After doing the flot thing and removing the code still same results.

 

So on catoriges.php in relation to the product tabs not wokring correctly. Specifically the left menu wont extend when trying to navigate to other pages and it loads an entire index page into my top most page. The error in console is

Uncaught Error: Time mode requires the flot.time plugin.

 

As for Php.info im not sure what driver reference im suppose to be looking for.

 

Screenshots to follow this post in a little bit.

 

The sources panel does show that admin/js/order_handler.js is loading

 

display: none is also in css file, for some reason the browser isnt respecting it

Link to comment
Share on other sites

To install the new jQuery flot, replace the files from the new version with the ones you have in ./ext/flot/./, then in ./admin/includes/template_top.php find this code:

<script type="text/javascript" src="<?php echo tep_catalog_href_link('ext/flot/jquery.flot.js'); ?>"></script>

Replace with

<script type="text/javascript" src="<?php echo tep_catalog_href_link('ext/flot/jquery.flot.js'); ?>"></script>
<script type="text/javascript" src="<?php echo tep_catalog_href_link('ext/flot/jquery.flot.time.min.js'); ?>"></script>

Thank you that fixed the graphs issue. They are displaying now.

Link to comment
Share on other sites

Ok,

 

After doing the flot thing and removing the code still same results.

 

So on catoriges.php in relation to the product tabs not wokring correctly. Specifically the left menu wont extend when trying to navigate to other pages and it loads an entire index page into my top most page. The error in console is

Uncaught Error: Time mode requires the flot.time plugin.

 

As for Php.info im not sure what driver reference im suppose to be looking for.

 

Screenshots to follow this post in a little bit.

 

The sources panel does show that admin/js/order_handler.js is loading

 

display: none is also in css file, for some reason the browser isnt respecting it

 

See my reply in Post #31 on how to fix this, apply the change to template_top.php.

 

After you have made sure that the jQuery flot time module has been loaded, then right click the console and select "Preserve Log upon navigation" and go to your categories.php page again and see if there are any more errors.

Link to comment
Share on other sites

jQuery/Ajax Advanced Order Handler for osCommerce 2.3.3 Revision 2

 

- Big Update -

 

 

 

New Features and changes in Revision 2

  • Using the new HTML5 ProgressEvent interface or AJAX 2 to display a Bootstrap Progress Bar with the real amount of orders updated when batch updating orders.
  • All queries have been converted to MySQLi Prepared Statements for a big Security & Performance increase.
  • New Order Class in Admin added to make use of the performance benefits from using Prepared Statements when querying the database in a loop.
  • Comet / Ajax Long-Polling function remade so now it only polls new orders from stream.php instead of making 2 requests.
  • Add a Product function has been replaced with jQuery Autocomplete.
  • I have improved the jQuery code to use Asynchronous requests together with jQuery.deferred. This will speed up the Ajax requests and make handling appear in a more linear soft kind of way (No page locks).
  • There will now be a lot more Growl Notifications when you update orders etc. I have tried to include JSON Error/Success callbacks from most functions to make Order Handling more like a real Application.
  • More tool tips have been added as requested.
  • It's now possible to sort the orders Ascending/Descending by pressing on the the respective table heading column.
  • The Sort by number of products in order function now works as it should.
  • The Admin Menu now slides out/in by toggling a nice iOS 7 Toggle Switch which gives you 100% window width when working with your orders.
  • The Order Search function has been improved. It now uses Select2 3.4.8 jQuery Add-On with Ajax to suggest orders while typing. Pressing enter after a search term will search as usual, clicking on the suggested order will take you directly to it.
  • Search by Customers name, Delivery name, Billing name, Order Number, Customer Number or E-Mail Address.
  • In addition to the Fixed Bottom Navbar, there is now also a Fixed Top Navbar with the rest of the Drop Downs and Buttons that are necessary to batch control the order.
  • New hidden button that appears over Growl notifications to quickly remove all notifications.
  • New nicer jQuery Windows instead of ugly Javascript Prompts when updating order information.
  • ScrollNav jQuery Plugin to Autohide the Top Navbar when Scrolling the page
  • Lots of Bug Fixes & More!

 

Download Add-On here: http://addons.oscommerce.com/info/9055

Link to comment
Share on other sites

Found a couple of new bugs in the new Revision.

 

in order_handler.js find this code:

	    notify = $( "input[name=autoupdatestatus]" ).prop( "checked" ),
	    autoupdatestatus = $( "input[name=autoupdatestatus]" ).prop( "checked" );

Replace with:

	    notify = $( "input[name=notify]" ).prop( "checked" ),
	    autoupdatestatus = $( "input[name=autoupdatestatus]" ).prop( "checked" );

 

I'll post fixes for the other fixes when I have worked some more since the update so I know exactly what needs to be changed.

Link to comment
Share on other sites

There is a bug that prevents form data from being submitted/included when Batch Updating (Invoices/Export/Envelope) orders.

 

Follow the steps below to fix it, this will also prevent the browser from opening a new tab when Exporting to XML/CSV.

 

 

 

 

Find the code below in ./admin/js/order_handler.js around line 145

   $( "#batch_orders" ).submit(function( event ) {
    event.preventDefault();
    var navbar = $( "#navbar" ).clone().appendTo( "body" ),
	    form = $( this ).find( "input" ).clone().appendTo( navbar );
    $( navbar ).submit();
    $( navbar ).remove();
    return false;
   });

 

Replace with:

   $( "body" ).on('submit', 'form#batch_orders', function(event){
    event.preventDefault();
    var navbar = $( "#navbar" ).clone().appendTo( "body" ),
	    form = $( this ).find( "input" ).clone().appendTo( navbar ),
	    target = navbar.find( $( "input[type='radio'][name='target_file']:checked" ) ).val();
    if ( target != "invoice.php" )
	    navbar[0].target = "_self";
    $( navbar ).submit();
    $( navbar ).remove();
    return false;
   });

 

 

Find the code below around line 917

   $('body').on('click', 'a.submit_button', function(event){
    event.preventDefault();
    var link = this.href,
	    notify = $( "input[name=autoupdatestatus]" ).prop( "checked" ),
	    autoupdatestatus = $( "input[name=autoupdatestatus]" ).prop( "checked" );
    if ( notify === true || autoupdatestatus === true ) {
	    $( ".progress" ).show();
	    var jqxhr = $.ajax({
		    xhr: function() {
			    var xhr = new window.XMLHttpRequest();
			    xhr.addEventListener("progress", function(evt) {
				    //if ( evt.loaded >= evt.total )
					    //return $( this ).ajaxLink(link + '&ajax=1', 'orderTable' );

				    if (evt.lengthComputable)
				    {   //evt.loaded the bytes browser receive
					    //evt.total the total bytes seted by the header
					    //
					    var percentComplete = (evt.loaded / evt.total)*100;
					    $('#progress-bar').css( "width", percentComplete + "%" );
					    $( "#progress-bar" ).find( "span" ).html( evt.loaded + "/" + evt.total + " Updated" );
				    }
			    }, false);
			    return xhr;
		    },
		    type: 'POST',
		    url: 'ajax_handler.php?action=update_orders_status',
		    data: $( "#navbar" ).serialize() + "&" + $( "#batch_orders" ).serialize()
	    });
	    jqxhr.done(function( payload ) {
		    $( ".progress" ).hide();
		    if( typeof( payload ) == 'number' ) {
			    var countOrdersUpdated = payload.toString().length;
			    $( this ).gritter( "Success", countOrdersUpdated + " Orders Updated." );
			    return $( this ).ajaxLink(link + '&ajax=1', 'orderTable' );
		    } else if( payload.status == 'error' ) {
			    $( this ).gritter( "Error", payload.message );
		    }
		    return false;
	    });
    } else {
	    newWin=window.open("","_newtab");
	    return $('#batch_orders').submit();
    }
    return false;
   });

Replace with:

   $('body').on('click', 'a.submit_button', function(event){
    event.preventDefault();
    var link = this.href,
	    notify = $( "input[name=autoupdatestatus]" ).prop( "checked" ),
	    autoupdatestatus = $( "input[name=autoupdatestatus]" ).prop( "checked" ),
	    target = $("input[type='radio'][name='target_file']:checked").val(),
	    form = $('#batch_orders');
    if ( notify === true || autoupdatestatus === true ) {
	    $( ".progress" ).show();
	    var jqxhr = $.ajax({
		    xhr: function() {
			    var xhr = new window.XMLHttpRequest();
			    xhr.addEventListener("progress", function(evt) {
				    //if ( evt.loaded >= evt.total )
					    //return $( this ).ajaxLink(link + '&ajax=1', 'orderTable' );

				    if (evt.lengthComputable)
				    {   //evt.loaded the bytes browser receive
					    //evt.total the total bytes seted by the header
					    //
					    var percentComplete = (evt.loaded / evt.total)*100;
					    $('#progress-bar').css( "width", percentComplete + "%" );
					    $( "#progress-bar" ).find( "span" ).html( evt.loaded + "/" + evt.total + " Updated" );
				    }
			    }, false);
			    return xhr;
		    },
		    type: 'POST',
		    url: 'ajax_handler.php?action=update_orders_status',
		    data: $( "#navbar" ).serialize() + "&" + $( "#batch_orders" ).serialize()
	    });
	    jqxhr.done(function( payload ) {
		    $( ".progress" ).hide();
		    if( typeof( payload ) == 'number' ) {
			    var countOrdersUpdated = payload.toString().length;
			    $( this ).gritter( "Success", countOrdersUpdated + " Orders Updated." );
			    return $( this ).ajaxLink(link + '&ajax=1', 'orderTable' );
		    } else if( payload.status == 'error' ) {
			    $( this ).gritter( "Error", payload.message );
		    }
		    return false;
	    });
    } else {
	    if ( target != "invoice.php" )
		    form[0].target = "_self";
	    else
		    newWin=window.open("","_newtab");
	    return form.submit();
    }
    return false;
   });

 

/*----------------------------------------------*/

 

 

Another bug prevented search by customers_email_address, in ./admin/order_handler.php around line 479, replace this code:

  TABLE_ORDERS_TOTAL . " ot on (o.orders_id = ot.orders_id) left join " .	
  TABLE_ORDERS_STATUS . " s on (o.orders_status=s.orders_status_id) where	
  (o.customers_name like ? or o.customers_email_address like ? or o.customers_id = ? or o.orders_id = ?) and s.language_id = ?
  and ot.class = 'ot_total' order by ".$orderby;
  $query_num_rows_query = array("SELECT count(*) as total FROM orders WHERE (customers_name like ? or customers_email_address like ? or customers_id like ?)", "sss", array('%'.$_GET['search'].'%', '%'.$_GET['search'].'%', '%'.$_GET['search'].'%'));

With this:

  TABLE_ORDERS_TOTAL . " ot on (o.orders_id = ot.orders_id) left join " .	
  TABLE_ORDERS_STATUS . " s on (o.orders_status=s.orders_status_id) where	
  (o.customers_name like ? or o.customers_email_address like ? or o.customers_id like ? or o.orders_id = ?) and s.language_id = ?
  and ot.class = 'ot_total' order by ".$orderby;
  $query_num_rows_query = array("SELECT count(*) as total FROM orders WHERE (customers_name like ? or customers_email_address like ? or customers_id like ?)", "sss", array('%'.$_GET['search'].'%', '%'.$_GET['search'].'%', '%'.$_GET['search'].'%'));

 

That's it!

 

Notice: When you batch update orders in Rev2 the Navbars will not update when the page does. This means that if you update your orders with the Update Status Switch set to Yes, then it will stay on the Yes position after the orders have been updated. So make sure you don't update them two times by mistake.

 

I'm going to add code to my own shop that prevents this by automatically switching the E-Mail and Update Status to a "No" position after submitting the form. If you need this yourselves, then just ask.

Link to comment
Share on other sites

If someone want the current value to be displayed in the Dialog boxes when changing values (names, street address, products name etc..) instead of just a placeholder, then apply this patch to ./admin/js/order_handler.js

 

Find three occasions of code that look like the one below at around line 404, 547 AND 1149

$.when( tdialog ).done(function(){
   $( "#newValue" ).attr( "placeholder", pred).trigger( "focus" );
});

 

 

Replace with

$.when( tdialog ).done(function(){
   $( "#newValue" ).attr( "placeholder", pred).val( pred ).trigger( "focus" );
});

Link to comment
Share on other sites

All right, if you want the 'Update Status' and 'E-Mail' Radio Buttons returned to "No" position after submitting the form, then find and replace this code around line 952 in ./admin/js/order_handler.js

 

 

 

$( ".progress" ).hide();
		    if( typeof( payload ) == 'number' ) {
			    var countOrdersUpdated = payload.toString().length;
			    $( this ).gritter( "Success", countOrdersUpdated + " Orders Updated." );
			    return $( this ).ajaxLink(link + '&ajax=1', 'orderTable' );
		    } else if( payload.status == 'error' ) {
			    $( this ).gritter( "Error", payload.message );

 

With this:

$( "#navbar" ).find($("input[type='radio'][name='notify']")).eq( 1 ).click();
		    $( "#navbar" ).find($("input[type='radio'][name='autoupdatestatus']")).eq( 1 ).click();
		    $( ".progress" ).hide();
		    if( typeof( payload ) == 'number' ) {
			    var countOrdersUpdated = payload.toString().length;
			    $( this ).gritter( "Success", countOrdersUpdated + " Orders Updated." );
			    return $( this ).ajaxLink(link + '&ajax=1', 'orderTable' );
		    } else if( payload.status == 'error' ) {
			    $( this ).gritter( "Error", payload.message );
		    }

Link to comment
Share on other sites

Hi,

 

Thank you for a great addon. I have one issues with it though. It seems to be affecting my CKEditor with this addon http://addons.oscommerce.com/info/8490/v,23

 

The CKEditor on the product edit page works without an issue.

Here is a picture of what it should look like

al3d0kxe.4lu.jpg

but a few seconds after loading the page it flicks to this

hssn2bzg.2f3.jpg

After playing around a bit the problem seems to be the file ext/jquery/ui/jquery-ui-1.10.4.custom.min.js but im not sure how to fix it.

 

Any help with this issue would be greatly appreciated. Thanks.

Link to comment
Share on other sites

Hi,

 

Thank you for a great addon. I have one issues with it though. It seems to be affecting my CKEditor with this addon http://addons.oscommerce.com/info/8490/v,23

 

The CKEditor on the product edit page works without an issue.

Here is a picture of what it should look like

http://iforce.co.nz/i/al3d0kxe.4lu.jpg[/img]

but a few seconds after loading the page it flicks to this

http://iforce.co.nz/i/hssn2bzg.2f3.jpg[/img]

After playing around a bit the problem seems to be the file ext/jquery/ui/jquery-ui-1.10.4.custom.min.js but im not sure how to fix it.

 

Any help with this issue would be greatly appreciated. Thanks.

 

Don't you worry Glycerine, we'll fix this in a flash. B)

 

However, I'm getting a 404 - File or directory not found. on both your links. No, sorry, now they worked..

 

Ok, the correct way in solving this would be to update your CKEditor so it supports the newest version of jQuery. The easy way would be to replace this in admin/includes/template_top.php:

 

<link rel="stylesheet" type="text/css" href="<?php echo tep_catalog_href_link('ext/jquery/ui/redmond/jquery-ui-1.10.4.css'); ?>">
<?php
   if ($PHP_SELF == 'order_handler.php') { ?>
<link rel="stylesheet" type="text/css" href="css/bootstrap-3.1.1.min.css">
<link rel="stylesheet" type="text/css" href="css/bootstrap-theme.3.1.1.min.css">
<link rel="stylesheet" type="text/css" href="css/bootstrap-multiselect-3.1.1.css">
<link rel="stylesheet" type="text/css" href="css/tikslusdialog.css">
<!-- <link rel="stylesheet" type="text/css" href="css/avgrund.css"> -->
<link rel="stylesheet" type="text/css" href="css/select2.css">
<link rel="stylesheet" type="text/css" href="css/line/red.css">
<?php
   }
?>
<link rel="stylesheet" type="text/css" href="includes/stylesheet.css">
<script type="text/javascript" src="<?php echo tep_catalog_href_link('ext/jquery/jquery-2.1.0.min.js'); ?>"></script>
<script type="text/javascript" src="<?php echo tep_catalog_href_link('ext/jquery/ui/jquery-ui-1.10.4.custom.min.js'); ?>"></script>

 

To this:

<?php
/* Pages that use new version of jQuery & jQuery-UI */
 if ($PHP_SELF == 'order_handler.php') { ?>
<link rel="stylesheet" type="text/css" href="<?php echo tep_catalog_href_link('ext/jquery/ui/redmond/jquery-ui-1.10.4.css'); ?>">
<link rel="stylesheet" type="text/css" href="css/bootstrap-3.1.1.min.css">
<link rel="stylesheet" type="text/css" href="css/bootstrap-theme.3.1.1.min.css">
<link rel="stylesheet" type="text/css" href="css/bootstrap-multiselect-3.1.1.css">
<link rel="stylesheet" type="text/css" href="css/tikslusdialog.css">
<!-- <link rel="stylesheet" type="text/css" href="css/avgrund.css"> -->
<link rel="stylesheet" type="text/css" href="css/select2.css">
<link rel="stylesheet" type="text/css" href="css/line/red.css">
<script type="text/javascript" src="<?php echo tep_catalog_href_link('ext/jquery/jquery-2.1.0.min.js'); ?>"></script>
<script type="text/javascript" src="<?php echo tep_catalog_href_link('ext/jquery/ui/jquery-ui-1.10.4.custom.min.js'); ?>"></script>
<?php
/* Pages that use old version of jQuery & jQuery-UI */
 } else {
?>
<link rel="stylesheet" type="text/css" href="<?php echo tep_catalog_href_link('ext/jquery/ui/redmond/jquery-ui-1.8.22.css'); ?>">
<script type="text/javascript" src="<?php echo tep_catalog_href_link('ext/jquery/jquery-1.8.0.min.js'); ?>"></script>
<script type="text/javascript" src="<?php echo tep_catalog_href_link('ext/jquery/ui/jquery-ui-1.8.22.min.js'); ?>"></script>
<?php
 }
?>
<link rel="stylesheet" type="text/css" href="includes/stylesheet.css">

 

You probably want to revert the modification you did in Step #5 to ./admin/includes/column_left.php. But it might work as it is.

This should solve this problem and any other than someone might have from updating jQuery.

 

To fix CKEditor, I would first check to see if there is a new version of it. If you can't find any, then check what the console has to say, there's probably some errors in it.

Link to comment
Share on other sites

If someone want a minimized version of all the css and js files from this package, use the ones I have attached to this post.

 

Then in ./admin/includes/template_top.php change this:

<link rel="stylesheet" type="text/css" href="css/bootstrap-3.1.1.min.css">
<link rel="stylesheet" type="text/css" href="css/bootstrap-theme.3.1.1.min.css">
<link rel="stylesheet" type="text/css" href="css/bootstrap-multiselect-3.1.1.css">
<link rel="stylesheet" type="text/css" href="css/tikslusdialog.css">
<!-- <link rel="stylesheet" type="text/css" href="css/avgrund.css"> -->
<link rel="stylesheet" type="text/css" href="css/select2.css">
<link rel="stylesheet" type="text/css" href="css/line/red.css">

To this:

<link rel="stylesheet" type="text/css" href="css/order_handler.min.css">
<!-- <link rel="stylesheet" type="text/css" href="css/bootstrap-3.1.1.min.css">
<link rel="stylesheet" type="text/css" href="css/bootstrap-theme.3.1.1.min.css">
<link rel="stylesheet" type="text/css" href="css/bootstrap-multiselect-3.1.1.css">
<link rel="stylesheet" type="text/css" href="css/tikslusdialog.css">
<link rel="stylesheet" type="text/css" href="css/avgrund.css">
<link rel="stylesheet" type="text/css" href="css/select2.css">
<link rel="stylesheet" type="text/css" href="css/line/red.css"> -->

 

Then in ./admin/order_handler.php, change this:

<script type="text/javascript" src="js/bootstrap-3.1.1.min.js"></script>
<script type="text/javascript" src="js/bootstrap-multiselect-3.1.1.js"></script>
<script type="text/javascript" src="js/select2.js"></script>
<script type="text/javascript" src="js/icheck.js"></script>
<script type="text/javascript" src="js/switchery.js"></script>
<script type="text/javascript" src="js/order_handler.js"></script>
<script type="text/javascript" src="js/jquery.gritter.js"></script>
<script type="text/javascript" src="js/tikslusdialog.js"></script>
<script type="text/javascript" src="js/history.js"></script>

To this:

<script type="text/javascript" src="js/order_handler.min.js"></script>
<script type="text/javascript" src="js/order_handler.js"></script>
<!-- <script type="text/javascript" src="js/bootstrap-3.1.1.min.js"></script>
<script type="text/javascript" src="js/bootstrap-multiselect-3.1.1.js"></script>
<script type="text/javascript" src="js/select2.js"></script>
<script type="text/javascript" src="js/icheck.js"></script>
<script type="text/javascript" src="js/switchery.js"></script>
<script type="text/javascript" src="js/order_handler.js"></script>
<script type="text/javascript" src="js/jquery.gritter.js"></script>
<script type="text/javascript" src="js/tikslusdialog.js"></script>
<script type="text/javascript" src="js/history.js"></script> -->

 

 

 

 

 

I couldn't upload .js files so rename the order_handler.min.js.css to order_handler.min.js.

 

Put the order_handler.min.js in ./admin/js/order_handler.min.js

Put the order_handler.min.css in ./admin/css/order_handler.min.css

Edited by Dr. Rolex
Link to comment
Share on other sites

Don't you worry Glycerine, we'll fix this in a flash. B)

 

However, I'm getting a 404 - File or directory not found. on both your links. No, sorry, now they worked..

 

Ok, the correct way in solving this would be to update your CKEditor so it supports the newest version of jQuery. The easy way would be to replace this in admin/includes/template_top.php:

 

<link rel="stylesheet" type="text/css" href="<?php echo tep_catalog_href_link('ext/jquery/ui/redmond/jquery-ui-1.10.4.css'); ?>">
<?php
if ($PHP_SELF == 'order_handler.php') { ?>
<link rel="stylesheet" type="text/css" href="css/bootstrap-3.1.1.min.css">
<link rel="stylesheet" type="text/css" href="css/bootstrap-theme.3.1.1.min.css">
<link rel="stylesheet" type="text/css" href="css/bootstrap-multiselect-3.1.1.css">
<link rel="stylesheet" type="text/css" href="css/tikslusdialog.css">
<!-- <link rel="stylesheet" type="text/css" href="css/avgrund.css"> -->
<link rel="stylesheet" type="text/css" href="css/select2.css">
<link rel="stylesheet" type="text/css" href="css/line/red.css">
<?php
}
?>
<link rel="stylesheet" type="text/css" href="includes/stylesheet.css">
<script type="text/javascript" src="<?php echo tep_catalog_href_link('ext/jquery/jquery-2.1.0.min.js'); ?>"></script>
<script type="text/javascript" src="<?php echo tep_catalog_href_link('ext/jquery/ui/jquery-ui-1.10.4.custom.min.js'); ?>"></script>

 

To this:

<?php
/* Pages that use new version of jQuery & jQuery-UI */
if ($PHP_SELF == 'order_handler.php') { ?>
<link rel="stylesheet" type="text/css" href="<?php echo tep_catalog_href_link('ext/jquery/ui/redmond/jquery-ui-1.10.4.css'); ?>">
<link rel="stylesheet" type="text/css" href="css/bootstrap-3.1.1.min.css">
<link rel="stylesheet" type="text/css" href="css/bootstrap-theme.3.1.1.min.css">
<link rel="stylesheet" type="text/css" href="css/bootstrap-multiselect-3.1.1.css">
<link rel="stylesheet" type="text/css" href="css/tikslusdialog.css">
<!-- <link rel="stylesheet" type="text/css" href="css/avgrund.css"> -->
<link rel="stylesheet" type="text/css" href="css/select2.css">
<link rel="stylesheet" type="text/css" href="css/line/red.css">
<script type="text/javascript" src="<?php echo tep_catalog_href_link('ext/jquery/jquery-2.1.0.min.js'); ?>"></script>
<script type="text/javascript" src="<?php echo tep_catalog_href_link('ext/jquery/ui/jquery-ui-1.10.4.custom.min.js'); ?>"></script>
<?php
/* Pages that use old version of jQuery & jQuery-UI */
} else {
?>
<link rel="stylesheet" type="text/css" href="<?php echo tep_catalog_href_link('ext/jquery/ui/redmond/jquery-ui-1.8.22.css'); ?>">
<script type="text/javascript" src="<?php echo tep_catalog_href_link('ext/jquery/jquery-1.8.0.min.js'); ?>"></script>
<script type="text/javascript" src="<?php echo tep_catalog_href_link('ext/jquery/ui/jquery-ui-1.8.22.min.js'); ?>"></script>
<?php
}
?>
<link rel="stylesheet" type="text/css" href="includes/stylesheet.css">

 

You probably want to revert the modification you did in Step #5 to ./admin/includes/column_left.php. But it might work as it is.

This should solve this problem and any other than someone might have from updating jQuery.

 

To fix CKEditor, I would first check to see if there is a new version of it. If you can't find any, then check what the console has to say, there's probably some errors in it.

 

Awesome thanks that seemed to have fix this issue but now the menu items look like this

i10xiz3p.exa.jpghttp://iforce.co.nz/i/i10xiz3p.exa.jpg

 

Something seems to be adding a fixed height of 284px to the elements

Link to comment
Share on other sites

Awesome thanks that seemed to have fix this issue but now the menu items look like this

http://iforce.co.nz/i/i10xiz3p.exa.jpg[/img]http://iforce.co.nz/i/i10xiz3p.exa.jpg

 

Something seems to be adding a fixed height of 284px to the elements

 

That's why I told you to revert the modification you did in Step #5 to ./admin/includes/column_left.php. You need to change it back to what you had before to have it work with jQuery 1.8.0. ;)

 

 

- Moving on -

 

If anyone want the Confirm dialogs to submit when you press ENTER, then do this modification to ./admin/js/tikslusdialog.js - replace this:

if($("#tdialog").css("display")=="block")
{
var code = (e.keyCode ? e.keyCode : e.which);
switch(code)
{
case 27: //escape key
if(options.closeKey==true)
$.fn.closeTdialog();
break;
}
}

With this:

if($("#tdialog").css("display")=="block")
{
var code = (e.keyCode ? e.keyCode : e.which);
switch(code)
{
case 13: //escape key
$(".button_confirm").click();
break;
case 27: //escape key
if(options.closeKey==true)
$.fn.closeTdialog();
break;
}
}

 

If you want the text/value in the Dialog to be preselected when you open it (to simplify copying to clipboard), the in ./admin/js/order_handler.js replace this:

$( "body" ).on( "click", "label#gritterRemove", function() {
 $.gritter.removeAll();
 $( "#gritterRemove" ).fadeOut( "slow" );
});

With this:

$( "body" ).on( "click", "label#gritterRemove", function() {
 $.gritter.removeAll();
 $( "#gritterRemove" ).fadeOut( "slow" );
});

$( "body" ).on( "focus", "#newValue", function(event){
// Select input field contents
 this.select();
});

 

 

Find this code around line 404 & line 547 (2 occasions, make sure you change the right ones)

 $.when( tdialog ).done(function(){
	 $( "#newValue" ).attr( "placeholder", pred).trigger( "focus" );
 });

Replace with:

 $.when( tdialog ).done(function(){
	 $( "#newValue" ).attr( "placeholder", pred).val( pred ).trigger( "focus" );
 });

 

 

 

 

This is another bug.

In the same file, find this code around line 338

pred = $( this ).html(),

 

Change to this:

pred = $( this ).attr( "data-pred" ),

Edited by Dr. Rolex
Link to comment
Share on other sites

If you, like me, need to pay taxes on all extra fees (e.g. shipping & payment costs), then you might find that the calculated tax isn't correct when updating/adding products to an order.

 

Especially when more than one tax class is used, problems with tax calculation can appear. You can fix this by replacing ./admin/orders_ajax.php with the new code found below.

 

Note however, that there is one place where you need to select which tax class/tax rate you want to use on these 'extra' costs.

 

In the code below, find this code:

$others_tax = mysqli_prepared_query("SELECT tc.tax_class_title, tr.tax_rate FROM $tablename_tc tc LEFT JOIN $tablename_tr tr ON (tc.tax_class_id = tr.tax_class_id) WHERE tc.tax_class_id = 1");

 

Change, if necessary, the last part of the code 'WHERE tc.tax_class_id = 1' so the number is the same as the tax_class_id that you want to use. Check the tax_rates TABLE in your database to see which one you want to use.

 

 

Replace ./admin/orders_ajax.php with the code below and then modify the code mentioned above to the correct tax_class_id

<?php
/*
 Created by Dr. Rolex - 2014-04-30
 Updated by Dr. Rolex - 2014-05-06
*/
 require('includes/application_top.php');
 require(DIR_WS_CLASSES . 'currencies.php');
 $currencies = new currencies();
 function tep_db_update_totals($order_id) {
   #Define Tables to Variables
   $tablename_o = TABLE_ORDERS;
   $tablename_ot = TABLE_ORDERS_TOTAL;
   $tablename_p = TABLE_PRODUCTS;
   $tablename_a = TABLE_PRODUCTS_ATTRIBUTES;
   $tablename_ad = TABLE_PRODUCTS_ATTRIBUTES_DOWNLOAD;
   $tablename_op = TABLE_ORDERS_PRODUCTS;
   $tablename_opa = TABLE_ORDERS_PRODUCTS_ATTRIBUTES;
   $tablename_po = TABLE_PRODUCTS_OPTIONS;
   $tablename_pov = TABLE_PRODUCTS_OPTIONS_VALUES;
   $tablename_opd = TABLE_ORDERS_PRODUCTS_DOWNLOAD;
   $tablename_s = TABLE_SPECIALS;
   $tablename_tc = TABLE_TAX_CLASS;
   $tablename_tr = TABLE_TAX_RATES;
   $currencies = new currencies();
 //we have to update the orders_total table
   $products_total_query = mysqli_prepared_query("SELECT final_price, products_quantity, products_tax from " . TABLE_ORDERS_PRODUCTS . " WHERE orders_id = ?", "i", array($order_id));
   $price = 0;
   $total = 0;
   $taxes = array();
   if (count($products_total_query) > 0) {
  foreach ($products_total_query as $products_total) {
    $iva = round((100 + (float)$products_total['products_tax']) / 100, 4);
    $price += (float)round(((float)$products_total['final_price'] * (int)$products_total['products_quantity']) * $iva, 2);
  //fill the array of taxes to know which tax is used.
    if (tep_not_null($products_total['products_tax']) && $products_total['products_tax'] > 0) {
	  $tax_description = mysqli_prepared_query("SELECT tax_description from " . TABLE_TAX_RATES . " WHERE tax_rate = ?", "d", array($products_total['products_tax']));
	  $tax_description = $tax_description[0];
	  if (sizeof($taxes)) {
	    $ya_esta = false;
	    for ($i=0; $i<sizeof($taxes); $i++) {
		  if (in_array($tax_description['tax_description'], $taxes[$i])) {
		    $ya_esta = $i;
		  }
	    }
	    if ($ya_esta === false) {
		  $taxes[] = array('description' => $tax_description['tax_description'], 'value' => round(((((float)$products_total['final_price'] * (int)$products_total['products_quantity']) * (float)$products_total['products_tax']) / 100), 4));
	    } else {
		  $taxes[$ya_esta]['value'] += round(((((float)$products_total['final_price'] * (int)$products_total['products_quantity']) * (float)$products_total['products_tax']) / 100), 4);
	    }
	  } else {
	    $taxes[] = array('description' => $tax_description['tax_description'], 'value' => round(((((float)$products_total['final_price'] * (int)$products_total['products_quantity']) * (float)$products_total['products_tax']) / 100), 4));
	  }
    }
  }
   }
   $orders_total_query = mysqli_prepared_query("SELECT * from " . TABLE_ORDERS_TOTAL . " WHERE orders_id = ? and class != 'ot_tax' order by sort_order", "i", array($order_id));
   $others_tax = mysqli_prepared_query("SELECT tc.tax_class_title, tr.tax_rate FROM $tablename_tc tc LEFT JOIN $tablename_tr tr ON (tc.tax_class_id = tr.tax_class_id) WHERE tc.tax_class_id = 1");
   foreach ($orders_total_query as $order_total) {
  if ($order_total['class'] == 'ot_subtotal') {
    $new_value = (float)$price;
    $new_text = $currencies->format($new_value);
    $total += (float)$new_value;
    $params = array($new_text, $new_value, $order_total['orders_total_id']);
    mysqli_prepared_query("update " . TABLE_ORDERS_TOTAL . " SET text = ?, value = ? WHERE orders_total_id = ?", "sdi", $params);
  } elseif ($order_total['class'] == 'ot_total') {
    $new_value = (float)$total;
    $new_text = '<strong>' . $currencies->format(round($new_value)) . '</strong>';
    $params = array($new_text, $new_value, $order_total['orders_total_id']);
    mysqli_prepared_query("update " . TABLE_ORDERS_TOTAL . " SET text = ?, value = ? WHERE orders_total_id = ?", "sdi", $params);
  } else {
    $updated = false;
    $other_tax = $order_total['value'] - ($order_total['value'] / ($others_tax[0]['tax_rate'] / 100 + 1));
    for ($i=0; $i<sizeof($taxes); $i++) {
	  if ($taxes[$i]['description'] == $others_tax[0]['tax_class_title']) {
	    $taxes[$i]['value'] += (float)$other_tax;
	    $updated = true;
	    break;
	  }
    }
    if ($updated === false) {
	  $taxes[] = array('description' => $others_tax[0]['tax_class_title'], 'value' => $other_tax);
    }
    $total += round((float)$order_total['value'], 4);
  }
   }
 //the taxes
   if (sizeof($taxes)) {
  $orders_total_tax_query = mysqli_prepared_query("SELECT * from " . TABLE_ORDERS_TOTAL . " WHERE orders_id = ? and class = 'ot_tax'", "i", array($order_id));

   //update the ot_tax with the same title
   //if title doesn't exist, INSERT it
  $tax_updated = array();
  foreach ($orders_total_tax_query as $orders_total_tax) {
    $eliminate_tax = true;
    for ($i=0; $i<sizeof($taxes); $i++) {
	  if (in_array($orders_total_tax['title'], $taxes[$i])) {
	    $eliminate_tax = false;
								  //keep in variable that this tax is done
	    $tax_updated[] = $orders_total_tax['title'];
								  //prepare text (value with currency)
	    $texto = number_format((float)$taxes[$i]['value'], 2);
	    $new_text = $currencies->format($texto);
	    $params = array($new_text, $taxes[$i]['value'], $orders_total_tax['orders_total_id']);
	    mysqli_prepared_query("update " . TABLE_ORDERS_TOTAL . " SET text = ?, value = ? WHERE orders_total_id = ? and class = 'ot_tax'", "sdi", $params);
	  }
    }
  //we have eliminate the last product of one tax_rate->eliminate the ot_field
    if ($eliminate_tax == true) {
	  mysqli_prepared_query("delete from " . TABLE_ORDERS_TOTAL . " WHERE orders_total_id = ? limit 1", "i", array($orders_total_tax['orders_total_id']));
    }
  }
   //INSERT a new tax rate in the orders_total table, if all of taxes[] is not in $tax_updated[]
  for ($i=0; $i<sizeof($taxes); $i++) {
    if ((!in_array($taxes[$i]['description'], $tax_updated)) && ((float)$taxes[$i]['value'] > 0)) {
						  //prepare text (value with currency)
	  $texto = round((float)$taxes[$i]['value'], 2);
						  //$texto = (string)$texto . $currency['symbol_right'];
	  $texto = $currencies->format($texto);
	  if ($taxes[$i]['description'] !== null)
	    $params = array($order_id, $taxes[$i]['description'], $texto, $taxes[$i]['value']);
	  mysqli_prepared_query("INSERT INTO " . TABLE_ORDERS_TOTAL . " (orders_id, title, text, value, class, sort_order) VALUES (?, ?, ?, ?, 'ot_tax', 3)", "issd", $params);
    }
  }
   }
 }

 #Define Tables to Variables
 $tablename_o = TABLE_ORDERS;
 $tablename_ot = TABLE_ORDERS_TOTAL;
 $tablename_p = TABLE_PRODUCTS;
 $tablename_a = TABLE_PRODUCTS_ATTRIBUTES;
 $tablename_ad = TABLE_PRODUCTS_ATTRIBUTES_DOWNLOAD;
 $tablename_op = TABLE_ORDERS_PRODUCTS;
 $tablename_opa = TABLE_ORDERS_PRODUCTS_ATTRIBUTES;
 $tablename_po = TABLE_PRODUCTS_OPTIONS;
 $tablename_pov = TABLE_PRODUCTS_OPTIONS_VALUES;
 $tablename_opd = TABLE_ORDERS_PRODUCTS_DOWNLOAD;
 $tablename_s = TABLE_SPECIALS;
 $tablename_tc = TABLE_TAX_CLASS;
 $action = $_GET['action'];
 if (($action == 'eliminate_field') || ($action == 'eliminate') || ($action == 'update_product')) {
   if ($action == 'eliminate') {
  mysqli_prepared_query("delete from " . TABLE_ORDERS_PRODUCTS . " WHERE orders_products_id = ? limit 1", "i", array($_GET['pID']));
  $attributes_query = mysqli_prepared_query("SELECT orders_products_attributes_id from " . TABLE_ORDERS_PRODUCTS_ATTRIBUTES . " WHERE orders_products_id = ?", "i", array($_GET['pID']));
   //if the products has attributes, eliminate them
  if (count($attributes_query) > 0) {
    foreach ($attributes_query as $attributes) {
	  mysqli_prepared_query("delete from " . TABLE_ORDERS_PRODUCTS_ATTRIBUTES . " WHERE orders_products_attributes_id = ? limit 1", "i", array($attributes['orders_products_attributes_id']));
    }
  }
  $message = "Product Removed.";
   } elseif ($action == 'eliminate_field') {
  $oID = (int)$_GET['oID'];
  $class = $_POST['total_class'];
  $title = urldecode($_POST['title']);
  $params = array($oID, $title, $class);
  mysqli_prepared_query("delete from " . TABLE_ORDERS_TOTAL . " WHERE orders_id = ? AND title = ? AND class = ? limit 1", "iss", $params);
  tep_db_update_totals($oID);
  $message = "Field Removed.";
   } else {
 // get the price to change order totals
 // but first, change it if we change price of attributes (so we get directly the good final_price)
  $field = $_GET['field'];
  if ($field == 'options') {
    $params = array( $_GET['new_value'], round((float)$_GET['option_price'], 4), $_GET['pID'], $_GET['extra']);
    mysqli_prepared_query("update " . TABLE_ORDERS_PRODUCTS_ATTRIBUTES . " SET products_options_VALUES = ?,  options_values_price = ? WHERE orders_products_id = ? and products_options = ?", "sdis", $params);

    $params = array(round((float)$_GET['option_price'], 4), $_GET['pID']);
    mysqli_prepared_query("update " . TABLE_ORDERS_PRODUCTS . " SET final_price = (products_price + ?) WHERE orders_products_id = ?", "di", $params);
    $message = "Product Options Updated.";
   } elseif (stristr($field, 'price')) {
    $adapt_price_query = mysqli_prepared_query("SELECT options_values_price from " . TABLE_ORDERS_PRODUCTS_ATTRIBUTES . " WHERE orders_products_id = ? and options_values_price != 0", "i", array($_GET['pID']));
    if (count($adapt_price_query)) {
	  $adapt_price = $adapt_price_query[0];
	  $option_price = (float)$adapt_price['options_values_price'];
    } else {
	  $option_price = 0;
    }
    if (stristr($field, '_excl')) {
	  $new_price = round((float)$_GET['new_value'], 4);
    } else {
	  $tax_query = mysqli_prepared_query("SELECT products_tax from " . TABLE_ORDERS_PRODUCTS . " WHERE orders_products_id = ? and products_tax != 0", "i", array($_GET['pID']));
	  if (count($tax_query)) {
	    $tax_ = $tax_query[0];
	    $percent = (float)$tax_['products_tax'];
	    $percent = round(($percent/100), 4);
	    $percent = $percent + 1;
	    $new_price = round(round((float)$_GET['new_value']/$percent, 4), 4);
	  } else {
	    $new_price = round((float)$_GET['new_value'], 4);
	  }
    }
    $params = array($new_price, ($new_price - $option_price), $_GET['pID']);
    mysqli_prepared_query("update " . TABLE_ORDERS_PRODUCTS . " SET final_price = ?, products_price = ? WHERE orders_products_id = ?", "ddi", $params);
    $message = "Product Price Updated.";
  } else {
    if (tep_not_null($field) && tep_not_null($_GET['new_value'])) {
	  $params = array($_GET['new_value'], $_GET['pID']);
	  mysqli_prepared_query("update " . TABLE_ORDERS_PRODUCTS . " SET ".tep_db_input($field)." = ? WHERE orders_products_id = ?", "si", $params);
	  $message = "Order Updated.";
    }
  }
   }
   #we have to update the orders_total table
   tep_db_update_totals($_GET['order']);
   #Send Success Message
   header('Content-Type: application/json');
   die( json_encode( array( 'status' => 'success', 'message' => $message ) ) );
 } elseif ($action == 'update_order_field') {
   $params = array($_GET['new_value'], $_GET['oID']);
   //mysqli_prepared_query("update ".tep_db_input($_GET['db_table'])." SET ".tep_db_input($_GET['field'])." = ? WHERE orders_id = ?", "si", $params);
   mysqli_prepared_query("UPDATE orders SET ".tep_db_input($_GET['field'])." = ? WHERE orders_id = ?", "si", $params);
   #Send Success Message
   header('Content-Type: application/json');
   die( json_encode( array( 'status' => 'success', 'message' => 'Field updated.' ) ) );
 } elseif ($action == 'search_orders') {
   $params = array($_GET['q'], '%'.$_GET['q'].'%', '%'.$_GET['q'].'%', '%'.$_GET['q'].'%', '%'.$_GET['q'].'%', $_GET['page_limit']);
   $orders_query = mysqli_prepared_query("SELECT orders_id, customers_name, customers_email_address, date_purchased FROM $tablename_o WHERE (orders_id = ? OR customers_name LIKE ? OR customers_email_address LIKE ? OR delivery_name LIKE ? OR billing_name LIKE ?) LIMIT ?", "issssi", $params);
   if (count($orders_query)) {
  $return_arr = array();
  foreach ($orders_query as $orders) {
    $row_array['id'] = tep_href_link(FILENAME_ORDERS_HANDLER, 'oID=' . $orders['orders_id'] . '&action=edit');
    $row_array['text'] = $orders['orders_id'] . ' - ' . $orders['customers_name'] . ' - ' . $orders['date_purchased'];
    array_push($return_arr, $row_array);
  }
   } else {
  $return_arr = array('value' => PRODUCTS_SEARCH_NO_RESULTS);
   }
   header('Content-Type: application/json');
   die( json_encode($return_arr) );
 } elseif ($action == 'search') { //search products in the db.
   $params = array('%'.$_GET['term'].'%', '%'.$_GET['term'].'%', $languages_id);
   $products_query = mysqli_prepared_query("SELECT distinct p.products_id, pd.products_name, p.products_model from " . TABLE_PRODUCTS_DESCRIPTION . " pd left join " . TABLE_PRODUCTS . " p on (p.products_id = pd.products_id) WHERE (pd.products_name like ? or  p.products_model like ?) and  pd.language_id = ? and p.products_status = '1' order  by pd.products_name asc limit 20", "ssi", $params);
   if (count($products_query)) {
  $return_arr = array();
  foreach ($products_query as $products) {
    $row_array['id'] = 'javascript:$( this ).selectProduct(\'' .  $products['products_id'] . '\', \'' .  addslashes(tep_output_string_protected($products['products_name'])) . '\');';
    $row_array['value'] = $products['products_name'] . (($products['products_model'] != '') ? ' (' . $products['products_model'] . ')' : '');
    array_push($return_arr, $row_array);
  }
   } else {
  $return_arr = array('value' => PRODUCTS_SEARCH_NO_RESULTS);
   }
   header('Content-Type: application/json');
   die( json_encode($return_arr) );
 } elseif ($action == 'attributes') {
 //we create an AJAX form
   $attributes = '<form name="attributes" id="attributes" action="" onsubmit="return( $( this ).setAttr() )"><input type="hidden" name="products_id" value="' . (int)$_GET['prID'] . '">';
 //this part comes integraly from OSC catalog/product_info.php
   $params = array($_GET['prID'], $languages_id);
   $products_attributes_query = mysqli_prepared_query("SELECT count(*) as total from " . TABLE_PRODUCTS_OPTIONS . " popt, " . TABLE_PRODUCTS_ATTRIBUTES . " patrib WHERE patrib.products_id = ? and patrib.options_id = popt.products_options_id and popt.language_id = ?", "ii", $params);
   $products_attributes = $products_attributes_query[0];
   if ($products_attributes['total'] > 0) {
  $attributes .= '<table border="0" cellspacing="0" cellpadding="2" class="dataTableRow" width="100%"><tr><td class="dataTableContent" colspan="2">' . TEXT_PRODUCT_OPTIONS . '</td>		    </tr>';
  $params = array($_GET['prID'], $languages_id);
  $products_options_name_query = mysqli_prepared_query("SELECT distinct popt.products_options_id, popt.products_options_name from " . TABLE_PRODUCTS_OPTIONS . " popt, " . TABLE_PRODUCTS_ATTRIBUTES . " patrib WHERE patrib.products_id = ? and patrib.options_id = popt.products_options_id and popt.language_id = ? order by popt.products_options_name", "ii", $params);
  foreach ($products_options_name_query as $products_options_name) {
    $products_options_array = array();
    $params = array($_GET['prID'], $products_options_name['products_options_id'], $languages_id);
    $products_options_query = mysqli_prepared_query("SELECT pov.products_options_values_id, pov.products_options_values_name, pa.options_values_price, pa.price_prefix from " . TABLE_PRODUCTS_ATTRIBUTES . " pa, " . TABLE_PRODUCTS_OPTIONS_VALUES . " pov WHERE pa.products_id = ? and pa.options_id = ? and pa.options_values_id = pov.products_options_values_id and pov.language_id = ?", "iii", $params);
    foreach ($products_options_query as $products_options) {
	  $products_options_array[] = array('id' => $products_options['products_options_values_id'], 'text' => $products_options['products_options_values_name']);
	  if ($products_options['options_values_price'] != '0') {
	    $products_options_array[sizeof($products_options_array)-1]['text'] .= ' (' . $products_options['price_prefix'] . $currencies->display_price($products_options['options_values_price'], tep_get_tax_rate($product_info['products_tax_class_id'])) .') ';
	  }
    }
    $attributes .= '<tr><td class="main">' . $products_options_name['products_options_name'] . ':</td><td class="main">' . tep_draw_pull_down_menu('atrid_' . $products_options_name['products_options_id'], $products_options_array, $selected_attribute) . '</td></tr>';
  }
  $button = '<span><button type="submit" onmouseover="$( this ).addClass( \'ui-state-hover\' );" onmouseout="$( this ).removeClass( \'ui-state-hover\' );" class="ui-button ui-widget ui-state-default ui-corner-all ui-button-text-icon-secondary ui-priority-secondary" role="button" aria-disabled="false" style="margin-bottom: 5px;"><span class="ui-button-icon-secondary ui-icon ui-icon-disk"></span><span class="ui-button-text">' . IMAGE_CONFIRM . '</span></button></span>';
  $attributes .= '<tr><td colspan="2">' . $button . '</td></tr></table></form>';
   } else {
  $button = '<span><button type="submit" class="ui-button ui-widget ui-state-default ui-corner-all ui-button-text-icon-secondary ui-priority-secondary" role="button" aria-disabled="false" style="margin-bottom: 5px;" onmouseover="$( this ).addClass( \'ui-state-hover\' );" onmouseout="$( this ).removeClass( \'ui-state-hover\' );"><span class="ui-button-icon-secondary ui-icon ui-icon-disk"></span><span class="ui-button-text">' . IMAGE_CONFIRM . '</span></button></span>';
  $attributes .= $button;
   }
   echo $attributes;
 } elseif ($action == 'set_attributes') {
   $attributes = array();
   $products_id = 0;
   $products_quantity = 0;
   foreach($_POST as $key => $value) {
  if ($key == 'products_id') {
    $products_id = $value;
  } elseif ($key == 'products_quantity') {
    $products_quantity = $value;
  } elseif (stristr($key, 'trid_')) {
    $attributes[] = array(substr($key, 6), $value);
  }
   }
   $orders_id = $_GET['oID'];
   $params = array($products_id, $languages_id);
   $product_info_query = mysqli_prepared_query("SELECT p.products_model, pd.products_name, p.products_price, p.products_tax_class_id from " . TABLE_PRODUCTS . " p left join " . TABLE_PRODUCTS_DESCRIPTION . " pd on p.products_id = pd.products_id WHERE p.products_id = ? and pd.language_id = ?", "ii", $params);
   $product_info = $product_info_query[0];
   if (DISPLAY_PRICE_WITH_TAX == 'true') {
  $tax_query = mysqli_prepared_query("SELECT tax_rate, tax_description from " . TABLE_TAX_RATES . " WHERE tax_rates_id = ?", "i", array($product_info['products_tax_class_id']));
  $tax_ = $tax_query[0];
  $tax = $tax_['tax_rate'];
  $tax_desc = $tax_['tax_description'];
   } else {
  $tax = 0;
   }
   $attribute_price_sum = 0;
   $attribute_update = false;
   if (sizeof($attributes) > 0) {
  $attribute_update = true;
  for ($j=0; $j<sizeof($attributes); $j++) {
    $attribute_price_query = mysqli_prepared_query("SELECT options_values_price, price_prefix from " . TABLE_PRODUCTS_ATTRIBUTES . " WHERE products_id = ? and options_id = ? and options_values_id = ?", "iii", array($products_id, $attributes[$j][0], $attributes[$j][1]));
    $attribute_price = $attribute_price_query[0];
    if ($attribute_price['price_prefix'] == '+') {
	  $attribute_price_sum += (float)$attribute_price['options_values_price'];
    } else {
	  $attribute_price_sum -= (float)$attribute_price['options_values_price'];
    }
    $attribute_name_query = mysqli_prepared_query("SELECT products_options_name from " . TABLE_PRODUCTS_OPTIONS . " WHERE products_options_id = ? and language_id = ?", "ii", array($attributes[$j][0], $languages_id));
    $attribute_name = $attribute_name_query[0];
    $options_name_query = mysqli_prepared_query("SELECT products_options_values_name from " . TABLE_PRODUCTS_OPTIONS_VALUES . " WHERE products_options_values_id = ? and language_id = ?", "ii", array($attributes[$j][1], $languages_id));
    $options_name = $options_name_query[0];
    $params = array($orders_id, $attribute_name['products_options_name'], $options_name['products_options_values_name'], $attribute_price['options_values_price'], $attribute_price['price_prefix']);
    mysqli_prepared_query("INSERT INTO " . TABLE_ORDERS_PRODUCTS_ATTRIBUTES . " (orders_id, orders_products_id, products_options, products_options_values, options_values_price, price_prefix) VALUES (?, 0, ?, ?, ?, ?)", "issds", $params);
  }
   }
   $special_price = mysqli_prepared_query("
  SELECT specials_new_products_price
  FROM $tablename_s
  WHERE products_id = ?
  AND status = 1", "i", array($products_id));
   $new_price = $special_price[0];

   if ($new_price) {
  $final_price = (float)$new_price['specials_new_products_price']+ (float)$attribute_price_sum;
   } else {
  $final_price = (float)$product_info['products_price'] + (float)$attribute_price_sum;
   }
   $params = array($orders_id, $products_id, $product_info['products_model'], $product_info['products_name'], $product_info['products_price'], $final_price, $tax, $products_quantity);
   mysqli_prepared_query("INSERT INTO $tablename_op (orders_id, products_id, products_model, products_name, products_price, final_price, products_tax, products_quantity) VALUES (?, ?, ?, ?, ?, ?, ?, ?)", "iissdddi", $params);
   $orders_products_id = tep_db_insert_id();
   if ($attribute_update == true){
  mysqli_prepared_query("UPDATE $tablename_opa SET orders_products_id = ? WHERE orders_products_id = 0", "i", array($orders_products_id));
   }
   tep_db_update_totals($orders_id);
   #Send Success Message
   header('Content-Type: application/json');
   die( json_encode( array( 'status' => 'success', 'message' => 'Product added.' ) ) );
 } elseif ($action == 'orders_total_update') {
   if ($_GET['column'] == 'value') {
   #Get the order's currency
  $currency_query = mysqli_prepared_query("SELECT currency, currency_value from " . TABLE_ORDERS . " WHERE orders_id = ?", "i", array($_GET['oID']));
  $currency = $currency_query[0];
  $text = $currencies->format((float)$_GET['new_value'], true, $currency['currency'], $currency['currency_value']);
  mysqli_prepared_query("update " . TABLE_ORDERS_TOTAL . " SET text = ? WHERE orders_id = ? and class = ?", "sis", array($text, $_GET['oID'], $_GET['class']));
   }
   mysqli_prepared_query("update " . TABLE_ORDERS_TOTAL . " SET " . tep_db_input($_GET['column']) . " = ? WHERE orders_id = ? and class = ?", "sis", array($_GET['new_value'], $_GET['oID'], $_GET['class']));
   tep_db_update_totals($_GET['oID']);
   #Send Success Message
   header('Content-Type: application/json');
   die( json_encode( array( 'status' => 'success', 'message' => 'Total Updated.' ) ) );
 } elseif ($action == 'new_order_total') {
   $sort_order_query = mysqli_prepared_query("SELECT max(sort_order) as maxim from " . TABLE_ORDERS_TOTAL . " WHERE orders_id = ? and class != 'ot_total'", "i", array($_GET['oID']));
   $sort_order = $sort_order_query[0];
   $new_sort_order = (int)$sort_order['maxim'] + 1;
  #Get the order's currency
   $currency_query = mysqli_prepared_query("SELECT currency, currency_value from " . TABLE_ORDERS . " WHERE orders_id = ?", "i", array($_GET['oID']));
   $currency = $currency_query[0];
   $class_query = mysqli_prepared_query("SELECT class from " . TABLE_ORDERS_TOTAL . " WHERE orders_id = ? and class like '%ot_extra_%'", "i", array($_GET['oID']));
   $classs = 'ot_extra_' . (count($class_query) + 1);
   $new_order_total_value_txt = $currencies->format($_GET['value'], true, $currency['currency'], $currency['currency_value']);
   mysqli_prepared_query("update " . TABLE_ORDERS_TOTAL . " SET sort_order = ? WHERE orders_id = ? and class = 'ot_total'", "ii", array(((int)$new_sort_order + 1), $_GET['oID']));
   #Fix Taxes
   if ( isset($_GET['add_tax']) && $_GET['add_tax'] == "1" ) {
  $selected_tax_query = mysqli_prepared_query("SELECT * from " . TABLE_TAX_RATES . " WHERE tax_class_id = ?", "i", array($_GET['tax_value']));
  $selected_tax = $selected_tax_query[0];
  $new_tax = $_GET['value'] * ( $selected_tax['tax_rate'] / 100 );
  $new_text = $currencies->format($new_tax, true, $currency['currency'], $currency['currency_value']);
  $orders_total_tax_query = mysqli_prepared_query("SELECT * from " . TABLE_ORDERS_TOTAL . " WHERE orders_id = ? and class = 'ot_tax'", "i", array($_GET['oID']));
  $tax_updated = false;
  foreach ($orders_total_tax_query as $orders_total_tax) {
    if ( $tax_updated === false ) {
	  if ( $orders_total_tax['title'] == $selected_tax['tax_description'] ) {
	    $new_tax += $orders_total_tax['value'];
	    $new_text = $currencies->format($new_tax, true, $currency['currency'], $currency['currency_value']);
	    mysqli_prepared_query("update " . TABLE_ORDERS_TOTAL . " SET text = ?, value = ? WHERE orders_total_id = ? and class = 'ot_tax'", "sdi", array($new_text, number_format($new_tax, 4), $orders_total_tax['orders_total_id']));
	    $tax_updated = true;
	    break;
	  }
    }
  }
  if ( $tax_updated === false ) {
    mysqli_prepared_query("INSERT INTO " . TABLE_ORDERS_TOTAL . " (orders_id, title, text, value, class, sort_order) VALUES (?, ?, ?, ?, 'ot_tax', 3)", "issd", array($_GET['oID'], $selected_tax['tax_description'], $new_text, $new_tax));
  }
   }
   mysqli_prepared_query("INSERT INTO " . TABLE_ORDERS_TOTAL . " (orders_id, title, text, value, class, sort_order) VALUES (?, ?, ?, ?, ?, ?)", "issdsi", array($_GET['oID'], $_GET['title'] . ':', $new_order_total_value_txt, round((float)$_GET['value'], 4), $classs, $new_sort_order));

 #Send Success Message
 header('Content-Type: application/json');
 die( json_encode( array( 'status' => 'success', 'message' => 'New Field Added.' ) ) );
 }
 ?>

 

 

Report if you have any issues..

Link to comment
Share on other sites

Hi Jonas

 

This is a great contribution. I just have a few requests if you could show how to implement this please:

 

I need the totals to look like this:

 

Sub-total (ex TAX)

Freight (ex TAX)

Extra Cost (Ex TAX)

TAX (Calculated on above)

Total (Inc tax)

 

If i add extra fields they need to go above TAX and the TAX is to be recalculated. All items need to show without TAX and added at the end as TOTAL (inc TAX). Could you show how this could be done please?

 

Also if you are adding extra fields to the above then the TOTAL amount does not get updated. And if you send an updated invoice the TOTAL will not show the amounts of the extra fields added to it. The only way i have found to update is when i change the price of a product. Could you please look into this bug if it is.

 

If it is also possible when editing a product (say description) or any other item the original value is in the field but when you type a letter it all erases. Is it possible to have the original data and we can delete or add what we need to it otherwise at times you need to write the whole description again if you want to add something to the end of it.

 

Great Contribution. Keep up the good work.

 

Thanks :)

Link to comment
Share on other sites

Big...very...very good work...great example of good programming...continue for this way :thumbsup:

 

Thanks! :P

 

There's still some things that needs fixing though, before more functionality can be added. After the bugs have been fixed, then I need to work on the performance, it kind of starts getting slow. And we don't want that! I'll probably butcher the jQuery add-on:s for whatever code that's needed and then start optimize the order_handler.js. There's a lot of code that need's to be remade..

 

I have added a pretty nice jQuery Slide-in Side panel where there will be some options to trigger/select so the Order Handler becomes more easy customizable.

 

I plan to make the Dialogs & Processes "minimizable", that is, you don't need to wait for them to complete before you move on, instead, simply minimize them to 'tray icons' and let them do their job in the background.

 

I can really recommend everyone to take a look at the free open source project MySQL Workbench. Using it to optimize queries with it's graphic 'EXPLAIN' results is very effective.

Using it as a backup/general MySQL manager is perfect as well. It even has a built in function to copy your query directly to PHP Prepared Statement code! (w00t)

It works on almost any platform/OS and it's free. So click here to get it now!

 

This is much better & secure alternative to handle the database than e.g. phpmyadmin.

 

 

If you're experiencing a problem with the top or bottom navbar not sliding back when you return from editing an order, then it might help to make this modification to ./admin/order_handler.php around line 670, replace this:

 

 //$('.comments').tooltip('toggle').tooltip('hide');

 

To this:

 $( "#navigationBottom" ).show();
 $( "#navigationTop" ).show();

Link to comment
Share on other sites

That's why I told you to revert the modification you did in Step #5 to ./admin/includes/column_left.php. You need to change it back to what you had before to have it work with jQuery 1.8.0. ;)

 

Ah thank you thank you must have over looked your recommendation in the last post. All working now.

Link to comment
Share on other sites

- Moving on -

 

All right, last one for tonight I think. In ./admin/order_poller.php around line 17, change this line:

 

if ( $_SERVER['HTTP_X_REQUESTED_WITH'] == "XMLHttpRequest" ) {

 

To this:

if ( $_GET['action'] == "duplicate" ) {

 

 

In ./admin/js/order_handler.js around line 1009, replace this code:

url: "order_poller.php?oID="+last_order_number+"&languages_id="+languages_id+order_by_quantity,

 

With this:

url: "order_poller.php?action=duplicate&oID="+last_order_number+"&languages_id="+languages_id+order_by_quantity,

 

 

This will fix a bug with the Ajax Long-Polling, preventing it from updating correctly when new orders have been placed.

 

Notice: I have included a new order_handler.min.js, if you want a minimized version. Rename it from order_handler.min.js.css to order_handler.min.js.

Edited by Dr. Rolex
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...