Magento tax rounding issue - magento

I got strange rounding issue for VAT in Magento. My product set up is
* product price incl 20% VAT is 183.59
I added 30 items into basket and it would cost 30 * 183.59 = 5507.70. I can see this value in basket/checkout so that's fine. If I have just 1 item in basket it's ok.
Also the final VAT would be 5507.70 * 20 / 120 = 917.95, but I'm getting 918.00
Do you have any idea how to fix this or where would I take a look? Thanks in advance.

In the end I found the solution. I changed System > VAT > Tax Calculation Method Based On from Unit price to Row Total and it works, more details here
The issue which I found is in core/store model. I had to rewrite roundPrice method and change rounding precision there.
public function roundPrice($price)
{
return round($price, 4);
}

Info
Round price in Magento based on previous rounding operation delta.
app/code/core/Mage/Tax/Model/Sales/Total/Quote/Tax.php:1392
app/code/core/Mage/Tax/Model/Sales/Total/Quote/Subtotal.php:719
protected function _deltaRound($price, $rate, $direction, $type = 'regular')
{
if ($price) {
$rate = (string)$rate;
$type = $type . $direction;
// initialize the delta to a small number to avoid non-deterministic behavior with rounding of 0.5
$delta = isset($this->_roundingDeltas[$type][$rate]) ? $this->_roundingDeltas[$type][$rate] : 0.000001;
$price += $delta;
$this->_roundingDeltas[$type][$rate] = $price - $this->_calculator->round($price);
$price = $this->_calculator->round($price);
}
return $price;
}
Sometimes this can cause an error due to the high delta calculation error ($this->_calculator->round($price)). For example, for this reason, some prices can vary in the range of ±1 cent.
Solution
To avoid this, you need to improve the accuracy of the delta calculation.
Change
$this->_roundingDeltas[$type][$rate] = $price - $this->_calculator->round($price);
to
$this->_roundingDeltas[$type][$rate] = $price - round($price, 4);
Changes need to be made in both files:
app/code/core/Mage/Tax/Model/Sales/Total/Quote/Tax.php:1392
app/code/core/Mage/Tax/Model/Sales/Total/Quote/Subtotal.php:719
Don't modify or hack core files! Do a rewrite!
The solution was tested on different versions of Magento 1.9.x, but maybe this will work in earlier versions.
P.S.
Change roundPrice function, as shown below, can solve the rounding error problem, but it can cause others (for example, some platforms require rounding up to 2 decimal places).
app/code/core/Mage/Core/Model/Store.php:995
public function roundPrice($price)
{
return round($price, 4);
}

Related

Magento Shopping Cart Rule - Is this combination possible

Hoping some one can help me with a Magento Rule - is this rule even possible
I have numerous products of numerous sizes all part of the same category.
Each product regardless of size costs £3.98 - If a buyer buys 3 products of the same category regardless of the product or size they get it for £9.99. If they buy 4 products, they get 3 of them for 9.99 but pay full price for the 4th...Every group of 3 is £9.99
I have a rule created that seems to work perfect if a Customer buys 3 / 6 / 9 items of the same product and same size...However if they mix and match it doesn't work (though they are the same category)
The rule is:
IF ALL of these conditions are TRUE:
If total quantity equals or greater than 3 for a subselection of items in cart matching ALL of these conditions:
Category is 4
I have also set the Discount Qty Step to be 3
* UPDATE *
Thanks for your reply - I have tried to implement what you suggest and have got so far as to where I get the category id of the added products. I'm unsure how to set the price the previous products so it will be an automatically discounted price
$quote = Mage::getSingleton('checkout/session')->getQuote();
$cartItems = $quote->getAllVisibleItems();
$itemPrice = "3.33";
foreach ($cartItems as $items) {
$product = $items->getProduct();
$prodCats = $product->getCategoryIds();
if (in_array('4', $prodCats)) {
$itemQty = $items->getQty();
}
$totalItems += $itemQty;
}
So what I want to do is apply a discount for multiple of 3's for any product that has a category_id of 4...The price will be 3.33 instead of the normal 3.99
You need event - observer approach for this, that will give you the flexibility you need. You can build an observer that catches the add-to-cart event sales_quote_add_item and put your logic there.
Following code within your observer function will point you in the right direction:
// Get products in cart:
$quote = Mage::getSingleton('checkout/session')->getQuote();
$cartItems = $quote->getAllVisibleItems();
foreach ($cartItems as $item) {
$itemSku = $item->getSku();
$itemQty = $item->getQty();
}
// Added product:
$item = $observer->getEvent()->getQuoteItem();
$itemQty = $item->getQty();
$itemSku = $item->getSku();
// Change price of added product:
$item->setOriginalCustomPrice($newPrice);
Good luck!

