Skip to content

Commit 14eb748

Browse files
committed
Merge branch 'ACP2E-3647' of https://github.com/adobe-commerce-tier-4/magento2ce into PR-Tier4-VK-2025-02-14
2 parents 9da45a7 + 5d58d59 commit 14eb748

File tree

4 files changed

+285
-3
lines changed

4 files changed

+285
-3
lines changed

app/code/Magento/SalesGraphQl/Model/Resolver/OrderTotal.php

Lines changed: 4 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 2019 Adobe
4+
* All Rights Reserved.
55
*/
66
declare(strict_types=1);
77

@@ -125,7 +125,8 @@ private function getDiscountDetails(OrderInterface $order): array
125125
'amount' => [
126126
'value' => abs((float) $order->getDiscountAmount()),
127127
'currency' => $order->getOrderCurrencyCode()
128-
]
128+
],
129+
'order_model' => $order
129130
];
130131
}
131132
return $orderDiscounts;
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
<?php
2+
/**
3+
* Copyright 2025 Adobe
4+
* All Rights Reserved.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\SalesGraphQl\Test\Unit\Model\Resolver;
9+
10+
use Magento\Framework\GraphQl\Query\Resolver\ContextInterface;
11+
use Magento\Framework\Api\ExtensionAttributesInterface;
12+
use PHPUnit\Framework\MockObject\MockObject;
13+
use PHPUnit\Framework\TestCase;
14+
use Magento\SalesGraphQl\Model\Resolver\OrderTotal;
15+
use Magento\Sales\Api\Data\OrderInterface;
16+
use Magento\Framework\GraphQl\Config\Element\Field;
17+
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
18+
use Magento\Framework\Exception\LocalizedException;
19+
20+
class OrderTotalTest extends TestCase
21+
{
22+
/**
23+
* @var OrderInterface|MockObject
24+
*/
25+
private $orderMock;
26+
27+
/**
28+
* @var OrderTotal|MockObject
29+
*/
30+
private $orderTotal;
31+
32+
/**
33+
* @var ContextInterface|MockObject
34+
*/
35+
private $contextMock;
36+
37+
/**
38+
* @var Field|MockObject
39+
*/
40+
private $fieldMock;
41+
42+
/**
43+
* @var ResolveInfo|MockObject
44+
*/
45+
private $resolveInfoMock;
46+
47+
/**
48+
* @var ExtensionAttributesInterface|MockObject
49+
*/
50+
private $extensionAttributesMock;
51+
52+
protected function setUp(): void
53+
{
54+
$this->contextMock = $this->createMock(ContextInterface::class);
55+
$this->fieldMock = $this->createMock(Field::class);
56+
$this->resolveInfoMock = $this->createMock(ResolveInfo::class);
57+
$this->orderMock = $this->createMock(OrderInterface::class);
58+
$this->orderMock->method('getOrderCurrencyCode')->willReturn('USD');
59+
$this->orderMock->method('getBaseCurrencyCode')->willReturn('USD');
60+
$this->orderMock->method('getBaseGrandTotal')->willReturn(100.00);
61+
$this->orderMock->method('getGrandTotal')->willReturn(110.00);
62+
$this->orderMock->method('getSubtotal')->willReturn(110.00);
63+
$this->orderMock->method('getTaxAmount')->willReturn(10.00);
64+
$this->orderMock->method('getShippingAmount')->willReturn(5.00);
65+
$this->orderMock->method('getShippingInclTax')->willReturn(7.00);
66+
$this->orderMock->method('getDiscountAmount')->willReturn(7.00);
67+
$this->orderMock->method('getDiscountDescription')->willReturn('TEST123');
68+
$this->orderTotal = new OrderTotal();
69+
}
70+
71+
public function testResolve(): void
72+
{
73+
$fieldMock = $this->createMock(Field::class);
74+
$resolveInfoMock = $this->createMock(ResolveInfo::class);
75+
$value = ['model' => $this->orderMock];
76+
$args = [];
77+
$this->extensionAttributesMock = $this->getMockBuilder(ExtensionAttributesInterface::class)
78+
->addMethods(['getAppliedTaxes', 'getItemAppliedTaxes'])
79+
->disableOriginalConstructor()
80+
->getMock();
81+
$this->extensionAttributesMock->expects($this->once())->method('getAppliedTaxes')->willReturn([]);
82+
$this->extensionAttributesMock->expects($this->once())->method('getItemAppliedTaxes')->willReturn([]);
83+
$this->orderMock->method('getExtensionAttributes')->willReturn($this->extensionAttributesMock);
84+
$result = $this->orderTotal->resolve($fieldMock, $this->contextMock, $resolveInfoMock, $value, $args);
85+
$this->assertArrayHasKey('base_grand_total', $result);
86+
$this->assertEquals(100.00, $result['base_grand_total']['value']);
87+
$this->assertEquals('USD', $result['base_grand_total']['currency']);
88+
$this->assertArrayHasKey('grand_total', $result);
89+
$this->assertEquals(110.00, $result['grand_total']['value']);
90+
$this->assertEquals('USD', $result['grand_total']['currency']);
91+
$this->assertArrayHasKey('subtotal', $result);
92+
$this->assertEquals(110.00, $result['subtotal']['value']);
93+
$this->assertEquals('USD', $result['subtotal']['currency']);
94+
$this->assertArrayHasKey('total_tax', $result);
95+
$this->assertEquals(10.00, $result['total_tax']['value']);
96+
$this->assertEquals('USD', $result['total_tax']['currency']);
97+
$this->assertArrayHasKey('discounts', $result);
98+
foreach ($result['discounts'] as $discount) {
99+
$this->assertEquals('TEST123', $discount['label']);
100+
$this->assertEquals(7.00, $discount['amount']['value']);
101+
$this->assertEquals('USD', $discount['amount']['currency']);
102+
$this->assertArrayHasKey('order_model', $discount);
103+
}
104+
}
105+
106+
public function testResolveThrowsExceptionForMissingModelValue(): void
107+
{
108+
$this->expectException(LocalizedException::class);
109+
$this->expectExceptionMessage('"model" value should be specified');
110+
$value = ['model' => null];
111+
$args = [];
112+
113+
$this->orderTotal->resolve($this->fieldMock, $this->contextMock, $this->resolveInfoMock, $value, $args);
114+
}
115+
}

