Predictive Inventory Management Service
The Predictive Inventory Management Service enables API callers to generate stock replenishment proposals based on historical data which includes supplier orders and customer orders.
Access info
Endpoint | https://predictive-inventory-management-api.socrate.io/graphql |
Required access keys | Tenant-level service access key |
Pricing | Please contact us for details at contact@bitsoftware.ro |
Notes | To call the service, the access key must be provided in the x-api-key header of the HTTP request. If you are using the GraphQL console, you can view the service’s documentation and schema only after entering an access key. Make sure that the scope of the key allows access to the queries and mutations that you require. For example, to grant the key access to all queries and mutations, the keys’s scope must be set to predictive-inventory-management-api:query:* predictive-inventory-management-api:mutation:* . |
Usage
Prerequisites
- The organization(s) for which reporting is done must exist in the SBS system. You can add new organizations either from the Organizations UI or programmatically from the Organizations Service.
- The following CSV files are required as input to te Predictive Inventory Management service (click the links below for information about the structure of the file):
Generating a replenishment proposal
To generate a replenishment proposal:
- Obtain from your ERP system the input CSV files to be used as input. For the structure of each file, see Appendix 1: Input structure.
- Create a new replenishment proposal by calling the
createReplenishmentProposal
mutation. You must supply as input argument, at the minimum, the target month, in the format YYYY-MM. As a result, a new replenishment proposal object is created, and the response contains the unique proposal ID. You will need to work with this ID in subsequent steps to further process the proposal and monitor its status. - Add all the input CSV files to the proposal. See Preparing input files.
- Run the
computeReplenishmentProposal
mutation. This triggers a computation that takes place from several minutes to several hours, depending on the size of input CSV files.
The outcome of computing a proposal, including any possible errors, is reported in the Process
object when querying the respective proposal. If the computation was successful, the process includes one or more of the following attributes:
- productCentricResult - This is the default result and it is always present. It contains, among other attributes, the name and download URL of the output file, with computation results grouped by product. For the structure of the output file, see Appendix 2: Output structure.
- customerCentricResult - This result is present if the proposal was created with the input parameter
splitByCustomer
= true. The result has the same structure as above, except that data inside the output file are grouped by customer. - industryCentricResult - This result is present if the proposal was created with the input parameter
splitByIndustry
= true. The result has the same structure as above, except that data inside the output file are grouped by industry code.
Preparing input files
After you have create a replenishment proposal, you can add all the CSV input files to it.
For each input CSV file, the steps are as follows:
- Run the
prepareFile
mutation, for example:
mutation prepareFile($replenishmentProposalId:ID!, $input:PrepareFileInput!) {
prepareFile(replenishmentProposalId:$replenishmentProposalId, input:$input) {
id
fileType
name
contentLength
uploadUrl
downloadUrl
createdAt
}
}
{
"replenishmentProposalId": "YOUR_REPLENISHMENT_PROPOSAL_ID",
"input": {
"fileType": "CustomerOrders",
"name": "customer-orders.csv"
}
}
In the response, you get the file’s upload URL at which you can upload the actual file.
- In the programming language of your API, make an HTTP
PUT
request to upload the file content to the upload URL. This step is similar to how you would create a file and then upload its content in the File Management Service, as described in the Tutorial: Create a file.
Note that you can add multiple files of the same type for the same replenishment proposal. For example, you can add several input CSV files of type “CustomerOrders”. If multiple files of the same type exist, SBS will aggregate and compute data found in all respective files.
After adding all the CSV files, you can check if they are indeed attached to the replenishment proposal by running the replenishmentProposal
query, for example:
query ReplenishmentProposal ($id:ID! $fileId:ID, $processId:ID) {
replenishmentProposal(id:$id) {
id
organizationId
files(id: $fileId) {
id fileType name contentLength uploadUrl downloadUrl createdAt
}
createdAt
}
}
{
"id": "YOUR_REPLENISHMENT_PROPOSAL_ID"
}
If your replenishment proposal looks good so far, you can proceed to running the computeReplenishmentProposal
mutation, for example:
mutation ComputeReplenishmentProposal ($id:ID!) {
computeReplenishmentProposal(id:$id) {
id
status
dataRange { from to }
targetMonth
errorMessages
createdAt
}
}
{
"id": "YOUR_REPLENISHMENT_PROPOSAL_ID"
}
Dealing with large input files
As mentioned above, when you add a file to the replenishment proposal, there are two steps involved:
- Run
prepareFile
and obtain the upload URL. - In the programming language of your API, make an HTTP
PUT
request to upload the file content to the upload URL.
For the second step, note, however, that the maximum file size that you can send in a single PUT request is 5 GB. Should you need to add larger files to the replenishment proposal, you can do so through the multipart upload mutations provided by the File Management Service. In this scenario, the process looks as follows:
- Run
prepareFile
and take notice thedata.prepareFile.id
returned in the response body. This ID corresponds to a file id of a file in File Management Service. - Provide the id above as input to the
initiateMultipartUpload
mutation and continue with the rest of steps required for multipart upload, as described in Uploading large files.
Processes
Each time when you run computeReplenishmentProposal
, a new process with status NEW is attached to the replenishment proposal. You can view the proposal and the status of all its processes by running the replenishmentProposal
query and requesting the processes
field in the response, for example:
query ReplenishmentProposal ($id:ID! $fileId:ID, $processId:ID) {
replenishmentProposal(id:$id) {
id
organizationId
targetMonth
splitByCustomer
splitByIndustry
files (id: $fileId) {
id fileType name contentLength uploadUrl downloadUrl createdAt
}
processes (id: $processId) {
id
status
dataRange { from to }
targetMonth
errorMessages
productCentricResult { id name contentLength createdAt downloadUrl }
customerCentricResult { id name contentLength createdAt downloadUrl }
industryCentricResult { id name contentLength createdAt downloadUrl }
totals {
csvLines { customerOrders supplierOrders allFileLines }
}
createdAt
}
createdAt
}
}
{
"id": "YOUR_REPLENISHMENT_PROPOSAL_ID"
}
The status of any process is initially NEW. The status NEW will normally change to INPROCESS after approximately 1 minute. Note that, if you run computeReplenishmentProposal
multiple times for the same proposal, each run will start a new process. In this case, you will need to track the status of each process separately. The processes
field of the replenishmentProposal
query provides a filter (by process ID) for that purpose.
The INPROCESS status of a process may take from a few minutes to a few hours, depending on the size of the input CSV files. After the INPROCESS status, the status may change to either ERROR (if errors are encountered) or DONE (upon successful processing).
If the status ERROR is encountered, check the errorMessages
response field of the respective process for details.
If the process completes with status DONE, it generates 1-3 CSV output files. As mentioned previously, the number of files depends on the input parameters supplied at proposal creation time to the createReplenishmentProposal
mutation.
If necessary, you may stop a running process through a call to killProcess
. However, this is possible only if the process has not generated any results (that is, if the result
field of the process is empty).
You may also delete a process through the deleteProcess
mutation. Deleting a running process is possible only if the process has generated no result yet.
Deleting replenishment proposals
You can delete replenishment proposals through a call to deleteReplenishmentProposal
. Note, however, that it is not possible to delete a replenishment proposal if it has at least one running process that has already generated some result file. To delete such a proposal, you will need to wait for the process to finish first.
Queries
organizations
Returns a list of active organizations defined for the given tenant.
Result
The result is an array of Organization
.
Organization
type
Attribute | Type | Description |
---|---|---|
id | ID! |
Specifies the organization’s unique identifier. |
name | String |
Specifies the organization’s name. |
replenishmentProposals
Returns the list of replenishment proposals for the organization ID supplied as input.
Arguments
Argument | Type | Description |
---|---|---|
organizationId | ID! |
Mandatory. The identifier of the organization to which the replenishment proposal belongs. |
filter | ReplenishmentProposalsFilter |
Optional. Supplies filtering criteria to the query. |
ReplenishmentProposalsFilter
input
Argument | Type | Description |
---|---|---|
createdAt | DateFilter |
Optional. Provides filtering options to the query. |
DateFilter
input
Attribute | Type | Description |
---|---|---|
from | Date |
Optional. Specifies a date in YYYY-MM-DD format. If provided, only records where the creation date starts with this date will be retrieved. |
to | Date |
Optional. Specifies a date in YYYY-MM-DD format. If provided, the query will retrieve only records having the creation date up to and including this date. |
Result
The result is an array of objects of type ReplenishmentProposal
.
replenishmentProposal
Retrieves a single replenishment proposal by ID.
Arguments
Argument | Type | Description |
---|---|---|
id | ID! |
Mandatory. The ID of the replenishment proposal to retrieve. |
Result
See the ReplenishmentProposal
type.
Mutations
computeReplenishmentProposal
Starts a process that computes a replenishment proposal, based on its current input data. Running this mutation will start a new process on each run.
Arguments
Attribute | Type | Description |
---|---|---|
id | ID! |
Mandatory. The identifier of the replenishment proposal to be computed. |
Result
See the Process
type.
createReplenishmentProposal
Creates a replenishment proposal.
Arguments
Attribute | Type | Description |
---|---|---|
organizationId | ID! |
Mandatory. The identifier of the organization for which this replenishment proposal is created. |
input | CreateReplenishmentProposalInput! |
Mandatory. Provides the actual input data to the mutation. |
CreateReplenishmentProposalInput
input
Attribute | Type | Description |
---|---|---|
targetMonth | Month! |
Mandatory. The month for which the replenishment proposal is computed. The value must have the YYYY-MM format. |
splitByCustomer | Boolean |
Optional. If this value is supplied, computing the proposal will generate a separate CSV output file in addition to the default one, with results grouped by customer ID. |
splitByIndustry | Boolean |
Optional. If this value is supplied, computing the proposal will generate CSV output file will be created in addition to the default one, with results grouped by industry code ID. |
demandCoverageType | DemandCoverageType |
Optional. An enum with the following valid values: Calendaristic, Business. |
Result
ReplenishmentProposal
type
Attribute | Type | Description |
---|---|---|
id | ID |
The identifier of the replenishment proposal. |
organizationId | ID |
The identifier of the organization for which this replenishment proposal was created. |
targetMonth | Month |
The target month for which the replenishment proposal was created. |
splitByCustomer | Boolean |
If true, indicates that the replenishment proposal was created with an option to produce a separate output file with results grouped by customer. |
splitByIndustry | Boolean |
If true, indicates that the replenishment proposal was created with an option to produce a separate output file with results grouped by industry. |
demandCoverageType | DemandCoverageType |
An enum with the following valid values: Calendaristic, Business. |
files (id: ID ) |
[File] |
The list of input files associated with the current proposal. You can optionally filter files by ID, by supplying the file ID as input argument to this field. |
processes (id: ID ) |
[Process] |
The list of processes associated with the current proposal. You can optionally filter processes by ID, by supplying the process ID as input argument to this field. |
createdAt | DateTime |
The date and time when the replenishment proposal was created. |
File
type
Attribute | Type | Description |
---|---|---|
id | ID |
The unique identifier of the file. You an use this ID to refer to the file also through the File Management Service. |
fileType | CsvFileType |
The type of data reported by the file. Valid values: CustomerOrders, SupplierOrders. |
name | String |
The file name. |
contentLength | Float |
The file size in bytes. |
uploadUrl(expiresIn: Int ) |
Uri |
The URL at which the file content can be uploaded. Note that the upload URL expires after the number of seconds supplied in the expiresIn parameter. |
downloadUrl(expiresIn: Int ) |
Uri |
The URL at which the file content can be downloaded. Note that the download URL expires after the number of seconds supplied in the expiresIn parameter. |
createdAt | DateTime |
The date and time when the file was created. |
Process
type
Attribute | Type | Description |
---|---|---|
id | ID |
The unique identifier of the file. |
status | ReplenishmentProposalStatus |
The status of the replenishment proposal. Valid values: NEW - computation has not started yet, INPROCESS - computation is in progress, DONE - computation has completed without errors, ERROR - computation has completed with errors. |
dataRange | DataRange |
The date range for which the replenishment proposal was created. |
targetMonth | Month! |
The month for which the replenishment proposal was created, in YYYY-MM format. |
errorMessages | [String] |
The list of error messages, if applicable. |
productCentricResult | ResultFile |
The standard output file created by the process. In the standard file, results are grouped by product ID. |
customerCentricResult | ResultFile |
An output file where results are grouped by customer ID. This file is created only if the replenishment proposal was created with the option splitByCustomer = true. |
industryCentricResult | ResultFile |
An output file where results are grouped by industry code ID. This file is created only if the replenishment proposal was created with the option splitByIndustry = true. |
totals | Totals |
The totals computed by this process. |
createdAt | DateTime |
The date and time when the process was created. |
DataRange
type
Attribute | Type | Description |
---|---|---|
from | Date |
The starting date of the range. |
to | Date |
The ending date of the range. |
ResultFile
type
Attribute | Type | Description |
---|---|---|
id | ID |
The unique identifier of the file. You an use this ID to refer to the file also through the File Management Service. |
name | String |
The file name. |
contentLength | Float |
The file size in bytes. |
downloadUrl(expiresIn) | Uri |
The URL at which the file content can be downloaded. Note that the download URL expires after the number of seconds supplied in the expiresIn parameter. |
createdAt | DateTime |
The date and time when the file was created. |
Totals
type
Attribute | Type | Description |
---|---|---|
csvLines | CsvFileLines |
The number of lines in each of the CSV files, as a CsvFileLines type. |
CsvFileLines
type
Attribute | Type | Description |
---|---|---|
customerOrders | Float |
Reports the number of lines in CustomerOrders.csv. |
supplierOrders | Float |
Reports the number of lines in SupplierOrders.csv. |
allFileLines | Float |
Reports the number of lines in both files above. |
deleteFile
Deletes a previously uploaded CSV file.
Arguments
Attribute | Type | Description |
---|---|---|
replenishmentProposalId | ID! |
Mandatory. The identifier of the replenishment proposal. |
fileId | ID! |
Mandatory. The identifier of the CSV file to be deleted. |
Result
DeletedFile
type
Attribute | Type | Description |
---|---|---|
id | ID |
The unique identifier of the file. You an use this ID to refer to the file also through the File Management Service. |
fileType | CsvFileType |
The type of data reported by the file. Valid values: CustomerOrders, SupplierOrders. |
name | String |
The file name. |
createdAt | DateTime |
The date and time when the file was created. |
deleteProcess
Deletes a computation process and the result files.
Arguments
Attribute | Type | Description |
---|---|---|
replenishmentProposalId | ID! |
Mandatory. The identifier of the replenishment proposal. |
processId | ID! |
Mandatory. The identifier of the process to be deleted. |
Result
See the Process
type.
deleteReplenishmentProposal
Deletes a replenishment proposal, including all its input and output files and processes.
Arguments
Attribute | Type | Description |
---|---|---|
id | ID! |
Mandatory. The ID of the replenishment proposal to be deleted. |
Result
See the ReplenishmentProposal
type.
killProcess
Stops a running computation process.
Arguments
Attribute | Type | Description |
---|---|---|
replenishmentProposalId | ID! |
Mandatory. The identifier of the replenishment proposal. |
processId | ID! |
Mandatory. The identifier of the process to be deleted. |
Result
See the Process
type.
prepareFile
Generates a URL at which you can upload a CSV file to be used as input to the computation. Run this mutation for each CSV file that is to be supplied as input for a replenishment proposal.
Arguments
Attribute | Type | Description |
---|---|---|
replenishmentProposalId | ID! |
Mandatory. The identifier of the replenishment proposal. |
input | PrepareFileInput! |
Mandatory. Supplies the input data to the mutation. |
PrepareFileInput
input
Attribute | Type | Description |
---|---|---|
fileType | CsvFileType! |
Mandatory. This is an enumeration that identifies the type of the CSV file. Valid values: CustomerOrders, SupplierOrders. |
name | String |
Optional. Supplies the name of the CSV file. |
Result
See the File
type.
Appendix 1: Input structure
The input to the Predictive Inventory Management Service consists of two CSV files:
- CustomerOrders.csv
- SupplierOrders.csv
You may supply multiple files of the same type as input as long as they follow the structure described below. Note the following:
- Each CSV file is comma-separated
- The first row in the CSV file should provide the column names (that is, the CSV file must include the header).
CustomerOrders.csv
Column | Type | Mandatory? | Description |
---|---|---|---|
product_id | String | Yes | The unique product identifier. Must not contain spaces. |
customer_id | String | No | The customer identifier. Must not contain spaces. |
industry_code_id | String | No | The industry code identifier. Must not contain spaces. |
product_group_id | String | No | The product group identifier. Must not contain spaces. |
is_return | Boolean | Yes | Indicates whether the order was a return. Valid values: true, false. The values 0 and 1 are also accepted. |
order_date | String | Yes | The date when the order was placed, in DD.MM.YYYY format. NOTE: The combination product_id + order_date + order_quantity must be unique, to ensure that no data was duplicated by mistake. |
order_quantity | Float | Yes | The quantify of products ordered. |
supplier_id | String | Yes | The provider identifier. |
SupplierOrders.csv
Column | Type | Mandatory? | Description |
---|---|---|---|
product_id | String | Yes | The unique product identifier. Must not contain spaces. |
is_return | Boolean | Yes | Indicates whether the order was a return. Valid values: true, false. The values 0 and 1 are also accepted. |
order_date | String | Yes | The date when the order was placed, in DD.MM.YYYY format. NOTE: The combination product_id + order_date + order_quantity must be unique, to ensure that no data was duplicated by mistake. |
order_quantity | Float | Yes | The quantify of products ordered. |
lead_time | Integer | Yes | The number of days in which the products were delivered. |
supplier_id | String | Yes | The identifier of the supplier. |
Appendix 2: Output structure
The result of computing a replenishment proposal is a CSV file having the structure described below.
Column | Type | Description |
---|---|---|
product_id | String | The unique product identifier. |
customer_id | String | The customer identifier. |
industry_code_id | String | The industry code identifier. |
product_group_id | String | The product group identifier. |
one_step_ahead | String | The month for which the levels are calculated (year-month). |
service_level | Float | The percentage level of service to cover. |
min_estimate_regular | Integer | Safety stock level under regular supply conditions (trigger-regular). |
max_estimate_regular | Integer | Replenish stock level under regular supply conditions (supply proposal-regular). |
min_estimate_conservative | Integer | Safety stock level under conservative supply conditions (trigger-conservative). |
max_estimate_conservative | Integer | Replenish stock level under conservative supply conditions (supply proposal-conservative). |
order_freq_estimate | Integer | Sales level for the delay time between supply orders. |
months_with_data | Integer | Number of months with historical data. |
model | String | The statistical model applied. |
monthly_sales_service_level_forecast | Integer | Monthly sales forecast at the given service level. |
monthly_sales_mean_prediction | Float | Average sales forecast. |
monthly_sales_std_prediction | Float | Standard deviation of the sales forecast. |
lead_time_mean | Float | Historical average of supply lead time. |
lead_time_std | Float | Historical standard deviation of supply lead time. |