Skip to content

Instantly share code, notes, and snippets.

@anstak
Last active March 14, 2019 15:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save anstak/01754c4fb59acd1822c9a76f4775a5dc to your computer and use it in GitHub Desktop.
Save anstak/01754c4fb59acd1822c9a76f4775a5dc to your computer and use it in GitHub Desktop.
Разработать микросервис на PHP для работы с Woocommerce через Rest API

Разработать микросервис на PHP для работы с Woocommerce через Rest API.

  • Микросервис должен работать на простом хостинге, т.е. нельзя использовать composer. Установка на хостинг должна проходить без бубна, просто распаковать в папку сайта, и все должно заработать.
  • Для коннекта к Woocommerce использовать официальную PHP библиотеку https://github.com/woocommerce/wc-api-php, но т.к. composer использовать нельзя, то просто скачать ее в корень.
  • Для работы с микросервисом будет использоваться JSON-RPC 2.0, подробности https://habr.com/ru/post/441854/.
  • Ниже я дам техническое описание, обязательно нужно посмотреть пометки внутри json и между ними, и только потом выполнять, т.к. для того что бы не было дублирования кода, лучше делать Модели для order и product.

Описание микросервиса:

  1. Все запросы отправляются с Content-Type: application/json, т.е. принимают JSON и отдают JSON:
  2. Урл для работы с микросервисом /api/v1 или /api/v1.php
  3. Методы: 3.1 Запрос:
{
  "id": "JsonRpcClient",
  "jsonrpc": "2.0",
  "method": "getProducts",
  "params": {
    "engine": "woocommerce",
    "url": 'https://hello-baby.store'
    "consumer_key": "ck_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
    "consumer_secret": "cs_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
    "page": 1,
    "per_page": 20,
    "search": ""
  }
}

Ответ от сервера HTTP/1.1 200 OK:

{
  "id": "JsonRpcClient",
  "jsonrpc": "2.0",
  "result": {
    "page": 1,
    "per_page": 20,
    "search": "",
    "products": [
       // тут array из продкутов, столько сколько указано в per_page или по умолчанию 50
      {
         "id":53,
         "name":"\u0426\u0438\u0444\u0440\u044b",
         "slug":"cifry",
         "permalink":"https:\/\/hello-baby.store\/product\/cifry\/",
         "status":"publish",
         "description":"",
         "short_description":"",
         "sku":"sku3",
         "price":"420",
         "regular_price":"420",
         "price_html":"<span class=\"woocommerce-Price-amount amount\"><span class=\"woocommerce-Price-currencySymbol\">&#8381;<\/span>420.00<\/span>",
         "manage_stock":false,
         "stock_quantity":null,
         "stock_status":"instock",
         "categories":[
            {
               "id":16,
               "name":"\u041f\u043e\u0442\u0435\u0448\u043a\u0438",
               "slug":"poteshki"
            }
         ],
        "tags":[тут tags],
        "images":[тут images],
        "attributes": [тут attributes],
        "default_attributes": [тут default_attributes],
        "links": [тут _links]
      }
    ]
  }
}

Если consumer_key и consumer_secret не проходят авторизацию в woocommerce, то ответ (HTTP/1.1 401) такой:

{
  "id": "JsonRpcClient",
  "jsonrpc": "2.0",
  "error": {
    "status": "status от woocommerce или 401",
    "code": "code от woocommerce или unauthorized"
    "message": "Unauthorized access to https://hello-baby.store"
  }
}

Если в engine стоит не woocommerce, то ответ (HTTP/1.1 500) такой:

{
  "id": "JsonRpcClient",
  "jsonrpc": "2.0",
  "error": {
    "status": "500",
    "code": "available_only_woocommerce",
    "message": "Available only Woocommerce"
  }
}

Что происходит на бэке:

$woocommerce = new Client(
    'https://hello-baby.store', 
    'ck_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX', 
    'cs_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
    [
        'version' => 'wc/v3',
    ]
);

