Copyright (C) 2018-2023 The Open Library Foundation
This software is distributed under the terms of the Apache License, Version 2.0. See the file "LICENSE" for more information.
This is the Orders business logic module.
- In case an acquisition unit has to be assigned to the Order it is required that user should have
orders.acquisitions-units-assignments.assign
to create a purchase order - In case an acquisition unit has to be modified(added/deleted) in the order, the user should have
orders.acquisitions-units-assignments.manage
to update a purchase Order - If the setting "isApprovalRequired" is set to true,an order approval is required to
OPEN
an order and the user should haveorders.item.approve
permissions toapprove
an order
Upon receiving a request to create a PO, it does the following:
- Validate PO content (vendor, acquisition units, settings based validation like order lines limit and etc.); then
- Save a PO object in
Pending
status; then - Retrieve the
id
of the PO and pass that to the related PO lines; then - Save the PO lines; then
- In case an order is in
Open
status and updates are required in the Inventory, it does the following:- Find or create instance record; then
- Update PO lines with instance record identifier; then
- Find or create holding record; then
- Find or create item record per unit of physical/electronic quantity identified in the order line record
- Update a PO object; then
- Retrieve the encumbrance transactions associated with each PO line based on fund distributions; then
- Make the appropriate encumbrance transactions against the associated funds
Upon receiving a request to update a PO, it does the following:
- validate PO content (vendor, acquisition units, settings based validation like order lines limit and etc.); then
- if provided PO doesn't contain PO Lines, just update the PO information via the
PUT /orders-storage/purchase-orders/<id>
endpoint - if provided PO contain PO Lines:
- Get the current list of PO Lines for this order; then
- Compare the provided list of PO Lines with what's in the database:
- if PO Line already exists, update it and any sub-objects
- if PO Line exists in the database, but not in the request, delete this PO Line
- if PO Line exists in the request but not in the database, create PO Line
- In case an order's status changes from
Pending
toOpen
and updates are required in the Inventory, it does the following:- Find or create instance record; then
- Update PO lines with instance record identifier; then
- Find or create holding record; then
- Find or create item record per unit of physical/electronic quantity identified in the order line record
- Update a PO object with
Open
status
Upon receiving a request to delete a PO, it does the following:
- Validate if PO is not restricted by acquisitions units or a user is a member of assigned units; then
- Retrieve PO lines by the
id
of the PO and delete them; then - Delete PO
Upon receiving a request to create a PO Line, it does the following:
- Validate PO Line content (interrelated fields, acquisition units based validation, settings based validation like order lines limit and etc.); then
- Save a PO Line sub-objects in the storage; then
- Save a PO Line content with references to the created sub-objects in the storage.
Upon receiving a request to update a PO Line, it does the following:
- Validate PO Line content (interrelated fields, acquisition units based validation and etc.); then
- Retrieve PO Line data from storage; then
- Validate that PO id of the PO Line from storage corresponds to order id in the path; then
- Depending on the content in the storage the sub-object updates are following:
- In case the sub-object is available in the storage and the updated PO Line data also contains this, the
PUT
request is being sent to the storage to corresponding endpoint.
For example, to update existingreportingCode
sub-objectPUT
request should be sent to /orders-storage/reporting-codes/{id} endpoint. - In case the sub-object is available in the storage but the updated PO Line data does not contain this anymore, the
DELETE
request is being sent to the storage to corresponding endpoint.
For example, to remove existingreportingCode
sub-objectDELETE
request should be sent to /orders-storage/reporting-codes/{id} endpoint. - In case the sub-object is not available in the storage but the updated PO Line data contains this, the
POST
request is being sent to the storage to corresponding endpoint.
For example, to addreportingCode
sub-objectPOST
request should be sent to /orders-storage/reporting-codes endpoint.
- In case the sub-object is available in the storage and the updated PO Line data also contains this, the
- Final step is to store the updated PO Line content with references to the created/updated sub-objects. The
PUT
request is being sent to /orders-storage/po-lines/{id} endpoint.
Note: the PO Line update might lead to Order's workflow status update (see MODORDERS-218 for more details)
Upon receiving a request to delete a PO Line, it does the following:
- Validate if PO is not restricted by acquisitions units or a user is a member of assigned units; then
- Retrieve PO line by the
id
; then - Validate that PO
id
of the PO Line corresponds to order id in the path; then - Delete PO Line and its sub-objects
Upon receiving a request to receive resources, it does the following:
- Retrieve piece records from the orders storage based on the request body.
- For those pieces which have item id the process is like following:
- Retrieve items from inventory.
- Update item entities with barcode (if specified) and status
- Send PUT requests to inventory to update items. In case any errors happen while updating items, the logic just collects them and does not stop entire process
- Update piece records with receiving information and send PUT requests to orders storage. If any errors happen, just collect them.
The following is expected to be update in piece:receivingStatus
: in case theitemStatus
isOn order
the status is set toExpected
, otherwise toReceived
locationId
: from the requestreceivedDate
: current date ornull
in case theitemStatus
isOn order
- Retrieve all involved PO Lines from the storage and updates receipt status.
- If all pieces of an order line have been received, the receipt status is
Fully Received
. - If more than one, but less than the total number of pieces have been received, it is
Partially Received
. - If none received, it is
Awaiting Receipt
. - If the calculated status is the same as current one, no update is made
- If all pieces of an order line have been received, the receipt status is
- Prepare response to the client taking into account any error happened processing particular piece record.
Sample of the requests:
- Request to receive pieces for 2 PO Lines
{ "toBeReceived": [ { "poLineId": "0804ddec-6545-404a-b54d-a693f505681d", "received": 1, "receivedItems": [ { "barcode": "0987654111", "itemStatus": "Received", "locationId": "fcd64ce1-6995-48f0-840e-89ffa2288371", "pieceId": "cb9b0468-f2b4-4a13-b64c-662c4c9ec3ed" } ] }, { "poLineId": "7f0c4975-885e-47d5-8d5a-793dffbba9b2", "received": 1, "receivedItems": [ { "barcode": "0987654333", "itemStatus": "In transit", "locationId": "758258bc-ecc1-41b8-abca-f7b610822ffd", "pieceId": "20241b8c-9076-4cf5-817b-f2c1e2cb242f" } ] } ], "totalRecords": 2 }
- Request to move a received piece back to
Expected
{ "toBeReceived": [ { "poLineId": "f217a5c2-2c56-4d05-9412-a96cfc8e52de", "received": 1, "receivedItems": [ { "itemStatus": "On order", "pieceId": "56fbfde4-6335-4dd7-9a03-d100821f1d18" } ] } ], "totalRecords": 1 }
Note: receiving might lead to Order's workflow status update (see MODORDERS-218 for more details)
CRUD APIs are available to manage acquisitions units and memberships (user-unit relations).
In order to avoid reference integrity issues when deleting acquisition units that are assigned to records, the logic implements a "soft delete" approach.
- When client sends
DELETE /acquisitions-units/units/<id>
, the logic gets acquisitions unit by specified id and updates it settingisDeleted
totrue
- When client sends
GET /acquisitions-units/units?query=<cql>
and<cql>
does not contain criteria byisDeleted
, the logic will search for records withisDeleted==false
. - To get all the units regardless of
isDeleted
value, the request should be likeGET /acquisitions-units/units?query=isDeleted=* AND (<cql>)
during tenant init, mod-orders creates producer with numPartitions which can be customized with env vars below:
- DI_ORDER_CREATED_READY_FOR_POST_PROCESSING_PARTITIONS
- DI_ORDER_CREATED_PARTITIONS
- DI_PENDING_ORDER_CREATED_PARTITIONS Default value is 1
See project MODORDERS at the FOLIO issue tracker.
Other modules are described, with further FOLIO Developer documentation at dev.folio.org