Copyright © 2005-2020

Copies of this document may be made for your own use and for distribution to others, provided that you do not charge any fee for such copies and further provided that each copy contains this Copyright Notice, whether distributed in print or electronically.

Overview

This guide describes the RESTful API of the OpenWMS.org WMS Receiving Service module and its usage. Some general terms and definitions are explained and declared in the first part of the document whereas in the second part the usage of the API is shown in a more use-case-driven approach.

Resources

A description of all used API resources.

Representation Formats

Basically JSON is used as representation format by default if not otherwise requested or mentioned below. XML format is supported for the index pages as well, but must be requested explicitly. Furthermore a vendor specific JSON format is used to represent resource representations. Therefore it’s absolutely required the Accept header denotes the demanded type. Find the type in the examples below.

Dates in JSON

Date or datetime fields are not treated specially in JSON. Within the scope of this API a date or datetime field is always expected and rendered as JSON String in ISO8601 format with timezone information and milliseconds: yyyy-MM-dd’T’HH:mm:ss.SSSZ.

Embedded Entities

For the sake of convenience some response entities may included embedded entities or even parts of it. A reference to the actual entity is provided as HAL link as well.

Error Responses

Beside the actual representation of resources, the server may result an error response in JSON format that contains basic information about the error occurred. This information is additional to the standard HTTP status code and may help clients to identify the error cause in order to re-phrase and send the request again.

Currently there are two types of errors with their own response formats.

Server Declined Errors

This kind of errors are sent by the server runtime environment even before the request had a chance to be processed.

An example response looks like this:

{
    "timestamp": 1512400854941,
    "status": 500,
    "error": "Internal Server Error",
    "exception": "org.ameba.oauth2.InvalidTokenException",
    "message": "JWT expired at 2017-12-04T15:04:43Z. Current time: 2017-12-04T15:20:54Z, ...",
    "path": "/v1/transport-units?bk=00000000000000004711"
}

The JSON structure contains the following fields.

Property Name Description

timestamp

When the error occurred on server side

status

The http status of the error

error

A short error text

exception

Internal class name of the Java exception type

message

A more descriptive error text describing the error in detail

path

The part of the URI for the REST resource that was queried

API Declined Errors

Those errors are thrown within the REST API validation and processing logic. For example, if a client request does not match the expected format or has produced an error on server side, the API will decline the request and return a response with status client-side error (4xx).

The structure of the response is aligned to the RFC7808. An example response looks like this:

{
    "message": "LocationGroup with name [NOT_EXISTS] not found",
    "messageKey": "COMMON.LOCATION_GROUP_NOT_FOUND",
    "obj" : [ "NOT_EXISTS" ],
    "httpStatus" : "404",
    "class" : "String"
}

The JSON structure contains the following fields.

Property Name Description

message

A short error text

messageKey

An unique identifier across the API that can be used to identify and translate the error message on the client side

obj

An array of possible passed arguments to the message

httpStatus

The http status of the error

class

The arguments type

Following message keys are currently used:

Message Key Description Action

not.found

The requested resource has not been found

The resource does not exist anymore or has never existed. The resource identifier must be verified

Index

The initial HTTP request to retrieve information about all available resources looks like the following. The Index page is a public available resource and does not need any authentication.

GET /index HTTP/1.1
Host: localhost:8080

The Index resource is returned in the response body with the response status of 200-OK. This main Index lists all primary resource entities to follow next.

HTTP/1.1 200 OK
Content-Type: application/hal+json
Content-Length: 125

{
  "_links" : {
    "receiving-order-index" : {
      "href" : "http://localhost:8080/v1/receiving-orders/index"
    }
  }
}

A client application only needs to know about the agreed link names and follow the corresponding href link to navigate to further resources.

ReceivingOrder

A ReceivingOrder represents an announcement of receiving goods into the warehouse. Usually these kind of orders are sent by the ERP system prior to the actual goods receipt. A ReceivingOrder is just the envelope that contains ReceivingOrderPositions, where each position determines the expected product to receive in its quantity.

