Skip to content

Commit 71ba44e

Browse files
committed
MAGETWO-59801: [Performance Bug] Tax Rules Form unusable with large # of tax rates
1 parent 3993417 commit 71ba44e

File tree

24 files changed

+1390
-72
lines changed

24 files changed

+1390
-72
lines changed

app/code/Magento/Tax/Block/Adminhtml/Rule/Edit/Form.php

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,7 @@ protected function _prepareForm()
185185
true
186186
);
187187

188+
$selectConfig = $this->getTaxRatesSelectConfig($formValues);
188189
$fieldset->addField(
189190
'tax_rate',
190191
'editablemultiselect',
@@ -196,7 +197,7 @@ protected function _prepareForm()
196197
'value' => isset($formValues['tax_rate']) ? $formValues['tax_rate'] : [],
197198
'required' => true,
198199
'element_js_class' => 'TaxRateEditableMultiselect',
199-
'select_config' => ['is_entity_editable' => true]
200+
'select_config' => $selectConfig
200201
]
201202
);
202203

@@ -257,6 +258,22 @@ protected function _prepareForm()
257258
return parent::_prepareForm();
258259
}
259260

261+
/**
262+
* Retrieve configuration options for tax rates editable multiselect
263+
*
264+
* @param array $formValues
265+
* @return array
266+
*/
267+
public function getTaxRatesSelectConfig($formValues)
268+
{
269+
$config = [
270+
'is_entity_editable' => true,
271+
'selected_values' => isset($formValues['tax_rate']) ? $formValues['tax_rate'] : []
272+
];
273+
274+
return $config;
275+
}
276+
260277
/**
261278
* Retrieve configuration options for tax class editable multiselect
262279
*
@@ -310,6 +327,16 @@ public function getTaxRateLoadUrl()
310327
return $this->getUrl('tax/rate/ajaxLoad/');
311328
}
312329

330+
/**
331+
* Retrieve next Tax Rates page URL
332+
*
333+
* @return string
334+
*/
335+
public function getTaxRatesPageUrl()
336+
{
337+
return $this->getUrl('tax/rule/ajaxLoadRates/');
338+
}
339+
313340
/**
314341
* Extract tax rule data in a format which is
315342
*
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
namespace Magento\Tax\Block\Grid\Renderer;
7+
8+
class Codes extends \Magento\Backend\Block\Widget\Grid\Column\Renderer\AbstractRenderer
9+
{
10+
/**
11+
* Renders rates codes grid column
12+
*
13+
* @param \Magento\Framework\DataObject $row
14+
* @return string
15+
*/
16+
public function render(\Magento\Framework\DataObject $row)
17+
{
18+
$ratesCodes = $row->getTaxRatesCodes();
19+
return is_array($ratesCodes) ? implode(', ', $ratesCodes) : '';
20+
}
21+
}
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
namespace Magento\Tax\Controller\Adminhtml\Rule;
7+
8+
use Magento\Framework\App\Action\Context;
9+
use Magento\Framework\App\Action\Action;
10+
use Magento\Framework\Controller\Result\Json;
11+
use Magento\Framework\Controller\ResultFactory;
12+
use Magento\Tax\Model\Rate\Provider as RatesProvider;
13+
use Magento\Framework\Api\SearchCriteriaBuilder;
14+
use Magento\Tax\Model\Calculation\Rate;
15+
16+
class AjaxLoadRates extends Action
17+
{
18+
const PAGE_PARAM_NAME = 'p';
19+
const FILTER_PARAM_NAME = 's';
20+
const SEARCH_CONDITION_TYPE = 'like';
21+
22+
/**
23+
* @var RatesProvider
24+
*/
25+
private $ratesProvider;
26+
27+
/** @var SearchCriteriaBuilder */
28+
private $searchCriteriaBuilder;
29+
30+
/**
31+
* @param Context $context
32+
* @param SearchCriteriaBuilder $searchCriteriaBuilder
33+
* @param RatesProvider $ratesProvider
34+
*/
35+
public function __construct(
36+
Context $context,
37+
SearchCriteriaBuilder $searchCriteriaBuilder,
38+
RatesProvider $ratesProvider
39+
) {
40+
parent::__construct($context);
41+
$this->searchCriteriaBuilder = $searchCriteriaBuilder;
42+
$this->ratesProvider = $ratesProvider;
43+
}
44+
45+
/**
46+
* Get rates page via AJAX
47+
*
48+
* @return Json
49+
*/
50+
public function execute()
51+
{
52+
$ratesPage = (int) $this->getRequest()->getParam(self::PAGE_PARAM_NAME);
53+
$ratesFilter = trim($this->getRequest()->getParam(self::FILTER_PARAM_NAME));
54+
55+
try {
56+
if (!empty($ratesFilter)) {
57+
$this->searchCriteriaBuilder->addFilter(
58+
Rate::KEY_CODE,
59+
'%'.$ratesFilter.'%',
60+
self::SEARCH_CONDITION_TYPE
61+
);
62+
}
63+
64+
$searchCriteria = $this->searchCriteriaBuilder
65+
->setPageSize(RatesProvider::PAGE_SIZE)
66+
->setCurrentPage($ratesPage)
67+
->create();
68+
69+
$options = $this->ratesProvider->toOptionArray($searchCriteria);
70+
71+
$response = [
72+
'success' => true,
73+
'errorMessage' => '',
74+
'result'=>$options,
75+
];
76+
} catch (\Exception $e) {
77+
$response = [
78+
'success' => false,
79+
'errorMessage' => __('An error occurred while loading tax rates.')
80+
];
81+
}
82+
83+
/** @var Json $resultJson */
84+
$resultJson = $this->resultFactory->create(ResultFactory::TYPE_JSON);
85+
$resultJson->setData($response);
86+
87+
return $resultJson;
88+
}
89+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
namespace Magento\Tax\Model\Api\SearchCriteria\JoinProcessor;
7+
8+
use Magento\Framework\Api\SearchCriteria\CollectionProcessor\JoinProcessor\CustomJoinInterface;
9+
use Magento\Framework\Data\Collection\AbstractDb;
10+
11+
/**
12+
* Class RateCode
13+
* @package Magento\Tax\Model\Api\SearchCriteria\JoinProcessor
14+
*/
15+
class RateCode implements CustomJoinInterface
16+
{
17+
/**
18+
* @param AbstractDb $collection
19+
* @return true
20+
*/
21+
public function apply(AbstractDb $collection)
22+
{
23+
$taxCalculationTableAlias = 'tc';
24+
25+
$collection->joinCalculationData($taxCalculationTableAlias);
26+
27+
$collection->getSelect()->joinLeft(
28+
['rc' => $collection->getTable('tax_calculation_rate')],
29+
"{$taxCalculationTableAlias}.tax_calculation_rate_id = rc.tax_calculation_rate_id",
30+
[]
31+
);
32+
33+
return true;
34+
}
35+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
7+
namespace Magento\Tax\Model\Rate;
8+
9+
use Magento\Framework\Convert\DataObject as Converter;
10+
use Magento\Tax\Api\TaxRateRepositoryInterface;
11+
use Magento\Framework\Api\SearchCriteriaInterface;
12+
use Magento\Tax\Model\Calculation\Rate;
13+
14+
/**
15+
* Paged Tax Rates source model.
16+
*/
17+
class Provider
18+
{
19+
const PAGE_SIZE = 100;
20+
21+
/** @var TaxRateRepositoryInterface */
22+
private $taxRateRepository;
23+
24+
/** @var Converter */
25+
protected $converter;
26+
27+
/**
28+
* Initialize dependencies.
29+
*
30+
* @param TaxRateRepositoryInterface $taxRateRepository
31+
* @param Converter $converter
32+
*/
33+
public function __construct(
34+
TaxRateRepositoryInterface $taxRateRepository,
35+
Converter $converter
36+
) {
37+
$this->taxRateRepository = $taxRateRepository;
38+
$this->converter = $converter;
39+
}
40+
41+
/**
42+
* Retrieve all tax rates as an options array.
43+
*
44+
* @param SearchCriteriaInterface $searchCriteria
45+
* @return array
46+
*/
47+
public function toOptionArray(SearchCriteriaInterface $searchCriteria)
48+
{
49+
$searchResults = $this->taxRateRepository->getList($searchCriteria);
50+
51+
return $this->converter->toOptionArray(
52+
$searchResults->getItems(),
53+
Rate::KEY_ID,
54+
Rate::KEY_CODE
55+
);
56+
}
57+
}

app/code/Magento/Tax/Model/Rate/Source.php

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,10 @@
77
namespace Magento\Tax\Model\Rate;
88

99
use Magento\Framework\Api\SearchCriteriaBuilder;
10+
use Magento\Framework\App\ObjectManager;
1011
use Magento\Framework\Convert\DataObject as Converter;
1112
use Magento\Tax\Api\TaxRateRepositoryInterface;
12-
use Magento\Tax\Model\Calculation\Rate;
13+
use Magento\Tax\Model\Rate\Provider as RateProvider;
1314

1415
/**
1516
* Tax rate source model.
@@ -28,21 +29,27 @@ class Source implements \Magento\Framework\Data\OptionSourceInterface
2829
/** @var Converter */
2930
protected $converter;
3031

32+
/** @var RateProvider */
33+
protected $rateProvider;
34+
3135
/**
3236
* Initialize dependencies.
3337
*
3438
* @param TaxRateRepositoryInterface $taxRateRepository
3539
* @param SearchCriteriaBuilder $searchCriteriaBuilder
3640
* @param Converter $converter
41+
* @param RateProvider $rateProvider
3742
*/
3843
public function __construct(
3944
TaxRateRepositoryInterface $taxRateRepository,
4045
SearchCriteriaBuilder $searchCriteriaBuilder,
41-
Converter $converter
46+
Converter $converter,
47+
RateProvider $rateProvider = null
4248
) {
4349
$this->taxRateRepository = $taxRateRepository;
4450
$this->searchCriteriaBuilder = $searchCriteriaBuilder;
4551
$this->converter = $converter;
52+
$this->rateProvider = $rateProvider ?: ObjectManager::getInstance()->get(RateProvider::class);
4653
}
4754

4855
/**
@@ -53,14 +60,14 @@ public function __construct(
5360
public function toOptionArray()
5461
{
5562
if (!$this->options) {
56-
$searchCriteria = $this->searchCriteriaBuilder->create();
57-
$searchResults = $this->taxRateRepository->getList($searchCriteria);
58-
$this->options = $this->converter->toOptionArray(
59-
$searchResults->getItems(),
60-
Rate::KEY_ID,
61-
Rate::KEY_CODE
62-
);
63+
$searchCriteria = $this->searchCriteriaBuilder
64+
->setPageSize(RateProvider::PAGE_SIZE)
65+
->setCurrentPage(1)
66+
->create();
67+
68+
$this->options = $this->rateProvider->toOptionArray($searchCriteria);
6369
}
70+
6471
return $this->options;
6572
}
6673
}

app/code/Magento/Tax/Model/ResourceModel/Calculation/Rule/Collection.php

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,10 +65,17 @@ public function joinCalculationData($alias)
6565
* @param string $secondaryJoinField
6666
* @param string $titleField
6767
* @param string $dataField
68+
* @param string $dataTitleField
6869
* @return \Magento\Tax\Model\ResourceModel\Calculation\Rule\Collection
6970
*/
70-
protected function _add($itemTable, $primaryJoinField, $secondaryJoinField, $titleField, $dataField)
71-
{
71+
protected function _add(
72+
$itemTable,
73+
$primaryJoinField,
74+
$secondaryJoinField,
75+
$titleField,
76+
$dataField,
77+
$dataTitleField = ''
78+
) {
7279
$children = [];
7380
foreach ($this as $rule) {
7481
$children[$rule->getId()] = [];
@@ -98,6 +105,9 @@ protected function _add($itemTable, $primaryJoinField, $secondaryJoinField, $tit
98105
foreach ($this as $rule) {
99106
if (isset($children[$rule->getId()])) {
100107
$rule->setData($dataField, array_keys($children[$rule->getId()]));
108+
if (!empty($dataTitleField)) {
109+
$rule->setData($dataTitleField, $children[$rule->getId()]);
110+
}
101111
}
102112
}
103113

@@ -136,7 +146,8 @@ public function addRatesToResult()
136146
'tax_calculation_rate_id',
137147
'tax_calculation_rate_id',
138148
'code',
139-
'tax_rates'
149+
'tax_rates',
150+
'tax_rates_codes'
140151
);
141152
}
142153

app/code/Magento/Tax/Model/TaxRuleCollection.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ protected function createTaxRuleCollectionItem(TaxRuleInterface $taxRule)
7878
$collectionItem->setCalculateSubtotal($taxRule->getCalculateSubtotal() ? '1' : '0');
7979
$collectionItem->setCustomerTaxClasses($taxRule->getCustomerTaxClassIds());
8080
$collectionItem->setProductTaxClasses($taxRule->getProductTaxClassIds());
81+
$collectionItem->setTaxRatesCodes($taxRule->getTaxRatesCodes());
8182
$collectionItem->setTaxRates($taxRule->getTaxRateIds());
8283
return $collectionItem;
8384
}

0 commit comments

Comments
 (0)