Skip to content

Commit b07a843

Browse files
committed
Merge branch 'multicoupon' of github.com:magento-lynx/magento2ce into multicoupon-delivery
2 parents fd9a4be + 575c037 commit b07a843

File tree

5 files changed

+100
-62
lines changed

5 files changed

+100
-62
lines changed

app/code/Magento/SalesGraphQl/Model/Formatter/Order.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
namespace Magento\SalesGraphQl\Model\Formatter;
99

10+
use Magento\Framework\Exception\LocalizedException;
1011
use Magento\Sales\Api\Data\OrderInterface;
1112
use Magento\SalesGraphQl\Model\Order\OrderAddress;
1213
use Magento\SalesGraphQl\Model\Order\OrderPayments;
@@ -43,13 +44,14 @@ public function __construct(
4344
*
4445
* @param OrderInterface $orderModel
4546
* @return array
47+
* @throws LocalizedException
4648
*/
4749
public function format(OrderInterface $orderModel): array
4850
{
4951
return [
5052
'created_at' => $orderModel->getCreatedAt(),
5153
'grand_total' => $orderModel->getGrandTotal(),
52-
'id' => base64_encode($orderModel->getEntityId()),
54+
'id' => base64_encode((string)$orderModel->getEntityId()),
5355
'increment_id' => $orderModel->getIncrementId(),
5456
'number' => $orderModel->getIncrementId(),
5557
'order_date' => $orderModel->getCreatedAt(),
@@ -59,6 +61,7 @@ public function format(OrderInterface $orderModel): array
5961
'shipping_address' => $this->orderAddress->getOrderShippingAddress($orderModel),
6062
'billing_address' => $this->orderAddress->getOrderBillingAddress($orderModel),
6163
'payment_methods' => $this->orderPayments->getOrderPaymentMethod($orderModel),
64+
'applied_coupons' => $orderModel->getCouponCode() ? ['code' => $orderModel->getCouponCode()] : [],
6265
'model' => $orderModel,
6366
];
6467
}

app/code/Magento/SalesGraphQl/etc/schema.graphqls

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ type CustomerOrder @doc(description: "Contains details about each of the custome
7373
created_at: String @deprecated(reason: "Use the `order_date` field instead.")
7474
grand_total: Float @deprecated(reason: "Use the `totals.grand_total` field instead.")
7575
token: String! @doc(description: "The token that can be used to retrieve the order using order query.") @resolver(class: "Magento\\SalesGraphQl\\Model\\Resolver\\Token")
76+
applied_coupons: [AppliedCoupon!]! @doc(description: "Coupons applied to the order.")
7677
}
7778

7879
type OrderAddress @doc(description: "Contains detailed information about an order's billing and shipping addresses."){

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

Lines changed: 40 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@
77

88
namespace Magento\SalesRule\Model\Coupon\Usage;
99

10+
use Magento\Framework\Api\SearchCriteriaBuilder;
11+
use Magento\SalesRule\Api\CouponRepositoryInterface;
1012
use Magento\SalesRule\Model\Coupon;
11-
use Magento\SalesRule\Model\CouponFactory;
1213
use Magento\SalesRule\Model\ResourceModel\Coupon\Usage;
1314
use Magento\SalesRule\Model\Rule\CustomerFactory;
1415
use Magento\SalesRule\Model\RuleFactory;
@@ -18,42 +19,20 @@
1819
*/
1920
class Processor
2021
{
21-
/**
22-
* @var RuleFactory
23-
*/
24-
private $ruleFactory;
25-
26-
/**
27-
* @var CustomerFactory
28-
*/
29-
private $ruleCustomerFactory;
30-
31-
/**
32-
* @var CouponFactory
33-
*/
34-
private $couponFactory;
35-
36-
/**
37-
* @var Usage
38-
*/
39-
private $couponUsage;
40-
4122
/**
4223
* @param RuleFactory $ruleFactory
4324
* @param CustomerFactory $ruleCustomerFactory
44-
* @param CouponFactory $couponFactory
4525
* @param Usage $couponUsage
26+
* @param CouponRepositoryInterface $couponRepository
27+
* @param SearchCriteriaBuilder $criteriaBuilder
4628
*/
4729
public function __construct(
48-
RuleFactory $ruleFactory,
49-
CustomerFactory $ruleCustomerFactory,
50-
CouponFactory $couponFactory,
51-
Usage $couponUsage
30+
private readonly RuleFactory $ruleFactory,
31+
private readonly CustomerFactory $ruleCustomerFactory,
32+
private readonly Usage $couponUsage,
33+
private readonly CouponRepositoryInterface $couponRepository,
34+
private readonly SearchCriteriaBuilder $criteriaBuilder
5235
) {
53-
$this->ruleFactory = $ruleFactory;
54-
$this->ruleCustomerFactory = $ruleCustomerFactory;
55-
$this->couponFactory = $couponFactory;
56-
$this->couponUsage = $couponUsage;
5736
}
5837

5938
/**
@@ -79,16 +58,18 @@ public function process(UpdateInfo $updateInfo): void
7958
*/
8059
public function updateCouponUsages(UpdateInfo $updateInfo): void
8160
{
82-
$coupon = $this->retrieveCoupon($updateInfo);
83-
if (!$coupon) {
61+
$isIncrement = $updateInfo->isIncrement();
62+
$coupons = $this->retrieveCoupons($updateInfo);
63+
64+
if ($updateInfo->isCouponAlreadyApplied()) {
8465
return;
8566
}
8667

87-
$isIncrement = $updateInfo->isIncrement();
88-
if (!$updateInfo->isCouponAlreadyApplied()
89-
&& ($updateInfo->isIncrement() || $coupon->getTimesUsed() > 0)) {
90-
$coupon->setTimesUsed($coupon->getTimesUsed() + ($isIncrement ? 1 : -1));
91-
$coupon->save();
68+
foreach ($coupons as $coupon) {
69+
if ($updateInfo->isIncrement() || $coupon->getTimesUsed() > 0) {
70+
$coupon->setTimesUsed($coupon->getTimesUsed() + ($isIncrement ? 1 : -1));
71+
$coupon->save();
72+
}
9273
}
9374
}
9475

@@ -129,11 +110,16 @@ public function updateCustomerRulesUsages(UpdateInfo $updateInfo): void
129110

130111
$isIncrement = $updateInfo->isIncrement();
131112
foreach ($updateInfo->getAppliedRuleIds() as $ruleId) {
113+
$rule = $this->ruleFactory->create();
114+
$rule->load($ruleId);
115+
if (!$rule->getId()) {
116+
continue;
117+
}
132118
$this->updateCustomerRuleUsages($isIncrement, $ruleId, $customerId);
133119
}
134120

135-
$coupon = $this->retrieveCoupon($updateInfo);
136-
if ($coupon) {
121+
$coupons = $this->retrieveCoupons($updateInfo);
122+
foreach ($coupons as $coupon) {
137123
$this->couponUsage->updateCustomerCouponTimesUsed($customerId, $coupon->getId(), $isIncrement);
138124
}
139125
}
@@ -167,17 +153,25 @@ private function updateCustomerRuleUsages(bool $isIncrement, int $ruleId, int $c
167153
* Retrieve coupon from update info
168154
*
169155
* @param UpdateInfo $updateInfo
170-
* @return Coupon|null
156+
* @return Coupon[]
171157
*/
172-
private function retrieveCoupon(UpdateInfo $updateInfo): ?Coupon
158+
private function retrieveCoupons(UpdateInfo $updateInfo): array
173159
{
174-
if (!$updateInfo->getCouponCode()) {
175-
return null;
160+
if (!$updateInfo->getCouponCode() && empty($updateInfo->getCouponCodes())) {
161+
return [];
176162
}
177163

178-
$coupon = $this->couponFactory->create();
179-
$coupon->loadByCode($updateInfo->getCouponCode());
164+
$coupons = $updateInfo->getCouponCodes();
165+
if ($updateInfo->getCouponCode() && !in_array($updateInfo->getCouponCode(), $coupons)) {
166+
array_unshift($coupons, $updateInfo->getCouponCode());
167+
}
180168

181-
return $coupon->getId() ? $coupon : null;
169+
return $this->couponRepository->getList(
170+
$this->criteriaBuilder->addFilter(
171+
'code',
172+
$coupons,
173+
'in'
174+
)->create()
175+
)->getItems();
182176
}
183177
}

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

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ class UpdateInfo extends DataObject
1919
private const CUSTOMER_ID_KEY = 'customer_id';
2020
private const IS_INCREMENT_KEY = 'is_increment';
2121
private const IS_COUPON_ALREADY_APPLIED = 'is_coupon_already_applied';
22+
private const COUPON_CODES = 'coupon_codes';
2223

2324
/**
2425
* Get applied rule ids
@@ -62,6 +63,27 @@ public function setCouponCode(string $value): void
6263
$this->setData(self::COUPON_CODE_KEY, $value);
6364
}
6465

66+
/**
67+
* Get coupon code
68+
*
69+
* @return string[]
70+
*/
71+
public function getCouponCodes(): array
72+
{
73+
return $this->getData(self::COUPON_CODES) ?? [];
74+
}
75+
76+
/**
77+
* Set coupon code
78+
*
79+
* @param string[] $value
80+
* @return void
81+
*/
82+
public function setCouponCodes(array $value): void
83+
{
84+
$this->setData(self::COUPON_CODES, $value);
85+
}
86+
6587
/**
6688
* Get customer id
6789
*

app/code/Magento/SalesRule/Test/Unit/Model/Coupon/Usage/ProcessorTest.php

Lines changed: 33 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,11 @@
77

88
namespace Magento\SalesRule\Test\Unit\Model\Coupon\Usage;
99

10+
use Magento\Framework\Api\SearchCriteriaBuilder;
11+
use Magento\Framework\Api\SearchCriteriaInterface;
12+
use Magento\SalesRule\Api\CouponRepositoryInterface;
13+
use Magento\SalesRule\Api\Data\CouponSearchResultInterface;
1014
use Magento\SalesRule\Model\Coupon;
11-
use Magento\SalesRule\Model\CouponFactory;
1215
use Magento\SalesRule\Model\Coupon\Usage\Processor;
1316
use Magento\SalesRule\Model\Coupon\Usage\UpdateInfo;
1417
use Magento\SalesRule\Model\ResourceModel\Coupon\Usage;
@@ -19,6 +22,9 @@
1922
use PHPUnit\Framework\MockObject\MockObject;
2023
use PHPUnit\Framework\TestCase;
2124

25+
/**
26+
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
27+
*/
2228
class ProcessorTest extends TestCase
2329
{
2430
/**
@@ -36,11 +42,6 @@ class ProcessorTest extends TestCase
3642
*/
3743
private $ruleCustomerFactoryMock;
3844

39-
/**
40-
* @var CouponFactory|MockObject
41-
*/
42-
private $couponFactoryMock;
43-
4445
/**
4546
* @var Usage|MockObject
4647
*/
@@ -51,22 +52,37 @@ class ProcessorTest extends TestCase
5152
*/
5253
private $updateInfoMock;
5354

55+
/**
56+
* @var CouponRepositoryInterface|CouponRepositoryInterface&MockObject|MockObject
57+
*/
58+
private $couponRepository;
59+
60+
/**
61+
* @var SearchCriteriaBuilder|SearchCriteriaBuilder&MockObject|MockObject
62+
*/
63+
private $criteriaBuilder;
64+
5465
/**
5566
* @inheritDoc
5667
*/
5768
protected function setUp(): void
5869
{
5970
$this->ruleFactoryMock = $this->createMock(RuleFactory::class);
6071
$this->ruleCustomerFactoryMock = $this->createMock(CustomerFactory::class);
61-
$this->couponFactoryMock = $this->createMock(CouponFactory::class);
6272
$this->couponUsageMock = $this->createMock(Usage::class);
6373
$this->updateInfoMock = $this->createMock(UpdateInfo::class);
74+
$this->couponRepository = $this->createMock(CouponRepositoryInterface::class);
75+
$this->criteriaBuilder = $this->createMock(SearchCriteriaBuilder::class);
76+
$this->criteriaBuilder->method('addFilter')->willReturnSelf();
77+
$searchCriteria = $this->createMock(SearchCriteriaInterface::class);
78+
$this->criteriaBuilder->method('create')->willReturn($searchCriteria);
6479

6580
$this->processor = new Processor(
6681
$this->ruleFactoryMock,
6782
$this->ruleCustomerFactoryMock,
68-
$this->couponFactoryMock,
69-
$this->couponUsageMock
83+
$this->couponUsageMock,
84+
$this->couponRepository,
85+
$this->criteriaBuilder
7086
);
7187
}
7288

@@ -92,8 +108,10 @@ public function testProcess($isIncrement, $timesUsed): void
92108
$this->updateInfoMock->expects($this->atLeastOnce())->method('isIncrement')->willReturn($isIncrement);
93109

94110
$couponMock = $this->createMock(Coupon::class);
95-
$this->couponFactoryMock->expects($this->exactly(2))->method('create')->willReturn($couponMock);
96-
$couponMock->expects($this->exactly(2))->method('loadByCode')->with($couponCode)->willReturnSelf();
111+
$searchResult = $this->createMock(CouponSearchResultInterface::class);
112+
$searchResult->method('getItems')
113+
->willReturn([$couponMock]);
114+
$this->couponRepository->method('getList')->willReturn($searchResult);
97115
$couponMock->expects($this->atLeastOnce())->method('getId')->willReturn($couponId);
98116
$couponMock->expects($this->atLeastOnce())->method('getTimesUsed')->willReturn($timesUsed);
99117
$couponMock->expects($this->any())->method('setTimesUsed')->with($setTimesUsed)->willReturnSelf();
@@ -127,12 +145,12 @@ public function testProcess($isIncrement, $timesUsed): void
127145
->addMethods(['getTimesUsed', 'setTimesUsed'])
128146
->disableOriginalConstructor()
129147
->getMock();
130-
$ruleMock->expects($this->once())->method('load')->willReturnSelf();
131-
$ruleMock->expects($this->once())->method('getId')->willReturn(true);
132-
$ruleMock->expects($this->once())->method('loadCouponCode')->willReturnSelf();
148+
$ruleMock->expects($this->atLeastOnce())->method('load')->willReturnSelf();
149+
$ruleMock->expects($this->atLeastOnce())->method('getId')->willReturn(true);
150+
$ruleMock->expects($this->atLeastOnce())->method('loadCouponCode')->willReturnSelf();
133151
$ruleMock->expects($this->any())->method('getTimesUsed')->willReturn($timesUsed);
134152
$ruleMock->expects($this->any())->method('setTimesUsed')->willReturn($setTimesUsed);
135-
$this->ruleFactoryMock->expects($this->once())->method('create')->willReturn($ruleMock);
153+
$this->ruleFactoryMock->expects($this->atLeastOnce())->method('create')->willReturn($ruleMock);
136154

137155
$this->processor->process($this->updateInfoMock);
138156
}

0 commit comments

Comments
 (0)