Purchase Orders

Getting Purchase Orders Data

This document outlines the procedure for making API calls to retrieve purchase order data from https://easycms.fi/public_api/get_purchase_orders/. Utilize various parameters to filter and customize your data retrieval.

Purchase Orders Data Retrieval

Fetch purchase order data effectively using the below API call. Apply different parameters to filter results according to your specific needs.

Endpoint and Method

  • Endpoint: https://easycms.fi/public_api/get_purchase_orders/
  • Method: GET or POST

Parameters | Payload

Each parameter can be used individually or in combination to refine your data retrieval:

  • TOKEN (api_key): Your unique API key for authentication. How to Create API Credentials.
  • username: Your login username.
  • password: Your login password.
  • account: Your specific account ID.
  • Pagination: To manage data effectively, this endpoint supports fetching up to 50 purchase orders at a time.
  • Parameters:
    • start - Specify the starting point of the row from which to begin fetching purchase orders.
    • limit - Control the number of purchase orders returned in a single request. The maximum limit is 50, but you can opt for a smaller number based on your needs.



Filters

To manage data effectively, this endpoint supports fetching up to 50 purchase orders at a time. Each filter parameter is optional and designed to refine your search for purchase orders.

  • id: To filter by a single purchase order ID. The value needs to be an integer. Returns a single order.
  • reference: To filter by purchase order reference number. The value needs to be an integer. Returns a single order.
  • supplier_id: To filter by supplier ID. The value needs to be an integer.
  • status: To filter by purchase order status. The value needs to be an integer:
    • 1 = Draft
    • 100 = Sent to supplier
    • 110 = Preparing
    • 120 = Shipped
    • 200 = Received
    • -1 = Cancelled
  • date_from: Filter orders from date (format: YYYY-MM-DD).
  • date_to: Filter orders to date (format: YYYY-MM-DD).
  • include_lines: Include purchase order lines in the response (1 = yes, 0 = no, default: 1).



Call Examples in Different Languages


# Get all purchase orders
curl -X POST 'https://easycms.fi/public_api/get_purchase_orders' \
-H 'Authorization1: TOKEN' \
-d 'username=USERNAME&password=PASSWORD&account=ACCOUNT_ID'

# Get a specific purchase order by ID
curl -X POST 'https://easycms.fi/public_api/get_purchase_orders' \
-H 'Authorization1: TOKEN' \
-d 'username=USERNAME&password=PASSWORD&account=ACCOUNT_ID&id=123'

# Get purchase orders by supplier and status
curl -X POST 'https://easycms.fi/public_api/get_purchase_orders' \
-H 'Authorization1: TOKEN' \
-d 'username=USERNAME&password=PASSWORD&account=ACCOUNT_ID&supplier_id=5&status=200'

$curl = curl_init();
curl_setopt_array($curl, array(
  CURLOPT_URL => "https://easycms.fi/public_api/get_purchase_orders",
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_POST => true,
  CURLOPT_POSTFIELDS => http_build_query([
    'username' => 'USERNAME', 
    'password' => 'PASSWORD', 
    'account' => 'ACCOUNT_ID',
    'supplier_id' => 5,
    'status' => 200,
    'include_lines' => 1
  ]),
  CURLOPT_HTTPHEADER => array("Authorization1: TOKEN"),
));
$response = curl_exec($curl);
curl_close($curl);
echo $response;

import requests
url = "https://easycms.fi/public_api/get_purchase_orders"
headers = {"Authorization1": "TOKEN"}
payload = {
    'username': 'USERNAME', 
    'password': 'PASSWORD', 
    'account': 'ACCOUNT_ID',
    'supplier_id': 5,
    'status': 200,
    'include_lines': 1
}
response = requests.post(url, headers=headers, data=payload)
print(response.text)

HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://easycms.fi/public_api/get_purchase_orders"))
    .headers("Authorization1", "TOKEN")
    .POST(HttpRequest.BodyPublishers.ofString(
        "username=USERNAME&password=PASSWORD&account=ACCOUNT_ID&supplier_id=5&status=200"
    ))
    .build();
HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());

const https = require('https');
const data = new URLSearchParams({ 
  username: 'USERNAME', 
  password: 'PASSWORD', 
  account: 'ACCOUNT_ID',
  supplier_id: 5,
  status: 200,
  include_lines: 1
}).toString();
const options = {
  hostname: 'easycms.fi',
  path: '/public_api/get_purchase_orders',
  method: 'POST',
  headers: {
    'Authorization1': 'TOKEN',
    'Content-Type': 'application/x-www-form-urlencoded',
    'Content-Length': data.length
  }
};
const req = https.request(options, (res) => {
  let data = '';
  res.on('data', (chunk) => { data += chunk; });
  res.on('end', () => { console.log(data); });
});
req.on('error', (e) => { console.error(e); });
req.write(data);
req.end();

import React, { useEffect, useState } from 'react';
function App() {
  const [purchaseOrdersData, setPurchaseOrdersData] = useState('');
  useEffect(() => {
    const fetchData = async () => {
      try {
        const response = await fetch('https://easycms.fi/public_api/get_purchase_orders', {
          method: 'POST',
          headers: {'Authorization1': 'TOKEN', 'Content-Type': 'application/x-www-form-urlencoded'},
          body: new URLSearchParams({
            username: 'USERNAME', 
            password: 'PASSWORD', 
            account: 'ACCOUNT_ID',
            supplier_id: 5,
            status: 200
          }).toString()
        });
        const data = await response.text();
        setPurchaseOrdersData(data);
      } catch (error) {
        console.error(error);
      }
    };
    fetchData();
  }, []);
  return (<div>{purchaseOrdersData}</div>);
}
export default App;

// Kotlin example requires using a third-party library like OkHttp for POST requests with a body
// Kotlin Example using OkHttp for POST request
import okhttp3.OkHttpClient
import okhttp3.FormBody
import okhttp3.Request

fun main() {
    val client = OkHttpClient()

    val formBody = FormBody.Builder()
        .add("username", "USERNAME")
        .add("password", "PASSWORD")
        .add("account", "ACCOUNT_ID")
        .add("supplier_id", "5")
        .add("status", "200")
        .add("include_lines", "1")
        .build()

    val request = Request.Builder()
        .url("https://easycms.fi/public_api/get_purchase_orders")
        .post(formBody)
        .addHeader("Authorization1", "TOKEN")
        .build()

    client.newCall(request).execute().use { response ->
        if (!response.isSuccessful) throw IOException("Unexpected code $response")

        println(response.body?.string())
    }
}

using System;
using System.Net.Http;
using System.Threading.Tasks;
class Program
{
    static async Task Main()
    {
        var token = "TOKEN";
        var content = new FormUrlEncodedContent(new[]
        {
            new KeyValuePair("username", "USERNAME"),
            new KeyValuePair("password", "PASSWORD"),
            new KeyValuePair("account", "ACCOUNT_ID"),
            new KeyValuePair("supplier_id", "5"),
            new KeyValuePair("status", "200"),
            new KeyValuePair("include_lines", "1")
        });
        using (var httpClient = new HttpClient())
        {
            httpClient.DefaultRequestHeaders.Add("Authorization1", token);
            var response = await httpClient.PostAsync("https://easycms.fi/public_api/get_purchase_orders", content);
            if (response.IsSuccessStatusCode)
            {
                var responseData = await response.Content.ReadAsStringAsync();
                Console.WriteLine(responseData);
            }
            else
            {
                Console.WriteLine($"Error: {response.StatusCode}");
            }
        }
    }
}




Handling Endpoint Results

When you make a request to the endpoint, you receive a JSON response containing various keys and values. Here's an explanation of the response keys and their meanings:


- `start`: This represents the starting index for the data. In this case, it's set to 0, indicating that the data starts from the first item.

- `limit`: The maximum number of items returned in the response. In this example, the limit is set to 50, meaning that the response will include up to 50 items.

- `count`: The number of items included in the current response. In this case, there is 1 item in the response.

- `total_count`: The total count of items available in the dataset. In this response, there is a total of 1 item available.

- `WHERE`: Shows the filter conditions applied to the query. For example, "id = 123" or "supplier_id = 5 AND status = 200".

    

- `id`: Purchase Order ID - The unique identifier for the purchase order.
- `reference`: Reference Number - The reference number for the purchase order.
- `supplier_id`: Supplier ID - The ID of the supplier for this purchase order.
- `supplier_name`: Supplier Name - The name of the supplier.
- `status`: Status Code - The current status of the purchase order (1, 100, 110, 120, 200, or -1).
- `status_title`: Status Title - The human-readable status title:
  - draft_order
  - order_sent_to_supplier
  - supplier_preparing_for_shipment
  - supplier_shipped
  - order_received
  - cancelled
- `purchase_date`: Purchase Date - The date when the order was created.
- `delivery_date`: Delivery Date - The expected or actual delivery date.
- `total`: Total - The total amount of the purchase order.
- `discount`: Discount - Any discount applied to the order.
- `note`: Note - General notes for the order.
- `admin_note`: Admin Note - Administrative notes.
- `delivery_instructions`: Delivery Instructions - Special delivery instructions.
- `title`: Title - The title of the purchase order.
- `payer_details`: Payer Details - Information about the payer.
- `payee_details`: Payee Details - Information about the payee.
- `email`: Email - Contact email address.
- `phone`: Phone - Contact phone number.
- `shipping_address`: Shipping Address - The delivery address.
- `shipping_city_id`: Shipping City ID - The city ID for shipping.
- `shipping_country_id`: Shipping Country ID - The country ID for shipping.
- `shipping_postal`: Shipping Postal - The postal code for shipping.
- `no_vat`: No VAT - Whether VAT is excluded (1 = yes, 0 = no).
- `currency_rate`: Currency Rate - The exchange rate if applicable.
- `paid_date`: Paid Date - The date when the order was paid.
- `deleted`: Deleted - Whether the order is deleted (0 = active, 1 = deleted).
- `purchase_lines`: Purchase Lines - Array of line items (if include_lines = 1).

These key-value pairs provide comprehensive information about the purchase orders and can be used for various purposes in your application.
    

Each purchase order line item contains the following fields:

- `purchase_line_id`: Purchase Line ID - The unique identifier for the line item.
- `pid`: Product ID - The product ID for this line.
- `product_name`: Product Name - The name of the product.
- `product_title`: Product Title - The title of the product.
- `quantity`: Ordered Quantity - The quantity that was originally ordered.
  This field is read-only when order status is 200 (received).
- `received_quantity`: Received Quantity - The quantity actually received.
  This field is only editable when order status is 200 (received).
  For orders not yet received, this defaults to 0.
- `arrival_date`: Arrival Date - The actual date when the goods arrived (format: YYYY-MM-DD).
- `unit_price`: Unit Price - The selling price per unit.
- `unit_price_buy`: Unit Price Buy - The purchase price per unit.
- `vat_percent`: VAT Percent - The VAT percentage for selling.
- `vat_percent_buy`: VAT Percent Buy - The VAT percentage for buying.
- `discount`: Discount - Any discount on this line.
- `location_id`: Location ID - The storage location (format: "locationId-shelfId").
- `best_before_date`: Best Before Date - The expiry date if applicable.
- `barcode`: Barcode - The product barcode.
- `line_note`: Line Note - Notes specific to this line.
- `stock_type_id`: Stock Type ID - The type of stock.
- `supplier_id`: Supplier ID - The supplier for this line item.
- `weight`: Weight - The weight of the product.
- `weight_type`: Weight Type - The unit of weight measurement.
- `received_confirmed`: Received Confirmed - `0` = pending confirmation, `1` = confirmed and stock moved. Audit trail is logged via KLogger.

### Understanding quantity vs received_quantity

The two quantity fields serve different purposes depending on the order status:

| Order Status | `quantity` (Ordered) | `received_quantity` (Received) |
|-------------|---------------------|-------------------------------|
| Draft (1) | Editable - the qty you plan to order | 0 (not applicable yet) |
| Sent (100) | Editable | 0 (not applicable yet) |
| Preparing (110) | Editable | 0 (not applicable yet) |
| Shipped (120) | Editable | 0 (not applicable yet) |
| **Received (200)** | **Read-only** - locked once received | **Editable** - the actual qty received |
| Cancelled (-1) | Read-only | Read-only |

