Skip to content

Commit c612267

Browse files
authored
Merge pull request #7985 from magento-gl/comm_78764_32435
[GL Bluetooth] Community Pull Requests delivery
2 parents fd49fbc + 71fbb40 commit c612267

File tree

5 files changed

+275
-0
lines changed

5 files changed

+275
-0
lines changed

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
use Magento\Sales\Api\OrderRepositoryInterface;
2020
use Magento\SalesGraphQl\Model\Formatter\Order as OrderFormatter;
2121
use Magento\SalesGraphQl\Model\Resolver\CustomerOrders\Query\OrderFilter;
22+
use Magento\SalesGraphQl\Model\Resolver\CustomerOrders\Query\OrderSort;
2223
use Magento\Store\Api\Data\StoreInterface;
2324
use Magento\Store\Model\StoreManagerInterface;
2425

@@ -49,6 +50,11 @@ class CustomerOrders implements ResolverInterface
4950
*/
5051
private $orderFormatter;
5152

53+
/**
54+
* @var OrderSort
55+
*/
56+
private $orderSort;
57+
5258
/**
5359
* @var StoreManagerInterface|mixed|null
5460
*/
@@ -59,19 +65,22 @@ class CustomerOrders implements ResolverInterface
5965
* @param SearchCriteriaBuilder $searchCriteriaBuilder
6066
* @param OrderFilter $orderFilter
6167
* @param OrderFormatter $orderFormatter
68+
* @param OrderSort $orderSort
6269
* @param StoreManagerInterface|null $storeManager
6370
*/
6471
public function __construct(
6572
OrderRepositoryInterface $orderRepository,
6673
SearchCriteriaBuilder $searchCriteriaBuilder,
6774
OrderFilter $orderFilter,
6875
OrderFormatter $orderFormatter,
76+
OrderSort $orderSort,
6977
?StoreManagerInterface $storeManager = null
7078
) {
7179
$this->orderRepository = $orderRepository;
7280
$this->searchCriteriaBuilder = $searchCriteriaBuilder;
7381
$this->orderFilter = $orderFilter;
7482
$this->orderFormatter = $orderFormatter;
83+
$this->orderSort = $orderSort;
7584
$this->storeManager = $storeManager ?? ObjectManager::getInstance()->get(StoreManagerInterface::class);
7685
}
7786

@@ -144,6 +153,10 @@ private function getSearchResult(array $args, int $userId, int $storeId, array $
144153
if (isset($args['pageSize'])) {
145154
$this->searchCriteriaBuilder->setPageSize($args['pageSize']);
146155
}
156+
if (isset($args['sort'])) {
157+
$sortOrders = $this->orderSort->createSortOrders($args);
158+
$this->searchCriteriaBuilder->setSortOrders($sortOrders);
159+
}
147160
return $this->orderRepository->getList($this->searchCriteriaBuilder->create());
148161
}
149162

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
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\SalesGraphQl\Model\Resolver\CustomerOrders\Query;
9+
10+
use Magento\Framework\Api\SortOrder;
11+
use Magento\Framework\Api\SortOrderBuilder;
12+
use Magento\Framework\GraphQl\Schema\Type\Enum\DataMapperInterface;
13+
14+
/**
15+
* Order sort allows to sort the collection by the specified field and direction
16+
*/
17+
class OrderSort
18+
{
19+
/**
20+
* The sortable field mapper name
21+
*/
22+
private const SORTABLE_FIELD_MAP = 'CustomerOrderSortableField';
23+
24+
/**
25+
* @var DataMapperInterface
26+
*/
27+
private $enumDataMapper;
28+
29+
/**
30+
* @var SortOrderBuilder
31+
*/
32+
private $sortOrderBuilder;
33+
34+
/**
35+
* @param DataMapperInterface $enumDataMapper
36+
* @param SortOrderBuilder $sortOrderBuilder
37+
*/
38+
public function __construct(
39+
DataMapperInterface $enumDataMapper,
40+
SortOrderBuilder $sortOrderBuilder
41+
) {
42+
$this->enumDataMapper = $enumDataMapper;
43+
$this->sortOrderBuilder = $sortOrderBuilder;
44+
}
45+
46+
/**
47+
* Create an array of sort orders for sorting customer orders by the specified field and direction
48+
*
49+
* @param array $args
50+
* @return SortOrder[]
51+
*/
52+
public function createSortOrders(array $args): array
53+
{
54+
$sortField = $this->getField($args['sort']['sort_field']);
55+
$sortOrder = $this->sortOrderBuilder
56+
->setField($sortField)
57+
->setDirection($args['sort']['sort_direction'])
58+
->create();
59+
return [$sortOrder];
60+
}
61+
62+
/**
63+
* Get sort field
64+
*
65+
* @param string $field
66+
* @return string
67+
*/
68+
private function getField(string $field): string
69+
{
70+
$enums = $this->enumDataMapper->getMappedEnums(self::SORTABLE_FIELD_MAP);
71+
72+
return $enums[strtolower($field)];
73+
}
74+
}