ReceivingOrder Index

The index with all possible operations on a ReceivingOrder can be retrieved with a GET request:

GET /v1/receiving-orders/index HTTP/1.1
Host: localhost:8080

The response lists all the operations possible on ReceivingOrders with a name and the corresponding href link:

HTTP/1.1 200 OK
Content-Type: application/hal+json
Content-Length: 760

{
  "_links" : {
    "receiving-order-findall" : {
      "href" : "http://localhost:8080/v1/receiving-orders"
    },
    "receiving-order-findbypkey" : {
      "href" : "http://localhost:8080/v1/receiving-orders/b65a7658-c53c-4a81-8abb-75ab67783f47"
    },
    "receiving-order-findbyorderid" : {
      "href" : "http://localhost:8080/v1/receiving-orders?orderId=4711"
    },
    "receiving-order-create" : {
      "href" : "http://localhost:8080/v1/receiving-orders"
    },
    "receiving-order-capture" : {
      "href" : "http://localhost:8080/v1/receiving-orders/b65a7658-c53c-4a81-8abb-75ab67783f47/capture"
    },
    "receiving-order-cancel" : {
      "href" : "http://localhost:8080/v1/receiving-orders/b65a7658-c53c-4a81-8abb-75ab67783f47"
    }
  }
}

Create a ReceivingOrder

The POST operation take a flat structure of a simple ReceivingOrder to create.

POST /v1/receiving-orders HTTP/1.1
Content-Type: application/json
Host: localhost:8080
Content-Length: 300

{
  "orderId" : "4712",
  "positions" : [ {
    "positionId" : "1",
    "quantityExpected" : {
      "@class" : "org.openwms.core.units.api.Piece",
      "unitType" : [ "org.openwms.core.units.api.PieceUnit", "PC" ],
      "magnitude" : 1
    },
    "product" : {
      "sku" : "SKU001"
    }
  } ]
}
Path Type Description

orderId

String

An unique identifier of the ReceivingOrder to create

positions[]

Array

An array of positions, must not be empty

positions[].positionId

String

Unique identifier of the ReceivingOrderPosition within the ReceivingOrder

positions[].quantityExpected

Object

The expected quantity of the Product

positions[].quantityExpected.@class

String

Must be one of the static values to identify the type of UOM

positions[].quantityExpected.unitType

Array

Must be one of the static values to identify the concrete UOM

positions[].quantityExpected.magnitude

Number

The amount

positions[].product.sku

String

The SKU of the expected Product

If the ReceivingOrder has been created successfully, the server returns the URI to the created resource:

HTTP/1.1 201 Created
Location: http://localhost:8080/v1/receiving-orders/d5236f64-bd1b-4493-b683-a733320c3ae3/

In case the client request did not match the server expectations because of invalid or missing fields in the request body, the server responds with:

HTTP/1.1 400 Bad Request

Find a ReceivingOrder by Persistent Key

A HTTP GET request is required to lookup a ReceivingOrder by its synthetic persistent key.

GET /v1/receiving-orders/d8099b89-bdb6-40d3-9580-d56aeadd578f HTTP/1.1
Host: localhost:8080

Unresolved directive in 2-receiving-order.adoc - include::/home/travis/build/openwms/org.openwms.wms.receiving/target/generated-snippets/order-find/request-fields.adoc[]

If the ReceivingOrder has been found, the server returns the order instance in the response body:

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 99

{
  "pKey" : "d8099b89-bdb6-40d3-9580-d56aeadd578f",
  "orderId" : "T4711",
  "state" : "CREATED"
}

In case the order does not exist, the server responds with a error of the client family because the pKey is expected to exist:

HTTP/1.1 404 Not Found
Content-Type: application/hal+json
Content-Length: 123

{
  "message" : "ReceivingOrder with pKey [unknown] does not exist",
  "messageKey" : "not.found",
  "httpStatus" : "404"
}

Find a ReceivingOrder by Order ID

A HTTP GET request is required to find a ReceivingOrder by it’s identifying business key, the order ID.

