Supply Chain Analytics Dashboard

Developed an interactive Supply Chain Analytics Dashboard in Power BI to analyze key performance metrics across multiple product categories, cities, and customer segments. The dashboard provides comprehensive insights into order fulfillment, delivery delays, and product demand, enabling better decision-making for supply chain optimization.
The solution incorporates advanced data modeling, performance tracking, and recommendations to improve On-Time, In-Full (OTIF) delivery rates, reduce delays, and enhance customer satisfaction. It covers supply chain data for Dallas, Houston, and Phoenix, highlighting key metrics such as Cycle Order Completion Time (COCT), Inventory Fill Rate (IFD), and Vendor Fill Rate (VFR).
 

Key Features of the Dashboard

  • Data Preparation and Integration:
    • Used Power BI Query to clean, transform, and structure raw supply chain data for accurate analysis.
    • Integrated customer orders, delivery records, and product inventory data from multiple sources into a unified dataset.
  • Metric and KPI Identification: Analyzed key supply chain metrics, including:
    • On-Time, In-Full (OTIF%): Measures delivery performance against expectations.
    • Order-to-Delivery (OTD%): Indicates the proportion of orders delivered on time.
    • Inventory Fill Rate (IFD%): Shows the percentage of inventory fulfilled as requested.
    • Vendor Fill Rate (VFR%): Measures vendor reliability in supplying orders.
    • Cycle Order Completion Time (COCT): Evaluates the average time required to complete an order.
  • Interactive Visualizations and Performance Tracking: Developed  interactive report pages to provide insights into:
    • Total orders by product category and city (Dairy, Beverage, Fruit, Food).
    • Delivery performance (delivered vs. undelivered quantities).
    • City-based and product-based analysis of supply chain metrics.
    • Trend analysis of order fulfillment, delays, and vendor performance over time.
    • Customer segmentation analysis for high-order and high-delay customers.
  • Product and City-Based Recommendations:
    • Identified supply chain bottlenecks and improvement areas.
    • Recommended inventory and logistics adjustments based on historical performance trends and seasonal demand forecasts.
  • Publishing and Deployment:
    • Published the dashboard to Power BI Service for seamless access and real-time insights.
    • Enabled drill-through and filtering capabilities for city-wise, product-wise, and customer-wise analytics.

 

Technologies & Tools

 

Data Cleaning ETL & Data Transformation BI & Visualization
excel_microsoft_icon.png power-query-colored.svg (1) Power-BI.pngDesktop/Web Service

 

Process Overview

  • Initial Planning: Developed a project plan and methodology.
  • Stakeholder Meetings: Held multiple sessions with stakeholders to review the comprehensive survey narrative report and the 71 Excel sheets contained within 12 datasets.
  • Metric Identification: Based on these reviews, identified and defined the critical metrics and KPIs necessary for quantifying investment opportunities in the private health sector.
  • Data Review: Conducted an extensive review of the 12 Excel datasets and 71 individual sheets from the survey, ensuring a deep understanding of the captured data.
  • Data Cleaning & Aggregation: Leveraged Excel and Microsoft Access to clean, aggregate, and model the raw survey data.
  • Data Import: Imported the refined data into PowerBI using Power Query.
  • Data Loading and Connection:
    • Connected the cleaned data to PowerBI.
    • Structured the data model to support interactive filtering and analysis.
  • Dashboard Creation and Design:
    • Expenditure Tracking: Visual representations of spending across various facilities.
    • Donation Analysis: Insights into donor contributions and allocation.
    • Trend Analysis: Identification of spending patterns over time.
    • Performance Analysis: Visualizations and metrics to assess the efficiency and effectiveness of services.
  • DAX Formulas: Developed calculated measures and KPIs using DAX for dynamic analysis.
  • Publishing: Published the dashboards from PowerBI Desktop to the PowerBI Service.
  • User Presentation: Demonstrated the interactive dashboards to end users, showcasing how the tool can uncover lucrative investment opportunities.

 

Outcome/Impact

Detected supply chain gaps

1. Average OTIF% was 29%, significantly below the target of 65.9%, signaling major delays and partial deliveries.

2. Delivery performance was below optimal levels across all three cities (Dallas, Houston, Phoenix).

Delays and fulfillment rates

1.The top delayed products included Whole Milk, Chocolate Milk, Greek Yogurt, and American Cheese.

