Skip to content

Commit 2bbf7e9

Browse files
author
Oleksii Korshenko
authored
🔃 [EngCom] Public Pull Requests - 2.2-develop
Accepted Public Pull Requests: - magento#13551: Fix json encoded attribute backend type to not encode attribute value multiple times (by @tkotosz) - magento-engcom/magento2ce#1095: magento#12817: Coupon code with canceled order (by @p-bystritsky) Fixed GitHub Issues: - magento#12817: Coupon code with canceled order (reported by @AleksLi) has been fixed in magento-engcom/magento2ce#1095 by @p-bystritsky in 2.2-develop branch Related commits: 1. cda7835 2. a7f6412 3. 8655554 4. bce7fc7 5. 29e5957 6. 7c98cc2 7. 24cb1ac 8. e1b33d4 9. 025c6b8 10. 6a21e85 11. 940cc64
2 parents 0839bd4 + 59efdd5 commit 2bbf7e9

File tree

16 files changed

+548
-299
lines changed

16 files changed

+548
-299
lines changed

app/code/Magento/Eav/Model/Entity/Attribute/Backend/JsonEncoded.php

+21-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ public function beforeSave($object)
4141
{
4242
// parent::beforeSave() is not called intentionally
4343
$attrCode = $this->getAttribute()->getAttributeCode();
44-
if ($object->hasData($attrCode)) {
44+
if ($object->hasData($attrCode) && !$this->isJsonEncoded($object->getData($attrCode))) {
4545
$object->setData($attrCode, $this->jsonSerializer->serialize($object->getData($attrCode)));
4646
}
4747
return $this;
@@ -61,4 +61,24 @@ public function afterLoad($object)
6161
$object->setData($attrCode, $this->jsonSerializer->unserialize($object->getData($attrCode) ?: '{}'));
6262
return $this;
6363
}
64+
65+
/**
66+
* Returns true if given param is a valid json value else false.
67+
*
68+
* @param string|int|float|bool|array|null $value
69+
* @return bool
70+
*/
71+
private function isJsonEncoded($value): bool
72+
{
73+
$result = is_string($value);
74+
if ($result) {
75+
try {
76+
$this->jsonSerializer->unserialize($value);
77+
} catch (\InvalidArgumentException $e) {
78+
$result = false;
79+
}
80+
}
81+
82+
return $result;
83+
}
6484
}

app/code/Magento/Eav/Test/Unit/Model/Entity/Attribute/Backend/JsonEncodedTest.php

+19
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,25 @@ public function testBeforeSave()
8282
$this->assertEquals(json_encode([1, 2, 3]), $product->getData('json_encoded'));
8383
}
8484

85+
/**
86+
* Test before save handler with already encoded attribute value
87+
*/
88+
public function testBeforeSaveWithAlreadyEncodedValue()
89+
{
90+
$product = new \Magento\Framework\DataObject(
91+
[
92+
'json_encoded' => [1, 2, 3]
93+
]
94+
);
95+
96+
// save twice
97+
$this->model->beforeSave($product);
98+
$this->model->beforeSave($product);
99+
100+
// check it is encoded only once
101+
$this->assertEquals(json_encode([1, 2, 3]), $product->getData('json_encoded'));
102+
}
103+
85104
/**
86105
* Test after load handler
87106
*/
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
7+
namespace Magento\SalesRule\Model\Coupon;
8+
9+
use Magento\Sales\Model\Order;
10+
use Magento\SalesRule\Model\Coupon;
11+
use Magento\SalesRule\Model\ResourceModel\Coupon\Usage;
12+
use Magento\SalesRule\Model\Rule\CustomerFactory;
13+
use Magento\SalesRule\Model\RuleFactory;
14+
15+
/**
16+
* Updates the coupon usages.
17+
*/
18+
class UpdateCouponUsages
19+
{
20+
/**
21+
* @var RuleFactory
22+
*/
23+
private $ruleFactory;
24+
25+
/**
26+
* @var RuleFactory
27+
*/
28+
private $ruleCustomerFactory;
29+
30+
/**
31+
* @var Coupon
32+
*/
33+
private $coupon;
34+
35+
/**
36+
* @var Usage
37+
*/
38+
private $couponUsage;
39+
40+
/**
41+
* @param RuleFactory $ruleFactory
42+
* @param CustomerFactory $ruleCustomerFactory
43+
* @param Coupon $coupon
44+
* @param Usage $couponUsage
45+
*/
46+
public function __construct(
47+
RuleFactory $ruleFactory,
48+
CustomerFactory $ruleCustomerFactory,
49+
Coupon $coupon,
50+
Usage $couponUsage
51+
) {
52+
$this->ruleFactory = $ruleFactory;
53+
$this->ruleCustomerFactory = $ruleCustomerFactory;
54+
$this->coupon = $coupon;
55+
$this->couponUsage = $couponUsage;
56+
}
57+
58+
/**
59+
* Executes the current command.
60+
*
61+
* @param Order $subject
62+
* @param bool $increment
63+
* @return Order
64+
*/
65+
public function execute(Order $subject, bool $increment)
66+
{
67+
if (!$subject || !$subject->getAppliedRuleIds()) {
68+
return $subject;
69+
}
70+
// lookup rule ids
71+
$ruleIds = explode(',', $subject->getAppliedRuleIds());
72+
$ruleIds = array_unique($ruleIds);
73+
$customerId = (int)$subject->getCustomerId();
74+
// use each rule (and apply to customer, if applicable)
75+
foreach ($ruleIds as $ruleId) {
76+
if (!$ruleId) {
77+
continue;
78+
}
79+
$this->updateRuleUsages($increment, (int)$ruleId, $customerId);
80+
}
81+
$this->updateCouponUsages($subject, $increment, $customerId);
82+
83+
return $subject;
84+
}
85+
86+
/**
87+
* Update the number of rule usages.
88+
*
89+
* @param bool $increment
90+
* @param int $ruleId
91+
* @param int $customerId
92+
*/
93+
private function updateRuleUsages(bool $increment, int $ruleId, int $customerId)
94+
{
95+
/** @var \Magento\SalesRule\Model\Rule $rule */
96+
$rule = $this->ruleFactory->create();
97+
$rule->load($ruleId);
98+
if ($rule->getId()) {
99+
$rule->loadCouponCode();
100+
if ($increment || $rule->getTimesUsed() > 0) {
101+
$rule->setTimesUsed($rule->getTimesUsed() + ($increment ? 1 : -1));
102+
$rule->save();
103+
}
104+
if ($customerId) {
105+
$this->updateCustomerRuleUsages($increment, $ruleId, $customerId);
106+
}
107+
}
108+
}
109+
110+
/**
111+
* Update the number of rule usages per customer.
112+
*
113+
* @param bool $increment
114+
* @param int $ruleId
115+
* @param int $customerId
116+
*/
117+
private function updateCustomerRuleUsages(bool $increment, int $ruleId, int $customerId)
118+
{
119+
/** @var \Magento\SalesRule\Model\Rule\Customer $ruleCustomer */
120+
$ruleCustomer = $this->ruleCustomerFactory->create();
121+
$ruleCustomer->loadByCustomerRule($customerId, $ruleId);
122+
if ($ruleCustomer->getId()) {
123+
if ($increment || $ruleCustomer->getTimesUsed() > 0) {
124+
$ruleCustomer->setTimesUsed($ruleCustomer->getTimesUsed() + ($increment ? 1 : -1));
125+
}
126+
} elseif ($increment) {
127+
$ruleCustomer->setCustomerId($customerId)->setRuleId($ruleId)->setTimesUsed(1);
128+
}
129+
$ruleCustomer->save();
130+
}
131+
132+
/**
133+
* Update the number of coupon usages.
134+
*
135+
* @param Order $subject
136+
* @param bool $increment
137+
* @param int $customerId
138+
*/
139+
private function updateCouponUsages(Order $subject, bool $increment, int $customerId)
140+
{
141+
$this->coupon->load($subject->getCouponCode(), 'code');
142+
if ($this->coupon->getId()) {
143+
if ($increment || $this->coupon->getTimesUsed() > 0) {
144+
$this->coupon->setTimesUsed($this->coupon->getTimesUsed() + ($increment ? 1 : -1));
145+
$this->coupon->save();
146+
}
147+
if ($customerId) {
148+
$this->couponUsage->updateCustomerCouponTimesUsed($customerId, $this->coupon->getId(), $increment);
149+
}
150+
}
151+
}
152+
}

