Skip to content

Commit 8ca03c7

Browse files
committed
Merge branch 'AC-2238' into spartans_pr_15042025
2 parents c14ebb2 + ce0a2bd commit 8ca03c7

File tree

4 files changed

+308
-4
lines changed

4 files changed

+308
-4
lines changed
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
<?php
2+
/**
3+
* Copyright 2025 Adobe
4+
* All Rights Reserved.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\Tax\Controller\Adminhtml\Rate;
9+
10+
use Magento\Backend\App\AbstractAction;
11+
use Magento\Backend\App\Action\Context;
12+
use Magento\Framework\App\Action\HttpGetActionInterface;
13+
use Magento\Framework\App\Action\HttpPostActionInterface;
14+
use Magento\Framework\Controller\ResultFactory;
15+
use Magento\Tax\Api\TaxRateRepositoryInterface;
16+
use Psr\Log\LoggerInterface;
17+
18+
/**
19+
* Bulk Delete selected catalog price rules
20+
*/
21+
class MassDelete extends AbstractAction implements HttpPostActionInterface, HttpGetActionInterface
22+
{
23+
/**
24+
* Authorization level of a basic admin session
25+
*
26+
* @see _isAllowed()
27+
*/
28+
public const ADMIN_RESOURCE = 'Magento_Tax::manage_tax';
29+
30+
/**
31+
* @param Context $context
32+
* @param TaxRateRepositoryInterface $taxRateRepository
33+
* @param LoggerInterface $logger
34+
*/
35+
public function __construct(
36+
Context $context,
37+
private TaxRateRepositoryInterface $taxRateRepository,
38+
private LoggerInterface $logger
39+
) {
40+
parent::__construct($context);
41+
}
42+
43+
/**
44+
* Delete selected catalog price rules
45+
*
46+
* @return \Magento\Backend\Model\View\Result\Redirect
47+
* @throws \Magento\Framework\Exception\LocalizedException|\Exception
48+
*/
49+
public function execute()
50+
{
51+
$ids = $this->getRequest()->getParam('tax_rate_ids');
52+
$taxRateDeleted = 0;
53+
$taxRateDeleteError = 0;
54+
foreach ($ids as $rateId) {
55+
try {
56+
$this->taxRateRepository->deleteById((int)$rateId);
57+
$taxRateDeleted++;
58+
} catch (\Exception $e) {
59+
$this->logger->error($e->getMessage());
60+
$taxRateDeleteError++;
61+
}
62+
}
63+
64+
if ($taxRateDeleted) {
65+
$this->messageManager->addSuccessMessage(
66+
__('A total of %1 record(s) have been deleted.', $taxRateDeleted)
67+
);
68+
}
69+
70+
if ($taxRateDeleteError) {
71+
$this->messageManager->addErrorMessage(
72+
__(
73+
'A total of %1 record(s) haven\'t been deleted. Please see server logs for more details.',
74+
$taxRateDeleteError
75+
)
76+
);
77+
}
78+
return $this->resultFactory->create(ResultFactory::TYPE_REDIRECT)->setPath('tax/*/');
79+
}
80+
}
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
<?php
2+
/**
3+
* Copyright 2025 Adobe
4+
* All Rights Reserved.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\Tax\Test\Unit\Controller\Adminhtml\Rate;
9+
10+
use Magento\Backend\Model\View\Result\Redirect;
11+
use Magento\Framework\App\RequestInterface;
12+
use Magento\Framework\Controller\ResultFactory;
13+
use Magento\Framework\Message\ManagerInterface;
14+
use PHPUnit\Framework\MockObject\MockObject;
15+
use Magento\Backend\App\Action\Context;
16+
use PHPUnit\Framework\TestCase;
17+
use Magento\Tax\Controller\Adminhtml\Rate\MassDelete;
18+
use Magento\Tax\Api\TaxRateRepositoryInterface;
19+
use Psr\Log\LoggerInterface;
20+
21+
class MassDeleteTest extends TestCase
22+
{
23+
/**
24+
* @var TaxRateRepositoryInterface|MockObject
25+
*/
26+
private $taxRateRepositoryMock;
27+
28+
/**
29+
* @var LoggerInterface|MockObject
30+
*/
31+
private $loggerMock;
32+
33+
/**
34+
* @var Context|MockObject
35+
*/
36+
protected $contextMock;
37+
38+
/**
39+
* @var MassDelete
40+
*/
41+
protected $massDelete;
42+
43+
/**
44+
* @var RequestInterface|MockObject
45+
*/
46+
protected $requestMock;
47+
48+
/**
49+
* @var ManagerInterface|MockObject
50+
*/
51+
protected $messageManagerMock;
52+
53+
/**
54+
* @var Redirect|MockObject
55+
*/
56+
protected $resultRedirectMock;
57+
58+
/**
59+
* @var ResultFactory|MockObject
60+
*/
61+
protected $resultFactory;
62+
63+
protected function setUp(): void
64+
{
65+
$this->requestMock = $this->getMockBuilder(RequestInterface::class)
66+
->onlyMethods(['getParam'])
67+
->getMockForAbstractClass();
68+
$this->contextMock = $this->createMock(Context::class);
69+
70+
$this->messageManagerMock = $this->getMockBuilder(ManagerInterface::class)
71+
->getMockForAbstractClass();
72+
73+
$this->resultRedirectMock = $this->getMockBuilder(Redirect::class)
74+
->onlyMethods(['setPath'])
75+
->disableOriginalConstructor()
76+
->getMock();
77+
78+
$this->resultFactory = $this->createMock(ResultFactory::class);
79+
$this->resultFactory->method('create')->willReturn($this->resultRedirectMock);
80+
$this->contextMock->method('getResultFactory')->willReturn($this->resultFactory);
81+
$this->contextMock->method('getMessageManager')->willReturn($this->messageManagerMock);
82+
$this->contextMock->method('getRequest')->willReturn($this->requestMock);
83+
84+
$this->loggerMock = $this->createMock(LoggerInterface::class);
85+
86+
$this->taxRateRepositoryMock = $this->createMock(TaxRateRepositoryInterface::class);
87+
$this->massDelete = new MassDelete($this->contextMock, $this->taxRateRepositoryMock, $this->loggerMock);
88+
}
89+
90+
public function testExecute()
91+
{
92+
$data = [1];
93+
$this->requestMock->expects(self::any())
94+
->method('getParam')
95+
->willReturn($data);
96+
97+
$this->taxRateRepositoryMock->expects($this->once())
98+
->method('deleteById')
99+
->with(1)
100+
->willReturn(true);
101+
102+
$this->messageManagerMock->expects($this->once())
103+
->method('addSuccessMessage')
104+
->with(__('A total of %1 record(s) have been deleted.', $data));
105+
106+
$this->massDelete->execute();
107+
}
108+
}

