---
# System prepended metadata

title: RETAIL B2B USECASE

---

# Retail B2B Store Warehouse order USECASE

  For retail B2B usecase we have store purchase orders.
  
## Overview

Demand forecasting is done for grocery products in JioMart Partner Fulfillment Centers (Warehouses in TelOS). The forecast is done at the Warehouse-SKU level on weekly basis.

## Schema Onboarding

Schema onboarding will happen via telos workbench(UI). Different kind of schemas needed to onboard:
1.	Collections –> Any ordinal/text data should be defined as a set of defined value. 
        
        
| Collection name  | Symbolic/Ordinal | items                                                           |
| ---------------- | ---------------- | --------------------------------------------------------------- |
| transaction_type | Symbolic         | UPI,CASH,CARD,WALLET                                            |
| zone             | Symbolic         | East, West, North, South                                        |
| seasons          | Ordinal          | winter, spring, summer, moonsoon, autumn                        |
| week_type        | Ordinal          | weekday, weekend                                                |
| days_of-week     | Ordinal          | monday, tuesday, wednesday, thursday, friday , saturday, sunday |

<br>
 

 
2.	Quantity –> All data types needed in the system.  
           
           
  | Quantity   | datatype | range             |
  | ---------- | -------- | ----------------- |
  | amount     | float    | 0 to (float.Max)  |
  | count      | integer  | 0 to (int.Max)    |
  | percentage | float    | 0 to 100          |
  | is_free    | binary   | 0 or  1           |
  | date       | date     | dd:mm:yy hh:mm:ss |


3.	Entity –> All static data and relationship between different entities will be onboarded. 
              
| Entity     | bizid  |  attributes  |
| --------------- | ------------------ | ---------|
| sku     | productskuid | |
| store    | storeid |     |
| warehouse     | fc_id | zone|
| category     | category_name  ||
| class     | class_name |          | 
|   group  | group_name |          | 
| department     | department_name |          | 
| pincode    | pincode |          | 
| brand    | brandid |          | 
|article| fc_productid|

| Subject     | predicate  | Object|
| --------------- | ------------------ | --------|
| sku     | belongs_to | category|
| sku    | belongs_to |    class |
| sku     | belongs_to | group|
| sku     | belongs_to  |department|
| sku    | has_brand|    brand      | 
| sku  | has_article |    article      | 
| store     | is_in | pincode         | 

4.	Event –> POS Transaction event and  KeyValue events for aggregation.
           Example: Event with Keys as (store * sku) and (warehouse * sku)
> [name=supriyopaul] Example tables for event data for better uderstanding

| Event     | Keys  |  Values  |
| --------------- | ------------------ | ---------|
| POS_Transaction     | store, sku | transaction_type, amount, count, date |
|     | warehouse, sku | transaction_type, amount, count, date     |

           
5. Functions -> Ingestion and feature engineering functions schema will be defined with the help of incoming and outgoing events schema.

<br>

## Knowledge Onboarding