app/code/Magento/SalesRuleGraphQl/Model/Resolver/Coupon.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ public function __construct(
3333
*/
3434
public function resolve(Field $field, $context, ResolveInfo $info, ?array $value = null, ?array $args = null)
3535
{
36+
if (isset($value['order_model'])) {
37+
return ['code' => $value['order_model']->getCouponCode()];
38+
}
3639
if (!isset($value['discount_model'])) {
3740
throw new LocalizedException(__('"discount_model" value should be specified'));
3841
}
Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
<?php
2+
/**
3+
* Copyright 2025 Adobe
4+
* All Rights Reserved.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\SalesRuleGraphQl\Test\Unit\Model\Resolver;
9+
10+
use Magento\Framework\Exception\LocalizedException;
11+
use Magento\Framework\GraphQl\Config\Element\Field;
12+
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
13+
use Magento\Quote\Api\Data\CartInterface;
14+
use Magento\SalesRule\Api\Data\CouponInterface;
15+
use Magento\SalesRule\Api\Data\RuleDiscountInterface;
16+
use Magento\SalesRule\Model\GetCoupons;
17+
use Magento\Sales\Api\Data\OrderInterface;
18+
use Magento\SalesRule\Model\Quote\GetCouponCodes;
19+
use Magento\SalesRuleGraphQl\Model\Resolver\Coupon;
20+
use PHPUnit\Framework\MockObject\MockObject;
21+
use PHPUnit\Framework\TestCase;
22+
use Magento\Framework\GraphQl\Query\Resolver\ContextInterface;
23+
24+
class CouponTest extends TestCase
25+
{
26+
/**
27+
* @var GetCouponCodes|MockObject
28+
*/
29+
private $getCouponCodesMock;
30+
31+
/**
32+
* @var GetCoupons|MockObject
33+
*/
34+
private $getCouponsMock;
35+
36+
/**
37+
* @var Coupon|MockObject
38+
*/
39+
private $resolver;
40+
41+
/**
42+
* @var ContextInterface|MockObject
43+
*/
44+
private $contextMock;
45+
46+
/**
47+
* @var Field|MockObject
48+
*/
49+
private $fieldMock;
50+
51+
/**
52+
* @var ResolveInfo|MockObject
53+
*/
54+
private $resolveInfoMock;
55+
56+
protected function setUp(): void
57+
{
58+
$this->getCouponCodesMock = $this->createMock(GetCouponCodes::class);
59+
$this->getCouponsMock = $this->createMock(GetCoupons::class);
60+
$this->contextMock = $this->createMock(ContextInterface::class);
61+
$this->fieldMock = $this->createMock(Field::class);
62+
$this->resolveInfoMock = $this->createMock(ResolveInfo::class);
63+
$this->resolver = new Coupon(
64+
$this->getCouponCodesMock,
65+
$this->getCouponsMock
66+
);
67+
}
68+
69+
public function testResolveWithOrderModel(): void
70+
{
71+
$orderModel = $this->createMock(OrderInterface::class);
72+
$orderModel->expects($this->once())
73+
->method('getCouponCode')
74+
->willReturn('TEST1234');
75+
$result = $this->resolver->resolve(
76+
$this->fieldMock,
77+
$this->contextMock,
78+
$this->resolveInfoMock,
79+
['order_model' => $orderModel]
80+
);
81+
82+
$this->assertEquals(['code' => 'TEST1234'], $result);
83+
}
84+
85+
public function testResolveWithoutDiscountModel(): void
86+
{
87+
$this->expectException(LocalizedException::class);
88+
$this->expectExceptionMessage('"discount_model" value should be specified');
89+
$this->resolver->resolve(
90+
$this->fieldMock,
91+
$this->contextMock,
92+
$this->resolveInfoMock,
93+
[]
94+
);
95+
}
96+
97+
public function testResolveWithoutQuoteModel(): void
98+
{
99+
$this->expectException(LocalizedException::class);
100+
$this->expectExceptionMessage('"quote_model" value should be specified');
101+
$this->resolver->resolve(
102+
$this->fieldMock,
103+
$this->contextMock,
104+
$this->resolveInfoMock,
105+
['discount_model' => $this->createMock(RuleDiscountInterface::class)]
106+
);
107+
}
108+
109+
public function testResolveWithoutCoupon(): void
110+
{
111+
$quoteModel = $this->createMock(CartInterface::class);
112+
$discountModel = $this->createMock(RuleDiscountInterface::class);
113+
$this->getCouponCodesMock->method('execute')->willReturn([]);
114+
$this->getCouponsMock->method('execute')->willReturn([]);
115+
$result = $this->resolver->resolve(
116+
$this->fieldMock,
117+
$this->contextMock,
118+
$this->resolveInfoMock,
119+
['discount_model' => $discountModel, 'quote_model' => $quoteModel]
120+
);
121+
122+
$this->assertNull($result);
123+
}
124+
125+
public function testResolveWithMatchingRuleId(): void
126+
{
127+
$quoteModel = $this->createMock(CartInterface::class);
128+
$discountModel = $this->createMock(RuleDiscountInterface::class);
129+
$discountModel->method('getRuleID')->willReturn(123);
130+
$couponMock = $this->createMock(CouponInterface::class);
131+
$couponMock->method('getRuleId')->willReturn(123);
132+
$couponMock->method('getCode')->willReturn('TEST1234');
133+
$this->getCouponCodesMock->method('execute')->willReturn(['test']);
134+
$this->getCouponsMock->method('execute')->willReturn([$couponMock]);
135+
$result = $this->resolver->resolve(
136+
$this->fieldMock,
137+
$this->contextMock,
138+
$this->resolveInfoMock,
139+
['discount_model' => $discountModel, 'quote_model' => $quoteModel]
140+
);
141+
142+
$this->assertEquals(['code' => 'TEST1234'], $result);
143+
}
144+
145+
public function testResolveNoMatchingRuleId(): void
146+
{
147+
$quoteModel = $this->createMock(CartInterface::class);
148+
$discountModel = $this->createMock(RuleDiscountInterface::class);
149+
$discountModel->method('getRuleID')->willReturn(123);
150+
$couponMock = $this->createMock(CouponInterface::class);
151+
$couponMock->method('getRuleId')->willReturn(321);
152+
$this->getCouponCodesMock->method('execute')->willReturn(['test']);
153+
$this->getCouponsMock->method('execute')->willReturn([$couponMock]);
154+
$result = $this->resolver->resolve(
155+
$this->fieldMock,
156+
$this->contextMock,
157+
$this->resolveInfoMock,
158+
['discount_model' => $discountModel, 'quote_model' => $quoteModel]
159+
);
160+
161+
$this->assertNull($result);
162+
}
163+
}

0 commit comments

Comments
 (0)