Magento 2 Get Sales Order Data Using GraphQL

In Magento 2.3.x using GraphQL, we can get sales order data. There are multiple Magento core module which uses GraphQL for getting data like category, product, CMS page and block. Here customer module uses the GraphQL for getting data of a specific entity. Magento 2 doesn’t use GraphQL for sales specific entity in core module.

We will see further how can we get the order data using GraphQL in Magento 2 by passing order id. We can get the details of order entity, billing address and shipping address and ordered items in the order.

You need to create first registration files for our module as registration.php and module.xml. Here we have used Magemeta as Packagename where SalesOrderGraphQl is a module name.

Path: app/code/Magemeta/SalesOrderGraphQl/registration.php

<?php
\Magento\Framework\Component\ComponentRegistrar::register(
    \Magento\Framework\Component\ComponentRegistrar::MODULE,
    'Magemeta_SalesOrderGraphQl',
    __DIR__
);

Create module.xml file on following path:

Path: app/code/Magemeta/SalesOrderGraphQl/etc/module.xml

<?xml version="1.0"?>
 
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magenOur Module depends on GraphQL and Sales Module so we have given dependency on module.xml file.to:framework:Module/etc/module.xsd">
    <module name="Magemeta_SalesOrderGraphQl">
        <sequence>
            <module name="Magento_Sales"/>
            <module name="Magento_GraphQl"/>
        </sequence>
    </module>
</config>

Our Module depends on core GraphQL and sales module so we have added both modules dependencies in module.xml file.

Every GraphQl module must contain schema.graphqls file under the etc folder of a module.

schema.graphqls is at the center of any GraphQL query implementation and explains what data can be queried in the query. So we can define our basic structure of query data in the schema.graphqls file.

Create schema.graphqls file on following path:

Path: app/code/Magemeta/SalesOrderGraphQl/etc/schema.graphqls

type Query {
    salesOrder (
        id: Int @doc(description: "id of sales order")
    ): SalesOrder @resolver(class: "Magemeta\\SalesOrderGraphQl\\Model\\Resolver\\SalesOrder") @doc(description: "This sales order query returns the information about an order")
}
 
type SalesOrder @doc(description: "SalesOrder graphql collects data of specific order") {
    increment_id: String @doc(description: "Increment id of sales order")
    customer_name: String @doc(description: "Customer name of sales order")
    grand_total: String @doc(description: "Grand total of sales order")
    is_guest_customer : Boolean @doc(description: "Specifies if the order was placed by guest customer")
    created_at: String @doc(description: "Created date of sales order")
    shipping_method: String @doc(description: "Shipping method of sales order")
    shipping: [Shipping] @doc(description: "An array of shipping data of order") @resolver(class: "Magemeta\\SalesOrderGraphQl\\Model\\Resolver\\Shipping")
    billing: [Billing] @doc(description: "An array of billing data of sales order") @resolver(class: "Magemeta\\SalesOrderGraphQl\\Model\\Resolver\\Billing")
    items: [Items] @doc(description: "An array of all items data of sales order") @resolver(class: "Magemeta\\SalesOrderGraphQl\\Model\\Resolver\\Items")
}
 
type Billing @doc(description: "An array containing all the billing fields of sales order") {
 name: String @doc(description: "Billing name of sales order")
    street: String @doc(description: "Billing street of sales order")
    city: String @doc(description: "Billing city of sales order")
    region: String @doc(description: "Billing region of sales order")
    country: String @doc(description: "Billing country of sales order")
    postcode: String @doc(description: "Billing postcode of sales order")
    telephone: String @doc(description: "Billing telephone of sales order")
    fax: String @doc(description: "Billing fax of sales order")
    company: String @doc(description: "Billing company of sales order")
}
 
type Shipping @doc(description: "An array containing all the shipping fields of sales order") {
 name: String @doc(description: "Shipping name of sales order")
    street: String @doc(description: "Shipping street of sales order")
    city: String @doc(description: "Shipping city of sales order")
    region: String @doc(description: "Shipping region of sales order")
    country: String @doc(description: "Shipping country of sales order")
    postcode: String @doc(description: "Shipping postcode of sales order")
    telephone: String @doc(description: "Shipping telephone of sales order")
    fax: String @doc(description: "Shipping fax of sales order")
    company: String @doc(description: "Shipping company of sales order")
}
 
type Items @doc(description: "An array containing all the items of sales order") {
 sku: String @doc(description: "SKU of sales order item")
    title: String @doc(description: "title of sales order item")
    price: Float @doc(description: "price of sales order item")
}

Now we have to define schema.graphql file with multiple different type for billing, shipping and Items type to get information of each entity of order data. Each type has a specific field to display in GraphQL result.

We need to define each field in schema.graphql schema file, which you want to show in response for a graphQl query. For Billing schema type, you have to specify each field related to the billing. For shipping schema, you have to specify a required field, same for Items type you have to pass a required field to show as response.