app/code/Magento/SalesRule/Model/ResourceModel/Coupon/Usage.php

+5-4
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,10 @@ protected function _construct()
2727
*
2828
* @param int $customerId
2929
* @param mixed $couponId
30+
* @param bool $increment
3031
* @return void
3132
*/
32-
public function updateCustomerCouponTimesUsed($customerId, $couponId)
33+
public function updateCustomerCouponTimesUsed($customerId, $couponId, $increment = true)
3334
{
3435
$connection = $this->getConnection();
3536
$select = $connection->select();
@@ -44,13 +45,13 @@ public function updateCustomerCouponTimesUsed($customerId, $couponId)
4445

4546
$timesUsed = $connection->fetchOne($select, [':coupon_id' => $couponId, ':customer_id' => $customerId]);
4647

47-
if ($timesUsed > 0) {
48+
if ($timesUsed !== false) {
4849
$this->getConnection()->update(
4950
$this->getMainTable(),
50-
['times_used' => $timesUsed + 1],
51+
['times_used' => $timesUsed + ($increment ? 1 : -1)],
5152
['coupon_id = ?' => $couponId, 'customer_id = ?' => $customerId]
5253
);
53-
} else {
54+
} elseif ($increment) {
5455
$this->getConnection()->insert(
5556
$this->getMainTable(),
5657
['coupon_id' => $couponId, 'customer_id' => $customerId, 'times_used' => 1]

app/code/Magento/SalesRule/Observer/SalesOrderAfterPlaceObserver.php

-110
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
7+
namespace Magento\SalesRule\Plugin;
8+
9+
use Magento\Sales\Model\Order;
10+
use Magento\SalesRule\Model\Coupon\UpdateCouponUsages;
11+
12+
class CouponUsagesDecrement
13+
{
14+
/**
15+
* @var UpdateCouponUsages
16+
*/
17+
private $updateCouponUsages;
18+
19+
public function __construct(
20+
UpdateCouponUsages $updateCouponUsages
21+
) {
22+
$this->updateCouponUsages = $updateCouponUsages;
23+
}
24+
25+
/**
26+
* Decrements number of coupon usages after cancelling order.
27+
*
28+
* @param Order $subject
29+
* @param callable $proceed
30+
* @return Order
31+
*/
32+
public function aroundCancel(Order $subject, callable $proceed)
33+
{
34+
$canCancel = $subject->canCancel();
35+
$returnValue = $proceed();
36+
if ($canCancel) {
37+
$returnValue = $this->updateCouponUsages->execute($returnValue, false);
38+
}
39+
40+
return $returnValue;
41+
}
42+
}

0 commit comments

Comments
 (0)