2. Most orders faced 1-3 day delays, leading to lower customer satisfaction and lost revenue opportunities.

Location Specific Insights

1. Houston excelled in OTD% and OTIF%, while Phoenix had the most delays

2. Dallas showed the lowest fulfillment rates, needing improvement.

 

Screenshots / Demo

 

Technical Highlights

 

Scalable Database Architecture

Designed database to support large-scale data processing for 5,000+ health facilities using SQL Server Database Management System.

Automated Data Processing

Developed a set of stored procedures tailored to data movement, validation, and backup management. These procedures enable seamless data integrity checks, structured data transfers, and reliable disaster recovery mechanisms, minimizing manual intervention and processing delays.

Reliable Backup & Recovery

Ensured daily database backups for disaster recovery and data integrity.

Optimized Query Performance

Implemented optimized indexing strategies tailored to frequently accessed columns. Since the database processes millions of records across 5,000+ health facilities, queries involving patient records, service utilization, inventory management, and financial transactions needed to be highly responsive.

 

Final Thoughts

The Supply Chain Analytics Dashboard project showcases my ability to transform raw supply chain data into actionable insights using Power BI. Through advanced data modeling, KPI tracking, and visualization techniques, I successfully delivered a solution that enables logistics managers, inventory planners, and business analysts to make data-driven supply chain optimizations.

This project highlights my expertise in Power BI development, supply chain analytics, and data-driven decision-making, demonstrating the real-world impact of interactive dashboards in logistics and operations management.

1. Procedure for data staging

                    

CREATE PROCEDURE [dbo].[UpdateHFMonitoringTableValues]
AS
BEGIN
    -- Delete orphaned records from DateValues, NumberValues, and TextValues tables
    DELETE FROM DateValues 
    WHERE ReportId NOT IN (SELECT id FROM Reports);

    DELETE FROM NumberValues 
    WHERE ReportId NOT IN (SELECT id FROM Reports);

    DELETE FROM TextValues 
    WHERE ReportId NOT IN (SELECT id FROM Reports);

    -- Declare variables
    DECLARE @TotalReports INTEGER;
    DECLARE @DateValues INTEGER;
    DECLARE @NumberValues INTEGER;
    DECLARE @TextValues INTEGER;
    DECLARE @GrandTotal INTEGER;
    DECLARE @GrandTotal2 INTEGER;

    -- Get counts of NumberValues and TextValues
    SET @NumberValues = (SELECT COUNT(*) FROM NumberValues);
    SET @TextValues = (SELECT COUNT(*) FROM TextValues);

    -- Calculate GrandTotal from TempHFMonitoringrecords
    SET @GrandTotal = (
        SELECT NumberValues + TextValues AS Total 
        FROM TempHFMonitoringrecords
    );

    SET @GrandTotal2 = @NumberValues + @TextValues;

    -- Compare GrandTotal values
    IF @GrandTotal <> @GrandTotal2
    BEGIN
        SET @TotalReports = (SELECT COUNT(*) FROM Reports);
        SET @DateValues = (SELECT COUNT(*) FROM DateValues);

        -- Truncate TempHFMonitoringrecords table
        TRUNCATE TABLE TempHFMonitoringrecords;

        -- Insert new values into TempHFMonitoringrecords
        INSERT INTO TempHFMonitoringrecords (TotalReports, NumberValues, DateValues, TextValues) 
        VALUES (@TotalReports, @NumberValues, @DateValues, @TextValues);

        -- Execute related stored procedures
        EXEC dbo.spHFMonitoringNumberValues;
        EXEC dbo.spHFNutritionServicesValues;
        EXEC dbo.spHFMonitoringfindings;
        EXEC dbo.spHFSAMDataQuality;

        -- Optional: Uncomment to view records
        -- SELECT * FROM TempHFMonitoringrecords;
    END
END
2. Aggregates New IMAM Cases

                    

SELECT 
    ProvCode, 
    ProvName, 
    Year, 
    Month, 
    SUM(TotalNewCases) AS Num, 
    1 AS Denom