**Example**: You order 100 units (`quantity = 100`). When the shipment arrives, you count 95 units in good condition. You set `received_quantity = 95` while `quantity` remains 100. The difference helps track delivery discrepancies.

The admin CMS calculates totals using:
- `quantity` when status is NOT 200 (for pre-receipt calculations)
- `received_quantity` when status IS 200 (for actual received totals)
    

{
  "INFO": {
    "start": 0,
    "limit": 50,
    "count": 1,
    "total_count": 1,
    "WHERE": "id = 123"
  },
  "OUTPUT": [
    {
      "id": 123,
      "reference": 2024001,
      "supplier_id": 5,
      "supplier_name": "Supplier Oy",
      "status": 200,
      "status_title": "order_received",
      "purchase_date": "2024-01-15 10:30:00",
      "delivery_date": "2024-01-20 14:00:00",
      "total": 1500.00,
      "discount": 0.00,
      "note": "Order notes",
      "admin_note": "",
      "delivery_instructions": "Deliver to warehouse B",
      "title": "Monthly Restock Order",
      "payer_details": "",
      "payee_details": "",
      "email": "orders@supplier.com",
      "phone": "+358 40 123 4567",
      "shipping_address": "123 Industrial Street",
      "shipping_city_id": 1,
      "shipping_country_id": 74,
      "shipping_postal": "00100",
      "no_vat": 0,
      "currency_rate": 1.0,
      "paid_date": null,
      "deleted": 0,
      "purchase_lines": [
        {
          "purchase_line_id": 456,
          "pid": 12345,
          "product_name": "Product Name",
          "product_title": "Product Title",
          "quantity": 100,
          "received_quantity": 95,
          "arrival_date": "2024-01-19",
          "unit_price": 100.00,
          "unit_price_buy": 80.00,
          "vat_percent": 24.00,
          "vat_percent_buy": 24.00,
          "discount": 0.00,
          "location_id": "1-5",
          "best_before_date": "2025-12-31",
          "barcode": "1234567890123",
          "line_note": "",
          "stock_type_id": 1,
          "supplier_id": 5,
          "weight": 1.5,
          "weight_type": "kg"
        }
      ]
    }
  ]
}
      

Purchase Order Status Flow

Purchase orders follow a status flow from creation to completion:

Status Code Title Description
1 draft_order Order is in draft state, can be modified
100 order_sent_to_supplier Order has been sent to supplier
110 supplier_preparing_for_shipment Supplier is preparing the order
120 supplier_shipped Order has been shipped by supplier
200 order_received Order received - stock is updated based on received_quantity
-1 cancelled Order has been cancelled

Note: When a purchase order status changes to 200 (received), the stock levels are automatically updated based on the received_quantity field in each line item. The quantity field (ordered qty) becomes read-only at this point.


Error Handling

Here are the possible error messages and their meanings:

  • UN-AUTHORIZED - _user_name_password_is_set_but_wrong_value!: Incorrect username or password.
  • this_account_does_not_exist_or_your_credentials_do_not_match_this_account: The account doesn't exist or mismatched credentials.
  • UN-AUTHORIZED - header is set but the header value is not correct!: Incorrect authorization header value.
  • maximum_query_size_is_50_rows_per_query: Exceeded maximum limit of 50 rows per query.
  • id_must_be_a_valid_positive_integer: Invalid id parameter value.
  • reference_must_be_a_valid_positive_integer: Invalid reference parameter value.
  • purchase_order_not_found: The specified purchase order was not found.
  • supplier_id_must_be_a_valid_positive_integer: Invalid supplier_id parameter value.
  • status_must_be_a_valid_integer: Invalid status parameter value.
  • invalid_date_format_for_date_from: The date_from parameter is not in YYYY-MM-DD format.
  • invalid_date_format_for_date_to: The date_to parameter is not in YYYY-MM-DD format.
  • error_retrieving_purchase_orders_data: A database error occurred while retrieving data.
  • NOT AUTHORIZED!: Authentication failed - no valid credentials provided.