$woocommerce->get('products', Array("page" => 1, "per_page": 20))
  • Если мы в запросе НЕ ОТПРАВЛЕМ "page", "per_page" или "search" то отдавать по дефолту первую страницу и 50 продуктов.
  • В ответе обязательно указать текущие "page", "per_page" и "search". Если "search" пустая, то отдаем пустую строку "".
  • Теперь нужно сделать преобразование ответа от woocommerce списка продуктов. Можете посмотреть как выглядит ответ тут https://woocommerce.github.io/woocommerce-rest-api-docs/?php#list-all-products Нам нужно каждый продукт преобразовать в такой вид (удалить лишнее):
  {
    "id":56,
    "name":"\u0410\u043b\u0444\u0430\u0432\u0438\u0442",
    "slug":"alfavit",
    "permalink":"https:\/\/hello-baby.store\/product\/alfavit\/",
    "date_created_gmt": "2017-03-23T17:03:12",
    "date_modified_gmt": "2017-03-23T17:03:12",    
    "status":"publish",
    "description":"<p>\u0410\u043b\u0444\u0430\u0432\u0438\u0442<\/p>\n",
    "short_description":"",
    "sku":"sku1",
    "price":"890",
    "regular_price":"890",
    "price_html":"<span class=\"woocommerce-Price-amount amount\"><span class=\"woocommerce-Price-currencySymbol\">&#8381;<\/span>890.00<\/span>",
    "manage_stock":false,
    "stock_quantity":null,
    "stock_status":"instock",
    "categories":[тут categories],
    "tags":[тут tags],
    "images":[тут images],
    "attributes": [тут attributes],
    "default_attributes": [тут default_attributes],
    "links": [тут _links]
}

3.2 Запрос:

{
  "id": "JsonRpcClient",
  "jsonrpc": "2.0",
  "method": "getOrders",
  "params": {
    "engine": "woocommerce",
    "url": 'https://hello-baby.store'
    "consumer_key": "ck_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
    "consumer_secret": "cs_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
    "page": 1,
    "per_page": 50,
    "search": ""
  }
}

Ответ от сервера HTTP/1.1 200 OK:

Тут я сразу делаю пометки, какие поля переименовывем, и модифицируем. Если поля нет то оно не нужно.

{
  "id": "JsonRpcClient",
  "jsonrpc": "2.0",
  "result": {
    "page": 1,
    "per_page": 20,
    "search": "",
    "orders": [
      {
          "id": 727,
          "order_key": "wc_order_58d2d042d1d",
          "status": "processing",
          "currency": "USD",
          "date_created_gmt": "2017-03-22T16:28:02",
          "date_modified_gmt": "2017-03-22T16:28:08",
          "discount_total": "0.00",
          "shipping_total": "10.00",
          "total": "29.35",
          "customer_note": "",
          "customer": { это переименованое поле "billing"
            "name": "John Doe", это first_name . ' ' . last_name
            "address": "969 Market", это address_1 . ' ' . address_2
            "city": "San Francisco",
            "state": "CA",
            "postcode": "94103",
            "country": "US",
            "email": "john.doe@example.com",
            "phone": "(555) 555-5555"
          }
          "date_paid_gmt": "2017-03-22T19:28:08",
          "date_completed_gmt": null,
          "cart_items": [ это переименованое поле "line_items", часть полей удалена
            {
              "id": 315,
              "name": "Woo Single #1",
              "product_id": 93,
              "variation_id": 0,
              "quantity": 2,
              "subtotal": "6.00",
              "total": "6.00",
              "sku": "",
              "price": 3
            }
          ],
          "additional_items": [тут merge двух array "shipping_lines" и "tax_lines", но в каждом элементе нужно добавить type "shipping" или "tax" соответственно
            {
              "type": "tax",
              "id": 318,
              "rate_code": "US-CA-STATE TAX",
              "rate_id": 75,
              "label": "State Tax",
              "compound": false,
              "tax_total": "1.35",
              "shipping_tax_total": "0.00",
              "meta_data": []
            },
            {
              "type": "shipping",
              "id": 317,
              "method_title": "Flat Rate",
              "method_id": "flat_rate",
              "total": "10.00",
              "total_tax": "0.00",
              "taxes": [],
              "meta_data": []
            }
          ],
          "links": [тут _links]
        }      
    ]
  }
}

Алгоритм работы такой же как и с products, так же должны быть ошибки на engine и неправильные ключи,

Здесь так же должен быть "page", "per_page" и "search", только запрос к Woocommerce $woocommerce->get('orders', ..параметры).