app/code/Magento/Tax/view/adminhtml/layout/tax_rate_block.xml

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
<?xml version="1.0"?>
22
<!--
3-
/**
4-
* Copyright © Magento, Inc. All rights reserved.
5-
* See COPYING.txt for license details.
6-
*/
3+
* Copyright 2013 Adobe
4+
* All Rights Reserved.
75
-->
86
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
97
<body>
@@ -16,6 +14,20 @@
1614
<argument name="default_dir" xsi:type="string">ASC</argument>
1715
<argument name="save_parameters_in_session" xsi:type="string">1</argument>
1816
</arguments>
17+
<block class="Magento\Backend\Block\Widget\Grid\Massaction" name="adminhtml.tax.rate.set.grid.massaction" as="grid.massaction">
18+
<arguments>
19+
<argument name="massaction_id_field" xsi:type="string">tax_calculation_rate_id</argument>
20+
<argument name="form_field_name" xsi:type="string">tax_rate_ids</argument>
21+
<argument name="use_select_all" xsi:type="string">1</argument>
22+
<argument name="options" xsi:type="array">
23+
<item name="delete" xsi:type="array">
24+
<item name="label" xsi:type="string" translate="true">Delete</item>
25+
<item name="url" xsi:type="string">tax/rate/massDelete</item>
26+
<item name="confirm" xsi:type="string" translate="true">Are you sure you want to delete selected items?</item>
27+
</item>
28+
</argument>
29+
</arguments>
30+
</block>
1931
<block class="Magento\Backend\Block\Widget\Grid\ColumnSet" name="adminhtml.catalog.product.set.grid.columnSet" as="grid.columnSet">
2032
<arguments>
2133
<argument name="id" xsi:type="string">tax_rate_grid</argument>
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
<?php
2+
/**
3+
* Copyright 2025 Adobe
4+
* All Rights Reserved.
5+
*/
6+
7+
declare(strict_types=1);
8+
9+
namespace Magento\Tax\Controller\Adminhtml\Rate;
10+
11+
use Magento\Framework\Exception\LocalizedException;
12+
use Magento\TestFramework\Fixture\AppArea;
13+
use Magento\TestFramework\Fixture\DataFixture;
14+
use Magento\TestFramework\Fixture\DataFixtureStorage;
15+
use Magento\TestFramework\Fixture\DataFixtureStorageManager;
16+
use Magento\TestFramework\TestCase\AbstractBackendController;
17+
use Magento\Tax\Test\Fixture\TaxRate as TaxRateFixture;
18+
use Magento\Tax\Model\Calculation\RateFactory;
19+
use Magento\Framework\App\Request\Http as HttpRequest;
20+
use Magento\Framework\Message\ManagerInterface;
21+
22+
/**
23+
* Test class for mass delete tax rate in admin grid
24+
*
25+
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
26+
*/
27+
#[
28+
AppArea('adminhtml')
29+
]
30+
class MassDeleteTest extends AbstractBackendController
31+
{
32+
/**
33+
* @var DataFixtureStorage
34+
*/
35+
private $fixtures;
36+
37+
/**
38+
* @var RateFactory
39+
*/
40+
private $rateFactory;
41+
42+
/**
43+
* @throws LocalizedException
44+
*/
45+
protected function setUp(): void
46+
{
47+
parent::setUp();
48+
$this->fixtures = DataFixtureStorageManager::getStorage();
49+
$this->rateFactory = $this->_objectManager->create(RateFactory::class);
50+
}
51+
52+
#[
53+
DataFixture(
54+
TaxRateFixture::class,
55+
[
56+
'tax_country_id' => 'US',
57+
'code' => 'Test Rate US',
58+
'rate' => '10',
59+
],
60+
'tax_rate_us',
61+
),
62+
DataFixture(
63+
TaxRateFixture::class,
64+
[
65+
'tax_country_id' => 'DE',
66+
'code' => 'Test Rate DE',
67+
'rate' => '21',
68+
],
69+
'tax_rate_de',
70+
),
71+
]
72+
public function testMassDelete(): void
73+
{
74+
$rate1 = $this->fixtures->get('tax_rate_us');
75+
$rate2 = $this->fixtures->get('tax_rate_de');
76+
self::assertNotNull($rate1->getId());
77+
$params = ['tax_rate_ids' => [$rate1->getId()]];
78+
$request = $this->getRequest();
79+
$request->setParams($params);
80+
$request->setMethod(HttpRequest::METHOD_POST);
81+
$url = 'backend/tax/rate/massDelete';
82+
$this->dispatch($url);
83+
self::assertEquals('A total of 1 record(s) have been deleted.', $this->getSuccessMessage());
84+
$afterDeleteUsRate = $this->rateFactory->create()->load($rate1->getId());
85+
self::assertNull($afterDeleteUsRate->getId());
86+
self::assertNotNull($rate2->getId());
87+
}
88+
89+
/**
90+
* Gets success message after dispatching the controller.
91+
*
92+
* @return string|null
93+
*/
94+
private function getSuccessMessage(): ?string
95+
{
96+
/** @var ManagerInterface $messageManager */
97+
$messageManager = $this->_objectManager->get(ManagerInterface::class);
98+
$messages = $messageManager->getMessages(true)->getItems();
99+
if ($messages) {
100+
return $messages[0]->getText();
101+
}
102+
return null;
103+
}
104+
}

0 commit comments

Comments
 (0)