Skip to content

Commit 98159c0

Browse files
committed
Merge remote-tracking branch 'origin/AC-14888' into spartans_pr_11082025
2 parents 0ad2a03 + e8d1e64 commit 98159c0

File tree

2 files changed

+327
-1
lines changed

2 files changed

+327
-1
lines changed

app/code/Magento/SalesGraphQl/Model/OrderItem/DataProvider.php

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,20 @@
1010
use Magento\Catalog\Api\Data\ProductInterface;
1111
use Magento\Catalog\Api\ProductRepositoryInterface;
1212
use Magento\Framework\Api\SearchCriteriaBuilder;
13+
use Magento\Framework\App\ObjectManager;
1314
use Magento\Sales\Api\Data\OrderInterface;
1415
use Magento\Sales\Api\Data\OrderItemInterface;
1516
use Magento\Sales\Api\OrderItemRepositoryInterface;
1617
use Magento\Sales\Api\OrderRepositoryInterface;
17-
use Magento\Framework\App\ObjectManager;
1818
use Magento\Tax\Helper\Data as TaxHelper;
1919

2020
/**
2121
* Data provider for order items
2222
*/
2323
class DataProvider
2424
{
25+
public const APPLIED_TO_ITEM = 'ITEM';
26+
public const APPLIED_TO_SHIPPING = 'SHIPPING';
2527
/**
2628
* @var OrderItemRepositoryInterface
2729
*/
@@ -240,6 +242,7 @@ private function getDiscountDetails(OrderInterface $associatedOrder, OrderItemIn
240242
} else {
241243
$discounts [] = [
242244
'label' => $associatedOrder->getDiscountDescription() ?? __('Discount'),
245+
'applied_to' => $this->getAppliedTo($associatedOrder),
243246
'amount' => [
244247
'value' => abs((float) $orderItem->getDiscountAmount()),
245248
'currency' => $associatedOrder->getOrderCurrencyCode()
@@ -249,4 +252,18 @@ private function getDiscountDetails(OrderInterface $associatedOrder, OrderItemIn
249252
}
250253
return $discounts;
251254
}
255+
256+
/**
257+
* Get entity type the discount is applied to
258+
*
259+
* @param OrderInterface $order
260+
* @return string
261+
*/
262+
private function getAppliedTo($order)
263+
{
264+
if ((float) $order->getShippingDiscountAmount() > 0) {
265+
return self::APPLIED_TO_SHIPPING;
266+
}
267+
return self::APPLIED_TO_ITEM;
268+
}
252269
}
Lines changed: 309 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,309 @@
1+
<?php
2+
/**
3+
* Copyright 2025 Adobe
4+
* All Rights Reserved.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\GraphQl\Sales;
9+
10+
use Exception;
11+
use Magento\Catalog\Test\Fixture\Product as ProductFixture;
12+
use Magento\Checkout\Test\Fixture\PlaceOrder as PlaceOrderFixture;
13+
use Magento\Checkout\Test\Fixture\SetBillingAddress;
14+
use Magento\Checkout\Test\Fixture\SetDeliveryMethod as SetDeliveryMethodFixture;
15+
use Magento\Checkout\Test\Fixture\SetPaymentMethod as SetPaymentMethodFixture;
16+
use Magento\Checkout\Test\Fixture\SetShippingAddress;
17+
use Magento\Customer\Test\Fixture\Customer;
18+
use Magento\Framework\Exception\LocalizedException;
19+
use Magento\Quote\Test\Fixture\AddProductToCart;
20+
use Magento\Quote\Test\Fixture\ApplyCoupon as ApplyCouponFixture;
21+
use Magento\Quote\Test\Fixture\CustomerCart;
22+
use Magento\SalesRule\Model\Rule as SalesRule;
23+
use Magento\SalesRule\Test\Fixture\Rule as SalesRuleFixture;
24+
use Magento\TestFramework\Fixture\DataFixture;
25+
use Magento\TestFramework\Fixture\DataFixtureStorage;
26+
use Magento\TestFramework\Fixture\DataFixtureStorageManager;
27+
use Magento\TestFramework\Helper\Bootstrap;
28+
use Magento\TestFramework\TestCase\GraphQlAbstract;
29+
30+
/**
31+
* Test customer orders GraphQL query with coupon codes
32+
*/
33+
class OrderItemDiscountAppliedToTest extends GraphQlAbstract
34+
{
35+
private const COUPON_CODE = 'COUPON-CODE-2025';
36+
private const DISCOUNT_AMOUNT = 10;
37+
38+
/**
39+
* @var DataFixtureStorage
40+
*/
41+
private $fixtures;
42+
43+
/**
44+
* @inheritDoc
45+
* @throws LocalizedException
46+
*/
47+
protected function setUp(): void
48+
{
49+
parent::setUp();
50+
$this->fixtures = Bootstrap::getObjectManager()->get(DataFixtureStorageManager::class)->getStorage();
51+
}
52+
53+
/**
54+
* Test that applied_to field returns correct value for item-level discounts
55+
*
56+
* @throws Exception
57+
*/
58+
#[
59+
DataFixture(
60+
SalesRuleFixture::class,
61+
[
62+
'name' => 'Test Sales Rule with Coupon',
63+
'is_active' => 1,
64+
'coupon_type' => SalesRule::COUPON_TYPE_SPECIFIC,
65+
'coupon_code' => self::COUPON_CODE,
66+
'discount_amount' => self::DISCOUNT_AMOUNT,
67+
'simple_action' => 'by_percent',
68+
'stop_rules_processing' => false,
69+
'is_advanced' => 1
70+
],
71+
as: 'sales_rule'
72+
),
73+
DataFixture(
74+
ProductFixture::class,
75+
[
76+
'price' => 100.00,
77+
'sku' => 'test-product-coupon'
78+
],
79+
as: 'product'
80+
),
81+
DataFixture(Customer::class, as: 'customer'),
82+
DataFixture(CustomerCart::class, ['customer_id' => '$customer.id$'], as: 'cart'),
83+
DataFixture(
84+
AddProductToCart::class,
85+
[
86+
'cart_id' => '$cart.id$',
87+
'product_id' => '$product.id$',
88+
'qty' => 1
89+
]
90+
),
91+
DataFixture(
92+
ApplyCouponFixture::class,
93+
[
94+
'cart_id' => '$cart.id$',
95+
'coupon_codes' => [self::COUPON_CODE]
96+
]
97+
),
98+
DataFixture(SetBillingAddress::class, ['cart_id' => '$cart.id$']),
99+
DataFixture(SetShippingAddress::class, ['cart_id' => '$cart.id$']),
100+
DataFixture(SetDeliveryMethodFixture::class, ['cart_id' => '$cart.id$']),
101+
DataFixture(SetPaymentMethodFixture::class, ['cart_id' => '$cart.id$']),
102+
DataFixture(PlaceOrderFixture::class, ['cart_id' => '$cart.id$'], 'order')
103+
]
104+
public function testOrderItemDiscountAppliedToFieldForItemDiscount()
105+
{
106+
$customer = $this->fixtures->get('customer');
107+
$currentEmail = $customer->getEmail();
108+
$currentPassword = 'password';
109+
110+
// Generate customer token
111+
$generateToken = $this->generateCustomerTokenMutation($currentEmail, $currentPassword);
112+
$tokenResponse = $this->graphQlMutation($generateToken);
113+
$customerToken = $tokenResponse['generateCustomerToken']['token'];
114+
115+
// Query customer orders with detailed item information including discounts and coupons
116+
$query = $this->getCustomerOrdersWithCouponQuery();
117+
$response = $this->graphQlQuery(
118+
$query,
119+
[],
120+
'',
121+
$this->getCustomerHeaders($customerToken)
122+
);
123+
124+
// Validate response structure
125+
$this->assertArrayHasKey('customer', $response);
126+
$this->assertArrayHasKey('orders', $response['customer']);
127+
$this->assertArrayHasKey('items', $response['customer']['orders']);
128+
$this->assertNotEmpty($response['customer']['orders']['items']);
129+
130+
$order = $response['customer']['orders']['items'][0];
131+
132+
// Validate order has items
133+
$this->assertArrayHasKey('items', $order);
134+
$this->assertNotEmpty($order['items']);
135+
136+
$orderItem = $order['items'][0];
137+
138+
// Validate order item structure
139+
$this->assertArrayHasKey('product_sku', $orderItem);
140+
$this->assertEquals('test-product-coupon', $orderItem['product_sku']);
141+
$this->assertArrayHasKey('discounts', $orderItem);
142+
$this->assertNotEmpty($orderItem['discounts']);
143+
$discount = $orderItem['discounts'][0];
144+
$this->assertArrayHasKey('applied_to', $discount);
145+
$this->assertEquals('ITEM', $discount['applied_to']);
146+
}
147+
148+
/**
149+
* Test that applied_to field returns correct value for shipping discounts
150+
*
151+
* @throws Exception
152+
*/
153+
#[
154+
DataFixture(
155+
SalesRuleFixture::class,
156+
[
157+
'name' => 'Test Shipping Discount Rule',
158+
'is_active' => 1,
159+
'coupon_type' => SalesRule::COUPON_TYPE_NO_COUPON,
160+
'discount_amount' => self::DISCOUNT_AMOUNT,
161+
'simple_action' => 'by_percent',
162+
'apply_to_shipping' => 1,
163+
'stop_rules_processing' => false,
164+
'is_advanced' => 1
165+
],
166+
as: 'sales_rule'
167+
),
168+
DataFixture(
169+
ProductFixture::class,
170+
[
171+
'price' => 100.00,
172+
'sku' => 'test-product-coupon'
173+
],
174+
as: 'product'
175+
),
176+
DataFixture(Customer::class, as: 'customer'),
177+
DataFixture(CustomerCart::class, ['customer_id' => '$customer.id$'], as: 'cart'),
178+
DataFixture(
179+
AddProductToCart::class,
180+
[
181+
'cart_id' => '$cart.id$',
182+
'product_id' => '$product.id$',
183+
'qty' => 1
184+
]
185+
),
186+
DataFixture(SetBillingAddress::class, ['cart_id' => '$cart.id$']),
187+
DataFixture(SetShippingAddress::class, ['cart_id' => '$cart.id$']),
188+
DataFixture(SetDeliveryMethodFixture::class, ['cart_id' => '$cart.id$']),
189+
DataFixture(SetPaymentMethodFixture::class, ['cart_id' => '$cart.id$']),
190+
DataFixture(PlaceOrderFixture::class, ['cart_id' => '$cart.id$'], 'order')
191+
]
192+
public function testOrderItemDiscountAppliedToFieldForShippingDiscount()
193+
{
194+
$customer = $this->fixtures->get('customer');
195+
$currentEmail = $customer->getEmail();
196+
$currentPassword = 'password';
197+
198+
// Generate customer token
199+
$generateToken = $this->generateCustomerTokenMutation($currentEmail, $currentPassword);
200+
$tokenResponse = $this->graphQlMutation($generateToken);
201+
$customerToken = $tokenResponse['generateCustomerToken']['token'];
202+
203+
// Query customer orders with detailed item information including discounts and coupons
204+
$query = $this->getCustomerOrdersWithCouponQuery();
205+
$response = $this->graphQlQuery(
206+
$query,
207+
[],
208+
'',
209+
$this->getCustomerHeaders($customerToken)
210+
);
211+
212+
// Validate response structure
213+
$this->assertArrayHasKey('customer', $response);
214+
$this->assertArrayHasKey('orders', $response['customer']);
215+
$this->assertArrayHasKey('items', $response['customer']['orders']);
216+
$this->assertNotEmpty($response['customer']['orders']['items']);
217+
218+
$order = $response['customer']['orders']['items'][0];
219+
220+
// Validate order has items
221+
$this->assertArrayHasKey('items', $order);
222+
$this->assertNotEmpty($order['items']);
223+
224+
$orderItem = $order['items'][0];
225+
226+
// Validate order item structure
227+
$this->assertArrayHasKey('product_sku', $orderItem);
228+
$this->assertEquals('test-product-coupon', $orderItem['product_sku']);
229+
$this->assertArrayHasKey('discounts', $orderItem);
230+
$this->assertNotEmpty($orderItem['discounts']);
231+
$discount = $orderItem['discounts'][0];
232+
233+
$this->assertArrayHasKey('applied_to', $discount);
234+
$this->assertEquals('SHIPPING', $discount['applied_to']);
235+
}
236+
237+
/**
238+
* Get GraphQL query for customer orders with coupon information
239+
*
240+
* @return string
241+
*/
242+
private function getCustomerOrdersWithCouponQuery(): string
243+
{
244+
return <<<QUERY
245+
query {
246+
customer {
247+
firstname
248+
lastname
249+
orders {
250+
items {
251+
order_number
252+
status
253+
order_date
254+
items {
255+
product_sku
256+
product_name
257+
quantity_ordered
258+
discounts {
259+
applied_to
260+
}
261+
}
262+
}
263+
page_info {
264+
current_page
265+
page_size
266+
total_pages
267+
}
268+
total_count
269+
}
270+
}
271+
}
272+
QUERY;
273+
}
274+
275+
/**
276+
* Generate customer token mutation
277+
*
278+
* @param string $email
279+
* @param string $password
280+
* @return string
281+
*/
282+
private function generateCustomerTokenMutation(string $email, string $password): string
283+
{
284+
return <<<MUTATION
285+
mutation {
286+
generateCustomerToken(
287+
email: "{$email}"
288+
password: "{$password}"
289+
) {
290+
token
291+
}
292+
}
293+
MUTATION;
294+
}
295+
296+
/**
297+
* Get customer authorization headers
298+
*
299+
* @param string $token
300+
* @return array
301+
*/
302+
private function getCustomerHeaders(string $token): array
303+
{
304+
return [
305+
'Authorization' => 'Bearer ' . $token,
306+
'Store' => 'default'
307+
];
308+
}
309+
}

0 commit comments

Comments
 (0)