Skip to content

Commit a620729

Browse files
authored
Merge pull request #5868 from magento-mpi/PR-2020-07-09
[mpi] MC-35226: Elasticsearch Filters Product Prices Differently than MySQL
2 parents 099886a + 2ba6b46 commit a620729

File tree

28 files changed

+714
-158
lines changed

28 files changed

+714
-158
lines changed

app/code/Magento/Braintree/Plugin/DisableQuoteAddressValidation.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
namespace Magento\Braintree\Plugin;
99

1010
use Magento\Quote\Model\QuoteManagement;
11-
use Magento\Quote\Api\CartManagementInterface;
1211
use Magento\Quote\Model\Quote;
1312

1413
/**
@@ -36,7 +35,8 @@ public function beforeSubmit(
3635
$orderData = []
3736
) {
3837
if ($quote->getPayment()->getMethod() == 'braintree_paypal' &&
39-
$quote->getCheckoutMethod() == CartManagementInterface::METHOD_GUEST) {
38+
(!$quote->getCustomer() || !$quote->getCustomer()->getAddresses())
39+
) {
4040
$billingAddress = $quote->getBillingAddress();
4141
$billingAddress->setShouldIgnoreValidation(true);
4242
$quote->setBillingAddress($billingAddress);
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
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+
namespace Magento\Braintree\Test\Unit\Plugin;
9+
10+
use Magento\Braintree\Plugin\DisableQuoteAddressValidation;
11+
use Magento\Customer\Api\Data\CustomerInterface;
12+
use Magento\Quote\Model\Quote;
13+
use Magento\Quote\Model\Quote\Address;
14+
use Magento\Quote\Model\Quote\Payment;
15+
use Magento\Quote\Model\QuoteManagement;
16+
use PHPUnit\Framework\TestCase;
17+
18+
class DisableQuoteAddressValidationTest extends TestCase
19+
{
20+
/**
21+
* @var DisableQuoteAddressValidation
22+
*/
23+
private $model;
24+
25+
/**
26+
* @inheritDoc
27+
*/
28+
protected function setUp()
29+
{
30+
parent::setUp();
31+
$this->model = new DisableQuoteAddressValidation();
32+
}
33+
34+
/**
35+
* @param string $paymentMethod
36+
* @param bool $isGuest
37+
* @param array $addresses
38+
* @param bool $skipValidation
39+
* @throws \Magento\Framework\Exception\LocalizedException
40+
* @dataProvider beforeSubmitDataProvider
41+
*/
42+
public function testBeforeSubmit(
43+
string $paymentMethod,
44+
bool $isGuest,
45+
array $addresses,
46+
bool $skipValidation
47+
) {
48+
$subject = $this->createMock(QuoteManagement::class);
49+
$quote = $this->createMock(Quote::class);
50+
$payment = $this->createMock(Payment::class);
51+
$customer = $this->createMock(CustomerInterface::class);
52+
$billingAddress = $this->createPartialMock(Address::class, ['setShouldIgnoreValidation']);
53+
$quote->method('getPayment')->willReturn($payment);
54+
$quote->method('getCustomer')->willReturn($isGuest ? null : $customer);
55+
$quote->method('getBillingAddress')->willReturn($billingAddress);
56+
$customer->method('getAddresses')->willReturn($addresses);
57+
$payment->method('getMethod')->willReturn($paymentMethod);
58+
$billingAddress->expects($skipValidation ? $this->once() : $this->never())
59+
->method('setShouldIgnoreValidation')
60+
->with(true);
61+
$this->model->beforeSubmit($subject, $quote, []);
62+
}
63+
64+
/**
65+
* @return array
66+
*/
67+
public function beforeSubmitDataProvider(): array
68+
{
69+
return [
70+
['braintree_paypal', true, [] ,true],
71+
['braintree_paypal', false, [], true],
72+
['braintree_paypal', false, [[]], false],
73+
['payflowpro', true, [] ,false],
74+
['payflowpro', false, [], false],
75+
['payflowpro', false, [[]], false],
76+
];
77+
}
78+
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
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+
namespace Magento\Catalog\Model;
9+
10+
use Magento\Catalog\Api\ProductRepositoryInterface;
11+
use Magento\Framework\App\RequestInterface;
12+
use Magento\Framework\Exception\NoSuchEntityException;
13+
use Magento\PageCache\Model\Spi\PageCacheTagsPreprocessorInterface;
14+
use Magento\Store\Model\StoreManagerInterface;
15+
16+
/**
17+
* Add product identities to "noroute" page
18+
*
19+
* Ensure that "noroute" page has necessary product tags
20+
* so it can be invalidated once the product becomes visible again
21+
*/
22+
class ProductNotFoundPageCacheTags implements PageCacheTagsPreprocessorInterface
23+
{
24+
private const NOROUTE_ACTION_NAME = 'cms_noroute_index';
25+
/**
26+
* @var ProductRepositoryInterface
27+
*/
28+
private $productRepository;
29+
/**
30+
* @var StoreManagerInterface
31+
*/
32+
private $storeManager;
33+
/**
34+
* @var RequestInterface
35+
*/
36+
private $request;
37+
38+
/**
39+
* @param RequestInterface $request
40+
* @param ProductRepositoryInterface $productRepository
41+
* @param StoreManagerInterface $storeManager
42+
*/
43+
public function __construct(
44+
RequestInterface $request,
45+
ProductRepositoryInterface $productRepository,
46+
StoreManagerInterface $storeManager
47+
) {
48+
$this->productRepository = $productRepository;
49+
$this->storeManager = $storeManager;
50+
$this->request = $request;
51+
}
52+
53+
/**
54+
* @inheritDoc
55+
*/
56+
public function process(array $tags): array
57+
{
58+
if ($this->request->getFullActionName() === self::NOROUTE_ACTION_NAME) {
59+
try {
60+
$productId = (int) $this->request->getParam('id');
61+
$product = $this->productRepository->getById(
62+
$productId,
63+
false,
64+
$this->storeManager->getStore()->getId()
65+
);
66+
} catch (NoSuchEntityException $e) {
67+
$product = null;
68+
}
69+
if ($product) {
70+
$tags = array_merge($tags, $product->getIdentities());
71+
}
72+
}
73+
return $tags;
74+
}
75+
}

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,4 +120,13 @@
120120
<plugin name="catalog_app_action_dispatch_controller_context_plugin"
121121
type="Magento\Catalog\Plugin\Framework\App\Action\ContextPlugin" />
122122
</type>
123+
<type name="\Magento\PageCache\Model\PageCacheTagsPreprocessorComposite">
124+
<arguments>
125+
<argument name="preprocessors" xsi:type="array">
126+
<item name="catalog_product_view" xsi:type="array">
127+
<item name="product_not_found" xsi:type="object">Magento\Catalog\Model\ProductNotFoundPageCacheTags</item>
128+
</item>
129+
</argument>
130+
</arguments>
131+
</type>
123132
</config>

