Skip to content

Commit fb5eccf

Browse files
authored
Merge pull request #2513 from magento-tsg/2.3-develop-pr17
Fixed issues: - MAGETWO-90144 [Forwardport] Fixed amount discount for whole cart applying an extra cent to the discount amount for - MAGETWO-90310 [Magento Cloud] - PayPal pop up does not work with virtual product (gift card) - MAGETWO-90313 Import existing customer with only three columns will override customer group_id and store_id
2 parents 14a5702 + ddeb591 commit fb5eccf

File tree

14 files changed

+782
-84
lines changed

14 files changed

+782
-84
lines changed

app/code/Magento/CustomerImportExport/Model/Import/Customer.php

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -378,19 +378,11 @@ protected function _prepareDataForUpdate(array $rowData)
378378
$this->_newCustomers[$emailInLowercase][$rowData[self::COLUMN_WEBSITE]] = $entityId;
379379
}
380380

381-
$entityRow = [
382-
'group_id' => empty($rowData['group_id']) ? self::DEFAULT_GROUP_ID : $rowData['group_id'],
383-
'store_id' => empty($rowData[self::COLUMN_STORE]) ? 0 : $this->_storeCodeToId[$rowData[self::COLUMN_STORE]],
384-
'created_at' => $createdAt->format(\Magento\Framework\Stdlib\DateTime::DATETIME_PHP_FORMAT),
385-
'updated_at' => $now->format(\Magento\Framework\Stdlib\DateTime::DATETIME_PHP_FORMAT),
386-
'entity_id' => $entityId,
387-
];
388-
389381
// password change/set
390382
if (isset($rowData['password']) && strlen($rowData['password'])) {
391383
$rowData['password_hash'] = $this->_customerModel->hashPassword($rowData['password']);
392384
}
393-
385+
$entityRow = ['entity_id' => $entityId];
394386
// attribute values
395387
foreach (array_intersect_key($rowData, $this->_attributes) as $attributeCode => $value) {
396388
$attributeParameters = $this->_attributes[$attributeCode];
@@ -429,12 +421,21 @@ protected function _prepareDataForUpdate(array $rowData)
429421

430422
if ($newCustomer) {
431423
// create
424+
$entityRow['group_id'] = empty($rowData['group_id']) ? self::DEFAULT_GROUP_ID : $rowData['group_id'];
425+
$entityRow['store_id'] = empty($rowData[self::COLUMN_STORE])
426+
? \Magento\Store\Model\Store::DEFAULT_STORE_ID : $this->_storeCodeToId[$rowData[self::COLUMN_STORE]];
427+
$entityRow['created_at'] = $createdAt->format(\Magento\Framework\Stdlib\DateTime::DATETIME_PHP_FORMAT);
428+
$entityRow['updated_at'] = $now->format(\Magento\Framework\Stdlib\DateTime::DATETIME_PHP_FORMAT);
432429
$entityRow['website_id'] = $this->_websiteCodeToId[$rowData[self::COLUMN_WEBSITE]];
433430
$entityRow['email'] = $emailInLowercase;
434431
$entityRow['is_active'] = 1;
435432
$entitiesToCreate[] = $entityRow;
436433
} else {
437434
// edit
435+
$entityRow['updated_at'] = $now->format(\Magento\Framework\Stdlib\DateTime::DATETIME_PHP_FORMAT);
436+
if (!empty($rowData[self::COLUMN_STORE])) {
437+
$entityRow['store_id'] = $this->_storeCodeToId[$rowData[self::COLUMN_STORE]];
438+
}
438439
$entitiesToUpdate[] = $entityRow;
439440
}
440441

app/code/Magento/Payment/Model/Method/AbstractMethod.php

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,14 @@
66

77
namespace Magento\Payment\Model\Method;
88

9+
use Magento\Framework\App\ObjectManager;
910
use Magento\Framework\DataObject;
1011
use Magento\Payment\Model\InfoInterface;
1112
use Magento\Payment\Model\MethodInterface;
1213
use Magento\Payment\Observer\AbstractDataAssignObserver;
1314
use Magento\Quote\Api\Data\PaymentMethodInterface;
1415
use Magento\Sales\Model\Order\Payment;
16+
use Magento\Directory\Helper\Data as DirectoryHelper;
1517

1618
/**
1719
* Payment method abstract model
@@ -194,6 +196,11 @@ abstract class AbstractMethod extends \Magento\Framework\Model\AbstractExtensibl
194196
*/
195197
protected $logger;
196198

199+
/**
200+
* @var DirectoryHelper
201+
*/
202+
private $directory;
203+
197204
/**
198205
* @param \Magento\Framework\Model\Context $context
199206
* @param \Magento\Framework\Registry $registry
@@ -205,6 +212,7 @@ abstract class AbstractMethod extends \Magento\Framework\Model\AbstractExtensibl
205212
* @param \Magento\Framework\Model\ResourceModel\AbstractResource $resource
206213
* @param \Magento\Framework\Data\Collection\AbstractDb $resourceCollection
207214
* @param array $data
215+
* @param DirectoryHelper $directory
208216
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
209217
*/
210218
public function __construct(
@@ -217,7 +225,8 @@ public function __construct(
217225
\Magento\Payment\Model\Method\Logger $logger,
218226
\Magento\Framework\Model\ResourceModel\AbstractResource $resource = null,
219227
\Magento\Framework\Data\Collection\AbstractDb $resourceCollection = null,
220-
array $data = []
228+
array $data = [],
229+
DirectoryHelper $directory = null
221230
) {
222231
parent::__construct(
223232
$context,
@@ -231,6 +240,7 @@ public function __construct(
231240
$this->_paymentData = $paymentData;
232241
$this->_scopeConfig = $scopeConfig;
233242
$this->logger = $logger;
243+
$this->directory = $directory ?: ObjectManager::getInstance()->get(DirectoryHelper::class);
234244
$this->initializeData($data);
235245
}
236246

@@ -584,11 +594,14 @@ public function validate()
584594
} else {
585595
$billingCountry = $paymentInfo->getQuote()->getBillingAddress()->getCountryId();
586596
}
597+
$billingCountry = $billingCountry ?: $this->directory->getDefaultCountry();
598+
587599
if (!$this->canUseForCountry($billingCountry)) {
588600
throw new \Magento\Framework\Exception\LocalizedException(
589601
__('You can\'t use the payment type you selected to make payments to the billing country.')
590602
);
591603
}
604+
592605
return $this;
593606
}
594607

app/code/Magento/Paypal/Controller/Express/AbstractExpress/PlaceOrder.php

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
namespace Magento\Paypal\Controller\Express\AbstractExpress;
99

10+
use Magento\Framework\Exception\LocalizedException;
1011
use Magento\Paypal\Model\Api\ProcessableException as ApiProcessableException;
1112

1213
/**
@@ -118,15 +119,27 @@ public function execute()
118119
return;
119120
} catch (ApiProcessableException $e) {
120121
$this->_processPaypalApiError($e);
122+
} catch (LocalizedException $e) {
123+
$this->processException($e, $e->getRawMessage());
121124
} catch (\Exception $e) {
122-
$this->messageManager->addExceptionMessage(
123-
$e,
124-
__('We can\'t place the order.')
125-
);
126-
$this->_redirect('*/*/review');
125+
$this->processException($e, 'We can\'t place the order.');
127126
}
128127
}
129128

