Get sales order data using Graphql in Magento 2.

GraphQL is a new concept from Magento 2.3 version in Magento eCommerce. Using Graphql we can get sales order data. There are many default core module uses GraphQl for getting data like, Product, CMS Page, and Block, Customer module uses Graphql for getting data of a specific entity. Magento Doesn’t use GraphQl for Sales Specific entity in core module.

I have just demonstrated how to get order data using GraphQl in Magento 2 based on order id. We can get details of Order basic entity, billing address and shipping address and Used items in Order.

For Create Order data GraphQl we need to create Module in Magento 2, If you are new to GraphQl, Please refer GraphQl Basics info for Magento 2

You need to create first registration.php and module.xml file for defining our module. Here I have used Rbj as Packagename where SalesGraphQl is a module name.

Path: app/code/Rbj/SalesGraphQl/registration.php

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

Create module.xml file, Path: app/code/Rbj/SalesGraphQl/etc/module.xml

<?xml version="1.0"?>

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
    <module name="Rbj_SalesGraphQl">
        <sequence>
            <module name="Magento_Sales"/>
            <module name="Magento_GraphQl"/>
        </sequence>
    </module>
</config>

Our Module depends on GraphQL and Sales Module so we have given dependency on 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 describes the what data can be queried. So You can define your query data basic skeleton under the schema.graphqls file.

Createschema.graphqls file, Path: app/code/Rbj/SalesGraphQl/etc/schema.graphqls

type Query {
    salesOrder (
        id: Int @doc(description: "Id of the Sales Order")
    ): SalesOrder @resolver(class: "Rbj\\SalesGraphQl\\Model\\Resolver\\SalesOrder") @doc(description: "The Sales Order query returns information about a Sales order")
}

type SalesOrder @doc(description: "Sales Order graphql gather Data of specific order information") {
    increment_id: String @doc(description: "Increment Id of Sales Order")
    customer_name: String @doc(description: "Customername of Sales Order")
    grand_total: String @doc(description: "Grand total of Sales Order")
    is_guest_customer : Boolean @doc(description: "Specifies if this otder was placed by Guest cusotmer")
    created_at: String @doc(description: "Creation 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: "Rbj\\SalesGraphQl\\Model\\Resolver\\Shipping")
    billing: [Billing] @doc(description: "An array of billing data of order") @resolver(class: "Rbj\\SalesGraphQl\\Model\\Resolver\\Billing")
    items: [Items] @doc(description: "An array of all items data of order") @resolver(class: "Rbj\\SalesGraphQl\\Model\\Resolver\\Items")
}

type Billing @doc(description: "An array containing all the billing fields of order") {
	name: String @doc(description: "Billing City of Sales Order")
    street: String @doc(description: "Billing City of Sales Order")
    city: String @doc(description: "Billing City of Sales Order")
    region: String @doc(description: "Billing City of Sales Order")
    country: String @doc(description: "Billing City of Sales Order")
    postcode: String @doc(description: "Billing City of Sales Order")
    telephone: String @doc(description: "Billing City of Sales Order")
    fax: String @doc(description: "Billing City of Sales Order")
    company: String @doc(description: "Billing City of Sales Order")
}

type Shipping @doc(description: "An array containing all the shipping fields of order") {
	name: String @doc(description: "Shipping City of Sales Order")
    street: String @doc(description: "Shipping City of Sales Order")
    city: String @doc(description: "Shipping City of Sales Order")
    region: String @doc(description: "Shipping City of Sales Order")
    country: String @doc(description: "Shipping City of Sales Order")
    postcode: String @doc(description: "Shipping City of Sales Order")
    telephone: String @doc(description: "Shipping City of Sales Order")
    fax: String @doc(description: "Shipping City of Sales Order")
    company: String @doc(description: "Shipping City of Sales Order")
}

type Items @doc(description: "An array containing all the items of 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")
}

I have to define schema.graphql file with multiple different type for billing, shipping and items type to get info of each entity of order data. Each type has a specific field to display in GraphQl result.

You need to define each field in schema file, you want to show in response for a graphQl query. For Billing Schema type, You need to specify each field related to billing, For Shipping Schema, you need to specify a required field, same for Items type you need to pass required field to show as response.

Now we need to write our custom logic for the dynamic value of order data. For that, we need to create a resolver php file to get a dynamic value of specific order.

Create SalesOrder.php file,
Path: app/code/Rbj/SalesGraphQl/Model/Resolver/SalesOrder.php

<?php
declare(strict_types=1);

namespace Rbj\SalesGraphQl\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, used 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 specified'));
        }

        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();
            }
            $pageData = [
                '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 $pageData;
    }
}

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

Get Shipping address of Placed order, We have created a separate file for fetch Shipping address data in GraphQl response. file is used for fetch shipping records of an order.

Path: app/code/Rbj/SalesGraphQl/Model/Resolver/Shipping.php

<?php
declare(strict_types=1);

namespace Rbj\SalesGraphQl\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;
    }
}

For Get Billing address of Placed order, We have created a separate file for fetch Billing address data in GraphQl response.
Path: app/code/Rbj/SalesGraphQl/Model/Resolver/Billing.php

<?php
declare(strict_types=1);

namespace Rbj\SalesGraphQl\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;
    }
}

For Display all the items of Order, We need to create Items.php as defined in the schema file. We got a response as an array of items for an placed order.

Path: app/code/Rbj/SalesGraphQl/Model/Resolver/Items.php

<?php
declare(strict_types=1);

namespace Rbj\SalesGraphQl\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 Product Items of 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 Run Upgrade command to install our custom Sales module.

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

You can check your GraphQL query response in a browser by installing chrome extension ChromeiQL or Altair GraphQL addon.

sales order data by id Graphql
Magento 2 Get sales order data by id Graphql

In Request Body, You need to pass the required data(field) to request payload for getting a response of Sales Order record,

We have pass sales_order id as 2 for fetch records of Sales Order Id 2. Based on define id in request result will be shown data of order of specific id.

Request Payload,

{
  salesOrder (id: 2) {
      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
      }
  }
}

Result for Order id 2, I have added two products for order id 2 so in response they display both items in items array with billing and shipping info:

{
  "data": {
    "salesOrder": {
      "increment_id": "000000002",
      "customer_name": "Rakesh Jesadiya",
      "grand_total": "723.0000",
      "is_guest_customer": false,
      "created_at": "2018-11-18 13:42:23",
      "shipping_method": "flatrate_flatrate",
      "shipping": [
        {
          "name": "Rakesh Jesadiya",
          "street": "Test 1",
          "city": "Ahmedabad",
          "region": "Georgia",
          "country": null,
          "postcode": "45455",
          "telephone": "1234567890",
          "fax": null,
          "company": null
        }
      ],
      "billing": [
        {
          "name": "Rb Biling J Billing",
          "street": "Abcd 1",
          "city": "Ahmedabad",
          "region": "California",
          "country": null,
          "postcode": "45454",
          "telephone": "12312345",
          "fax": null,
          "company": "Test"
        }
      ],
      "items": [
        {
          "title": "Test Product 1",
          "sku": "Test Product 1",
          "price": 100
        },
        {
          "title": "Test Product 2",
          "sku": "Test Product 2",
          "price": 199
        }
      ]
    }
  }
}