app/code/Magento/Checkout/view/frontend/web/js/model/address-converter.js

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,37 @@ define([
1616

1717
var countryData = customerData.get('directory-data');
1818

19+
/**
20+
* Find region by code
21+
*
22+
* @param {Int} countryId
23+
* @param {String} regionCode
24+
* @returns {Object}
25+
*/
26+
function findCountryRegionByCode(countryId, regionCode) {
27+
var data = countryData()[countryId] || {},
28+
id,
29+
region;
30+
31+
if (data.regions) {
32+
for (id in data.regions) {
33+
// eslint-disable-next-line max-depth
34+
if (data.regions[id].code === regionCode) {
35+
region = $.extend(
36+
true,
37+
{
38+
id: id
39+
},
40+
data.regions[id]
41+
);
42+
break;
43+
}
44+
}
45+
}
46+
47+
return region;
48+
}
49+
1950
return {
2051
/**
2152
* Convert address form data to Address object
@@ -27,12 +58,24 @@ define([
2758
// clone address form data to new object
2859
var addressData = $.extend(true, {}, formData),
2960
region,
30-
regionName = addressData.region;
61+
regionName = addressData.region,
62+
field,
63+
mappings = {
64+
'country_id': 'countryId',
65+
'region_id': 'regionId',
66+
'region_code': 'regionCode'
67+
};
3168

3269
if (mageUtils.isObject(addressData.street)) {
3370
addressData.street = this.objectToArray(addressData.street);
3471
}
3572

73+
for (field in mappings) {
74+
if (!addressData[field] && addressData[mappings[field]]) {
75+
addressData[field] = addressData[mappings[field]];
76+
}
77+
}
78+
3679
addressData.region = {
3780
'region_id': addressData['region_id'],
3881
'region_code': addressData['region_code'],
@@ -50,6 +93,14 @@ define([
5093
addressData.region['region_code'] = region.code;
5194
addressData.region.region = region.name;
5295
}
96+
} else if (
97+
addressData['country_id'] &&
98+
addressData['region_code'] &&
99+
(region = findCountryRegionByCode(addressData['country_id'], addressData['region_code']))
100+
) {
101+
addressData.region['region_id'] = region.id;
102+
addressData.region['region_code'] = region.code;
103+
addressData.region.region = region.name;
53104
} else if (
54105
!addressData['region_id'] &&
55106
countryData()[addressData['country_id']] &&

app/code/Magento/Elasticsearch/Elasticsearch5/Model/Adapter/FieldMapper/Product/FieldProvider/FieldType/Converter.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ class Converter implements ConverterInterface
1919
*/
2020
private const ES_DATA_TYPE_TEXT = 'text';
2121
private const ES_DATA_TYPE_KEYWORD = 'keyword';
22-
private const ES_DATA_TYPE_FLOAT = 'float';
22+
private const ES_DATA_TYPE_DOUBLE = 'double';
2323
private const ES_DATA_TYPE_INT = 'integer';
2424
private const ES_DATA_TYPE_DATE = 'date';
2525
/**#@-*/
@@ -32,7 +32,7 @@ class Converter implements ConverterInterface
3232
private $mapping = [
3333
self::INTERNAL_DATA_TYPE_STRING => self::ES_DATA_TYPE_TEXT,
3434
self::INTERNAL_DATA_TYPE_KEYWORD => self::ES_DATA_TYPE_KEYWORD,
35-
self::INTERNAL_DATA_TYPE_FLOAT => self::ES_DATA_TYPE_FLOAT,
35+
self::INTERNAL_DATA_TYPE_FLOAT => self::ES_DATA_TYPE_DOUBLE,
3636
self::INTERNAL_DATA_TYPE_INT => self::ES_DATA_TYPE_INT,
3737
self::INTERNAL_DATA_TYPE_DATE => self::ES_DATA_TYPE_DATE,
3838
];

app/code/Magento/Elasticsearch/Elasticsearch5/Model/Client/Elasticsearch.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -279,7 +279,7 @@ public function addFieldsMapping(array $fields, $index, $entityType)
279279
'match' => 'price_*',
280280
'match_mapping_type' => 'string',
281281
'mapping' => [
282-
'type' => 'float',
282+
'type' => 'double',
283283
'store' => true,
284284
],
285285
],

app/code/Magento/Elasticsearch/Model/Adapter/FieldMapper/Product/FieldProvider/FieldType/Converter.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ class Converter implements ConverterInterface
1616
* Text flags for Elasticsearch field types
1717
*/
1818
private const ES_DATA_TYPE_STRING = 'string';
19-
private const ES_DATA_TYPE_FLOAT = 'float';
19+
private const ES_DATA_TYPE_DOUBLE = 'double';
2020
private const ES_DATA_TYPE_INT = 'integer';
2121
private const ES_DATA_TYPE_DATE = 'date';
2222
/**#@-*/
@@ -29,7 +29,7 @@ class Converter implements ConverterInterface
2929
private $mapping = [
3030
self::INTERNAL_DATA_TYPE_STRING => self::ES_DATA_TYPE_STRING,
3131
self::INTERNAL_DATA_TYPE_KEYWORD => self::ES_DATA_TYPE_STRING,
32-
self::INTERNAL_DATA_TYPE_FLOAT => self::ES_DATA_TYPE_FLOAT,
32+
self::INTERNAL_DATA_TYPE_FLOAT => self::ES_DATA_TYPE_DOUBLE,
3333
self::INTERNAL_DATA_TYPE_INT => self::ES_DATA_TYPE_INT,
3434
self::INTERNAL_DATA_TYPE_DATE => self::ES_DATA_TYPE_DATE,
3535
];

app/code/Magento/Elasticsearch/SearchAdapter/Query/ValueTransformer/TextTransformer.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ public function transform(string $value): string
5757
*/
5858
private function escape(string $value): string
5959
{
60-
$pattern = '/(\+|-|&&|\|\||!|\(|\)|\{|}|\[|]|\^|"|~|\*|\?|:|\\\)/';
60+
$pattern = '/(\+|-|&&|\|\||!|\(|\)|\{|}|\[|]|\^|"|~|\/|\*|\?|:|\\\)/';
6161
$replace = '\\\$1';
6262

6363
return preg_replace($pattern, $replace, $value);
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
7+
declare(strict_types=1);
8+
9+
namespace Magento\Elasticsearch\Setup\Patch\Data;
10+
11+
use Magento\Framework\Setup\ModuleDataSetupInterface;
12+
use Magento\Framework\Setup\Patch\DataPatchInterface;
13+
use Magento\Framework\Indexer\IndexerRegistry;
14+
use Magento\CatalogSearch\Model\Indexer\Fulltext as FulltextIndexer;
15+
16+
/**
17+
* Invalidate fulltext index
18+
*/
19+
class InvalidateIndex implements DataPatchInterface
20+
{
21+
/**
22+
* @var ModuleDataSetupInterface
23+
*/
24+
private $moduleDataSetup;
25+
26+
/**
27+
* @var IndexerRegistry
28+
*/
29+
private $indexerRegistry;
30+
31+
/**
32+
* @param ModuleDataSetupInterface $moduleDataSetup
33+
* @param IndexerRegistry $indexerRegistry
34+
*/
35+
public function __construct(ModuleDataSetupInterface $moduleDataSetup, IndexerRegistry $indexerRegistry)
36+
{
37+
$this->moduleDataSetup = $moduleDataSetup;
38+
$this->indexerRegistry = $indexerRegistry;
39+
}
40+
41+
/**
42+
* @inheritDoc
43+
*/
44+
public function apply()
45+
{
46+
$this->indexerRegistry->get(FulltextIndexer::INDEXER_ID)->invalidate();
47+
return $this;
48+
}
49+
50+
/**
51+
* @inheritDoc
52+
*/
53+
public static function getDependencies()
54+
{
55+
return [];
56+
}
57+
58+
/**
59+
* @inheritDoc
60+
*/
61+
public function getAliases()
62+
{
63+
return [];
64+
}
65+
}

0 commit comments

Comments
 (0)