3.3 Это последний метод

Запрос:

{
  "id": "JsonRpcClient",
  "jsonrpc": "2.0",
  "method": "createOrder",
  "params": {
    "engine": "woocommerce",
    "url": 'https://hello-baby.store'
    "consumer_key": "ck_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
    "consumer_secret": "cs_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
    "order": {
      'set_paid': true,
      "currency": "RUB",
      "status": "completed",
      "customer": { это поле должно дублировать как в shipping так и в billing, обязательно только поля name и address, остальные могут быть пустыми
          'name': 'John Doe', в woocommerce есть first_name и last_name, это мы записываем в first_name
          'address': '969 Market', это будет в поле "address_1"
          'city': 'San Francisco',
          'state': 'CA',
          'postcode': '94103',
          'country': 'US',
          'email': 'john.doe@example.com',
          'phone': '(555) 555-5555'      
      },
      "cart_items": [ это line_items
        [
          "name": "Товар 1 со скидкой 30 руб"
          'product_id': 93,
          'quantity': 2,
          'subtotal': '420'
          'total': '390'
        ],
        [
          "name": "Товар 2 без скидки"
          'product_id': 93,
          'quantity': 1,
          'subtotal': '890'
          'total': '890'
        ]
      ],
      "additional_items": [ // тут по полю type определяем что это и создаем 'shipping_lines'
        {
          "type": "shipping",
          'method_id' => 'flat_rate',
          'method_title' => 'Flat Rate',
          "total": 90, 
        }
      ]
    }
  }
}

В ответ должен прилететь сохраненный и преобразованый order, по тем же правилам что и в getOrders

{
  "id": "JsonRpcClient",
  "jsonrpc": "2.0", 
  тут естественно "page", "per_page" и "search" уже не нужны, т.к. в order передаем только что созданый заказ
  "result": {
    "order": {
          "id": 727,
          "order_key": "wc_order_58d2d042d1d",
          "status": "processing",
          "currency": "USD",
          "date_created_gmt": "2017-03-22T16:28:02",
          "date_modified_gmt": "2017-03-22T16:28:08",
          "discount_total": "0.00",
          "shipping_total": "10.00",
          "total": "29.35",
          "customer_note": "",
          "customer": { это переименованое поле "billing"
            "name": "John Doe", это first_name . ' ' . last_name
            "address": "969 Market", это address_1 . ' ' . address_2
            "city": "San Francisco",
            "state": "CA",
            "postcode": "94103",
            "country": "US",
            "email": "john.doe@example.com",
            "phone": "(555) 555-5555"
          }
          "date_paid_gmt": "2017-03-22T19:28:08",
          "date_completed_gmt": null,
          "cart_items": [ это переименованое поле "line_items", часть полей удалена
            {
              "id": 315,
              "name": "Woo Single #1",
              "product_id": 93,
              "variation_id": 0,
              "quantity": 2,
              "subtotal": "6.00",
              "total": "6.00",
              "sku": "",
              "price": 3
            }
          ],
          "additional_items": [тут merge двух array "shipping_lines" и "tax_lines", но в каждом элементе нужно добавить type "shipping" или "tax" соответственно
            {
              "type": "tax",
              "id": 318,
              "rate_code": "US-CA-STATE TAX",
              "rate_id": 75,
              "label": "State Tax",
              "compound": false,
              "tax_total": "1.35",
              "shipping_tax_total": "0.00",
              "meta_data": []
            },
            {
              "type": "shipping",
              "id": 317,
              "method_title": "Flat Rate",
              "method_id": "flat_rate",
              "total": "10.00",
              "total_tax": "0.00",
              "taxes": [],
              "meta_data": []
            }
          ],
          "links": [тут _links]
        }
  }
}

При создании заказа так же должна быть проверка на engine и ключи, но еще добавляется обработка ошибок от самого woocommerce. Если вдруг у нас не будет какого-то обязательного поля, от woocommerce прилетит ошибка, ее нужно так же передать.

{
  "id": "JsonRpcClient",
  "jsonrpc": "2.0",
  "error": {
    "status": "тут статус от woocommerce",
    "code": "тут code от woocommerce",
    "message": "тут message от woocommerce"
  }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment