.. _stock-api:

Stock API
=========

The endpoints below ``/api/stock`` allow for batch-oriented, :ref:`idempotent <idempotency>` mass updates of product
stock quantities.

There are three different types of stock updates:

* ``PUT /api/stock/set/{idempotencyKey}`` sets a product's stock at a location to a specific, absolute quantity,

* ``PUT /api/stock/change/{idempotencyKey}`` changes a product's stock at a location by a specific, relative quantity, and

* ``PUT /api/stock/relocate/{idempotencyKey}`` moves a specific quantity of product stock from one location to another.

Each of these endpoints takes a list of independent operations which are executed in order. When doing mass updates, we
recommend sending large batches for optimum performance. The maximum allowed batch size is 1000.

All of these endpoints require an arbitrary, unique idempotency key to be specified as a path component of the request
URL. This idempotency key must be reused when retrying the same batch of operations after a server or network failure.
It must not be reused when sending a new batch of operations. See :ref:`idempotency` for further details on this. Note
that retrying batches of operations which returned ``success: false`` will not lead to a successful result, since
operation-level failures are usually caused by the operation being rejected due to logical problems (usually
insufficient stock or incorrectly specified stock locations). These will instead have to be attempted again in a new
request after fixing the original cause of failure.

For all individual stock operations, the product (article detail) for which stock should be changed must be specified by
the database ID of the corresponding article detail entity. Locations from which or to which stock can be moved can
either be a warehouse (in which case the bin location to use is chosen by a :ref:`default strategy <picking-order>`) or
a bin location. Warehouses are specified by their database ID or their code. Bin locations can either be specified by
their database ID, or by their code and the warehouse code or the database ID of the warehouse (since the bin location
code is unique on a per-warehouse basis).

**Examples of valid bin location specifications**:

.. code-block:: yaml

    "binLocation": {
        "id": 9
    }

.. code-block:: yaml

    "binLocation": {
        "code": "a1",
        "warehouseId": "2"
    }

.. code-block:: yaml

    "binLocation": {
        "code": "a1",
        "warehouseCode": "MW"
    }

**Examples of valid warehouse specifications**:

.. code-block:: yaml

    "warehouse": {
        "id": 9
    }

.. code-block:: yaml

    "warehouse": {
        "code": "MW"
    }

.. http:put:: /api/stock/set/{idempotencyKey}

    Process a batch of stock-set operations. Each operation sets the stock quantity for a product on a specific stock
    location to the specified stock quantity.

    :param string idempotencyKey: the :ref:`idempotency key <idempotency>` for the request

    :<json object [*]: an individual operation of the batch
    :<json any [*].id: an optional, arbitrary correlation ID for the operation. This will be returned as ``operationId``
        in the operation's result entry.
    :<json integer [*].articleDetailId: the database ID of the article detail (product) for which to update stock
    :<json integer [*].quantity: the stock quantity to set on the specified stock location
    :<json object [*].warehouse: a warehouse on which to set the total stock quantity for the product
    :<json integer [*].warehouse.id: the database ID of the warehouse. Either this or the warehouse's shorthand code
        must be specified.
    :<json string [*].warehouse.code: the shorthand code of the warehouse. Either this or the warehouse's database ID
        must be specified.
    :<json object [*].binLocation: a bin location on which to set the total stock quantity for the product
    :<json integer [*].binLocation.id: the database ID of the bin location. Either this or a valid combination of
        bin location code and a valid warehouse identifier must be specified.
    :<json string [*].binLocation.code: the shorthand code of the bin location. If this is used to identify the bin
        location, the warehouse must also be specified by its database ID or its shorthand code.
    :<json integer [*].binLocation.warehouseId: the database ID of the warehouse containing the bin location
    :<json string [*].binLocation.warehouseCode: the shorthand code of the warehouse containing the bin location

    :>json boolean success: ``true`` if all operations of the batch were executed successfully, ``false`` otherwise
    :>json string message: an explanatory message which is present when there was at least one unsuccessful operation
        in the batch
    :>json string idempotencyKey: the :ref:`idempotency key <idempotency>` of the batch
    :>json timestamp createdAt: the point in time when all operations in the batch were completed
    :>json any results[*].operationId: the value of the ``id`` property of the operation, if it was present in the
        request
    :>json boolean results[*].success: ``true`` if the operation was completed successfully, ``false`` otherwise. Note
        that retrying the batch with the same idempotency key will not change the result for this operation.
    :>json string results[*].message: an explanation of what went wrong which is only present when the operation was not
        successful

    **Example request**:

    .. http:example:: curl wget httpie

        PUT /api/stock/set/18fc8921-8da5-4f0e-b368-ef0b66dd4ca0 HTTP/1.1
        Content-Type: application/json
        Host: localhost

        [
            {
                "articleDetailId": 114,
                "quantity": 200,
                "warehouse": {
                    "id": 1
                }
            },
            {
                "articleDetailId": 113,
                "quantity": 100,
                "binLocation": {
                    "id": 45
                }
            }
        ]

    **Example response**:

    .. code-block:: http

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

        {
            "success": true,
            "idempotencyKey": "18fc8921-8da5-4f0e-b368-ef0b66dd4ca0",
            "createdAt": "2019-03-12T16:45:04+0200",
            "results": [
                {
                    "success": true
                },
                {
                    "success": true
                }
            ]
        }

