Skip to main content
Version: Fleeto

Product Management

Author(s)

  • Reshmi Karan
  • Sayan Mukherjee
  • Sanket Mal
  • Ayan Ghosh

Last Updated Date

2024-11-15


SRS References


Version History

VersionDateChangesAuthor
1.02024-10-18Initial draftReshmi Karan, Sayan Mukherjee
2.02024-10-30Structure changeSanket Mal
3.02024-11-04Added new APIs:
Get all base products, Get all versions, Get all catalogs, Get all configurations
Sanket Mal
4.02024-11-15A few changes in structure and Revised screen layout to improve user experience. Add api for status update of base product , catalog & config . Add API for image upload for any catalog and image delete for any catalog.Sanket Mal, Ayan Ghosh

Feature Overview

Objective:
To design a product management system that tracks various products like scooters, bikes, parts, or accessories. The system will manage product versions, configurations, and pricing. This feature will allow creating of both saleable and non-saleable parts and product configurations.

Scope:
The feature is specifically for Fleeto, allowing them to handle stock.

Dependencies:


Requirements

  1. A user should be able to create a base product (e.g., Fleeto Magnum).

The base product represents the primary version of the product without any specifications like color or power configurations. Action: Create a base product entity in the system (e.g., BaseProduct table with fields like Name, Description, etc.).

  1. Add Multiple Versions of Base Product.

For each base product, users should be able to add multiple versions. Action: Create a ProductVersion table that is linked to the BaseProduct table. Fields in ProductVersion: VersionName etc. Each version will be mapped to its respective base product.

  1. Add Multiple Product Catalogs for Each Version

Each version of the product will have multiple catalogs with different specifications (for instance, red Fleeto Magnum, blue Fleeto Magnum with specific configurations like different battery capacities, colors, etc.). Action: Create a CatalogProduct table, linked to ProductVersion. The catalog will define the various product configurations (e.g., color, capacity, etc.).

note

First add product Catalog then user can add configaration(unique) Only


note

If the product type is either Parts or Accessories, adding a configuration explicitly for the catalog is not required. In such cases, a default configuration is automatically created when the catalog is added, using the same catalog details.

  1. Product Price Management

Each catalog product will have a price defined with a valid date range, and only one active price can exist at a time for a catalog. Details: A catalog product can have multiple prices over time, but at any given moment, only one price range can be active. Action: Create a ProductCatalogPrice table with fields like Price, ValidFrom, ValidTo, and PriceState.

  1. Background Scheduler for Setting End Price Date

A background scheduler should be implemented to set the end date for old prices when a new price starts. Action: Implement a background service that will periodically check for new prices and update the end dates for old prices accordingly.


Design Specifications

  • UI/UX Design:
    (Include wireframes, mockups, or links to design files.) Base product - base product

    Catalog - Catalog

    Config - config

    Add Price - Add config

  • Data Models:

    public record BaseProduct
    {
    [XLColumn(Ignore = true)]
    public Guid BaseProductId { get; set; }
    [XLColumn(Header = "Base Product Code")]
    public string? ProductCode { get; set; }
    public required string Name { get; init; }
    [XLColumn(Header = "Item Type")]
    public required ProductType ItemType { get; init; }
    [XLColumn(Header = "Sub Type")]
    public required SubItemType SubItemType { get; init; }
    public string? Brand { get; init; }
    public string? Model { get; init; }
    public ProductStatus Status { get; init; }
    public string? Description { get; init; }
    [XLColumn(Ignore = true)]
    public string? LogUserName { get; set; }
    [XLColumn(Ignore = true)]
    public System.DateTime? LogDts { get; set; }
    [System.Text.Json.Serialization.JsonIgnore]
    [Newtonsoft.Json.JsonIgnore]
    [XLColumn(Ignore = true)]
    public int TotalNumber { get; init; }
    }
    public record ProductVersion
    {
    public Guid VersionId { get; set; }
    public Guid BaseProductId { get; init; }
    public required string VersionName { get; init; }
    public string? Description { get; init; }
    public ProductStatus VersionStatus { get; init; }
    public string? LogUserName { get; set; }
    public System.DateTime? LogDts { get; set; } = DateTime.Now;
    [System.Text.Json.Serialization.JsonIgnore]
    [Newtonsoft.Json.JsonIgnore]
    public int TotalNumber { get; init; }
    }
    public record BaseProductFilter
    {
    public string? BaseProductCode { get; init; }
    public string? Name { get; init; }
    public ProductType? ItemType { get; init; }
    public SubItemType? SubItemType { get; init; }
    public string? Brand { get; init; }
    public string? Model { get; init; }
    public ProductStatus? Status { get; init; }
    public int PageNumber { get; set; }
    public int RowsPerPage { get; set; }
    public bool IsExcel { get; init; } = false;
    }
    public record ProductCatalog
    {
    [XLColumn(Ignore = true)]
    public Guid CatalogProductId { get; set; }
    [XLColumn(Ignore = true)]
    public Guid VersionId { get; init; }
    [XLColumn(Ignore = true)]
    public Guid BaseProductId { get; init; }
    [XLColumn(Header = "Catalog Code")]
    public string? CatalogCode { get; set; }
    [XLColumn(Header = "Catalog Name")]
    public required string CatalogName { get; init; }
    public string? Year { get; set; }
    [XLColumn(Header = "HSN Code")]
    public required string HsnCode { get; init; }
    public decimal Weight { get; init; }
    public required string Colour { get; init; }
    [XLColumn(Header = "Item Type")]
    public ProductType ItemType { get; init; }
    public ProductStatus Status { get; init; }
    public string? Description { get; init; }
    [XLColumn(Header = "Selling Type")]
    public SellingType SellingType { get; init; }
    [XLColumn(Ignore = true)]
    public string? LogUserName { get; set; }
    [XLColumn(Ignore = true)]
    public System.DateTime? LogDts { get; set; } = DateTime.Now;
    [XLColumn(Header = "GST Rate")]
    [AllowedValues("GST-0", "GST-5", "GST-12", "GST-18", "GST-28")]
    public string? GstRate { get; set; }
    [XLColumn(Ignore = true)]
    [JsonProperty("imageJson")]
    public List<ImageInfo> Images { get; set; } = [];
    [XLColumn(Ignore = true)]
    public List<CatalogConfig> ConfigarationInfo { get; set; } = [];
    [XLColumn(Ignore = true)]
    [System.Text.Json.Serialization.JsonIgnore]
    public int TotalNumber { get; set; }
    }
    public record CatalogWithVersion : ProductCatalog
    {
    public string? VersionName { get; init; }
    public ProductStatus VersionStatus { get; init; }
    }
    public record CatalogInformation
    {
    [XLColumn(Ignore = true)]
    public Guid BaseProductId { get; init; }
    [XLColumn(Ignore = true)]
    public Guid VersionId { get; init; }
    [XLColumn(Ignore = true)]
    public Guid CatalogProductId { get; init; }
    [XLColumn(Header = "Catalog Name")]
    public string? CatalogName { get; init; }
    [XLColumn(Header = "Catalog Code")]
    public string? CatalogCode { get; init; }
    [XLColumn(Header = "Base Product Name")]
    public string? BaseProductName { get; init; }
    public string? Model { get; init; }
    public string? Colour { get; init; }
    [XLColumn(Header = "Item Type")]
    public ProductType ItemType { get; init; }
    [XLColumn(Header = "Sub Type")]
    public SubItemType SubItemType { get; init; }
    [XLColumn(Header = "Version Name")]
    public string? VersionName { get; init; }
    public string? Description { get; init; }
    public string? Year { get; init; }
    [XLColumn(Header = "HSN Code")]
    public string? HsnCode { get; init; }
    public decimal Weight { get; init; }
    [AllowedValues("GST-0", "GST-5", "GST-12", "GST-18", "GST-28")]
    [XLColumn(Header = "GST Rate")]
    public string? GstRate { get; init; }
    [XLColumn(Header = "Catalog Status")]
    public ProductStatus CatalogStatus { get; init; }
    [XLColumn(Header = "Selling Type")]
    public SellingType SellingType { get; init; }
    [XLColumn(Ignore = true)]
    [System.Text.Json.Serialization.JsonIgnore]
    public string? ImagesAsString { get; set; }
    [XLColumn(Ignore = true)]
    [JsonProperty("imageJson")]
    public List<ImageInfo> Images { get; set; } = [];
    [XLColumn(Ignore = true)]
    [System.Text.Json.Serialization.JsonIgnore]
    public int TotalNumber { get; init; }
    }
    public record ConfigInformation : CatalogInformation
    {
    [XLColumn(Ignore = true)]
    public Guid ConfigId { get; init; }

    [XLColumn(Header = "Config Name")]
    public string? ConfigName { get; init; }
    [XLColumn(Header = "Config Code")]
    public string? ConfigCode { get; init; }
    [XLColumn(Header = "Config Status")]
    public ProductStatus ConfigStatus { get; init; }
    [XLColumn(Ignore = true)]
    public List<AdditionalInfo> AdditionalInfos { get; set; } = [];
    [XLColumn(Header = "Additional Info")]
    [System.Text.Json.Serialization.JsonIgnore]
    public string? AdditionalInfosString { get; set; }
    [XLColumn(Header = "Active Price")]
    public decimal ActivePrice { get; init; }

    }
    public record CatalogConfig
    {
    public Guid ConfigId { get; set; }
    public Guid CatalogProductId { get; init; }
    public string? Description { get; init; }
    public string? ConfigCode { get; set; }
    public required string ConfigName { get; init; }
    public List<AdditionalInfo> AdditionalInfos { get; set; } = [];
    public List<ProductCatalogPrice> Price { get; set; } = [];
    public ProductStatus Status { get; init; }
    [XLColumn(Header = "Item Type")]
    public ProductType ItemType { get; init; }
    public string? LogUserName { get; set; }
    public System.DateTime? LogDts { get; set; } = DateTime.Now;
    }

    public record ProductCatalogPrice
    {
    [XLColumn(Ignore = true)]
    public Guid PriceId { get; set; }
    [XLColumn(Ignore = true)]
    public Guid CatalogProductId { get; init; }
    [XLColumn(Ignore = true)]
    public required Guid ConfigId { get; init; }
    public decimal Price { get; init; }
    [XLColumn(Header = "Valid From")]
    public DateTime ValidFrom { get; set; }
    [XLColumn(Header = "valid To")]
    public DateTime? ValidTo { get; set; }
    [XLColumn(Header = "Current Price Status")]
    public PriceState Status { get; set; }
    [XLColumn(Ignore = true)]
    public string? LogUserName { get; set; }
    [XLColumn(Ignore = true)]
    public System.DateTime? LogDts { get; set; } = DateTime.Now;
    }
    public record ProductCatalogPriceDetail : ProductCatalogPrice
    {
    [XLColumn(Header = "Config Code")]
    public string? ConfigCode { get; init; }
    [XLColumn(Header = "Config Name")]
    public string? ConfigName { get; init; }
    [XLColumn(Header = "Catalog Name")]
    public string? CatalogName { get; init; }
    [XLColumn(Header = "Catalog Code")]
    public string? CatalogCode { get; set; }
    [XLColumn(Ignore = true)]
    [System.Text.Json.Serialization.JsonIgnore]
    public int TotalNumber { get; set; }
    }

    public record CatalogFilter
    {
    public Guid? CatalogId { get; init; }
    public Guid? BaseProductId { get; init; }
    public string? CatalogName { get; init; }
    public string? BaseProductName { get; init; }
    public string? VersionName { get; init; }
    public string? CatalogCode { get; init; }
    public string? Model { get; init; }
    public string? Color { get; init; }
    public SellingType? SellingType { get; init; }
    public ProductType? ItemType { get; init; }
    public ProductStatus? CatalogStatus { get; init; }
    public SubItemType? SubItemType { get; init; }
    public int PageNumber { get; set; }
    public int RowsPerPage { get; set; }
    public bool IsExcel { get; init; } = false;
    }
    public record ConfigFilter : CatalogFilter
    {
    public Guid? ConfigId { get; init; }
    public ProductStatus? ConfigStatus { get; init; }
    public string? CatalogConfigCode { get; init; }
    public string? CatalogConfigName { get; init; }
    public List<AdditionalInfo> AdditionalInfos { get; init; } = [];
    }
    public record PriceFilter
    {
    public Guid? ConfigId { get; init; }
    public string? ConfigCode { get; init; }
    public string? ConfigName { get; init; }
    public DateTime? ValidFrom { get; set; }
    public DateTime? ValidTo { get; set; }
    public PriceState? Status { get; set; }
    public int PageNumber { get; set; }
    public int RowsPerPage { get; set;}
    public bool IsExcel { get; init; } = false;
    }
    public class ImageInfo
    {
    public string? ImageId { get; set; }
    }
    public enum PriceState
    {
    [Description("None")]
    None = 0,
    [Description("Active")]
    Active = 1,
    [Description("Inactive")]
    InActive = 2,
    [Description("Disabled")]
    Disable = 3,
    [Description("Scheduled")]
    Scheduled = 4
    }
    public enum SellingType
    {
    Unknown,
    Saleable,
    NonSaleable
    }

  • API Interfaces:
    (Define the APIs required for this feature, including endpoints, methods, request/response formats.)

    EndpointMethodParametersResponseResponse Status Codes
    /product/add/baseproductPOSTBaseProduct (required)BaseProduct200, 400, 403, 500
    /product/get/baseproductsPOSTBaseProductFilterServerPaginatedData<BaseProduct>200, 400, 403, 404, 500
    /product/get/allbaseproductsGETList<BaseProduct>200, 400, 403, 404, 500
    /product/add/versionPOSTProductVersion (required)ProductVersion200, 400, 403, 500
    /product/get/allversionGETList<ProductVersion>200, 400, 403, 404, 500
    /product/add/catalogPOSTProductCatalog (required)ProductCatalog200, 400, 403, 500
    /product/get/catalogPOSTCatalogFilterServerPaginatedData<CatalogInformation>200, 400, 403, 404, 500
    /product/get/configPOSTConfigFilterServerPaginatedData<ConfigInformation>200, 400, 403, 404, 500
    /product/get/allcatalogGETList<ProductCatalog>200, 400, 403, 404, 500
    /product/add/configurationPOSTCatalogConfig (required)CatalogConfig200, 400, 403, 500
    /product/get/allconfigurationGETList<CatalogConfig>200, 400, 403, 404, 500
    /product/set/catalog/pricePOSTProductCatalogPrice (required)ProductCatalogPrice200, 400, 403, 500
    /product/get/catalog/pricePOSTCatalogConfigidServerPaginatedData<ProductCatalogPriceDetail>200, 400, 403, 404, 500
    /product/update/baseproductstatusPATCHStatusUpdateRequestMessage200, 400, 403, 500
    /product/update/catalogstatusPATCHStatusUpdateRequestMessage200, 400, 403, 500
    /product/update/configstatusPATCHStatusUpdateRequestMessage200, 400, 403, 500
    /product/{catalogid}/uploadfilesPOSTGuid catalogid, IFormFileCollection filesList<ImageInfo>200, 400, 403, 500
    /product/{catalogid}/deletefilesDELETEGuid catalogid, string imageIdMessage200, 400, 403, 500
  • Third-Party Integrations:
    (List any third-party services or tools that need to be integrated.)

  • Workflow:

Flow Chart - Flow Chart

Development Tasks & Estimates

NoTask NameEstimate (Hours)DependenciesNotes
1Backend Create product cycle models2 hours
2Backend Create Database schema2 hours
3Backend Api for Add Base Product3 hours1,2
4Backend Api for get paginated Base Product4 hours
5Backend Api for Add Product version3 hours
6Backend Api for add product Catalog3 hours
7Backend Api for get paginated config6 hours
8Backend Api for Update Catalog configuration only3 hours
9Backend Api for add price3 hours
10Backend Api for get price3 hours
11Backend Background scheduler set end price date4.5 hours
12Backend Testing7 hours
13Backend Integration Testing4 hours
14Frontend product screen change2 hours
15Frontend product api and structure change2 hours
16Frontend product version add screen2 hours
17Frontend product version api and structure2 hours
18Frontend base product screen add3 hours
19Frontend base product api and structure change2 hours
20Frontend product table view change api and screen3 hours
21Frontend product base product show inside table collapsible3 hours
22Frontend product all get call change and show as per need in dropdown3 hours
23Frontend product catalog create with component and product dropdown show3.5 hours
24Frontend product catalog create with component api add and structure add1.5 hours
25Frontend product Price create/update with startdate and enddate multiple at a time3.5 hours
26Frontend product Price create with startdate and enddate api create & structure add1.5 hours
27Frontend product filter add3 hours
27Frontend Product Prices show in a dialog2.5 hours
28Frontend whole testing6 hours
29Backend Api for get all baseproducts3 hours
30Backend Api for get all version3 hours
31Backend Api for get all catalog3 hours
32Backend Api for get all catalog config3 hours
33Backend When Item Type is Parts or Accessories then at the time of adding cataog make a default config with same details3 hours
34Frontend Base product screen5 hours
35Frontend Add version ui2 hours
36Frontend Catalog Screen4 hours
37Frontend Add config ui2 hours
38Frontend Config screen5 hours
39Backend Api for base product status update5 hours
40Backend Api for catalog status update3 hours
41Backend Api for config status update3 hours
42Backend Api for catalog image upload4 hours
43Backend Api for catalog image delete3 hours
44Backend Api for get paginated catalog4 hours
45Frontend Integrate update base product status API2 hours
46Frontend Integrate update catalog status API2 hours
47Frontend Integrate update config status API2 hours
48Frontend Integrate update catalog image upload5 hours
Total152 hours

Testing & Quality Assurance

  • Unit Tests:
  1. Base Product Creation

Objective: Ensure that base products (e.g., Fleeto Magnum) are correctly added, validating necessary fields like name and description. Key Tests: Create a valid base product. Handle invalid product creation (e.g., missing name).

  1. Product Version Creation

Objective: Verify that multiple versions of a base product can be added with differing attributes (e.g., colors, battery specifications). Key Tests: Successfully add multiple versions for a base product. Ensure product versions are linked correctly to the base product.

  1. Catalog Product Creation

Objective: Ensure catalog products are added for each version, including saleable and non-saleable items. Key Tests: Validate catalog product creation for multiple versions. Handle unrecognized items by adding them to the component list.

  1. Catalog Price Management by date range

Objective: Ensure that catalog prices are correctly managed and activated within their specified date ranges, with no overlap between active prices. Key Tests: Set a valid price range for a catalog product. Ensure that only one active price exists at any time. Handle price deactivation when the date expires

  1. Background Scheduler for Setting End Price Date

Objective: Implement a background scheduler to automatically set the end date for old prices when a new price starts, ensuring proper price management. Key Tests: Scheduled Execution of Price Updates. Set End Date for Old Prices When a New Price Starts.

  • Integration Tests:

    1. Base product
    2. Version
    3. Catalog
    4. Configuration
    5. Price
  • Acceptance Criteria:

  • Testing Tools:


Deployment Considerations

(Describe any deployment considerations, including environment configurations, feature toggles, or migration steps.)

  • Configuration Changes:

      CREATE TABLE tblBaseProduct (
    BaseProductId UUID PRIMARY KEY,
    Name TEXT,
    ItemType VARCHAR(50),
    SubType VARCHAR(50),
    Brand VARCHAR(100),
    Model VARCHAR(100),
    Description VARCHAR(255),
    ProductCode TEXT,
    Status VARCHAR(50),
    LogUserName VARCHAR(50),
    LogDTS TIMESTAMP WITH TIME ZONE
    );


    CREATE TABLE tblProductVersion (
    VersionID UUID PRIMARY KEY, -- Version ID (PK)
    BaseProductId UUID,
    VersionName VARCHAR(100),
    Description VARCHAR(255),
    VersionStatus TEXT,
    LogUserName VARCHAR(50),
    LogDTS TIMESTAMP WITH TIME ZONE ,
    CONSTRAINT FK_ProductVersion FOREIGN KEY (BaseProductId) REFERENCES tblBaseProduct(BaseProductId)
    );

    CREATE TABLE tblProductCatalog (
    CatalogProductId UUID PRIMARY KEY,
    VersionId UUID NOT NULL,
    BaseProductId UUID NOT NULL,
    CatalogCode VARCHAR(100),
    CatalogName VARCHAR(255),
    Description TEXT,
    Colour text,
    images jsonb,
    GstRate text,
    HsnCode text,
    Year int,
    Weight decimal,
    Status text,
    ItemType VARCHAR(50),
    SellingType VARCHAR(50),
    LogDTS TIMESTAMP WITH TIME ZONE,
    LogUserName VARCHAR(50),
    CONSTRAINT FK_ProductVersion FOREIGN KEY (VersionId) REFERENCES tblProductVersion(VersionID),
    CONSTRAINT FK_ProductBase FOREIGN KEY (BaseProductId) REFERENCES tblBaseProduct(BaseProductId)
    );

    CREATE TABLE tblCatalogConfig (
    ConfigId UUID PRIMARY KEY,
    CatalogProductId UUID not null,
    CatalogProductCode VARCHAR(100),
    CatalogProductName VARCHAR(255),
    Description TEXT,
    LogDTS TIMESTAMP WITH TIME ZONE,
    LogUserName VARCHAR(50),
    Status text,
    AdditionalInfos Jsonb,
    ItemType VARCHAR(50),
    FOREIGN KEY (CatalogProductId) REFERENCES tblProductCatalog(CatalogProductId)
    );

    CREATE TABLE tblCatalogPrice (
    PriceId UUID PRIMARY KEY,
    ConfigId UUID not null,
    CatalogProductId UUID not null,
    Price DECIMAL(10, 2),
    StartDate TIMESTAMP WITH TIME ZONE,
    EndDate TIMESTAMP WITH TIME ZONE,
    LogDTS TIMESTAMP WITH TIME ZONE,
    LogUserName VARCHAR(50),
    Status text,
    FOREIGN KEY (CatalogProductId) REFERENCES tblProductCatalog(CatalogProductId),
    FOREIGN KEY (ConfigId) REFERENCES tblCatalogConfig(ConfigId)
    );




  • Rollout Plan:
    (Outline the plan for rolling out the feature, including any phased releases.)


Risks & Mitigations

(Identify potential risks and the strategies to mitigate them.)

RiskImpactLikelihoodMitigation Strategy
Product for distributorHighMediumMaintain a ConsumerId. Determine the appropriate stage in the workflow for adding it, considering the involvement of the distributor.

Review & Approval

(Include a section for review and approval by stakeholders.)

  • Reviewer:
    Abhishak Kumar Roy

  • Approval Date:
    2024-11-01


Notes
(Add any additional notes or considerations related to the feature development here.)