Next, we have to write our custom logic for the dynamic value of sales order data and to do so, we will need to create a resolver php file to get the dynamic value of specific order.

Create SalesOrder.php file on following path:
Path: app/code/Magemeta/SalesOrderGraphQl/Model/Resolver/SalesOrder.php

<?php
declare(strict_types=1);
 
namespace Magemeta\SalesOrderGraphQl\Model\Resolver;
 
use Magento\Framework\Exception\NoSuchEntityException;
use Magento\Framework\GraphQl\Config\Element\Field;
use Magento\Framework\GraphQl\Exception\GraphQlInputException;
use Magento\Framework\GraphQl\Exception\GraphQlNoSuchEntityException;
use Magento\Framework\GraphQl\Query\ResolverInterface;
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
 
/**
 * Sales Order field resolver for GraphQL request processing
 */
class SalesOrder implements ResolverInterface
{
    public function __construct(
        \Magento\Sales\Api\OrderRepositoryInterface $orderRepository
    ) {
        $this->orderRepository = $orderRepository;
    }
 
    /**
     * @inheritdoc
     */
    public function resolve(
        Field $field,
        $context,
        ResolveInfo $info,
        array $value = null,
        array $args = null
    ) {
        $salesId = $this->getSalesId($args);
        $salesData = $this->getSalesData($salesId);
        return $salesData;
    }
 
    /**
     * @param array $args
     * @return int
     * @throws GraphQlInputException
     */
    private function getSalesId(array $args): int
    {
        if (!isset($args['id'])) {
            throw new GraphQlInputException(__('"sales id should be provided'));
        }
        return (int)$args['id'];
    }
 
    /**
     * @param int $orderId
     * @return array
     * @throws GraphQlNoSuchEntityException
     */
    private function getSalesData(int $orderId): array
    {
        try {
            $order = $this->orderRepository->get($orderId);
            $billigAddress = $order->getBillingAddress()->getData();
            $shippingAddress = $order->getShippingAddress()->getData();
            foreach ($order->getAllVisibleItems() as $item) {
                $itemsData[] = $item->getData();
            }
            $salesData = [
                'increment_id' => $order->getIncrementId(),
                'grand_total' => $order->getGrandTotal(),
                'customer_name' => $order->getCustomerFirstname().' '.$order->getCustomerLastname(),
                'created_at' => $order->getCreatedAt(),
                'is_guest_customer' => !empty($order->getCustomerIsGuest()) ? 1 : 0,
                'shipping_method' => $order->getShippingMethod(),
                'shipping_address' => $shippingAddress,
                'billing_address' => $billigAddress,
                'items' => $itemsData
            ];
        } catch (NoSuchEntityException $e) {
            throw new GraphQlNoSuchEntityException(__($e->getMessage()), $e);
        }
        return $salesData;
    }
}

Now we will need to create Shipping.php, Billing.php and Items.php file for getting shipping, billing and items data of an order.

To get the shipping address of the sales order, we have created a separate file to get the shipping address information as a GraphQl response. You need to create the following file which will fetch the shipping records of the sales order.

Path: app/code/Magemeta/SalesOrderGraphQl/Model/Resolver/Shipping.php

<?php
declare(strict_types=1);
 
namespace Magemeta\SalesOrderGraphQl\Model\Resolver;
 
use Magento\Framework\GraphQl\Exception\GraphQlInputException;
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
use Magento\Framework\GraphQl\Config\Element\Field;
use Magento\Framework\GraphQl\Query\Resolver\ValueFactory;
use Magento\Framework\GraphQl\Query\ResolverInterface;
 
/**
 * Retrieves the Shipping information object
 */
class Shipping implements ResolverInterface
{
    /**
     * @inheritdoc
     */
    public function resolve(Field $field, $context, ResolveInfo $info, array $value = null, array $args = null)
    {
        if (!isset($value['shipping_address'])) {
             return null;
        }
        $shippingData = $value['shipping_address'];
        $shippingAddress = [];
        $shippingAddress['shipping']['name'] = $shippingData['firstname'].' '.$shippingData['lastname'];
        $shippingAddress['shipping']['street'] = count($shippingData['street']) > 1 ? implode(" , ",$shippingData['street']) : $shippingData['street'];
        $shippingAddress['shipping']['city'] = $shippingData['city'];
        $shippingAddress['shipping']['region'] = $shippingData['region'];
        $shippingAddress['shipping']['country_id'] = $shippingData['country_id'];
        $shippingAddress['shipping']['postcode'] = $shippingData['postcode'];
        $shippingAddress['shipping']['telephone'] = $shippingData['telephone'];
        $shippingAddress['shipping']['fax'] = $shippingData['fax'];
        $shippingAddress['shipping']['company'] = $shippingData['company'];
        return $shippingAddress;
    }
}