Knowledge data should get onboarded into knowledge graph once schema is created. Biz-ids will get saved to id-garden which is backed by Redis and names will get saved to name-garden(elasticsearch) and all attributes, qualifiers, predicates will be stored in ArangoDb.

 ![](https://hackmd.io/_uploads/HkpFpulL2.png)
 <br>

## FUNCTIONS :

### Ingestion :
/function/retail/b2b_sales_order_ingestion
Ingestion will consume raw purchase-order Json coming on Kafka topic and will convert it to standardized event proto. 

Steps:
1.	 Identify incoming Json keys among  biz-id, attributes, facets or property with the help of ingestion config.
2.	Fetch telos ids for string biz-ids (sku, store, warehouse).

<br><br>
 
![](https://hackmd.io/_uploads/BknmSlVtn.png)


<br><br>

### Compute :
/function/retail/b2b_sales_order_compute
Compute function is responsible for modifying the incoming event by adding new properties or attributes to it. For any kind of arithmetic, logarithmic operation compute will evaluate it using expression engine sdk.
In Demand forecasting use case, we are calculating total sales_price , mrp and discount percentage for each line item.

compute {  
   total_sales_revenue= count x sales_price  
   total_mrp = count x mrp 
   "discount" = ("mrp" -"saleprice")*100/"mrp"
}

![](https://hackmd.io/_uploads/ByDyNgEKn.png)


<br><br>

### Quantise :
/function/retail/b2b_sales_order_quantise
Quantisation function is responsible for deriving any temporal, spatial , binning kind of information from the existing incoming fields in the events.
For example, from order_date field we can derived further temporal fields like week_type, week_day, month, season etc.

<br>

![](https://hackmd.io/_uploads/BymRIe4Kn.png)

### Enrich :
/function/retail/b2b_sales_order_enrich
Enrich function is responsible for filling any missing knowledge related data in the incoming events, like predicates and attributes of the entities.
It makes a query to the knowledge Lake to fetch required fields for the incoming entities.
For example, category, brand, pincode are not there in the incoming sales_order event. Enrich fetch it for every sku ( category, brand), store (pincode).

<br>

![](https://hackmd.io/_uploads/ByqrdlVY3.png)



### Pivot :
/function/retail/b2b_sales_order_pivot
Pivot function is responsible for splitting one event to  multiple event based on the key config. The result will be n events having different record keys with same or different value set.
In Demand forecasting use case, we are creating record key -> warehouse * sku, store * sku, store * brand, store * category etc.

 
![](https://hackmd.io/_uploads/SyfmRdlUn.png)


<br>
<br>

### Reduce :
/function/reduce/retail/order/warehouse*sku
Reduce function is responsible for doing real time in-memory processing using kafka streams. Incoming events will get aggregated over different time-windows resulting in multiple sink topics.
In Demand forecasting use case, we are having weekly time windows on warehouse * sku as a key. Aggregation we are doing is SUM, AVERAGE, PERCENTAGE, MOVING_AVERAGE.

<br>

![](https://hackmd.io/_uploads/B1a2FlNFh.png)

<br><br>

## Feature Repository:

Features created by reduce function will get saved to feature repo (Cassandra) as a time series data. The record keys i.e., warehouse and sku are partitioned for fast search and insert. Also, data is sorted by created date which is a cluster key so that finding top N records are efficient.
** Feature Repo will be used for training as well as inferencing of models.


#### List of features getting stores in feature repository in time-series form:

1.	/feature/retail/warehouse_x_sku/weekly/count/sum 
2.	/feature/retail/warehouse_x_sku/weekly/discount/percentage 
3.	/feature/retail/warehouse_x_sku/weekly/sales_price/average 
4.	/feature/retail/warehouse_x_sku/weekly/mrp/average 
5.	/feature/retail/warehouse_x_sku/weekly/amount/sum
6.	/feature/retail/warehouse_x_sku/weekly/lag_1/amount
7.	/feature/retail/warehouse_x_sku/weekly/lag_2/amount
8.	/feature/retail/warehouse_x_sku/weekly/lag_4/amount
9.	/feature/retail/warehouse_x_sku/weekly/lag_5/amount
10.	/feature/retail/warehouse_x_sku/weekly/moving_average_1/amount
11.	/feature/retail/warehouse_x_sku/weekly/moving_average_2/amount


#### Feature repository data storage:


| warehouse | sku   | feature             | value | timestamp  |
| --------- | ----- | ------------------- | ----- | ---------- |
| 10002     | 40001 | count_sum           | 50    | 14/05/2023 |
| 10002     | 40001 | discount_perc       | 13.5  | 14/05/2023 |
| 10002     | 40001 | sales_price_average | 3450  | 14/05/2023 |
| 10002     | 40001 | amount_sum          | 4000  | 14/05/2023 |
| 10002     | 40002 | count_sum           | 50    | 14/05/2023 |
| 10002     | 40002 | discount_perc       | 13.5  | 14/05/2023 |
| 10002     | 40002 | sales_price_average | 3450  | 14/05/2023 |
| 10002     | 40002 | amount_sum          | 4000  | 14/05/2023 |
| 10002     | 40001 | count_sum           | 50    | 07/05/2023 |
| 10002     | 40001 | discount_perc       | 13.5  | 07/05/2023 |
| 10002     | 40001 | sales_price_average | 3450  | 07/05/2023 |
| 10002     | 40001 | amount_sum          | 4000  | 07/05/2023 |


#### Different fetch queries available on feature repository:

1.	Fetch Latest(1) features( discount_perc, sales_price_average) for warehouse (10002).
2.	Fetch Latest features( discount_perc, sales_price_average) for warehouse (10002) and sku (40001).
3.	Fetch Latest N features( discount_perc, sales_price_average) for warehouse (10002).
4.	Fetch features( discount_perc, sales_price_average) for warehouse (10002) for date range (01/04/2023 - 30/04/2023)
5.	Fetch features( discount_perc) for warehouse (10002) where value > 40.
6.	Any custom query in form of CQL (Cassandra Query Language).





### TBD 

Usecase: 

Any Fetch operation - leads to query operation


Usecase: Training Fetch
Model: Demand forecasting for warehouse * sku

Data required: 
warehouse*sku - record_key, (window - weekly)

/feature/retail/warehouse_x_sku/weekly/count/sum
/feature/retail/warehouse_x_sku/weekly/discount/percentage
/feature/retail/warehouse_x_sku/weekly/sales_price/average
/feature/retail/warehouse_x_sku/weekly/mrp/average
/feature/retail/warehouse_x_sku/weekly/amount/sum
/feature/retail/warehouse_x_sku/weekly/lag_1/amount
/feature/retail/warehouse_x_sku/weekly/lag_2/amount
/feature/retail/warehouse_x_sku/weekly/lag_4/amount
/feature/retail/warehouse_x_sku/weekly/lag_5/amount
/feature/retail/warehouse_x_sku/weekly/moving_average_1/amount
/feature/retail/warehouse_x_sku/weekly/moving_average_2/amount

/attribute/retail/warehouse/location/lat_long
/attribute/retail/warehouse/capacity
/predicate/retail/warehouse/state
/predicate/retail/sku/category
/predicate/retail/sku/brand


Training Fetch data: The above data points needs to be fetched from feature and knowledge for last week. 

```plantuml
@startuml
entity "Warehouse" as warehouse {
  + fc_id : uint64
  --
  location : spatial
  capacity : uint32
  state : symbolic
  zone: symbolic
}

entity "SKU" as sku {
  + productskuid : uint64
  --
  category : uint64
  class : uint64
  group : uint64
  department : uint64
  brand : uint64
  article : uint64
}

entity "Warehouse x SKU" as Warehouse_x_SKU {
  + fc_id : uint64
  + sku_id : uint64
  + timestamp : temporal
  --
  window : temporal
  count_sum : f32
  discount_percentage : f32
  sales_price_average : f32
  mrp_average : f32
  amount_sum : f32
  lag_1_amount : f32
  lag_2_amount : f32
  lag_4_amount : f32
  lag_5_amount : f32
  moving_average_1_amount : f32
  moving_average_2_amount : f32
}

warehouse ||--o{ Warehouse_x_SKU : has
sku ||--o{ Warehouse_x_SKU : has
@enduml

```