FROM (
    -- First UNION query
    SELECT 
        p.ProvCode, 
        p.ProvName, 
        n.Year, 
        n.Month, 
        SUM(ISNULL(otptfu.z3score, 0)) + 
        SUM(ISNULL(otptfu.odema, 0)) + 
        SUM(ISNULL(otptfu.MUAC115, 0)) AS TotalNewCases
    FROM dbo.NMR n
    INNER JOIN dbo.tblOTPTFU otptfu ON n.NMRID = otptfu.NMRID
    INNER JOIN dbo.FacilityInfo fi ON n.FacilityID = fi.FacilityID
    INNER JOIN dbo.Districts d ON fi.DistCode = d.DistCode
    INNER JOIN dbo.Provinces p ON d.ProvCode = p.ProvCode
    WHERE n.Year > 1395
    GROUP BY n.Year, n.Month, p.ProvCode, p.ProvName
    
    UNION ALL
    
    -- Second UNION query
    SELECT 
        p1.ProvCode, 
        p1.ProvName, 
        n1.Year, 
        n1.Month, 
        SUM(ISNULL(otp.z3score, 0)) + 
        SUM(ISNULL(otp.odema, 0)) + 
        SUM(ISNULL(otp.MUAC115, 0)) AS TotalNewCases
    FROM dbo.NMR n1
    INNER JOIN dbo.tblOTP otp ON n1.NMRID = otp.NMRID
    INNER JOIN dbo.FacilityInfo fi1 ON n1.FacilityID = fi1.FacilityID
    INNER JOIN dbo.Districts d1 ON fi1.DistCode = d1.DistCode
    INNER JOIN dbo.Provinces p1 ON d1.ProvCode = p1.ProvCode
    WHERE n1.Year > 1395
    GROUP BY n1.Year, n1.Month, p1.ProvCode, p1.ProvName
) AS mm
GROUP BY ProvCode, ProvName, Year, Month;
3. Aggregates by Province and Indicator

                    

SELECT 
    CONCAT(p.ProvCode, tpc.FacilityTypeId, tpc.IndicatorId, tpc.[Year], tpc.[Month]) AS Id,
    p.ProvCode AS ProvinceId,
    p.ProvName AS Province,
    tpc.FacilityTypeId,
    ft.TypeAbbrv AS FacilityType,
    tpc.IndicatorId,
    ic.IndicatorName,
    tpc.Implementer,
    tpc.Module,
    tpc.Year AS [Year],
    tpc.Month AS [Month],
    tpc.Quarter AS Quarter,
    SUM(tpc.Num) AS Num,
    SUM(tpc.Denom) AS Denom
FROM dbo.totalpivotcombined_sbp tpc
INNER JOIN dbo.FacilityInfo fi ON tpc.FacilityID = fi.FacilityID
INNER JOIN dbo.Districts d ON fi.DistCode = d.DistCode
INNER JOIN dbo.Provinces p ON d.ProvCode = p.ProvCode
INNER JOIN dbo.FacilityTypes ft ON fi.FacilityType = ft.FacTypeCode
INNER JOIN dbo.Indicatorscombined ic ON tpc.IndicatorId = ic.IndicatorId
GROUP BY 
    p.ProvCode, 
    p.ProvName, 
    tpc.FacilityTypeId, 
    ft.TypeAbbrv, 
    tpc.IndicatorId, 
    ic.IndicatorName, 
    tpc.Implementer, 
    tpc.Module, 
    tpc.Year, 
    tpc.Month, 
    tpc.Quarter;
4. Supply Request Details

                    

WITH CTE_HF_ReqDetails AS (
    SELECT 
        hfrd.Id,
        hfrd.RequestId,
        hfrd.FacilityId,
        fi.FacilityName,
        hfrd.SupplyId,
        hfrd.FacilityTypeId,
        ft.TypeAbbrv AS FacilityType,
        d.DistName AS District,
        p.ProvName AS Province,
        imp.ImpAcronym AS Implementer,
        CONVERT(INT, hfrd.Children) AS Children,
        CONVERT(FLOAT, ROUND(hfrd.Buffer, 2)) AS Buffer,
        CONVERT(INT, hfrd.CurrentBalance) AS CurrentBalance,
        CONVERT(INT, hfrd.Adjustment) AS Adjustment,
        hfrd.AdjComment,
        CONVERT(FLOAT, hfrd.StockForChildren) AS StockForChildren,
        hfrd.Program,
        tss.Item,
        CONVERT(FLOAT, ISNULL(hfrd.Adjustment, 0)) + 
        CONVERT(FLOAT, ISNULL(hfrd.StockForChildren, 0)) AS TotalNeeded,
        hfrd.Esttype,
        sr.RequesttypeId,
        -- Adding a row number to uniquely identify each record per facility & supply
        ROW_NUMBER() OVER (PARTITION BY hfrd.FacilityId, hfrd.SupplyId ORDER BY hfrd.RequestId DESC) AS RowNum,
        -- Calculating the running total of stock adjustments per facility
        SUM(hfrd.Adjustment) OVER (PARTITION BY hfrd.FacilityId ORDER BY hfrd.RequestId) AS RunningTotalAdjustment,
        -- Calculating the average buffer per province
        AVG(hfrd.Buffer) OVER (PARTITION BY p.ProvCode) AS AvgBufferPerProvince
    FROM dbo.scmHFReqDetails hfrd
    INNER JOIN dbo.FacilityInfo fi ON hfrd.FacilityId = fi.FacilityID
    INNER JOIN dbo.FacilityTypes ft ON hfrd.FacilityTypeId = ft.FacTypeCode
    INNER JOIN dbo.tlkpSstock tss ON hfrd.SupplyId = tss.sstockID
    INNER JOIN dbo.Districts d ON fi.DistCode = d.DistCode
    INNER JOIN dbo.scmRequest srq ON hfrd.RequestId = srq.RequestId
    INNER JOIN dbo.scmRounds sr ON srq.RequestPeriod = sr.RoundId
    INNER JOIN dbo.Provinces p ON srq.ProvinceId = p.ProvCode
    INNER JOIN dbo.Implementers imp ON srq.ImpId = imp.ImpCode
)
SELECT * FROM CTE_HF_ReqDetails;
5. Compare, insert and update

                    

ALTER PROCEDURE [dbo].[UpdateNutritionMNPCampaigns]
    @Username NVARCHAR(50)