129+
/**
130+
* Process exception.
131+
*
132+
* @param \Exception $exception
133+
* @param string $message
134+
*
135+
* @return void
136+
*/
137+
private function processException(\Exception $exception, string $message): void
138+
{
139+
$this->messageManager->addExceptionMessage($exception, __($message));
140+
$this->_redirect('*/*/review');
141+
}
142+
130143
/**
131144
* Process PayPal API's processable errors
132145
*

app/code/Magento/Paypal/Model/Express/Checkout.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -899,7 +899,12 @@ protected function _setExportedAddressData($address, $exportedAddress)
899899
{
900900
// Exported data is more priority if we came from Express Checkout button
901901
$isButton = (bool)$this->_quote->getPayment()->getAdditionalInformation(self::PAYMENT_INFO_BUTTON);
902-
if (!$isButton) {
902+
903+
// Since country is required field for billing and shipping address,
904+
// we consider the address information to be empty if country is empty.
905+
$isEmptyAddress = ($address->getCountryId() === null);
906+
907+
if (!$isButton && !$isEmptyAddress) {
903908
return;
904909
}
905910

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\SalesRule\Model;
9+
10+
use Magento\Framework\Pricing\PriceCurrencyInterface;
11+
12+
/**
13+
* Round price and save rounding operation delta.
14+
*/
15+
class DeltaPriceRound
16+
{
17+
/**
18+
* @var PriceCurrencyInterface
19+
*/
20+
private $priceCurrency;
21+
22+
/**
23+
* @var float[]
24+
*/
25+
private $roundingDeltas;
26+
27+
/**
28+
* @param PriceCurrencyInterface $priceCurrency
29+
*/
30+
public function __construct(PriceCurrencyInterface $priceCurrency)
31+
{
32+
$this->priceCurrency = $priceCurrency;
33+
}
34+
35+
/**
36+
* Round price based on previous rounding operation delta.
37+
*
38+
* @param float $price
39+
* @param string $type
40+
* @return float
41+
*/
42+
public function round(float $price, string $type): float
43+
{
44+
if ($price) {
45+
// initialize the delta to a small number to avoid non-deterministic behavior with rounding of 0.5
46+
$delta = isset($this->roundingDeltas[$type]) ? $this->roundingDeltas[$type] : 0.000001;
47+
$price += $delta;
48+
$roundPrice = $this->priceCurrency->round($price);
49+
$this->roundingDeltas[$type] = $price - $roundPrice;
50+
$price = $roundPrice;
51+
}
52+
53+
return $price;
54+
}
55+
56+
/**
57+
* Reset all deltas.
58+
*
59+
* @return void
60+
*/
61+
public function resetAll(): void
62+
{
63+
$this->roundingDeltas = [];
64+
}
65+
66+
/**
67+
* Reset deltas by type.
68+
*
69+
* @param string $type
70+
* @return void
71+
*/
72+
public function reset(string $type): void
73+
{
74+
if (isset($this->roundingDeltas[$type])) {
75+
unset($this->roundingDeltas[$type]);
76+
}
77+
}
78+
}