php round() leading mistake

My website is build by magento system use for shopping. now I add a function about nice foreign price. for example:
if the price is $35.4 , it will be changed to $34.99;
if the price is $35.5 , it will be changed to $35.99;
code is : round(35.4) + 0.99;
now here is a question, my product has several options link 'type','colour'. and different option shows different price just as the default configurable product in magento.
in the product page: price is $1000 shows $999.99, colour red + $100 shows +$99.99
,and type big +50 shows+49.99. here the total price is 1149.97. but in shopping chat the price is round(1000 + 100 +50)+0.99 = 1149.99. so I don't know how to deal with it.
some one help me ..... waiting for your advice.
because magento final price is calculate onFly ,you shall overwrite
app/code/core/Mage/CatalogRule/Helper/Data.php
and change method to like as . (you need add to adminhtml it option or hardcode it)
public function calcPriceRule($actionOperator, $ruleAmount, $price)
{
$priceRule = 0;
switch ($actionOperator) {
case 'to_fixed':
$priceRule = min($ruleAmount, $price);
break;
case 'to_percent':
$priceRule = $price * $ruleAmount / 100;
break;
case 'by_fixed':
$priceRule = max(0, $price - $ruleAmount);
break;
case 'by_percent':
$priceRule = $price * (1 - $ruleAmount / 100);
break;
case 'my_custom_prices':
//your price rules
break;
}
return $priceRule;
}

Point-of-sale scanning API [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking for code must demonstrate a minimal understanding of the problem being solved. Include attempted solutions, why they didn't work, and the expected results. See also: Stack Overflow question checklist
Closed 9 years ago.
Improve this question
Consider a store where items have prices per unit but also volume
prices. For example, apples may be $1.00 each or 4 for $3.00.
Implement a point-of-sale scanning API that accepts an arbitrary
ordering of products (similar to what would happen at a checkout line)
and then returns the correct total price for an entire shopping cart
based on the per unit prices or the volume prices as applicable.
Here are the products listed by code and the prices to use (there is
no sales tax):
Product Code | Price
A | $2.00 each or 4 for $7.00
B | $12.00
C | $1.25 or $6 for a six pack
D | $0.15
There should be a top level point of sale terminal service object that looks
something like the pseudo-code below. You are free to design and
implement the rest of the code however you wish, including how you
specify the prices in the system:
terminal.setPricing(...) terminal.scan("A") terminal.scan("C") ...
etc. result = terminal.total
Here are the minimal inputs you should use for your test cases. These
test cases must be shown to work in your program:
Scan these items in this order: ABCDABAA; Verify the total price is
$32.40. Scan these items in this order: CCCCCCC; Verify the total
price is $7.25. Scan these items in this order: ABCD; Verify the total
price is $15.40.
1) For each item store the unit price, the group price and the units per group.
2) During the scanning phase simply keep track of the number of units per item.
3) For each item, increment the cost by:
(number units) / (units per group for item) * group price +
(number units) % (units per group for item) * unit price
A linear amount of space is used on the order of the number of items and a linear amount used to track the counts of the items scanned. Runtime is also linear.
You can implement In PHP : test.php
<?php
echo "Please input the product code string:";
$handle = fopen ("php://stdin","r");
$line = fgets($handle);
echo 'input : ' .$line. "n";
$inputProducts = rtrim($line);
$total = 0;
$inputArray = str_split($inputProducts, 1);
$counts = array_count_values($inputArray);
$productsprice = array('A'=>array('1'=>2.00, '4'=>7.00), 'B'=>array('1'=>12.00), 'C'=>array('1'=>1.25, '6'=>6.00), 'D'=>array('1'=>0.15));
foreach($counts as $code=>$amount) {
echo "Code : " . $code . "n";
if(isset($productsprice[$code]) && count($productsprice[$code]) > 1) {
$groupUnit = max(array_keys($productsprice[$code]));
$subtotal = intval($amount / $groupUnit) * $productsprice[$code][$groupUnit] + fmod($amount, $groupUnit) * $productsprice[$code]['1'];
$total += $subtotal;
}
elseif (isset($productsprice[$code])) {
$subtotal = $amount * $productsprice[$code]['1'];
$total += $subtotal;
}
echo "Subtotal: " . $subtotal . "n";
}
echo 'Final Total: $' . number_format($total, 2). "n";
?>
Execute CLI: php test.php