AS
BEGIN
    SET NOCOUNT ON; -- Prevent extra result sets from interfering with SELECT statements.

    -- Insert new records into NutritionMNPCampaigns if they do not already exist
    INSERT INTO [dbo].[NutritionMNPCampaigns] (
        ProvinceID, Year, Month, 
        Children6to59MonthReceivedMNPMale, Children6to59MonthReceivedMNPFemale,
        MDsTrainedOnMIYCNMale, MDsTrainedOnMIYCNFemale, MidwivesTrainedOnMIYCN,
        NursesTrainedOnMIYCNMale, NursesTrainedOnMIYCNFemale, 
        NCsReceived12DaysInitialTraining, NCsReceived6DaysRefresherTraining, 
        FoodDemoSessions, CHWsReceivedMonthlyIncentiveMale, CHWsReceivedMonthlyIncentiveFemale,
        TargetWomenReceivedCashWithNutritionServices, 
        BoysUnder2WeightedForGrowthCommunity, GirlsUnder2WeightedForGrowthCommunity, 
        NoofAdolescentGirlsReceivedIronFolicAcid, 
        ChschwstrainedonCBNPmale, ChschwstrainedonCBNPfemale,
        ChschwstrainedonMNPmale, ChschwstrainedonMNPfemale, 
        ChwschwstrainedoncomWIFSmale, ChwschwstrainedoncomWIFSfemale, 
        ChwschwstrainedonmontherMUACmale, ChwschwstrainedonmontherMUACfemale,
        CampaignVitaminAMale, CampaignVitaminAFemale,
        NoHPsupportedbyCBNPprogram, Username, Updatedate
    )
    SELECT 
        v.ProvinceID, v.Year, v.Month, 
        v.Children6to59MonthReceivedMNPMale, v.Children6to59MonthReceivedMNPFemale, 
        v.MDsTrainedOnMIYCNMale, v.MDsTrainedOnMIYCNFemale, v.MidwivesTrainedOnMIYCN, 
        v.NursesTrainedOnMIYCNMale, v.NursesTrainedOnMIYCNFemale, 
        v.NCsReceived12DaysInitialTraining, v.NCsReceived6DaysRefresherTraining, 
        v.FoodDemoSessions, v.CHWsReceivedMonthlyIncentiveMale, v.CHWsReceivedMonthlyIncentiveFemale, 
        v.TargetWomenReceivedCashWithNutritionServices, 
        v.BoysUnder2WeightedForGrowthCommunity, v.GirlsUnder2WeightedForGrowthCommunity, 
        v.NoofAdolescentGirlsReceivedIronFolicAcid, 
        v.ChschwstrainedonCBNPmale, v.ChschwstrainedonCBNPfemale,
        v.ChschwstrainedonMNPmale, v.ChschwstrainedonMNPfemale, 
        v.ChwschwstrainedoncomWIFSmale, v.ChwschwstrainedoncomWIFSfemale, 
        v.ChwschwstrainedonmontherMUACmale, v.ChwschwstrainedonmontherMUACfemale,
        v.CampaignVitaminAMale, v.CampaignVitaminAFemale,
        v.NoHPsupportedbyCBNPprogram, v.Username, v.Updatedate
    FROM dbo.vTempNutritionMNPCampaigns v
    WHERE 
        CONCAT(v.ProvinceID, v.Year, v.Month) NOT IN 
        (SELECT CONCAT(ProvinceID, Year, Month) FROM NutritionMNPCampaigns)
        AND v.ProvinceID IS NOT NULL 
        AND (v.Year * 100 + v.Month) <= (YEAR(GETDATE()) * 100 + MONTH(GETDATE()));

    -- Update existing records if they were updated within the last 60 days by the specified user
    UPDATE n
    SET 
        n.Children6to59MonthReceivedMNPMale = t.Children6to59MonthReceivedMNPMale,
        n.Children6to59MonthReceivedMNPFemale = t.Children6to59MonthReceivedMNPFemale,
        n.MDsTrainedOnMIYCNMale = t.MDsTrainedOnMIYCNMale,
        n.MDsTrainedOnMIYCNFemale = t.MDsTrainedOnMIYCNFemale,
        n.MidwivesTrainedOnMIYCN = t.MidwivesTrainedOnMIYCN,
        n.NursesTrainedOnMIYCNMale = t.NursesTrainedOnMIYCNMale,
        n.NursesTrainedOnMIYCNFemale = t.NursesTrainedOnMIYCNFemale,
        n.NCsReceived12DaysInitialTraining = t.NCsReceived12DaysInitialTraining,
        n.NCsReceived6DaysRefresherTraining = t.NCsReceived6DaysRefresherTraining,
        n.FoodDemoSessions = t.FoodDemoSessions,
        n.CHWsReceivedMonthlyIncentiveMale = t.CHWsReceivedMonthlyIncentiveMale,
        n.CHWsReceivedMonthlyIncentiveFemale = t.CHWsReceivedMonthlyIncentiveFemale,
        n.TargetWomenReceivedCashWithNutritionServices = t.TargetWomenReceivedCashWithNutritionServices,
        n.BoysUnder2WeightedForGrowthCommunity = t.BoysUnder2WeightedForGrowthCommunity,
        n.GirlsUnder2WeightedForGrowthCommunity = t.GirlsUnder2WeightedForGrowthCommunity,
        n.NoofAdolescentGirlsReceivedIronFolicAcid = t.NoofAdolescentGirlsReceivedIronFolicAcid,
        n.ChschwstrainedonCBNPmale = t.ChschwstrainedonCBNPmale,
        n.ChschwstrainedonCBNPfemale = t.ChschwstrainedonCBNPfemale,
        n.ChschwstrainedonMNPmale = t.ChschwstrainedonMNPmale,
        n.ChschwstrainedonMNPfemale = t.ChschwstrainedonMNPfemale,
        n.ChwschwstrainedoncomWIFSmale = t.ChwschwstrainedoncomWIFSmale,
        n.ChwschwstrainedoncomWIFSfemale = t.ChwschwstrainedoncomWIFSfemale,
        n.ChwschwstrainedonmontherMUACmale = t.ChwschwstrainedonmontherMUACmale,
        n.ChwschwstrainedonmontherMUACfemale = t.ChwschwstrainedonmontherMUACfemale,
        n.CampaignVitaminAMale = t.CampaignVitaminAMale,
        n.CampaignVitaminAFemale = t.CampaignVitaminAFemale,
        n.NoHPsupportedbyCBNPprogram = t.NoHPsupportedbyCBNPprogram,
        n.Username = t.Username,
        n.Updatedate = t.Updatedate
    FROM NutritionMNPCampaigns n
    INNER JOIN vTempNutritionMNPCampaigns t
        ON n.ProvinceID = t.ProvinceID 
        AND n.Year = t.Year 
        AND n.Month = t.Month
    WHERE 
        n.Username = @Username 
        AND DATEDIFF(DAY, n.Updatedate, GETDATE()) < 60;
END;