.. http:put:: /api/stock/change/{idempotencyKey}

    Process a batch of stock-change operations. Each operation changes the stock quantity for a product on a specific
    stock location by a positive or negative value.

    :param string idempotencyKey: the :ref:`idempotency key <idempotency>` for the request

    :<json object [*]: an individual operation of the batch
    :<json any [*].id: an optional, arbitrary correlation ID for the operation. This will be returned as ``operationId``
        in the operation's result entry.
    :<json integer [*].articleDetailId: the database ID of the article detail (product) for which to update stock
    :<json integer [*].quantity: the quantity to change the stock value by. Must not be 0.
    :<json object [*].warehouse: a warehouse for which to change the total stock quantity for the product
    :<json integer [*].warehouse.id: the database ID of the warehouse. Either this or the warehouse's shorthand code
        must be specified.
    :<json string [*].warehouse.code: the shorthand code of the warehouse. Either this or the warehouse's database ID
        must be specified.
    :<json object [*].binLocation: a bin location on which to change the stock quantity for the product
    :<json integer [*].binLocation.id: the database ID of the bin location. Either this or a valid combination of
        bin location code and a valid warehouse identifier must be specified.
    :<json string [*].binLocation.code: the shorthand code of the bin location. If this is used to identify the bin
        location, the warehouse must also be specified by its database ID or its shorthand code.
    :<json integer [*].binLocation.warehouseId: the database ID of the warehouse containing the bin location
    :<json string [*].binLocation.warehouseCode: the shorthand code of the warehouse containing the bin location

    :>json boolean success: ``true`` if all operations of the batch were executed successfully, ``false`` otherwise
    :>json string message: an explanatory message which is present when there was at least one unsuccessful operation
        in the batch
    :>json string idempotencyKey: the :ref:`idempotency key <idempotency>` of the batch
    :>json timestamp createdAt: the point in time when all operations in the batch were completed
    :>json any results[*].operationId: the value of the ``id`` property of the operation, if it was present in the
        request
    :>json boolean results[*].success: ``true`` if the operation was completed successfully, ``false`` otherwise. Note
        that retrying the batch with the same idempotency key will not change the result for this operation.
    :>json string results[*].message: an explanation of what went wrong which is only present when the operation was not
        successful

    **Example request**:

    .. http:example:: curl wget httpie

        PUT /api/stock/change/a352326b-80bc-40e6-8a90-2576d047522a HTTP/1.1
        Content-Type: application/json
        Host: localhost

        [
            {
                "articleDetailId": 171,
                "quantity": -5,
                "warehouse": {
                    "id": 1
                }
            },
            {
                "articleDetailId": 172,
                "quantity": 10,
                "binLocation": {
                    "id": 14
                }
            }
        ]

    **Example response**:

    .. code-block:: http

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

        {
            "success": true,
            "idempotencyKey": "a352326b-80bc-40e6-8a90-2576d047522a",
            "createdAt": "2019-01-01T12:00:00+0200",
            "results": [
                {
                    "success": true
                },
                {
                    "success": true
                }
            ]
        }