GET /v1/receiving-orders?orderId=T4711 HTTP/1.1
Host: localhost:8080

If the ReceivingOrder has been found, the server returns the order instance in the response body:

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 99

{
  "pKey" : "d8099b89-bdb6-40d3-9580-d56aeadd578f",
  "orderId" : "T4711",
  "state" : "CREATED"
}

In case the order does not exist, the server responds in the same way like Find a ReceivingOrder by Persistent Key.

Find all ReceivingOrders

A HTTP GET request to the primary resource is required to find all ReceivingOrders. Notice, this method is foreseen for UI applications and may change in future API versions.

GET /v1/receiving-orders HTTP/1.1
Host: localhost:8080

Returns an array of ReceivingOrders or an empty array:

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 205

[ {
  "pKey" : "3a02cdb7-8fea-44a6-a885-12bcd2e07cfb",
  "orderId" : "4716",
  "state" : "PROCESSED"
}, {
  "pKey" : "d8099b89-bdb6-40d3-9580-d56aeadd578f",
  "orderId" : "T4711",
  "state" : "CREATED"
} ]

Cancel a ReceivingOrder

An earlier posted ReceivingOrder can be cancelled for further processing. The client needs to send a HTTP DELETE request with the unique identifier of the order.

DELETE /v1/receiving-orders/3c9ff87c-3852-404c-8723-100dc9cd57be/ HTTP/1.1
Host: localhost:8080

If the ReceivingOrder has been cancelled, the server returns the order as part of the response body:

HTTP/1.1 204 No Content

In case the order couldn’t be cancelled because the order is already in process or has been processed, the server responds with:

HTTP/1.1 403 Forbidden
Content-Type: application/hal+json
Content-Length: 279

{
  "message" : "Cancellation of ReceivingOrder [4716] is not allowed because order is already in state [PROCESSED]",
  "messageKey" : "CANCELLATION.DENIED",
  "obj" : [ "4716", "PROCESSED", "3a02cdb7-8fea-44a6-a885-12bcd2e07cfb" ],
  "httpStatus" : "403",
  "class" : "String"
}

Capture Receivings

When products arrive at the warehouse they were usually preregistered with a ReceivingOrder and its ReceivingOrderPositions. This is called an expected receipt. Also unexpected receipts may occur, any unplanned material that needs to be stored in the warehouse without any previously received order information. Unexpected receipts may also happen as part of an expected receipt when a supplier ships more of a product that was previously announced in a ReceivingOrderPosition.

Capturing receipts happens at goods in, where the material arrives and is scanned (captured). The scanned articles are assigned to ReceivingOrderPositions and basically assigned to a TransportUnit (with all its logical compartments on top).

To capture an amount of a Product in the context of a ReceivingOrder the caller sends a POST request:

POST /v1/receiving-orders/d8099b89-bdb6-40d3-9580-d56aeadd578f/capture HTTP/1.1
Content-Type: application/json
Host: localhost:8080
Content-Length: 255

{
  "quantityReceived" : {
    "@class" : "org.openwms.core.units.api.Piece",
    "unitType" : [ "org.openwms.core.units.api.PieceUnit", "PC" ],
    "magnitude" : 1
  },
  "product" : {
    "sku" : "C1"
  },
  "barcode" : "4711",
  "loadUnitLabel" : "1"
}

If an open and not satisfied position with the same demanded Product exists in the ReceivingOrder the captured quantity is assigned to that position and the server responds with success:

HTTP/1.1 500 Internal Server Error
Content-Type: application/hal+json
Content-Length: 122

{
  "message" : "Received a goods receipt but all ReceivingOrderPositions are already satisfied",
  "httpStatus" : "500"
}

If no open positions exist in the ReceivingOrder or the Product does not fit to the demanded Products, the server cannot capture the article and responds with an error:

HTTP/1.1 500 Internal Server Error
Content-Type: application/hal+json
Content-Length: 122

{
  "message" : "Received a goods receipt but all ReceivingOrderPositions are already satisfied",
  "httpStatus" : "500"
}