To get billing address of sales order, we have created following file to get billing address information in GraphQL response.
Path: app/code/Magemeta/SalesOrderGraphQl/Model/Resolver/Billing.php

declare(strict_types=1);
 
namespace Magemeta\SalesOrderGraphQl\Model\Resolver;
 
use Magento\Framework\GraphQl\Exception\GraphQlInputException;
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
use Magento\Framework\GraphQl\Config\Element\Field;
use Magento\Framework\GraphQl\Query\Resolver\ValueFactory;
use Magento\Framework\GraphQl\Query\ResolverInterface;
 
/**
 * Retrieves the Billing information object
 */
class Billing implements ResolverInterface
{
    /**
     * @inheritdoc
     */
    public function resolve(Field $field, $context, ResolveInfo $info, array $value = null, array $args = null)
    {
        if (!isset($value['billing_address'])) {
             return null;
        }
        $billingData = $value['billing_address'];
        $billingAddress = [];
        $billingAddress['billing']['name'] = $billingData['firstname'].' '.$billingData['lastname'];
        $billingAddress['billing']['street'] = count($billingData['street']) > 1 ? implode(" , ",$billingData['street']) : $billingData['street'];
        $billingAddress['billing']['city'] = $billingData['city'];
        $billingAddress['billing']['region'] = $billingData['region'];
        $billingAddress['billing']['country_id'] = $billingData['country_id'];
        $billingAddress['billing']['postcode'] = $billingData['postcode'];
        $billingAddress['billing']['telephone'] = $billingData['telephone'];
        $billingAddress['billing']['fax'] = $billingData['fax'];
        $billingAddress['billing']['company'] = $billingData['company'];
        return $billingAddress;
    }
}

To display all the items of an order, we need to create Items.php as defined in the schema file. We will get a response as an array of items for the order.

Path: app/code/Magemeta/SalesOrderGraphQl/Model/Resolver/Items.php

<?php
declare(strict_types=1);
 
namespace Magemeta\SalesOrderGraphQl\Model\Resolver;
 
use Magento\Framework\GraphQl\Exception\GraphQlInputException;
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
use Magento\Framework\GraphQl\Config\Element\Field;
use Magento\Framework\GraphQl\Query\Resolver\ValueFactory;
use Magento\Framework\GraphQl\Query\ResolverInterface;
use Magento\CatalogGraphQl\Model\Resolver\Product\Websites\Collection;
 
/**
 * Retrieves the Items information object
 */
class Items implements ResolverInterface
{
    /**
     * Get all the items of sales order.
     * @inheritdoc
     */
    public function resolve(Field $field, $context, ResolveInfo $info, array $value = null, array $args = null)
    {
        if (!isset($value['items'])) {
             return null;
        }
        $itemArray = [];
        foreach ($value['items'] as $key => $item) {
            $itemArray[$key]['sku'] = $item['sku'];
            $itemArray[$key]['title'] = $item['name'];
            $itemArray[$key]['price'] = $item['price'];
        }
        return $itemArray;
    }
}

Now finally run the setup:upgrade command to install our custom sales order module.

php bin/magento setup:upgrade
php bin/magento cache:flush

We have passed sales_order id as 10 to fetch the records of sales order id as 10. You can get the following data once you query following request payload:

Request Payload:

{
  salesOrder (id: 10) {
      increment_id
      customer_name
      grand_total
      is_guest_customer
      created_at
      shipping_method
      shipping {
        name
        street
        city
        region
        country
        postcode
        telephone
        fax
        company
      }
      billing {
        name
        street
        city
        region
        country
        postcode
        telephone
        fax
        company
      }
      items {
        title
        sku
        price
      }
  }
}

Response for above request payload with order id as 10 will display all the products for order id 10 with items array with billing and shipping information as shown below:

{
  "data": {
    "salesOrder": {
      "increment_id": "000000050",
      "customer_name": "Magemeta Test",
      "grand_total": "100.0000",
      "is_guest_customer": false,
      "created_at": "2019-10-19 10:23:11",
      "shipping_method": "flatrate_flatrate",
      "shipping": [
        {
          "name": "Magemeta Test",
          "street": "Test Street 1",
          "city": "Brunswick",
          "region": "Georgia",
          "country": null,
          "postcode": "31520",
          "telephone": "1234567890",
          "fax": null,
          "company": null
        }
      ],
      "billing": [
        {
          "name": "Magemeta Test",
          "street": "Test Street 1",
          "city": "Brunswick",
          "region": "Georgia",
          "country": null,
          "postcode": "31520",
          "telephone": "1234567890",
          "fax": null,
          "company": null
        }
      ],
      "items": [
        {
          "title": "Test Product 1",
          "sku": "Test Product 1",
          "price": 100
        },
        {
          "title": "Test Product 2",
          "sku": "Test Product 2",
          "price": 200
        }
      ]
    }
  }
}

Leave a Reply