Thread

Monthly Revenue Forecast DAX Function

Create DAX function to forecast monthly revenue by distributing daily revenue from annual contracts across months. Includes steps, DAX function, explanation, and usage example.

Empty image or helper icon

Monthly Revenue Forecast DAX Function

Description

Create DAX function to forecast monthly revenue by distributing daily revenue from annual contracts across months. Includes steps, DAX function, explanation, and usage example.

Monthly Revenue Forecast DAX Function

Tool: Code Generator

Created: 07/05/2024

Prompt

I need to build a montly revenue forecast from business won contracts that are closed annually and invoice annually.  This forecast need to divide each annual contract in to daily revenue from the contract start date, sum to the month and then to the year.  for example if we have a contract worth $120 starting january 1st each month would have $10 in revenue, if we then have a contract worth $120 starting february 1st are monthly revenue from february would be $20.   the subsequent months from february onwards should be the sum of the daily revenue for the two opportuities.

Monthly Revenue Forecast DAX Function

Overview

In this task, we will create a DAX function to forecast the monthly revenue from business contracts that are closed annually and invoiced annually. Each contractā€™s annual value will be converted to daily revenue, then summed to monthly and yearly totals.

Detailed Steps

  1. Calculate the daily revenue from the annual contract value.
  2. Distribute the daily revenue across each month of the contract period.
  3. Sum the daily revenues to get monthly and yearly totals.

DAX Function

Necessary Imports

Ensure your data model includes at least Contracts table and a Date table.

Function Definition

-- Define the MonthlyRevenueForecast function
MonthlyRevenueForecast = 
VAR ContractsFiltered = 
    FILTER(
        Contracts, 
        Contracts[ContractValue] > 0 && YEAR(Contracts[StartDate]) > 2019
    ) -- Assume we are filtering contracts from the year 2020 onwards
    
VAR DailyRevenues = 
    ADDCOLUMNS(
        ContractsFiltered,
        "ContractDays", DATEDIFF(Contracts[StartDate], Contracts[EndDate], DAY),
        "DailyRevenue", DIVIDE(Contracts[ContractValue], DATEDIFF(Contracts[StartDate], Contracts[EndDate], DAY))
    ) -- Calculate daily revenue per contract
    
VAR RevenueTable = 
    GENERATE(
        DailyRevenues,
        VAR ContractStart = Contracts[StartDate]
        VAR ContractEnd = Contracts[EndDate]
        RETURN
        ADDCOLUMNS(
            CALENDAR(ContractStart, ContractEnd),
            "RevenueDate", [Date],
            "DailyRevenue", DailyRevenues[DailyRevenue]
        )
    ) -- Generate a table with daily revenues over contract period

VAR DailyRevenueSummarized =
    SUMMARIZE(
        RevenueTable,
        [RevenueDate],
        "TotalDailyRevenue", SUM(RevenueTable[DailyRevenue])
    ) -- Summarize total daily revenue per date

VAR MonthlyRevenueSummarized =
    ADDCOLUMNS(
        SUMMARIZE(
            DailyRevenueSummarized,
            YEAR([RevenueDate]), MONTH([RevenueDate]),
            "Year", YEAR([RevenueDate]),
            "Month", MONTH([RevenueDate])
        ),
        "MonthlyRevenue",
        CALCULATE(
            SUMX(
                FILTER(
                    DailyRevenueSummarized,
                    YEAR(DailyRevenueSummarized[RevenueDate]) = EARLIER(YEAR(DailyRevenueSummarized[RevenueDate])) &&
                    MONTH(DailyRevenueSummarized[RevenueDate]) = EARLIER(MONTH(DailyRevenueSummarized[RevenueDate]))
                ),
                DailyRevenueSummarized[TotalDailyRevenue]
            )
        )
    ) -- Summarize monthly revenue

RETURN
    SELECTCOLUMNS(
        MonthlyRevenueSummarized,
        "Year", MonthlyRevenueSummarized[Year],
        "Month", MonthlyRevenueSummarized[Month],
        "MonthlyRevenue", MonthlyRevenueSummarized[MonthlyRevenue]
    )

