I have found that the best way to manipulate how Magento calculates taxes is to just let Magento do what it wants to do.
As a developer, your tendency might be to think "hey, I have this quote, now I need to access some kind of setTaxAmount()
method". This might ultimately be backwards thinking.
Magento's collectTotals()
method does a lot of stuff each time an order/quote is accessed, so simply setting a tax amount on a quote is not going to be the best route.
In your case, I assume that your customer models include information about taxability... ie, you might have a customer group that has to pay taxes and another group that is tax exempt. If you manipulate the associated admin config values so that users in the tax exempt group aren't charged tax, you would be halfway home. Then during checkout at the desired step, assign the user to the proper customer group, and then when collectTotals()
fires, the existing logic for taxable customer groups will work out whether the customer should be charged tax or not.
To think of a specific example of my own, I am working on a module that will call a third-party tax service, pass it a validated address to determine local tax rates, a list of cart items, and the service returns how much tax the order should have.
While initially working on this, I thought similar to you... I should call this service, get the tax amount, and then I will simply set this tax amount on the quote.
This was problematic.
Ultimately what I decided to do was to fire my own observer method that gets called before collectTotals()
, and then rely on all the built-in logic to handle various tax situations. When a user submit's their shipping address during checkout, I will then use that address and their cart items to call the tax service and return me a tax amount. Based on this value, I then calculate what their tax rate is (ie. 3.7%) since the service only returns a tax amount and not a tax rate.
Once I have a tax rate that I want to use, I then programmatically create a new tax zone and rate in Magento based on the user's postal code (Zip+4 in my case).
Again, since this happens before collectTotals()
I am able add new tax zones and rates on the fly based on a user's information. As collectTotals()
gets called, it has no idea what I've done, all it knows is that this user's postal code matches a tax zone, so it should apply the proper tax rate to their quote.
Updating the quantity means that the full quote has to be recalculated invalidating the chosen payment and shipment methods. This will require the user to go back to these steps and choose the new information.
It can probably be done using a custom controller that adds the new quantity then calling that over AJAX for example but after every quantity change you will have to send the user back to the shipment method step or at least prevent him from checking out so he can move back himself. All in all I highly doubt it will be very user friendly.
Best Answer
So via the admin area you can normally edit orders that are not completed. On the order overview page you should see a button
Edit
. What this will do is cancel the old order and simply let you create a new order. Here you can change the quantity that has been ordered.