Skip to content

Commit 7c6d41a

Browse files
MAGETWO-97423: Price column in sales_order_item table shows the price including tax when Custom Price is applied on admin order
1 parent 08fbdf1 commit 7c6d41a

File tree

5 files changed

+213
-32
lines changed

5 files changed

+213
-32
lines changed

app/code/Magento/Tax/Model/Sales/Total/Quote/CommonTaxCollector.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -688,6 +688,9 @@ public function updateItemTaxInfo($quoteItem, $itemTaxDetails, $baseItemTaxDetai
688688
{
689689
//The price should be base price
690690
$quoteItem->setPrice($baseItemTaxDetails->getPrice());
691+
if ($quoteItem->getCustomPrice() && $this->taxHelper->applyTaxOnCustomPrice()) {
692+
$quoteItem->setCustomPrice($baseItemTaxDetails->getPrice());
693+
}
691694
$quoteItem->setConvertedPrice($itemTaxDetails->getPrice());
692695
$quoteItem->setPriceInclTax($itemTaxDetails->getPriceInclTax());
693696
$quoteItem->setRowTotal($itemTaxDetails->getRowTotal());

app/code/Magento/Tax/Test/Unit/Model/Sales/Total/Quote/CommonTaxCollectorTest.php

Lines changed: 99 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -3,79 +3,106 @@
33
* Copyright © Magento, Inc. All rights reserved.
44
* See COPYING.txt for license details.
55
*/
6+
declare(strict_types=1);
67

78
namespace Magento\Tax\Test\Unit\Model\Sales\Total\Quote;
89

9-
/**
10-
* Test class for \Magento\Tax\Model\Sales\Total\Quote\Tax
11-
*/
1210
use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
11+
use Magento\Tax\Helper\Data as TaxHelper;
12+
use Magento\Tax\Api\Data\TaxDetailsItemInterface;
13+
use Magento\Quote\Model\Quote\Item as QuoteItem;
14+
use Magento\Store\Model\Store;
15+
use Magento\Tax\Model\Sales\Total\Quote\CommonTaxCollector;
16+
use Magento\Tax\Model\Config;
17+
use Magento\Quote\Model\Quote\Address as QuoteAddress;
18+
use Magento\Quote\Model\Quote;
19+
use Magento\Tax\Api\Data\QuoteDetailsItemInterface;
20+
use Magento\Tax\Api\Data\TaxClassKeyInterface;
21+
use Magento\Tax\Model\Sales\Quote\ItemDetails;
22+
use Magento\Tax\Model\TaxClass\Key as TaxClassKey;
23+
use Magento\Tax\Api\Data\QuoteDetailsItemInterfaceFactory;
24+
use Magento\Tax\Api\Data\TaxClassKeyInterfaceFactory;
25+
use Magento\Quote\Api\Data\ShippingAssignmentInterface;
26+
use Magento\Quote\Api\Data\ShippingInterface;
27+
use Magento\Quote\Model\Quote\Address\Total as QuoteAddressTotal;
28+
use PHPUnit\Framework\MockObject\MockObject;
29+
use PHPUnit\Framework\TestCase;
1330

1431
/**
32+
* Common tax collector test
33+
*
1534
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
1635
*/
17-
class CommonTaxCollectorTest extends \PHPUnit\Framework\TestCase
36+
class CommonTaxCollectorTest extends TestCase
1837
{
1938
/**
20-
* @var \Magento\Tax\Model\Sales\Total\Quote\CommonTaxCollector
39+
* @var CommonTaxCollector
2140
*/
2241
private $commonTaxCollector;
2342

2443
/**
25-
* @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Tax\Model\Config
44+
* @var MockObject|Config
2645
*/
2746
private $taxConfig;
2847

2948
/**
30-
* @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Quote\Model\Quote\Address
49+
* @var MockObject|QuoteAddress
3150
*/
3251
private $address;
3352

3453
/**
35-
* @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Quote\Model\Quote
54+
* @var MockObject|Quote
3655
*/
3756
private $quote;
3857

3958
/**
40-
* @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Store\Model\Store
59+
* @var MockObject|Store
4160
*/
4261
private $store;
4362

4463
/**
45-
* @var \PHPUnit_Framework_MockObject_MockObject|
64+
* @var MockObject
4665
*/
4766
protected $taxClassKeyDataObjectFactoryMock;
4867

4968
/**
50-
* @var \PHPUnit_Framework_MockObject_MockObject|
69+
* @var MockObject
5170
*/
5271
protected $quoteDetailsItemDataObjectFactoryMock;
5372

5473
/**
55-
* @var \Magento\Tax\Api\Data\QuoteDetailsItemInterface
74+
* @var QuoteDetailsItemInterface
5675
*/
5776
protected $quoteDetailsItemDataObject;
5877

5978
/**
60-
* @var \Magento\Tax\Api\Data\TaxClassKeyInterface
79+
* @var TaxClassKeyInterface
6180
*/
6281
protected $taxClassKeyDataObject;
6382

83+
/**
84+
* @var TaxHelper
85+
*/
86+
protected $taxHelper;
87+
88+
/**
89+
* {@inheritdoc}
90+
*/
6491
protected function setUp()
6592
{
6693
$objectManager = new ObjectManager($this);
6794

68-
$this->taxConfig = $this->getMockBuilder(\Magento\Tax\Model\Config::class)
95+
$this->taxConfig = $this->getMockBuilder(Config::class)
6996
->disableOriginalConstructor()
70-
->setMethods(['getShippingTaxClass', 'shippingPriceIncludesTax'])
97+
->setMethods(['getShippingTaxClass', 'shippingPriceIncludesTax', 'discountTax'])
7198
->getMock();
7299

73-
$this->store = $this->getMockBuilder(\Magento\Store\Model\Store::class)
100+
$this->store = $this->getMockBuilder(Store::class)
74101
->disableOriginalConstructor()
75102
->setMethods(['__wakeup'])
76103
->getMock();
77104

78-
$this->quote = $this->getMockBuilder(\Magento\Quote\Model\Quote::class)
105+
$this->quote = $this->getMockBuilder(Quote::class)
79106
->disableOriginalConstructor()
80107
->setMethods(['__wakeup', 'getStore'])
81108
->getMock();
@@ -84,39 +111,43 @@ protected function setUp()
84111
->method('getStore')
85112
->will($this->returnValue($this->store));
86113

87-
$this->address = $this->getMockBuilder(\Magento\Quote\Model\Quote\Address::class)
114+
$this->address = $this->getMockBuilder(QuoteAddress::class)
88115
->disableOriginalConstructor()
89116
->getMock();
90117

91118
$this->address->expects($this->any())
92119
->method('getQuote')
93120
->will($this->returnValue($this->quote));
94121
$methods = ['create'];
95-
$this->quoteDetailsItemDataObject = $objectManager->getObject(
96-
\Magento\Tax\Model\Sales\Quote\ItemDetails::class
97-
);
98-
$this->taxClassKeyDataObject = $objectManager->getObject(\Magento\Tax\Model\TaxClass\Key::class);
122+
$this->quoteDetailsItemDataObject = $objectManager->getObject(ItemDetails::class);
123+
$this->taxClassKeyDataObject = $objectManager->getObject(TaxClassKey::class);
99124
$this->quoteDetailsItemDataObjectFactoryMock
100-
= $this->createPartialMock(\Magento\Tax\Api\Data\QuoteDetailsItemInterfaceFactory::class, $methods);
125+
= $this->createPartialMock(QuoteDetailsItemInterfaceFactory::class, $methods);
101126
$this->quoteDetailsItemDataObjectFactoryMock->expects($this->any())
102127
->method('create')
103128
->willReturn($this->quoteDetailsItemDataObject);
104129
$this->taxClassKeyDataObjectFactoryMock =
105-
$this->createPartialMock(\Magento\Tax\Api\Data\TaxClassKeyInterfaceFactory::class, $methods);
130+
$this->createPartialMock(TaxClassKeyInterfaceFactory::class, $methods);
106131
$this->taxClassKeyDataObjectFactoryMock->expects($this->any())
107132
->method('create')
108133
->willReturn($this->taxClassKeyDataObject);
134+
$this->taxHelper = $this->getMockBuilder(TaxHelper::class)
135+
->disableOriginalConstructor()
136+
->getMock();
109137
$this->commonTaxCollector = $objectManager->getObject(
110-
\Magento\Tax\Model\Sales\Total\Quote\CommonTaxCollector::class,
138+
CommonTaxCollector::class,
111139
[
112140
'taxConfig' => $this->taxConfig,
113141
'quoteDetailsItemDataObjectFactory' => $this->quoteDetailsItemDataObjectFactoryMock,
114-
'taxClassKeyDataObjectFactory' => $this->taxClassKeyDataObjectFactoryMock
142+
'taxClassKeyDataObjectFactory' => $this->taxClassKeyDataObjectFactoryMock,
143+
'taxHelper' => $this->taxHelper,
115144
]
116145
);
117146
}
118147

119148
/**
149+
* Test for GetShippingDataObject
150+
*
120151
* @param array $addressData
121152
* @param bool $useBaseCurrency
122153
* @param string $shippingTaxClass
@@ -128,8 +159,8 @@ public function testGetShippingDataObject(
128159
$useBaseCurrency,
129160
$shippingTaxClass,
130161
$shippingPriceInclTax
131-
) {
132-
$shippingAssignmentMock = $this->createMock(\Magento\Quote\Api\Data\ShippingAssignmentInterface::class);
162+
): void {
163+
$shippingAssignmentMock = $this->createMock(ShippingAssignmentInterface::class);
133164
$methods = [
134165
'getShippingDiscountAmount',
135166
'getShippingTaxCalculationAmount',
@@ -139,8 +170,10 @@ public function testGetShippingDataObject(
139170
'getBaseShippingAmount',
140171
'getBaseShippingDiscountAmount'
141172
];
142-
$totalsMock = $this->createPartialMock(\Magento\Quote\Model\Quote\Address\Total::class, $methods);
143-
$shippingMock = $this->createMock(\Magento\Quote\Api\Data\ShippingInterface::class);
173+
/** @var MockObject|QuoteAddressTotal $totalsMock */
174+
$totalsMock = $this->createPartialMock(QuoteAddressTotal::class, $methods);
175+
$shippingMock = $this->createMock(ShippingInterface::class);
176+
/** @var MockObject|ShippingAssignmentInterface $shippingAssignmentMock */
144177
$shippingAssignmentMock->expects($this->once())->method('getShipping')->willReturn($shippingMock);
145178
$shippingMock->expects($this->once())->method('getAddress')->willReturn($this->address);
146179
$baseShippingAmount = $addressData['base_shipping_amount'];
@@ -184,9 +217,44 @@ public function testGetShippingDataObject(
184217
}
185218

186219
/**
220+
* Update item tax info
221+
*
222+
* @return void
223+
*/
224+
public function testUpdateItemTaxInfo(): void
225+
{
226+
/** @var MockObject|QuoteItem $quoteItem */
227+
$quoteItem = $this->getMockBuilder(QuoteItem::class)
228+
->disableOriginalConstructor()
229+
->setMethods(['getPrice', 'setPrice', 'getCustomPrice', 'setCustomPrice'])
230+
->getMock();
231+
$this->taxHelper->method('applyTaxOnCustomPrice')->willReturn(true);
232+
$quoteItem->method('getCustomPrice')->willReturn(true);
233+
/** @var MockObject|TaxDetailsItemInterface $itemTaxDetails */
234+
$itemTaxDetails = $this->getMockBuilder(TaxDetailsItemInterface::class)
235+
->disableOriginalConstructor()
236+
->getMock();
237+
/** @var MockObject|TaxDetailsItemInterface $baseItemTaxDetails */
238+
$baseItemTaxDetails = $this->getMockBuilder(TaxDetailsItemInterface::class)
239+
->disableOriginalConstructor()
240+
->getMock();
241+
242+
$quoteItem->expects($this->once())->method('setCustomPrice');
243+
244+
$this->commonTaxCollector->updateItemTaxInfo(
245+
$quoteItem,
246+
$itemTaxDetails,
247+
$baseItemTaxDetails,
248+
$this->store
249+
);
250+
}
251+
252+
/**
253+
* Data for testGetShippingDataObject
254+
*
187255
* @return array
188256
*/
189-
public function getShippingDataObjectDataProvider()
257+
public function getShippingDataObjectDataProvider(): array
190258
{
191259
$data = [
192260
'free_shipping' => [

dev/tests/integration/testsuite/Magento/Tax/Model/Sales/Total/Quote/SetupUtil.php

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,12 @@
99
use Magento\Framework\App\Config\ScopeConfigInterface;
1010
use Magento\Tax\Model\Config;
1111
use Magento\Tax\Model\Calculation;
12+
use Magento\Quote\Model\Quote\Item\Updater;
13+
use \Magento\Catalog\Api\ProductRepositoryInterface;
1214

1315
/**
16+
* Setup utility for quote
17+
*
1418
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
1519
*/
1620
class SetupUtil
@@ -666,7 +670,18 @@ public function setupQuote($quoteData)
666670
$quote = $this->createQuote($quoteData, $customer);
667671

668672
$this->addProductToQuote($quote, $quoteData['items']);
669-
673+
if (isset($quoteData['update_items'])) {
674+
$updater = $this->objectManager->get(Updater::class);
675+
$productRepository = $this->objectManager->get(ProductRepositoryInterface::class);
676+
foreach ($quoteData['update_items'] as $sku => $updateItem) {
677+
$product = $productRepository->get($sku);
678+
$quoteItem = $quote->getItemByProduct($product);
679+
$updater->update(
680+
$quoteItem,
681+
$updateItem
682+
);
683+
}
684+
}
670685
//Set shipping amount
671686
if (isset($quoteData['shipping_method'])) {
672687
$quote->getShippingAddress()->setShippingMethod($quoteData['shipping_method']);
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
use Magento\Tax\Model\Config;
9+
use Magento\Tax\Model\Sales\Total\Quote\SetupUtil;
10+
11+
$taxCalculationData['including_tax_with_custom_price'] = [
12+
'config_data' => [
13+
SetupUtil::CONFIG_OVERRIDES => [
14+
Config::CONFIG_XML_PATH_PRICE_INCLUDES_TAX => 1,
15+
Config::CONFIG_XML_PATH_APPLY_ON => 0
16+
],
17+
SetupUtil::TAX_RATE_OVERRIDES => [
18+
SetupUtil::TAX_RATE_TX => 8.25,
19+
SetupUtil::TAX_STORE_RATE => 8.25,
20+
],
21+
SetupUtil::TAX_RULE_OVERRIDES => [
22+
],
23+
],
24+
'quote_data' => [
25+
'billing_address' => [
26+
'region_id' => SetupUtil::REGION_TX,
27+
],
28+
'shipping_address' => [
29+
'region_id' => SetupUtil::REGION_TX,
30+
],
31+
'items' => [
32+
[
33+
'sku' => 'simple1',
34+
'price' => 16.24,
35+
'qty' => 1,
36+
],
37+
],
38+
'update_items' => [
39+
'simple1' => [
40+
'custom_price' => 14,
41+
'qty' => 1,
42+
],
43+
],
44+
],
45+
'expected_results' => [
46+
'address_data' => [
47+
'subtotal' => 12.93,
48+
'base_subtotal' => 12.93,
49+
'subtotal_incl_tax' => 14,
50+
'base_subtotal_incl_tax' => 14,
51+
'tax_amount' => 1.07,
52+
'base_tax_amount' => 1.07,
53+
'shipping_amount' => 0,
54+
'base_shipping_amount' => 0,
55+
'shipping_incl_tax' => 0,
56+
'base_shipping_incl_tax' => 0,
57+
'shipping_taxable' => 0,
58+
'base_shipping_taxable' => 0,
59+
'shipping_tax_amount' => 0,
60+
'base_shipping_tax_amount' => 0,
61+
'discount_amount' => 0,
62+
'base_discount_amount' => 0,
63+
'discount_tax_compensation_amount' => 0,
64+
'base_discount_tax_compensation_amount' => 0,
65+
'shipping_discount_tax_compensation_amount' => 0,
66+
'base_shipping_discount_tax_compensation_amount' => 0,
67+
'grand_total' => 14,
68+
'base_grand_total' => 14,
69+
],
70+
'items_data' => [
71+
'simple1' => [
72+
'row_total' => 12.93,
73+
'base_row_total' => 12.93,
74+
'tax_percent' => 8.25,
75+
'price' => 12.93,
76+
'custom_price' => 12.93,
77+
'original_custom_price' => 14,
78+
'base_price' => 12.93,
79+
'price_incl_tax' => 14,
80+
'base_price_incl_tax' => 14,
81+
'row_total_incl_tax' => 14,
82+
'base_row_total_incl_tax' => 14,
83+
'tax_amount' => 1.07,
84+
'base_tax_amount' => 1.07,
85+
'discount_amount' => 0,
86+
'base_discount_amount' => 0,
87+
'discount_percent' => 0,
88+
'discount_tax_compensation_amount' => 0,
89+
'base_discount_tax_compensation_amount' => 0,
90+
],
91+
],
92+
],
93+
];

dev/tests/integration/testsuite/Magento/Tax/_files/tax_calculation_data_aggregated.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
* Copyright © Magento, Inc. All rights reserved.
44
* See COPYING.txt for license details.
55
*/
6+
declare(strict_types=1);
67

78
/**
89
* Global array that holds test scenarios data
@@ -31,3 +32,4 @@
3132
require_once __DIR__ . '/scenarios/multi_tax_rule_two_row_calculate_subtotal_yes_row.php';
3233
require_once __DIR__ . '/scenarios/multi_tax_rule_two_row_calculate_subtotal_yes_total.php';
3334
require_once __DIR__ . '/scenarios/including_tax_apply_tax_after_discount.php';
35+
require_once __DIR__ . '/scenarios/including_tax_with_custom_price.php';

0 commit comments

Comments
 (0)