app/code/Magento/SalesGraphQl/etc/graphql/di.xml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,4 +42,14 @@
4242
</argument>
4343
</arguments>
4444
</type>
45+
<type name="Magento\Framework\GraphQl\Schema\Type\Enum\DefaultDataMapper">
46+
<arguments>
47+
<argument name="map" xsi:type="array">
48+
<item name="CustomerOrderSortableField" xsi:type="array">
49+
<item name="number" xsi:type="string">increment_id</item>
50+
<item name="created_at" xsi:type="string">created_at</item>
51+
</item>
52+
</argument>
53+
</arguments>
54+
</type>
4555
</config>

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ type Customer {
2525
filter: CustomerOrdersFilterInput @doc(description: "Defines the filter to use for searching customer orders."),
2626
currentPage: Int = 1 @doc(description: "Specifies which page of results to return. The default value is 1."),
2727
pageSize: Int = 20 @doc(description: "Specifies the maximum number of results to return at once. The default value is 20."),
28+
sort: CustomerOrderSortInput @doc(description: "Specifies which field to sort on, and whether to return the results in ascending or descending order.")
2829
scope: ScopeTypeEnum @doc(description: "Specifies the scope to search for customer orders. The Store request header identifies the customer's store view code. The default value of STORE limits the search to the value specified in the header. Specify WEBSITE to expand the search to include all customer orders assigned to the website that is defined in the header, or specify GLOBAL to include all customer orders across all websites and stores."),
2930
): CustomerOrders @resolver(class: "Magento\\SalesGraphQl\\Model\\Resolver\\CustomerOrders") @cache(cacheable: false)
3031
}
@@ -33,6 +34,16 @@ input CustomerOrdersFilterInput @doc(description: "Identifies the filter to use
3334
number: FilterStringTypeInput @doc(description: "Filters by order number.")
3435
}
3536