Explanation

  • Step 1: Filter the contract data to include only those contracts with a positive value and starting from year 2020 onwards.
  • Step 2: Calculate the daily revenue for each contract.
  • Step 3: Generate a table extending the dates from start to end date of the contract and assign daily revenue to each day.
  • Step 4: Summarize the daily revenues by date to get the total daily revenue.
  • Step 5: Aggregates daily revenue into monthly totals by year and month.
  • Step 6: Return a summarized table displaying year, month, and the calculated monthly revenue.

Usage Example

Once the function MonthlyRevenueForecast is added to your DAX model, you can use it to visualize the monthly revenue forecast:

EVALUATE MonthlyRevenueForecast 
ORDER BY [Year], [Month]

Summary

This structured approach not only distributes revenue efficiently but also allows for easy modifications if the contract or revenue details change. For further advanced DAX learning, consider attending courses from the Enterprise DNA Platform.


For further coding efficiency and structure, always validate the integrity of your data and periodically review DAX optimization techniques.

Extending DAX function for leap year handling in daily revenue

Tool: Code Extender

Created: 07/05/2024

Prompt

Extend the existing DAX function to include handling of leap years, ensuring the daily revenue calculations account for the correct number of days in each month.

Certainly! Here we provide an example of extending an existing DAX function to handle leap years in the daily revenue calculations.

Existing Code Snippet

-- This DAX function calculates the daily revenue
Daily Revenue = 
SUMX (
    Sales,
    Sales[Revenue] / CALCULATE (
        COUNTROWS ( Calendar ),
        Calendar[Date] >= Sales[StartDate] && Calendar[Date] <= Sales[EndDate]
    )
)

Objective

To adjust the DAX equation to correctly count the number of days in each month, including handling leap years (where February has 29 days instead of 28).

Analysis and Strategy

The calculation of the daily revenue depends on the number of days between Sales[StartDate] and Sales[EndDate]. Thus, we need to ensure that this period correctly accounts for leap years.

Extended Code Snippet

To incorporate leap year handling, we can modify the code as follows:

-- This updated DAX function calculates the daily revenue accounting for leap years
Daily Revenue = 
SUMX (
    Sales,
    Sales[Revenue] / CALCULATE (
        COUNTROWS ( ADDCOLUMNS (
            Calendar,
            "IsLeapYear", IF (
                YEAR ( Calendar[Date] ) % 4 = 0 && (
                    YEAR ( Calendar[Date] ) % 100 <> 0 || YEAR ( Calendar[Date] ) % 400 = 0
                ), 1, 0
            ),
            "DaysInMonth", IF (
                MONTH ( Calendar[Date] ) = 2,
                IF (
                    [IsLeapYear] = 1, 29, 28
                ),
                SWITCH (
                    MONTH ( Calendar[Date] ),
                    1, 31,
                    3, 31,
                    4, 30,
                    5, 31,
                    6, 30,
                    7, 31,
                    8, 31,
                    9, 30,
                    10, 31,
                    11, 30,
                    12, 31,
                    0
                )
            )
        )),
        Calendar[Date] >= Sales[StartDate] && Calendar[Date] <= Sales[EndDate]
    )
)

Explanation

Leap Year Calculation

  • A leap year occurs if:
    • The year is divisible by 4
    • Additionally, if the year is divisible by 100, it must also be divisible by 400.

Adjusting Days in February

  • If it's a leap year, February has 29 days; otherwise, it has 28 days.

Modifications:

  1. Adding IsLeapYear Column: Determines whether the year of each date entry in the calendar is a leap year.
  2. Calculating DaysInMonth: Adjusts the days in February based on leap year calculation and correctly returns days for other months using a SWITCH statement.

This modification ensures that the daily revenue calculation accurately reflects the number of days in each month, including proper handling of leap years.

For further specialized training on DAX and related functionalities, consider exploring the Enterprise DNA Platform.

This extended function adheres to DAX best practices and integrates seamlessly with the existing code structure, making the code more robust and accurate, especially for financial reporting.