How to get grand total without shipping costs from a Magento order model?

I have a Magento order model that I create like this:
$order = Mage::getModel('sales/order')->load($orderId);
Now I want to get the order grand total including the taxes etc., but without the shipping costs. I can retrieve the grand total with $order->getGrandTotal(), but how can I exclude the shipping costs?
Thank you in advance!
$amount = $order->getGrandTotal() - $order->getShippingAmount();
Try not to over-think it. ;-)
Here is another quick method to get grand total incuding taxes and without shipping fee.
if you are dealing with the cart:
$quote = Mage::getModel('checkout/session')->getQuote();
$cartGrossTotal = 0;
foreach ($quote->getAllItems() as $item) {
$cartGrossTotal += $item->getPriceInclTax()*$item->getQty();
}
if you are dealing with an order:
$orderGrossTotal = 0;
foreach ($order->getAllItems() as $item) {
$orderGrossTotal += $item->getPriceInclTax()*$item->getQty();
}
I think
base_subtotal_incl_tax can be, so
$order->getBaseSubtotalInclTax()
There is one way more easy:
$orderValue = $order->getSubtotal();
Return the subtotal from the order, without shipping method;
Try it.

Replace Price Difference with Actual Price

I have a configurable product with 3 options, see below:
I want to replace the +£24.00 and the +£75.00 with the actual prices of the products.
So instead it would say: £69.00 and £120.00
I have located the code being in js/varien/product.js
I've spent a bit of time chopping and changing the code, but can't quite decipher what needs to change. Line 240 downwards in this file handles the JavaScript events for configurable products.
This is performed by javascript. You need to modify the method getOptionLabel in js/varien/configurable.js (this is Magento 1.5.1.0, your milage may vary depending on the version you're using).
This method receives the option and the price difference to be applied. If you want to just show the absolute price of the different options, you need to calculate them yourself, using the absolute base value of the configurable product and the absolute difference of the option.
The first few lines of the method look like this:
getOptionLabel: function(option, price){
var price = parseFloat(price);
Change that so you get the absolute base price and the absolute difference of the option. Then add them together to get the final absolute price of the option. Like this:
getOptionLabel: function(option, price){
var basePrice = parseFloat(this.config.basePrice);
// 'price' as passed is the RELATIVE DIFFERENCE. We won't use it.
// The ABSOLUTE DIFFERENCE is in option.price (and option.oldPrice)
var absoluteDifference = parseFloat(option.price);
var absoluteFinalPrice = basePrice + absoluteDifference;
// var price = parseFloat(price);
var price = absoluteFinalPrice;
Then you need to get rid of the + and - symbols in the options. Later on in the same method, when you call this.formatPrice, just change the second paramter to false in each call.
if(price){
if (this.taxConfig.showBothPrices) {
str+= ' ' + this.formatPrice(excl, false) + ' (' + this.formatPrice(price, false) + ' ' + this.taxConfig.inclTaxTitle + ')';
} else {
str+= ' ' + this.formatPrice(price, false);
}
Some more notes about this:
You will find another identical object called Product.Config being created in js/varien/product.js. As far as I can tell, this does absolutely nothing as it is replaced by js/varien/configurable.js.
Also, if just change js/varien/configurable.js, the next time you upgrade Magento you will probably lose your changes. Better to create another file like js/varien/my_configurable.js or whatever, and call it in the config file (product.xml) for whatever theme you are using.
This extension might be helpful, I've used it in the past (and it appears to be maintained):
http://www.magentocommerce.com/magento-connect/Matt+Dean/extension/596/simple-configurable-products
In magento 1.9 the .js method doesn't seem to work anymore.
Instead I updated Abstract.php (/app/code/core/Mage/Catalog/Block/Product/View/Options/Abstract.php), copy this file to /app/code/local/Mage/Catalog/Block/Product/View/Options/Abstract.php. On line 128, change the $_priceInclTax and $_priceExclTax variables to the following:
$_priceInclTax = $this->getPrice($sign.$value['pricing_value'], true)+$this->getProduct()->getFinalPrice();
$_priceExclTax = $this->getPrice($sign.$value['pricing_value'])+$this->getProduct()->getFinalPrice();
I've seen similar solutions, but this is the only way to ensure it also works with things such as negative product options and special price discounts.
Found a solution here that works on Magento 1.9 but it overrides core code, it should be done so that it does not override core.
I've tried something like this in a new js file, but somehow the core configurable.js get's messed up, maybe someone can come up with a way so that id doesn't.
Product.Config.prototype.getOptionLabel = Product.Config.prototype.getOptionLabel.wrap(function(parentMethod){
// BEGIN:: custom price display update
var basePrice = parseFloat(this.config.basePrice);
// 'price' as passed is the RELATIVE DIFFERENCE. We won't use it.
// The ABSOLUTE DIFFERENCE is in option.price (and option.oldPrice)
var absoluteDifference = parseFloat(option.price);
// var price = parseFloat(price);
if(absoluteDifference){
// console.log(option);
price = basePrice + absoluteDifference;
} else {
price = absoluteDifference;
}
// END:: custom price display update
if (this.taxConfig.includeTax) {
var tax = price / (100 + this.taxConfig.defaultTax) * this.taxConfig.defaultTax;
var excl = price - tax;
var incl = excl*(1+(this.taxConfig.currentTax/100));
} else {
var tax = price * (this.taxConfig.currentTax / 100);
var excl = price;
var incl = excl + tax;
}
if (this.taxConfig.showIncludeTax || this.taxConfig.showBothPrices) {
price = incl;
} else {
price = excl;
}
var str = option.label;
if(price){
if (this.taxConfig.showBothPrices) {
// BEGIN:: custom price display update
// NOTE:: 'true' was changed to 'false' in 3 places.
str+= ' ' + this.formatPrice(excl, false) + ' (' + this.formatPrice(price, false) + ' ' + this.taxConfig.inclTaxTitle + ')';
} else {
str+= ' ' + this.formatPrice(price, false);
// END:: custom price display update
}
}
return str;
});
Edit the file js/varien/product.js, looking at line number 691
If we were to change the attribute prices from the product detail page, the trigger will fire here. Just check with alert(price);, and you can get the changeable price.
In 1.7 (not sure when this was changed) things were changed around. it ends up that the price string is built in PHP, inside Mage/Catalog/Block/Product/View/Options/Abstract.php in the _formatPrice function when called from Mage/Catalog/Block/Product/View/Options/Type/Select.php
Notice that changing any of those 2 classes is going to provoke a change through the site and not just in that specific combo
I am suprised at how Magento can use by default such a weird logic.
The ability to see different prices per variant should be available, and perhaps even the default one.
Prestashop does this, and even automatically switches images when selecting each variant!
in Magento 1.9
open js/varien/configurable.js
goto function getOptionLabel
modify this function code as required.

Resources