Skip to content

Commit ee918f0

Browse files
Merge pull request #10122 from adobe-commerce-tier-4/PR_2025_09_19_flowers
[Support Tier-4 flowers] 09-19-2025 Regular delivery of bugfixes and improvements
2 parents 588eac3 + c2fe064 commit ee918f0

File tree

15 files changed

+430
-74
lines changed

15 files changed

+430
-74
lines changed

app/code/Magento/Customer/Model/Vat.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<?php
22
/**
3-
* Copyright © Magento, Inc. All rights reserved.
4-
* See COPYING.txt for license details.
3+
* Copyright 2014 Adobe
4+
* All Rights Reserved.
55
*/
66
namespace Magento\Customer\Model;
77

@@ -139,14 +139,14 @@ public function getCustomerGroupIdBasedOnVatNumber($customerCountryCode, $vatVal
139139
];
140140

141141
if (isset($vatClassToGroupXmlPathMap[$vatClass])) {
142-
$groupId = (int)$this->scopeConfig->getValue(
142+
$groupId = $this->scopeConfig->getValue(
143143
$vatClassToGroupXmlPathMap[$vatClass],
144144
ScopeInterface::SCOPE_STORE,
145145
$store
146146
);
147147
}
148148

149-
return $groupId;
149+
return $groupId ? (int)$groupId : null;
150150
}
151151

152152
/**
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<?php
2+
/**
3+
* Copyright 2025 Adobe
4+
* All Rights Reserved.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\Customer\Model;
9+
10+
use Magento\Framework\DataObject;
11+
use Magento\Framework\ObjectManager\ResetAfterRequestInterface;
12+
13+
/**
14+
* Storage for validated VAT data
15+
*/
16+
class VatValidationResultStorage extends DataObject implements ResetAfterRequestInterface
17+
{
18+
/**
19+
* Store VAT validated data by key
20+
*
21+
* @param string|int $vatNumber
22+
* @param string $countryCode
23+
* @param DataObject $vatValidationResult
24+
* @return void
25+
*/
26+
public function set(string|int $vatNumber, string $countryCode, DataObject $vatValidationResult): void
27+
{
28+
$this->setData($vatNumber . $countryCode, $vatValidationResult);
29+
}
30+
31+
/**
32+
* Retrieve VAT validated data by key
33+
*
34+
* @param string|int $vatNumber
35+
* @param string $countryCode
36+
* @return DataObject|null
37+
*/
38+
public function get(string|int $vatNumber, string $countryCode): ?DataObject
39+
{
40+
return $this->getData($vatNumber . $countryCode);
41+
}
42+
43+
/**
44+
* @inheritDoc
45+
*/
46+
public function _resetState(): void
47+
{
48+
$this->setData([]);
49+
}
50+
}

app/code/Magento/Customer/Observer/AfterAddressSaveObserver.php

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<?php
22
/**
3-
* Copyright © Magento, Inc. All rights reserved.
4-
* See COPYING.txt for license details.
3+
* Copyright 2011 Adobe
4+
* All Rights Reserved.
55
*/
66
declare(strict_types=1);
77

@@ -159,7 +159,10 @@ public function execute(Observer $observer)
159159
$customer->getStore()
160160
);
161161

