Skip to content

Unconstrained Forecast

Introduction

Et labore labore et laudantium quidem et molestiae sint est repudiandae rerum est ipsa autem ea unde voluptatum! Est eaque cumque aut amet voluptatem est architecto fugit.

Pre-Conditions

  • Masters that should be uploaded
    1. SKU Master
    2. Location Master
    3. Budget Master
    4. BOM Master
  • Global Configurations

Course of Events

  1. Retrieve Global Configurations:

    • Fetches the global configurations for the company to determine the time level (time_level_value).
  2. Delete Previous Data:

    • Deletes previous forecast data for the specified scenario and level.
  3. Update Master Data:

    • Updates master data from SKU, BOM, and location masters.
  4. Generate Constrained Forecast If True:

    • If constrained_forecast is True, generates a Level 0 forecast and updates the scenario name accordingly.
  5. Fetch Company Configurations:

    • Retrieves company-specific configurations including base level.
  6. Store Forecast Scenario:

    • Stores the forecast scenario in the database if it's not a constrained forecast.
    • Collection: forecast_scenario
  7. Generate Forecast:

    • Depending on the level parameter, generates the forecast:
      • For a list of levels: Iterates through the levels and generates the forecast for each.
      • For None: Runs forecast from ROS.
      • For a single level: Generates the forecast for the specified level.
    • Sends email notifications if necessary.

Function: run_flexi_forecast

Function Steps:

1. Notification Initialization:

  • Initializes notification and task IDs if the calling function is not norm_generate_func or forecastForInterDC.
  • Initiates a notification for generating the forecast from ROS.
  • Updates the status and user information for the task.

2. Data Retrieval:

  • Fetches SKU master data and active SKUs for the company.
  • Retrieves distinct ROS levels and collates them based on the channel collate dictionary.
  • Constructs the match query and group query for sales master data.

3. Data Partitioning:

  • Calculates the number of documents in the database and partitions them into multiple parts for parallel processing.

4. Parallel Processing:

  • Determines the number of processes to be used based on available cores.
  • Divides the data into arrays for multiprocessing and starts the forecast generation process using the forecast_store function.

5. Stage Completion:

  • Completes the stages of data retrieval and forecast generation, and updates the notifications and task statuses.

Helper Function: forecast_store

Function Steps:

  1. Data Parsing:

    • Parses and processes MongoDB objects.
    • Extracts sales data and constructs dictionaries for ROS values and SKU mappings.
  2. Forecast Calculation:

    • Fetches global configurations for the company.
    • Calls the calcForecastBasedOnBudget function to calculate the forecast based on budget and ROS values.
  3. Forecast Storage:

    • Stores the calculated forecast quantities and updates the forecast data.

Helper Function: calcForecastBasedOnBudget

The calcForecastBasedOnBudget function calculates the forecast based on the budget, ROS values, and other parameters.

Function Steps:

  1. Retrieve Global Configurations:

    • Fetches the global configurations for the company to determine the time level (time_level_value).
  2. Set Budget Parameters:

    • Sets parameters for budget calculation based on the time level and forecast duration.
  3. SKU Mapping

    • Maps SKU's to various category columns
    • skuCatgMap = getSkuCatgMap(companyId, categoryColumn='category', keyToBe=keyToBe, varcore=varcore)
    • Collection: sku_master
  4. Fetch Budget Data:

    • Fetches all budget data for the company and filters attributes based on budget removal settings.
    • Collection: budget_map
  5. Calculate Forecast:

    • Iterates through store SKUs and calculates the forecast quantity based on ROS values, budget factors, and various configurations.

      1. For a specific SKU-Location-Channel, consider a set of sales history values for N time buckets called group, ordered in descending order of time buckets.
      2. If outlier-correction is true, we compute the range of valid sales history values as,
      py
      min_sales_quantity = mean(group) - (std(group) * outlier_correction_value)
      
      max_sales_quantity = mean(group) + (std(group) * outlier_correction_value)

      Using these range values, we discard values from group that are not included in the range min_sales_quantity, max_sales_quantity (both inclusive)

      py
      group_filtered = [x for x in group if min_sales_quantity <= x <= max_sales_quantity]
      1. Now the latest history_horizon number of values are selected.
      python
      group_filtered_history_horizon = group_filtered[:history_horizon]
      1. Then the forecast is calculated
      py
      forecast_qty=round(float(ROS per day) * float(no of days) * float(budget factor), 5)
      1. Finally, the ROS for the SKU-Location-Channel is saved to the dict as
      py
       sku_store_ros['ros_list'] = sku_store_ros['ros'].str[1]
       sku_store_ros['sale_date_list'] = sku_store_ros['ros'].str[2]
       sku_store_ros['tb_start_date_list'] = sku_store_ros['ros'].str[3]
       sku_store_ros['ros'] = sku_store_ros['ros'].str[0].astype(float)
  6. Store Forecast Data:

    • Stores the calculated forecast data and handles bifurcation store data if provided.
      • ros_list, sale_date_list, tb_start_date_list are exploded using pd.DataFrame.explode() and written to ROS Bifurcated .csv file that is made available for download.
    • Collection: sales_master
  7. Create Forecast Bifurcated File:

  • Exports debug information and no-budget details to CSV files.
  • ROS Bifurcated data is not stored in database.

Exception Handling

  • Captures and logs exceptions, ensuring that the notification of the task status is updated to Failed in case of errors.

Validation Checks

Post Conditions

Exceptions

To Find

@execute.route('/generate/forecast', methods = ['POST'])

Improvements

  • budget_scenario_name=requestJson.get('budget_scenario_name', None) None should not be written