Domain model

The domain model of the SalesOrders-API consists of the core object types SalesOrderDraft, SalesOrder, Production, Pickup and Delivery.

In essence, a SalesOrderDraft represents an shopping basket in preparation. Once the preparation is done, the draft gets finalized and becomes an active shopping basket. In that state the enfore platform, e.g. the enforePOS application, can process it to become a SalesOrder which tracks the Production and fulfillment (Pickup, Shipment) of the items.

SalesOrderDraft

A SalesOrderDraft represents an active shopping basket in preparation. It can be (almost) freely modified. For example, items may be added or removed and different fulfillment options may be added, removed or updated as necessary.

Sales order draft lifecycle

A sales order draft is essentially a helper object for the creation of a sales order. The normal flow is that a sales order draft is created, items and fulfillments are added, removed, and modified, and then it is finalized to become an active shopping basket. In that state it is SalesOrderDraft anymore.

For example, to create a sales order for two products and with some customer information, the following endpoints would be called (payload/response omitted for brevity):

  1. POST /org/{org-id}/sales-order-drafts/ - create a new draft
  2. PUT /org/{org-id}/sales-order-drafts/{sales-order-draft-id}/customer - add customer information
  3. POST /org/{org-id}/sales-order-drafts/{sales-order-draft-id}/items - add first item
  4. POST /org/{org-id}/sales-order-drafts/{sales-order-draft-id}/items - add second item
  5. POST /org/{org-id}/sales-order-drafts/{sales-order-draft-id}/patch with SalesOrderDraftFinalizationRequest - finalize draft

Once created, a sales order draft exists until it either is explicitly deleted (via DELETE /org/{org-id}/sales-order-drafts/{sales-order-draft-id}) or until it is finalized.

Operations on a sales order draft

Between the creation of a new sales order draft and its explicit deletion or finalization, clients may perform any number of operations on the draft.

The order of those operations is not limited by the API. For example, one could create a draft, add two items, update the first item, add customer information, add a pickup, remove the second item, update the customer information and only then finalize the draft.

The only limitations are defined by the need to reference items from the fulfillments (pickups and deliveries). While it is possible to add an "empty" fulfillment (one without any items), for an item to be part of a fulfillment, the item has to first exist.

Note that the deletion of an item will remove all references to the item from any fulfillments or other items that currently reference it. This may cause a fulfillment to become "empty". Such fulfillments are removed when the draft is finalized.

SalesOrder

An SalesOrder represents a closed shopping basket or finalized list of items that are to be sold. It may still be unconfirmed and can be canceled, but its "content" (i.e., the items and additional information such as the customer) cannot be changed anymore.

Sales order lifecycle

The lifecycle of a sales order is relatively simple. The initial state is NEW and there are the three final states REJECTED, COMPLETED, and CANCELED. In between, a sales order may be put ON_HOLD at any time:

State diagram: Sales order

The meaning of the states is as follows:

StateMeaning
NEWThe order has been newly create and must not be either confirmed or rejected by the merchant.
CONFIRMEDThe order has been confirmed by the merchant which means that he intends to fulfill it.
REJECTEDThe order has been rejected by the merchant which means that he does not accept it and it won't be fulfilled.
IN_PROCESSThe order is being fulfilled. That is, items are produced and/or pickups/deliveries are active/outstanding.
COMPLETEDThe order has been completed. That is, all items have been produced and fulfilled (picked up or delivery) as necessary.
CANCELEDThe order has been canceled. That is, it once was confirmed any may have been partially fulfilled but for some reason it was decided to not complete it.
ON_HOLDThe order has temporarily been put "on hold". That is, the order and its depending items (productions, pickups, deliveries) cannot progress further except by returning to the previous state or by being canceled.

A sales order might have related object such as productions and fulfillments. Those related objects are separate resource in the API with their own status but the sales order holds links to the objects it is related to as well as an aggregated status.

The production_information field holds a SalesOrderProductionInformation structure that holds links to and an aggregated status for all productions related to the sales order (i.e., productions for items that are sold via the order).

The fulfillment_information field holds a SalesOrderFulfillmentInformation structure that holds links to and an aggregated status for all fulfillments related to the sales order (i.e., pickups and deliveries for items that are sold via the order).

The invoice_information field holds a SalesOrderInvoiceInformation structure that holds links to and an aggregated status for all invoices related to the sales order (i.e., invoices for the sales order or parts of the sales order).

The aggregated status only provides a rough overview on the status of the related objects:

StateMeaning
NOT_NECESSARYThere are no such related objects. For example, an order that is completely fulfilled "over the counter" would have NOT_NECESSARY as fulfillment_information.aggregated_status
PENDINGThere are related objects and none of them have been completed yet.
PARTLY_COMPLETEDThere are related objects and at least one of them has been completed and at least another one is not completed yet.
COMPLETEDThere are related objects and all of them are completed.

Note that the meaning of "completed" differs depending on the type of related object. For a Production it means that the item has been produced. For an Invoice it means that it has been fully paid.

Also note that related objects are created when the sales order gets CONFIRMED. That is a NEW or REJECTED order won't have related objects (yet).

Edge cases

While SalesOrders-API is focussed on the "retail" vertical and tries to provide a domain-specific view on the business data, the enfore platform provides some advanced features that cannot easily be mapped to this domain-specific view.

For example, for the "gastro" vertical, the platform allows "gastro orders" be be modified, even after they have already been confirmed and partly fulfilled (e.g., somone ordering a second drink). While such "gastro orders" should not be made available via the SalesOrders-API, we currently cannot easily distingush between "retail orders" and "gastro orders". Therefore, in an organization with mixed registers, the SalesOrders-API might expose such "gastro ordes". Those orders can be interacted with via the API just fine, but contrary to regular SalesOrder objects, they may exhibit mutations (e.g., an added item) that normally do not occur.