app/code/Magento/SalesRule/Model/Rule/Action/Discount/CartFixed.php

Lines changed: 53 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,14 @@
55
*/
66
namespace Magento\SalesRule\Model\Rule\Action\Discount;
77

8+
use Magento\Framework\App\ObjectManager;
9+
use Magento\Framework\Pricing\PriceCurrencyInterface;
10+
use Magento\SalesRule\Model\DeltaPriceRound;
11+
use Magento\SalesRule\Model\Validator;
12+
13+
/**
14+
* Calculates discount for cart item if fixed discount applied on whole cart.
15+
*/
816
class CartFixed extends AbstractDiscount
917
{
1018
/**
@@ -14,6 +22,33 @@ class CartFixed extends AbstractDiscount
1422
*/
1523
protected $_cartFixedRuleUsedForAddress = [];
1624

25+
/**
26+
* @var DeltaPriceRound
27+
*/
28+
private $deltaPriceRound;
29+
30+
/**
31+
* @var string
32+
*/
33+
private static $discountType = 'CartFixed';
34+
35+
/**
36+
* @param Validator $validator
37+
* @param DataFactory $discountDataFactory
38+
* @param PriceCurrencyInterface $priceCurrency
39+
* @param DeltaPriceRound $deltaPriceRound
40+
*/
41+
public function __construct(
42+
Validator $validator,
43+
DataFactory $discountDataFactory,
44+
PriceCurrencyInterface $priceCurrency,
45+
DeltaPriceRound $deltaPriceRound
46+
) {
47+
$this->deltaPriceRound = $deltaPriceRound;
48+
49+
parent::__construct($validator, $discountDataFactory, $priceCurrency);
50+
}
51+
1752
/**
1853
* @param \Magento\SalesRule\Model\Rule $rule
1954
* @param \Magento\Quote\Model\Quote\Item\AbstractItem $item
@@ -51,14 +86,22 @@ public function calculate($rule, $item, $qty)
5186
$cartRules[$rule->getId()] = $rule->getDiscountAmount();
5287
}
5388

54-
if ($cartRules[$rule->getId()] > 0) {
89+
$availableDiscountAmount = (float)$cartRules[$rule->getId()];
90+
$discountType = self::$discountType . $rule->getId();
91+
92+
if ($availableDiscountAmount > 0) {
5593
$store = $quote->getStore();
5694
if ($ruleTotals['items_count'] <= 1) {
57-
$quoteAmount = $this->priceCurrency->convert($cartRules[$rule->getId()], $store);
58-
$baseDiscountAmount = min($baseItemPrice * $qty, $cartRules[$rule->getId()]);
95+
$quoteAmount = $this->priceCurrency->convert($availableDiscountAmount, $store);
96+
$baseDiscountAmount = min($baseItemPrice * $qty, $availableDiscountAmount);
97+
$this->deltaPriceRound->reset($discountType);
5998
} else {
60-
$discountRate = $baseItemPrice * $qty / $ruleTotals['base_items_price'];
61-
$maximumItemDiscount = $rule->getDiscountAmount() * $discountRate;
99+
$ratio = $baseItemPrice * $qty / $ruleTotals['base_items_price'];
100+
$maximumItemDiscount = $this->deltaPriceRound->round(
101+
$rule->getDiscountAmount() * $ratio,
102+
$discountType
103+
);
104+
62105
$quoteAmount = $this->priceCurrency->convert($maximumItemDiscount, $store);
63106

64107
$baseDiscountAmount = min($baseItemPrice * $qty, $maximumItemDiscount);
@@ -67,7 +110,11 @@ public function calculate($rule, $item, $qty)
67110

68111
$baseDiscountAmount = $this->priceCurrency->round($baseDiscountAmount);
69112

70-
$cartRules[$rule->getId()] -= $baseDiscountAmount;
113+
$availableDiscountAmount -= $baseDiscountAmount;
114+
$cartRules[$rule->getId()] = $availableDiscountAmount;
115+
if ($availableDiscountAmount <= 0) {
116+
$this->deltaPriceRound->reset($discountType);
117+
}
71118

72119
$discountData->setAmount($this->priceCurrency->round(min($itemPrice * $qty, $quoteAmount)));
73120
$discountData->setBaseAmount($baseDiscountAmount);

0 commit comments

Comments
 (0)