37+
input CustomerOrderSortInput @doc(description: "CustomerOrderSortInput specifies the field to use for sorting search results and indicates whether the results are sorted in ascending or descending order.") {
38+
sort_field: CustomerOrderSortableField! @doc(description: "Specifies the field to use for sorting")
39+
sort_direction: SortEnum! @doc(description: "This enumeration indicates whether to return results in ascending or descending order")
40+
}
41+
42+
enum CustomerOrderSortableField @doc(description: "Specifies the field to use for sorting") {
43+
NUMBER @doc(description: "Sorts customer orders by number")
44+
CREATED_AT @doc(description: "Sorts customer orders by created_at field")
45+
}
46+
3647
type CustomerOrders @doc(description: "The collection of orders that match the conditions defined in the filter.") {
3748
items: [CustomerOrder]! @doc(description: "An array of customer orders.")
3849
page_info: SearchResultPageInfo @doc(description: "Contains pagination metadata.")

dev/tests/api-functional/testsuite/Magento/GraphQl/Sales/RetrieveOrdersByOrderNumberTest.php

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,18 @@
1616
use Magento\Sales\Model\ResourceModel\Order\Collection;
1717
use Magento\TestFramework\Helper\Bootstrap;
1818
use Magento\TestFramework\TestCase\GraphQlAbstract;
19+
use Magento\Catalog\Test\Fixture\Product as ProductFixture;
20+
use Magento\TestFramework\Fixture\DataFixture;
21+
use Magento\Checkout\Test\Fixture\SetDeliveryMethod;
22+
use Magento\Checkout\Test\Fixture\SetBillingAddress as SetBillingAddress;
23+
use Magento\Checkout\Test\Fixture\SetShippingAddress as SetShippingAddress;
24+
use Magento\Checkout\Test\Fixture\SetPaymentMethod as SetPaymentMethod;
25+
use Magento\Checkout\Test\Fixture\PlaceOrder as PlaceOrder;
26+
use Magento\Customer\Test\Fixture\Customer;
27+
use Magento\Quote\Test\Fixture\AddProductToCart as AddProductToCartFixture;
28+
use Magento\Quote\Test\Fixture\CustomerCart;
29+
use Magento\TestFramework\Fixture\DataFixtureStorage;
30+
use Magento\TestFramework\Fixture\DataFixtureStorageManager;
1931

2032
/**
2133
* Class RetrieveOrdersTest
@@ -34,6 +46,11 @@ class RetrieveOrdersByOrderNumberTest extends GraphQlAbstract
3446
/** @var ProductRepositoryInterface */
3547
private $productRepository;
3648

49+
/**
50+
* @var DataFixtureStorage
51+
*/
52+
private $fixtures;
53+
3754
protected function setUp():void
3855
{
3956
parent::setUp();
@@ -42,6 +59,7 @@ protected function setUp():void
4259
$this->orderRepository = $objectManager->get(OrderRepositoryInterface::class);
4360
$this->searchCriteriaBuilder = $objectManager->get(SearchCriteriaBuilder::class);
4461
$this->productRepository = $objectManager->get(ProductRepositoryInterface::class);
62+
$this->fixtures = $objectManager->get(DataFixtureStorageManager::class)->getStorage();
4563
}
4664

4765
/**
@@ -404,6 +422,155 @@ public function testGetMatchingOrdersForLowerQueryLength()
404422
$this->assertCount($response['customer']['orders']['total_count'], $response['customer']['orders']['items']);
405423
}
406424

425+
/**
426+
* @return void
427+
* @throws AuthenticationException
428+
*/
429+
#[
430+
DataFixture(Customer::class, ['email' => 'customer@example.com'], 'customer'),
431+
DataFixture(CustomerCart::class, ['customer_id' => '$customer.id$'], 'cart2'),
432+
DataFixture(ProductFixture::class, ['sku' => '100000002', 'price' => 10], 'p2'),
433+
DataFixture(AddProductToCartFixture::class, ['cart_id' => '$cart2.id$', 'product_id' => '$p2.id$']),
434+
DataFixture(SetBillingAddress::class, ['cart_id' => '$cart2.id$']),
435+
DataFixture(SetShippingAddress::class, ['cart_id' => '$cart2.id$']),
436+
DataFixture(SetDeliveryMethod::class, ['cart_id' => '$cart2.id$']),
437+
DataFixture(SetPaymentMethod::class, ['cart_id' => '$cart2.id$']),
438+
DataFixture(PlaceOrder::class, ['cart_id' => '$cart2.id$'], 'or2'),
439+
]
440+
441+
#[
442+
DataFixture(CustomerCart::class, ['customer_id' => '$customer.id$'], 'cart3'),
443+
DataFixture(ProductFixture::class, ['sku' => '100000003', 'price' => 10], 'p3'),
444+
DataFixture(AddProductToCartFixture::class, ['cart_id' => '$cart3.id$', 'product_id' => '$p3.id$']),
445+
DataFixture(SetBillingAddress::class, ['cart_id' => '$cart3.id$']),
446+
DataFixture(SetShippingAddress::class, ['cart_id' => '$cart3.id$']),
447+
DataFixture(SetDeliveryMethod::class, ['cart_id' => '$cart3.id$']),
448+
DataFixture(SetPaymentMethod::class, ['cart_id' => '$cart3.id$']),
449+
DataFixture(PlaceOrder::class, ['cart_id' => '$cart3.id$'], 'or3'),
450+
]
451+
452+
#[
453+
DataFixture(CustomerCart::class, ['customer_id' => '$customer.id$'], 'cart4'),
454+
DataFixture(ProductFixture::class, ['sku' => '100000004', 'price' => 10], 'p4'),
455+
DataFixture(AddProductToCartFixture::class, ['cart_id' => '$cart4.id$', 'product_id' => '$p4.id$']),
456+
DataFixture(SetBillingAddress::class, ['cart_id' => '$cart4.id$']),
457+
DataFixture(SetShippingAddress::class, ['cart_id' => '$cart4.id$']),
458+
DataFixture(SetDeliveryMethod::class, ['cart_id' => '$cart4.id$']),
459+
DataFixture(SetPaymentMethod::class, ['cart_id' => '$cart4.id$']),
460+
DataFixture(PlaceOrder::class, ['cart_id' => '$cart4.id$'], 'or4'),
461+
]
462+
463+
#[
464+
DataFixture(CustomerCart::class, ['customer_id' => '$customer.id$'], 'cart5'),
465+
DataFixture(ProductFixture::class, ['sku' => '100000005', 'price' => 10], 'p5'),
466+
DataFixture(AddProductToCartFixture::class, ['cart_id' => '$cart5.id$', 'product_id' => '$p5.id$']),
467+
DataFixture(SetBillingAddress::class, ['cart_id' => '$cart5.id$']),
468+
DataFixture(SetShippingAddress::class, ['cart_id' => '$cart5.id$']),
469+
DataFixture(SetDeliveryMethod::class, ['cart_id' => '$cart5.id$']),
470+
DataFixture(SetPaymentMethod::class, ['cart_id' => '$cart5.id$']),
471+
DataFixture(PlaceOrder::class, ['cart_id' => '$cart5.id$'], 'or5'),
472+
]
473+
474+
#[
475+
DataFixture(CustomerCart::class, ['customer_id' => '$customer.id$'], 'cart6'),
476+
DataFixture(ProductFixture::class, ['sku' => '100000006', 'price' => 10], 'p6'),
477+
DataFixture(AddProductToCartFixture::class, ['cart_id' => '$cart6.id$', 'product_id' => '$p6.id$']),
478+
DataFixture(SetBillingAddress::class, ['cart_id' => '$cart6.id$']),
479+
DataFixture(SetShippingAddress::class, ['cart_id' => '$cart6.id$']),
480+
DataFixture(SetDeliveryMethod::class, ['cart_id' => '$cart6.id$']),
481+
DataFixture(SetPaymentMethod::class, ['cart_id' => '$cart6.id$']),
482+
DataFixture(PlaceOrder::class, ['cart_id' => '$cart6.id$'], 'or6'),
483+
]
484+
485+
#[
486+
DataFixture(CustomerCart::class, ['customer_id' => '$customer.id$'], 'cart7'),
487+
DataFixture(ProductFixture::class, ['sku' => '100000007', 'price' => 10], 'p7'),
488+
DataFixture(AddProductToCartFixture::class, ['cart_id' => '$cart7.id$', 'product_id' => '$p7.id$']),
489+
DataFixture(SetBillingAddress::class, ['cart_id' => '$cart7.id$']),
490+
DataFixture(SetShippingAddress::class, ['cart_id' => '$cart7.id$']),
491+
DataFixture(SetDeliveryMethod::class, ['cart_id' => '$cart7.id$']),
492+
DataFixture(SetPaymentMethod::class, ['cart_id' => '$cart7.id$']),
493+
DataFixture(PlaceOrder::class, ['cart_id' => '$cart7.id$'], 'or7'),
494+
]
495+
496+
#[
497+
DataFixture(CustomerCart::class, ['customer_id' => '$customer.id$'], 'cart8'),
498+
DataFixture(ProductFixture::class, ['sku' => '100000008', 'price' => 10], 'p8'),
499+
DataFixture(AddProductToCartFixture::class, ['cart_id' => '$cart8.id$', 'product_id' => '$p8.id$']),
500+
DataFixture(SetBillingAddress::class, ['cart_id' => '$cart8.id$']),
501+
DataFixture(SetShippingAddress::class, ['cart_id' => '$cart8.id$']),
502+
DataFixture(SetDeliveryMethod::class, ['cart_id' => '$cart8.id$']),
503+
DataFixture(SetPaymentMethod::class, ['cart_id' => '$cart8.id$']),
504+
DataFixture(PlaceOrder::class, ['cart_id' => '$cart8.id$'], 'or8'),
505+
]
506+
public function testGetCustomerDescendingSortedOrders()
507+
{
508+
$query = <<<QUERY
509+
{
510+
customer {
511+
orders(
512+
sort: {
513+
sort_field: CREATED_AT,
514+
sort_direction: DESC
515+
}
516+
) {
517+
items {
518+
id
519+
number
520+
status
521+
order_date
522+
}
523+
}
524+
}
525+
}
526+
QUERY;
527+
528+
$currentEmail = 'customer@example.com';
529+
$currentPassword = 'password';
530+
$response = $this->graphQlQuery(
531+
$query,
532+
[],
533+
'',
534+
$this->customerAuthenticationHeader->execute($currentEmail, $currentPassword)
535+
);
536+
$this->assertArrayHasKey('orders', $response['customer']);
537+
$this->assertArrayHasKey('items', $response['customer']['orders']);
538+
$customerOrderItemsInResponse = $response['customer']['orders']['items'];
539+
540+
$order2 = $this->fixtures->get('or2')->getIncrementId();
541+
$order3 = $this->fixtures->get('or3')->getIncrementId();
542+
$order4 = $this->fixtures->get('or4')->getIncrementId();
543+
$order5 = $this->fixtures->get('or5')->getIncrementId();
544+
$order6 = $this->fixtures->get('or6')->getIncrementId();
545+
$order7 = $this->fixtures->get('or7')->getIncrementId();
546+
$order8 = $this->fixtures->get('or8')->getIncrementId();
547+
548+
$expectedOrderNumbersOptions = [$order8, $order7, $order6, $order5, $order4, $order3, $order2 ];
549+
$expectedOrderNumbers = $scalarTemp = [];
550+
$compDate = $prevComKey = '';
551+
foreach ($expectedOrderNumbersOptions as $comKey => $comData) {
552+
if ($compDate == $customerOrderItemsInResponse[$comKey]['order_date']) {
553+
$expectedOrderNumbers[] = $expectedOrderNumbers[$prevComKey];
554+
$scalarTemp = (array)$comData;
555+
$expectedOrderNumbers[$prevComKey] = $scalarTemp[0];
556+
} else {
557+
$scalarTemp = (array)$comData;
558+
$expectedOrderNumbers[] = $scalarTemp[0];
559+
}
560+
$prevComKey = $comKey;
561+
$compDate = $customerOrderItemsInResponse[$comKey]['order_date'];
562+
}
563+
564+
foreach ($expectedOrderNumbers as $key => $data) {
565+
$orderItemInResponse = $customerOrderItemsInResponse[$key];
566+
$this->assertEquals(
567+
$data,
568+
$orderItemInResponse['number'],
569+
"The order number is different than the expected for order - {$data}"
570+
);
571+
}
572+
}
573+
407574
/**
408575
* @magentoApiDataFixture Magento/Customer/_files/customer.php
409576
* @magentoApiDataFixture Magento/GraphQl/Sales/_files/orders_with_customer.php

0 commit comments

Comments
 (0)