162-
if (!$customer->getDisableAutoGroupChange() && $customer->getGroupId() != $newGroupId) {
162+
if (!$customer->getDisableAutoGroupChange() &&
163+
$newGroupId !== null &&
164+
$customer->getGroupId() != $newGroupId
165+
) {
163166
$customer->setGroupId($newGroupId);
164167
$customer->save();
165168
$this->customerSession->setCustomerGroupId($newGroupId);
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
<?php
2+
/**
3+
* Copyright 2025 Adobe
4+
* All Rights Reserved.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\Customer\Plugin\Model;
9+
10+
use Magento\Customer\Model\Vat;
11+
use Magento\Customer\Model\VatValidationResultStorage;
12+
13+
/**
14+
* Plugin to cache the VAT number validation result based on provided VAT number and country code
15+
*/
16+
class VatPlugin
17+
{
18+
/**
19+
* @param VatValidationResultStorage $vatValidationResultStorage
20+
*/
21+
public function __construct(
22+
private readonly VatValidationResultStorage $vatValidationResultStorage
23+
) {
24+
}
25+
26+
/**
27+
* Cache VAT number validation result
28+
*
29+
* @param Vat $subject
30+
* @param \Closure $proceed
31+
* @param string $countryCode
32+
* @param string $vatNumber
33+
* @param string $requesterCountryCode
34+
* @param string $requesterVatNumber
35+
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
36+
*/
37+
public function aroundCheckVatNumber(
38+
Vat $subject,
39+
\Closure $proceed,
40+
$countryCode,
41+
$vatNumber,
42+
$requesterCountryCode = '',
43+
$requesterVatNumber = ''
44+
) {
45+
$storedValidationResult = $this->vatValidationResultStorage->get($vatNumber, $countryCode);
46+
47+
if ($storedValidationResult) {
48+
return $storedValidationResult;
49+
}
50+
$validationResult = $proceed($countryCode, $vatNumber, $requesterCountryCode, $requesterVatNumber);
51+
52+
if ($validationResult->getRequestSuccess()) {
53+
$this->vatValidationResultStorage->set($vatNumber, $countryCode, $validationResult);
54+
}
55+
56+
return $validationResult;
57+
}
58+
}

app/code/Magento/Customer/etc/frontend/di.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,4 +133,7 @@
133133
<type name="Magento\Customer\Api\CustomerRepositoryInterface">
134134
<plugin name="customer_dobvalidation_plugin" type="Magento\Customer\Plugin\ValidateDobOnSave" sortOrder="10"/>
135135
</type>
136+
<type name="Magento\Customer\Model\Vat">
137+
<plugin name="cache_vat_validation_result" type="Magento\Customer\Plugin\Model\VatPlugin"/>
138+
</type>
136139
</config>

app/code/Magento/ImportExport/Model/Export/Entity/AbstractEntity.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<?php
22
/**
3-
* Copyright © Magento, Inc. All rights reserved.
4-
* See COPYING.txt for license details.
3+
* Copyright 2013 Adobe
4+
* All Rights Reserved.
55
*/
66
namespace Magento\ImportExport\Model\Export\Entity;
77

@@ -290,7 +290,7 @@ protected function _prepareEntityCollection(\Magento\Eav\Model\Entity\Collection
290290
$attrFilterType = \Magento\ImportExport\Model\Export::getAttributeFilterType($attribute);
291291

292292
if (\Magento\ImportExport\Model\Export::FILTER_TYPE_SELECT == $attrFilterType) {
293-
if (is_scalar($exportFilter[$attrCode]) && trim($exportFilter[$attrCode])) {
293+
if (is_scalar($exportFilter[$attrCode]) && strlen(trim($exportFilter[$attrCode]))) {
294294
$collection->addAttributeToFilter($attrCode, ['eq' => $exportFilter[$attrCode]]);
295295
}
296296
} elseif (\Magento\ImportExport\Model\Export::FILTER_TYPE_MULTISELECT == $attrFilterType) {

app/code/Magento/Quote/Observer/Frontend/Quote/Address/VatValidator.php

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,32 @@
11
<?php
22
/**
3-
* Copyright © Magento, Inc. All rights reserved.
4-
* See COPYING.txt for license details.
3+
* Copyright 2013 Adobe
4+
* All Rights Reserved.
55
*/
66
namespace Magento\Quote\Observer\Frontend\Quote\Address;
77

8+
use Magento\Customer\Helper\Address;
9+
use Magento\Customer\Model\Vat;
10+
811
class VatValidator
912
{
1013
/**
11-
* Customer address
12-
*
13-
* @var \Magento\Customer\Helper\Address
14+
* @var Address
1415
*/
1516
protected $customerAddress;
1617

1718
/**
18-
* Customer VAT
19-
*
20-
* @var \Magento\Customer\Model\Vat
19+
* @var Vat
2120
*/
2221
protected $customerVat;
2322

2423
/**
25-
* @param \Magento\Customer\Helper\Address $customerAddress
26-
* @param \Magento\Customer\Model\Vat $customerVat
24+
* @param Address $customerAddress
25+
* @param Vat $customerVat
2726
*/
2827
public function __construct(
29-
\Magento\Customer\Helper\Address $customerAddress,
30-
\Magento\Customer\Model\Vat $customerVat
28+
Address $customerAddress,
29+
Vat $customerVat
3130
) {
3231
$this->customerVat = $customerVat;
3332
$this->customerAddress = $customerAddress;

app/code/Magento/Ui/view/base/web/js/form/element/file-uploader.js

Lines changed: 60 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/**
2-
* Copyright © Magento, Inc. All rights reserved.
3-
* See COPYING.txt for license details.
2+
* Copyright 2016 Adobe
3+
* All Rights Reserved.
44
*/
55

66
/**
@@ -110,10 +110,9 @@ define([
110110
}
111111

112112
// code to allow duplicate files from same folder
113-
const modifiedFile = {
114-
...currentFile,
115-
id: currentFile.id + '-' + Date.now()
116-
};
113+
const modifiedFile = Object.assign({}, currentFile, {
114+
id: currentFile.id + '-' + Date.now()
115+
});
117116

118117
this.onLoadingStart();
119118
return modifiedFile;
@@ -177,10 +176,53 @@ define([
177176
let fileId = fileInput.id, fileName = fileInput.name,
178177
spanElement = '<span id=\'' + fileId + '\'></span>';
179178

180-
$('#' + fileId).closest('.file-uploader-area').attr('upload-area-id', fileName);
179+
$(fileInput).closest('.file-uploader-area').attr('upload-area-id', fileName);
181180
$(fileInput).replaceWith(spanElement);
182-
$('#' + fileId).closest('.file-uploader-area').find('.file-uploader-button:first').on('click', function () {
183-
$('#' + fileId).closest('.file-uploader-area').find('.uppy-Dashboard-browse').trigger('click');
181+
},
182+
183+
/**
184+
* Trigger the file browser dialog
185+
*
186+
* @param {jQuery} $area
187+
*/
188+
triggerFileBrowser: function ($area) {
189+
const $browseBtn = $area.find('.uppy-Dashboard-browse').first();
190+
191+
if ($browseBtn.length > 0) {
192+
$browseBtn[0].click();
193+
return;
194+
}
195+
196+
let $dashboard = $area.find('.uppy-Dashboard-inner'),
197+
$fileInput = $dashboard.find('input[type="file"]:visible').first();
198+
199+
if ($fileInput.length > 0) {
200+
$fileInput[0].click();
201+
}
202+
},
203+
204+
/**
205+
* Binds click events for file browser triggers using event delegation
206+
*
207+
* @param {String} fileId
208+
*/
209+
bindFileBrowserTriggers: function (fileId) {
210+
let self = this,
211+
$area = $('[upload-area-id="' + fileId + '"]').closest('.file-uploader-area'),
212+
$dropZone = $area.closest('[data-role=drop-zone]');
213+
214+
if (!$area.length) {
215+
$area = $('span[id="' + fileId + '"]').closest('.file-uploader-area');
216+
$dropZone = $area.closest('[data-role=drop-zone]');
217+
}
218+
219+
$area.off('click.fileUploader').on('click.fileUploader', '.file-uploader-button:first', function (e) {
220+
e.preventDefault();
221+
self.triggerFileBrowser($area);
222+
});
223+
$dropZone.off('click.fileUploader').on('click.fileUploader', '.file-uploader-placeholder', function (e) {
224+
e.preventDefault();
225+
self.triggerFileBrowser($area);
184226
});
185227
},
186228

@@ -216,11 +258,14 @@ define([
216258
* @param value
217259
* @returns {Promise<void>}
218260
*/
219-
async setImageSize(value) {
220-
let response = await fetch(value.url),
221-
blob = await response.blob();
222-
223-
value.size = blob.size;
261+
setImageSize: function (value) {
262+
return fetch(value.url)
263+
.then(function (response) {
264+
return response.blob();
265+
})
266+
.then(function (blob) {
267+
value.size = blob.size;
268+
});
224269
},
225270

226271
/**
@@ -614,6 +659,7 @@ define([
614659
*/
615660
onElementRender: function (fileInput) {
616661
this.initUploader(fileInput);
662+
this.bindFileBrowserTriggers(fileInput.id);
617663
},
618664

619665
/**

dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Export/ProductTest.php

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
use Magento\CatalogInventory\Api\StockItemRepositoryInterface;
2222
use Magento\CatalogInventory\Model\Stock\Item;
2323
use Magento\Directory\Helper\Data as DirectoryData;
24+
use Magento\Framework\App\Area;
2425
use Magento\Framework\App\Config\ReinitableConfigInterface;
2526
use Magento\Framework\App\Config\ScopeConfigInterface;
2627
use Magento\Framework\Exception\NoSuchEntityException;
@@ -998,4 +999,22 @@ public function testExportProductWithDateAndDatetimeAttributes(): void
998999
$this->assertMatchesRegularExpression('#datetime_attr=7/19/15,\p{Zs}3:30\p{Zs}AM#u', $csv);
9991000
$this->assertMatchesRegularExpression('#date_attr=2/7/17("|(,\w+=))#', $csv);
10001001
}
1002+
1003+
#[
1004+
AppArea(Area::AREA_ADMINHTML),
1005+
DataFixture(
1006+
AttributeFixture::class,
1007+
['frontend_input' => 'boolean', 'backend_type' => 'int', 'attribute_code' => 'yesno_attr']
1008+
),
1009+
DataFixture(ProductFixture::class, ['sku' => 'prod1']),
1010+
DataFixture(ProductFixture::class, ['sku' => 'prod2', 'yesno_attr' => '0']),
1011+
DataFixture(ProductFixture::class, ['sku' => 'prod3', 'yesno_attr' => '1']),
1012+
]
1013+
public function testExportProductWithYesNoAttribute(): void
1014+
{
1015+
$csv = $this->doExport(['yesno_attr' => '0']);
1016+
self::assertStringContainsString('prod2', $csv);
1017+
self::assertStringNotContainsString('prod1', $csv);
1018+
self::assertStringNotContainsString('prod3', $csv);
1019+
}
10011020
}

0 commit comments

Comments
 (0)