11-27-2023 03:24 PM
This post is to illustrate how to call a public function of a Finance Rule from within XFBR rule.
The Finance Rule has a function called EntityText8 splitter, and I need to call it from within a XFBR rule. To make it work, first need to make the Finance Rule "True" - Contains Global Functions for Formulas (in Rule Properties) and refer to the specific rule assembly in XFBR rule properties (screenshot2).
The XFBR rule reads:
11-27-2023 04:24 PM - edited 11-27-2023 04:27 PM
Hi DavidW,
What does the function entityText8Splitter do? IOW, what changes when you pass in srcEntity?
For better readability, post your code in a preformatted element:
'--------------------------------------------------------------------------------------------------------------------------------
'Returns the Entity in Text8 or emtpy
'--------------------------------------------------------------------------------------------------------------------------------
'BRString(SeedingXFBRStrings, Text8Entity, curEntity=|CVEntity|, curScenario=|CVScenario|)
'XFBR(SeedingXFBRStrings, Text8Entity, curEntity=|CVEntity|, curScenario=|CVScenario|)
If args.FunctionName.XFEqualsIgnoreCase("Text8Entity") Then
Dim curEntity As String = args.NameValuePairs.XFGetValue("curEntity")
Dim curScenario As String = args.NameValuePairs.XFGetValue("curScenario")
Dim scenarioId As Integer = BRApi.Finance.Members.GetMember(si, DimType.Scenario.Id, curScenario).MemberId
Dim curScenarioType As String = BRApi.Finance.Scenario.GetScenarioType(si, scenarioId).Id
Dim entityId As Integer = brapi.Finance.Members.GetMemberId(si, DimType.Entity.Id, curEntity)
Dim entityText8 As String = BRApi.Finance.Entity.Text(si, entityId, 8, curScenarioType, si.WorkflowClusterPk.TimeKey)
If entityText8.Length > 0 Then
'Define reference to business rule
Dim text8Splitter As New OneStream.BusinessRule.Finance.FcstSeeding.MainClass
If Not text8Splitter Is Nothing Then
Dim srcEntity As String
With text8Splitter.entityText8Splitter(entityText8)
srcEntity = .srcEntity
End With
Return srcEntity
Else
Return entityText8
End If
Else
Return ""
End If
11-28-2023 10:43 AM
Rob, Thanks for pointing out how to use the formatted style.
EntityText8splitter is a "string processor" function, returns different values (srcEntity, fcstSrcEntity, etc, ...). Instead of using more and more Entity Text fields for the same purpose (Forecast seeding in this case), Splitters are created to process and return drivers of "Seeding" exercise in different use cases. This is our response to the facts that logics are getting more complicated as business requirements change, and we have limited Text field for each member.
Public Function entityText8Splitter(entityText8 As String) As (srcEntity As String, fcstSrcEntity As String, operSign As String, srcU6 As String)
Dim srcEntity, fcstSrcEntity, operSign, srcU6 As String
srcEntity = entityText8
fcstSrcEntity = ""
operSign = ""
srcU6 = ""
If Instr(entityText8,"FcstSource") > 0 Then 'Test FcstSource existance
fcstSrcEntity = Mid(entityText8, Instr(entityText8,"FcstSource")+10, 101)
If Instr(fcstSrcEntity,",") > 0 Then
operSign = Mid(fcstSrcEntity, Instr(fcstSrcEntity,",")+1, 1)
srcEntity = Left(srcEntity, (srcEntity.Length - fcstSrcEntity.Length -10 -1)) 'FcstSource and ","
fcstSrcEntity = Left(fcstSrcEntity,Instr(fcstSrcEntity,",")-1)
Else
srcEntity = Left(srcEntity, (srcEntity.Length - fcstSrcEntity.Length -10 -1))
End If
End If
If srcEntity.XFContainsIgnoreCase("U6#") Then 'Test U6# existance
srcU6 = Mid(srcEntity, Instr(srcEntity, "U6#"),101)
srcEntity = Left(srcEntity, Instr(srcEntity, "U6#")-2)
If Instr(srcU6, ",") > 0 Then 'Test , existance
operSign = Mid(srcU6, Instr(srcU6, ",")+1, 1)
srcU6 = Left(srcU6, Instr(srcU6, ",")-1)
End If
End If
Return (srcEntity, fcstSrcEntity, operSign, srcU6)
End Function
11-28-2023 11:53 AM - edited 11-28-2023 11:59 AM
Code reuse rocks 🙂 . It looks like the requirements for EntityText8 may be evolving over time. Consider encapsulating the overall text processing functionality in its own class and create methods in the class to deal with the different parsing/mangling/processing needs, currently being dealt with using multiple IF statements.
Place the class in a BR of its own with other text processors:
Imports System
Imports System.Collections.Generic
Imports System.Data
Imports System.Data.Common
Imports System.Globalization
Imports System.IO
Imports System.Linq
Imports System.Windows.Forms
Imports Microsoft.VisualBasic
Imports OneStream.Finance.Database
Imports OneStream.Finance.Engine
Imports OneStream.Shared.Common
Imports OneStream.Shared.Database
Imports OneStream.Shared.Engine
Imports OneStream.Shared.Wcf
Imports OneStream.Stage.Database
Imports OneStream.Stage.Engine
Namespace OneStream.BusinessRule.DashboardStringFunction.TextProcessors
Public Class SomeOtherTextProcessor
'... other string parsing/mangling/processing used in multiple places
End Class
Public Class YetAnotherTextProcessor
'... other string parsing/mangling/processing used in multiple places
End Class
Public Class EntityText8Processor
Private _srcEntity As String
Private _fcstSrcEntity As String
Private _operSign As String
Private _srcU6 As String
Public ReadOnly Property SrcEntity As String
Get
Return _srcEntity
End Get
End Property
Public ReadOnly Property FcstSrcEntity As String
Get
Return _fcstSrcEntity
End Get
End Property
Public ReadOnly Property OperSign As String
Get
Return _operSign
End Get
End Property
Public ReadOnly Property SrcU6 As String
Get
Return _srcU6
End Get
End Property
Public Sub New(entityText8 As String)
_srcEntity = entityText8
_fcstSrcEntity = String.Empty
_operSign = String.Empty
_srcU6 = String.Empty
End Sub
Public Sub ProcessForecastSource()
Dim startIdx As Integer = InStr(_srcEntity, "FcstSource") + 10
_fcstSrcEntity = Mid(_srcEntity, startIdx, 101)
Dim hasComma As Boolean = InStr(_fcstSrcEntity, ",") > 0
If hasComma Then
_operSign = Mid(_fcstSrcEntity, InStr(_fcstSrcEntity, ",") + 1, 1)
_fcstSrcEntity = Left(_fcstSrcEntity, InStr(_fcstSrcEntity, ",") - 1)
End If
_srcEntity = Left(_srcEntity, startIdx - 11)
End Sub
Public Sub ProcessU6()
Dim u6Index As Integer = InStr(_srcEntity, "U6#")
_srcU6 = Mid(_srcEntity, u6Index, 101)
_srcEntity = Left(_srcEntity, u6Index - 2)
Dim hasComma As Boolean = InStr(_srcU6, ",") > 0
If hasComma Then
_operSign = Mid(_srcU6, InStr(_srcU6, ",") + 1, 1)
_srcU6 = Left(_srcU6, InStr(_srcU6, ",") - 1)
End If
End Sub
End Class
End Namespace
With this class, you can add new "processors" for each new requirement. by creating another "Process<thisToProcess>" sub.
Consume the class:
'Returns the Entity in Text8 or emtpy
'--------------------------------------------------------------------------------------------------------------------------------
'BRString(SeedingXFBRStrings, Text8Entity, curEntity=|CVEntity|, curScenario=|CVScenario|)
'XFBR(SeedingXFBRStrings, Text8Entity, curEntity=|CVEntity|, curScenario=|CVScenario|)
If args.FunctionName.XFEqualsIgnoreCase("Text8Entity") Then
Dim curEntity As String = args.NameValuePairs.XFGetValue("curEntity")
Dim curScenario As String = args.NameValuePairs.XFGetValue("curScenario")
Dim scenarioId As Integer = BRApi.Finance.Members.GetMember(si, DimType.Scenario.Id, curScenario).MemberId
Dim curScenarioType As String = CStr(BRApi.Finance.Scenario.GetScenarioType(si, scenarioId).Id)
Dim entityId As Integer = brapi.Finance.Members.GetMemberId(si, DimType.Entity.Id, curEntity)
Dim entityText8 As String = BRApi.Finance.Entity.Text(si, entityId, 8, curScenarioType, si.WorkflowClusterPk.TimeKey)
If entityText8.Length > 0 Then
Dim text8Splitter As New OneStream.BusinessRule.DashboardStringFunction.TextProcessors.EntityText8Processor(entityText8)
If InStr(text8Splitter.SrcEntity, "FcstSource") > 0 Then
text8Splitter.ProcessForecastSource()
End If
If InStr(text8Splitter.SrcEntity, "U6#") > 0 Then
text8Splitter.ProcessU6()
End If
entityText8 = text8Splitter.SrcEntity
End If
Return entityText8
End If
11-30-2023 08:24 AM
Yes, that's a very logical and concise solution. Thanks, Rob.