.. http:put:: /api/stock/relocate/{idempotencyKey}

    Process a batch of stock-relocate operations. Each operation moves stock of a specified product from a source stock
    location to a destination stock location. The operations can either move a specific quantity of stock or all stock
    currently residing on the source stock location.

    :param string idempotencyKey: the :ref:`idempotency key <idempotency>` for the request

    :<json object [*]: an individual operation of the batch
    :<json any [*].id: an optional, arbitrary correlation ID for the operation. This will be returned as ``operationId``
        in the operation's result entry.
    :<json integer [*].articleDetailId: the database ID of the article detail (product) for which to move stock
    :<json integer|string [*].quantity: the quantity of stock to move as a number, or the string "all" to move all
        of the product's stock which currently resides on the source stock location
    :<json object [*].(source|destination): the source stock location from which to move stock and the destination stock
        location to which to move the stock. Both must be specified and can each either be a warehouse or a bin
        location.
    :<json object [*].(source|destination).warehouse: a warehouse from/to which to move stock.
    :<json integer [*].(source|destination).warehouse.id: the database ID of the warehouse. Either this or the
        warehouse's shorthand code must be specified.
    :<json string [*].(source|destination).warehouse.code: the shorthand code of the warehouse. Either this or the
        warehouse's database ID must be specified.
    :<json object [*].(source|destination).binLocation: a bin location from/to which to move stock
    :<json integer [*].(source|destination).binLocation.id: the database ID of the bin location. Either this or a valid
        combination of bin location code and a valid warehouse identifier must be specified.
    :<json string [*].(source|destination).binLocation.code: the shorthand code of the bin location. If this is used to
        identify the bin location, the warehouse must also be specified by its database ID or its shorthand code.
    :<json integer [*].(source|destination).binLocation.warehouseId: the database ID of the warehouse containing the bin
        location
    :<json string [*].(source|destination).binLocation.warehouseCode: the shorthand code of the warehouse containing the
        bin location

    :>json boolean success: ``true`` if all operations of the batch were executed successfully, ``false`` otherwise
    :>json string message: an explanatory message which is present when there was at least one unsuccessful operation
        in the batch
    :>json string idempotencyKey: the :ref:`idempotency key <idempotency>` of the batch
    :>json timestamp createdAt: the point in time when all operations in the batch were completed
    :>json any results[*].operationId: the value of the ``id`` property of the operation, if it was present in the
        request
    :>json boolean results[*].success: ``true`` if the operation was completed successfully, ``false`` otherwise. Note
        that retrying the batch with the same idempotency key will not change the result for this operation.
    :>json string results[*].message: an explanation of what went wrong which is only present when the operation was not
        successful

    **Example request**:

    .. http:example:: curl wget httpie

        PUT /api/stock/relocate/8dcc60d8-8d09-4b2e-8b72-4aeb4e812ded HTTP/1.1
        Content-Type: application/json
        Host: localhost

        [
            {
                "articleDetailId": 113,
                "quantity": 10,
                "source": {
                    "binLocation": {
                        "id": 45
                    }
                },
                "destination": {
                    "binLocation": {
                        "id": 46
                    }
                }
            },
            {
                "articleDetailId": 120,
                "quantity": "all",
                "source": {
                    "warehouse": {
                        "id": 1
                    }
                },
                "destination": {
                    "warehouse": {
                        "id": 2
                    }
                }
            }
        ]

    **Example response**:

    .. code-block:: http

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

        {
            "success": true,
            "idempotencyKey": "8dcc60d8-8d09-4b2e-8b72-4aeb4e812ded",
            "createdAt": "2019-08-24T09:03:17+0200",
            "results": [
                {
                    "success": true
                },
                {
                    "success": true
                }
            ]
        }
