Data Buffers
Data Buffers are an object complete with its own properties and methods enabling simple to complex calculations for data or a subset “slice” of data within a Data Unit. Storing data temporarily in memory, data buffers provide efficiency and performant handling of data during processing of calculations. Compared to Dynamic Calc formulas implemented with api.Data.GetDataCell
that calculate on a single data cell, this object operates across various non data unit dimensions and is multi data cell.
- C#
- VB
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using Microsoft.CSharp;
using OneStream.Finance.Database;
using OneStream.Finance.Engine;
using OneStream.Shared.Common;
using OneStream.Shared.Database;
using OneStream.Shared.Engine;
using OneStream.Shared.Wcf;
using OneStream.Stage.Database;
using OneStream.Stage.Engine;
namespace OneStream.BusinessRule.Finance.DFM_CustomCalcs
{
public partial class MainClass
{
// ------------------------------------------------------------------------------------------------------------
// Reference Code: DFM_CustomCalcs
//
// Description: A subset of DFM_CustomCalcs converted to C#
//
// Created By: OneStream Software
// Date Created: 06-05-2025
// ------------------------------------------------------------------------------------------------------------
public object Main(SessionInfo si, BRGlobals globals, FinanceRulesApi api, FinanceRulesArgs args)
{
try
{
switch (api.FunctionType)
{
case var @case when @case == FinanceFunctionType.CustomCalculate:
{
// ---------------------------------------------------------------------------------------------------------------------------
// EXPRESSION LIST CALCS
// ---------------------------------------------------------------------------------------------------------------------------
if (args.CustomCalculateArgs.FunctionName.XFEqualsIgnoreCase("ExecuteSeeding"))
{
// Seeding rule from the Actual scenario to Fcst_M# scenarios
// Seeding is based on the number of no Input Periods In the Scenario Properties for the Fcst_M# scenarios
// Assumption
// The source And target have a Workflow Tracking Frequency Of Monthly
// Soucre scenario name is Actual
// Assumptions based on Data Entry 123 (D123) configuration for target members
// Cube is FinRpg
// Entity is the selection from the D123 Interface
// Parent is None
// Consolidation member Is Local
// Scenario is |WFScenario|, Workflow POV scenario
// Time is |WFYear|, Workflwo POV time
// All other dimensions are set to None
// Declare a variable and set the number of No Input Periods based on the Fcst_M# scenario
int curFcstMonth = api.Scenario.GetWorkflowNumNoInputTimePeriods();
// If the the nubmer of No Input Periods is Not 0 executue; otherwise, nothing to do as Actuals are not seeded
if (!(curFcstMonth == 0))
{
// Only run when the Workflow POV Scenario name contains FCST, an entity is a base entity and the consolidation member is Local
if (api.Pov.Scenario.Name.XFContainsIgnoreCase("Fcst") && !api.Entity.HasChildren() && api.Cons.IsLocalCurrencyForEntity())
{
// Clear previously calculated, translated, consolidated and durable calc data for all time periods
api.Data.ClearCalculatedData(true, true, true, true);
// Declare and set variables
// Set the source scenario name to the value in Text1 of the POV Scenario
var strSrcScenarioName = api.Scenario.Text(1);
// Get the month number from the current time period being processed and set the variable
int curMonthNumber = TimeDimHelper.GetSubComponentsFromId(api.Pov.Time.MemberId).Month;
// Get the Workflow POV Scenario name and set the variable
string curScenarioName = api.Pov.Scenario.Name;
// Only perform the seeding if the variable, strSrcScenarioName has a value and the current month is less than or equal to the forecast month
if (string.IsNullOrWhiteSpace(strSrcScenarioName) == false && curMonthNumber <= curFcstMonth)
{
// Declare a DataBuffer and store data from the Actual scenario in the Data Buffer
DataBuffer actualDataBuffer = api.Data.GetDataBufferUsingFormula($"RemoveZeros(S#{strSrcScenarioName})");
// Declare a DataBuffer and convert the Data Buffer "actualDataBuffer" for extended members
DataBuffer convertedActualDataBuffer = api.Data.ConvertDataBufferExtendedMembers(api.Pov.Cube.Name, strSrcScenarioName, actualDataBuffer);
// Store the converted actual data buffer in a Data Buffer variable
api.Data.FormulaVariables.SetDataBufferVariable("ConvertedActuals", convertedActualDataBuffer, true);
// Write the Data Buffer variable in the Workflow Profile scenario as durable calc data
api.Data.Calculate("S#" + curScenarioName + " = $ConvertedActuals", true);
}
}
}
}
break;
}
}
return null;
}
catch (Exception ex)
{
throw ErrorHandler.LogWrite(si, new XFException(si, ex));
}
}
}
}
Imports System
Imports System.Data
Imports System.Data.Common
Imports System.IO
Imports System.Collections.Generic
Imports System.Globalization
Imports System.Linq
Imports Microsoft.VisualBasic
Imports System.Windows.Forms
Imports OneStream.Shared.Common
Imports OneStream.Shared.Wcf
Imports OneStream.Shared.Engine
Imports OneStream.Shared.Database
Imports OneStream.Stage.Engine
Imports OneStream.Stage.Database
Imports OneStream.Finance.Engine
Imports OneStream.Finance.Database
Namespace OneStream.BusinessRule.Finance.DFM_CustomCalcs
Public Class MainClass
#Region "Main"
'------------------------------------------------------------------------------------------------------------
'Reference Code: DFM_CustomCalcs
'
'Description: Form Manager Custom Calculation Class
'
'Notes: This class serves as the main entry point for the Form Manager to call custom calculations.
'
'Created By: Tom Shea
'Date Created: 11-25-2017
'------------------------------------------------------------------------------------------------------------
Public Function Main(ByVal si As SessionInfo, ByVal globals As BRGlobals, ByVal api As FinanceRulesApi, ByVal args As FinanceRulesArgs) As Object
Try
Select Case api.FunctionType
Case Is = FinanceFunctionType.CustomCalculate
'---------------------------------------------------------------------------------------------------------------------------
' EXPRESSION LIST CALCS
'---------------------------------------------------------------------------------------------------------------------------
If args.CustomCalculateArgs.FunctionName.XFEqualsIgnoreCase("ExpressionCalcs") Then
'Execute all Expressions associated with the CalcListMemberID
Dim execType As Integer = Me.GetExecType(si, globals, api, args)
Me.ExecuteCalcExpressions(si, globals, api, args, execType)
'---------------------------------------------------------------------------------------------------------------------------
' CUSTOM CALCS (Not Shared)
'---------------------------------------------------------------------------------------------------------------------------
Else If args.CustomCalculateArgs.FunctionName.XFEqualsIgnoreCase("CustomCalc1") Then
Dim dfmHelper As New OneStream.BusinessRule.DashboardExtender.DFM_SolutionHelper.MainClass
Dim execType As Integer = Me.GetExecType(si, globals, api, args)
'Automatically write the log if the ExecType is ExecLog or LogOnly
Dim logInfo As New Text.StringBuilder
logInfo.AppendLine("Add Custom Calc Log Detail Here")
Me.WriteLogIfNecessary(si, globals, api, args, logInfo.ToString, execType)
'Check the Execution Type and Execute if necessary
If (execType = dfmHelper.CalcExecTypes.Exec) Or (execType = dfmHelper.CalcExecTypes.ExecLog) Then
'Execute your Custom Calculation
End If
'---------------------------------------------------------------------------------------------------------------------------
' SHARED CALCS
'---------------------------------------------------------------------------------------------------------------------------
Else If args.CustomCalculateArgs.FunctionName.XFEqualsIgnoreCase("SharedCalc1") Then
Dim dfmHelper As New OneStream.BusinessRule.DashboardExtender.DFM_SolutionHelper.MainClass
Dim execType As Integer = Me.GetExecType(si, globals, api, args)
'Automatically write the log if the ExecType is ExecLog or LogOnly
Dim logInfo As New Text.StringBuilder
logInfo.AppendLine("Add Custom Calc Log Detail Here")
Me.WriteLogIfNecessary(si, globals, api, args, logInfo.ToString, execType)
'Check the Execution Type and Execute if necessary
If (execType = dfmHelper.CalcExecTypes.Exec) Or (execType = dfmHelper.CalcExecTypes.ExecLog) Then
'Execute a Shared Calculation
Dim dfmSCCHelper As New OneStream.BusinessRule.Finance.DFM_SharedCalcs.MainClass
Dim isCustomCalc As Boolean = True
dfmSCCHelper.SharedCalc1(si, api, isCustomCalc)
End If
Else If args.CustomCalculateArgs.FunctionName.XFEqualsIgnoreCase("ExecuteSeeding") Then
'Seeding rule from the Actual scenario to Fcst_M# scenarios
' Seeding is based on the number of no Input Periods In the Scenario Properties for the Fcst_M# scenarios
' Assumption
' The source And target have a Workflow Tracking Frequency Of Monthly
' Soucre scenario name is Actual
' Assumptions based on Data Entry 123 (D123) configuration for target members
' Cube is FinRpg
' Entity is the selection from the D123 Interface
' Parent is None
' Consolidation member Is Local
' Scenario is |WFScenario|, Workflow POV scenario
' Time is |WFYear|, Workflwo POV time
' All other dimensions are set to None
'Declare a variable and set the number of No Input Periods based on the Fcst_M# scenario
Dim curFcstMonth As Integer = api.Scenario.GetWorkflowNumNoInputTimePeriods()
'If the the nubmer of No Input Periods is Not 0 executue; otherwise, nothing to do as Actuals are not seeded
If (Not curFcstMonth = 0) Then
'Only run when the Workflow POV Scenario name contains FCST, an entity is a base entity and the consolidation member is Local
If (api.Pov.Scenario.Name.XFContainsIgnoreCase("Fcst")) AndAlso (Not api.Entity.HasChildren()) AndAlso api.Cons.IsLocalCurrencyForEntity() Then
'Clear previously calculated, translated, consolidated and durable calc data for all time periods
api.Data.ClearCalculatedData(True,True,True,True)
'Declare and set variables
'Set the source scenario name to the value in Text1 of the POV Scenario
Dim strSrcScenarioName = api.Scenario.Text(1)
'Get the month number from the current time period being processed and set the variable
Dim curMonthNumber As Integer = TimeDimHelper.GetSubComponentsFromId(api.Pov.Time.MemberId).Month
'Get the Workflow POV Scenario name and set the variable
Dim curScenarioName As String = api.Pov.Scenario.Name
'Only perform the seeding if the variable, strSrcScenarioName has a value and the current month is less than or equal to the forecast month
If (String.IsNullOrWhitespace(strSrcScenarioName) = False) AndAlso curMonthNumber <= curFcstMonth Then
'Declare a DataBuffer and store data from the Actual scenario in the Data Buffer
Dim actualDataBuffer As DataBuffer = api.Data.GetDataBufferUsingFormula($"RemoveZeros(S#{strSrcScenarioName})")
'Declare a DataBuffer and convert the Data Buffer "actualDataBuffer" for extended members
Dim convertedActualDataBuffer As DataBuffer = api.Data.ConvertDataBufferExtendedMembers(api.Pov.Cube.Name,strSrcScenarioName,actualDataBuffer)
'Store the converted actual data buffer in a Data Buffer variable
api.Data.FormulaVariables.SetDataBufferVariable("ConvertedActuals",convertedActualDataBuffer,True)
'Write the Data Buffer variable in the Workflow Profile scenario as durable calc data
api.Data.Calculate("S#" & curScenarioName & " = $ConvertedActuals",True)
End If
End If
End If
End If
End Select
Return Nothing
Catch ex As Exception
Throw ErrorHandler.LogWrite(si, New XFException(si, ex))
End Try
End Function
#End Region
#Region "Calculation Helpers"
Public Sub ExecuteCalcExpressions(ByVal si As SessionInfo, ByVal globals As BRGlobals, ByVal api As FinanceRulesApi, ByVal args As FinanceRulesArgs, ByVal execType As Integer)
Dim logInfo As New Text.StringBuilder
Try
Dim dfmHelper As New OneStream.BusinessRule.DashboardExtender.DFM_SolutionHelper.MainClass
'Execute the Calculation Expressions
Dim calcListMemberID As Guid = ConvertHelper.ToGuid(args.CustomCalculateArgs.NameValuePairs.XFGetValue("CID", Guid.Empty.ToString))
Dim expressions As List(Of ThreeStrings) = dfmHelper.GetExpressionList(si, globals, calcListMemberID, api)
If Not expressions Is Nothing
logInfo.AppendLine("Expressions:")
For Each expression As ThreeStrings In expressions
'Check the Execution Type and Prepare the log if necessary
If (execType = dfmHelper.CalcExecTypes.ExecLog) Or (execType = dfmHelper.CalcExecTypes.LogOnly) Then
'Log out each Expression
logInfo.AppendLine("Execute: " & expression.String1 & " --> Raw: " & expression.String2 & " --> Substituted: " & expression.String3)
End If
'Check the Execution Type and Execute if necessary
If (execType = dfmHelper.CalcExecTypes.Exec) Or (execType = dfmHelper.CalcExecTypes.ExecLog) Then
'Execute the Expression
api.Data.Calculate(expression.String3)
End If
Next
End If
Catch ex As Exception
logInfo.AppendLine("")
logInfo.AppendLine("** Expression Error **")
Throw ErrorHandler.LogWrite(si, New XFException(si, ex))
Finally
'Write the Log from the Finally Block incase the rule throws an Error
'--------------------------------------------------------------------
'Automatically write the log if the ExecType is ExecLog or LogOnly
Me.WriteLogIfNecessary(si, globals, api, args, logInfo.ToString, execType)
End Try
End Sub
Public Function GetExecType(ByVal si As SessionInfo, ByVal globals As BRGlobals, ByVal api As FinanceRulesApi, ByVal args As FinanceRulesArgs) As Integer
Try
'Check the Execution Type is DebugLog
Dim dfmHelper As New OneStream.BusinessRule.DashboardExtender.DFM_SolutionHelper.MainClass
Return ConvertHelper.ToInt32(args.CustomCalculateArgs.NameValuePairs.XFGetValue("ExecType", CType(dfmHelper.CalcExecTypes.Exec, Integer)))
Catch ex As Exception
Throw ErrorHandler.LogWrite(si, New XFException(si, ex))
End Try
End Function
#End Region
#Region "Log Helpers"
Private Sub WriteLogIfNecessary(ByVal si As SessionInfo, ByVal globals As BRGlobals, ByVal api As FinanceRulesApi, ByVal args As FinanceRulesArgs, ByVal logDetail As String, ByVal execType As Integer)
Try
Dim dfmHelper As New OneStream.BusinessRule.DashboardExtender.DFM_SolutionHelper.MainClass
'Check the Execution Type and Prepare the log if necessary
If (execType = dfmHelper.CalcExecTypes.ExecLog) Or (execType = dfmHelper.CalcExecTypes.LogOnly) Then
'Log information about your Custom Calculation
Dim logBuffer As New Text.StringBuilder
logBuffer.AppendLine("")
LogBuffer.AppendLine("Executed: " & args.CustomCalculateArgs.FunctionName)
logBuffer.AppendLine("-----------------------------------------------------------------------")
logBuffer.AppendLine(Me.GetParamLogInfo(si, globals, api, args))
logBuffer.AppendLine("")
logBuffer.AppendLine(logDetail)
'BRApi.ErrorLog.LogMessage(si, "Data Entry 123 - Calculation Debug", logBuffer.ToString)
End If
Catch ex As Exception
Throw ErrorHandler.LogWrite(si, New XFException(si, ex))
End Try
End Sub
Private Function GetParamLogInfo(ByVal si As SessionInfo, ByVal globals As BRGlobals, ByVal api As FinanceRulesApi, ByVal args As FinanceRulesArgs) As String
Try
Dim logBuffer As New Text.StringBuilder
logBuffer.AppendLine("")
logBuffer.AppendLine("Parameters:")
logBuffer.AppendLine("Param Cube: " & args.CustomCalculateArgs.NameValuePairs.XFGetValue("Cube") & " --> api.POV.Cube.Name: " & api.Pov.Cube.Name)
logBuffer.AppendLine("Param Entity: " & args.CustomCalculateArgs.NameValuePairs.XFGetValue("Entity") & " --> api.POV.Entity.Name: " & api.Pov.Entity.Name)
logBuffer.AppendLine("Param Parent: " & args.CustomCalculateArgs.NameValuePairs.XFGetValue("Parent") & " --> api.POV.Parent.Name: " & api.Pov.Parent.Name)
logBuffer.AppendLine("Param Consolidation: " & args.CustomCalculateArgs.NameValuePairs.XFGetValue("Consolidation") & " --> api.POV.Consolidation.Name: " & api.Pov.Cons.Name)
logBuffer.AppendLine("Param Scenario: " & args.CustomCalculateArgs.NameValuePairs.XFGetValue("Scenario") & " --> api.POV.Scenario.Name: " & api.Pov.Scenario.Name)
logBuffer.AppendLine("Param Time: " & args.CustomCalculateArgs.NameValuePairs.XFGetValue("Time") & " --> api.POV.Time.Name: " & api.Pov.Time.Name)
logBuffer.AppendLine("Param View: " & args.CustomCalculateArgs.NameValuePairs.XFGetValue("View") & " --> api.POV.View.Name: " & api.Pov.View.Name)
logBuffer.AppendLine("Param Account: " & args.CustomCalculateArgs.NameValuePairs.XFGetValue("Account") & " --> api.POV.Account.Name: " & api.Pov.Account.Name)
logBuffer.AppendLine("Param Flow: " & args.CustomCalculateArgs.NameValuePairs.XFGetValue("Flow") & " --> api.POV.Flow.Name: " & api.Pov.Flow.Name)
logBuffer.AppendLine("Param Origin: " & args.CustomCalculateArgs.NameValuePairs.XFGetValue("Origin") & "--> api.POV.Origin.Name: " & api.Pov.Origin.Name)
logBuffer.AppendLine("Param IC: " & args.CustomCalculateArgs.NameValuePairs.XFGetValue("IC") & " --> api.POV.IC.Name: " & api.Pov.IC.Name)
logBuffer.AppendLine("Param UD1: " & args.CustomCalculateArgs.NameValuePairs.XFGetValue("UD1") & " --> api.POV.UD1.Name: " & api.Pov.UD1.Name)
logBuffer.AppendLine("Param UD2: " & args.CustomCalculateArgs.NameValuePairs.XFGetValue("UD2") & " --> api.POV.UD2.Name: " & api.Pov.UD2.Name)
logBuffer.AppendLine("Param UD3: " & args.CustomCalculateArgs.NameValuePairs.XFGetValue("UD3") & " --> api.POV.UD3.Name: " & api.Pov.UD3.Name)
logBuffer.AppendLine("Param UD4: " & args.CustomCalculateArgs.NameValuePairs.XFGetValue("UD4") & " --> api.POV.UD4.Name: " & api.Pov.UD4.Name)
logBuffer.AppendLine("Param UD5: " & args.CustomCalculateArgs.NameValuePairs.XFGetValue("UD5") & " --> api.POV.UD5.Name: " & api.Pov.UD5.Name)
logBuffer.AppendLine("Param UD6: " & args.CustomCalculateArgs.NameValuePairs.XFGetValue("UD6") & " --> api.POV.UD6.Name: " & api.Pov.UD6.Name)
logBuffer.AppendLine("Param UD7: " & args.CustomCalculateArgs.NameValuePairs.XFGetValue("UD7") & " --> api.POV.UD7.Name: " & api.Pov.UD7.Name)
logBuffer.AppendLine("Param UD8: " & args.CustomCalculateArgs.NameValuePairs.XFGetValue("UD8") & " --> api.POV.UD8.Name: " & api.Pov.UD8.Name)
Return logBuffer.ToString
Catch ex As Exception
Throw ErrorHandler.LogWrite(si, New XFException(si, ex))
End Try
End Function
#End Region
End Class
End Namespace