Can I test a manual input before save and/or calculate
- 4 years ago
Yes, this is possible, you need a SaveDataEventHandler Business rule for it. Here are some code samples:
First the basic function, only testing the input itself:
Public Function Main(ByVal si As SessionInfo, ByVal globals As BRGlobals, ByVal api As Object, ByVal args As SaveDataEventHandlerArgs) As Object Try '------------------------ ' Validate entered values '------------------------ 'Only test manual input If args.NewDataCell.DataCellPK.OriginId = DimConstants.Forms Then '--------------------------- 'Account must be between 0-1 '--------------------------- Dim accountToTest As String = "60000" 'Test, if it is the account to test If args.NewDataCell.DataCellPK.AccountId = BRApi.Finance.Members.GetMemberId(si, dimtype.Account.Id, accountToTest) Then 'The input amount Dim dCellAmount As Decimal = args.NewDataCell.CellAmount 'Test the amount If dCellAmount > 1 Or dCellAmount < 0 Then 'Throw an error to prevent the save args.Cancel = True Throw New Exception("Account: " & environment.NewLine & "Value entered must be between 0% and 100%" & environment.NewLine) End If End If End If Return args.DefaultReturnValue Catch ex As Exception Throw ErrorHandler.LogWrite(si, New XFException(si, ex)) End Try End Function
And here a sample how to check if Forms and Import together have fit the test:
Public Function Main(ByVal si As SessionInfo, ByVal globals As BRGlobals, ByVal api As Object, ByVal args As SaveDataEventHandlerArgs) As Object Try '------------------------ ' Validate entered values '------------------------ 'Only test manual input If args.NewDataCell.DataCellPK.OriginId = DimConstants.Forms Then '--------------------------- 'Account must be between 0-1 '--------------------------- Dim accountToTest As String = "60000" 'Test, if it is the account to test If args.NewDataCell.DataCellPK.AccountId = BRApi.Finance.Members.GetMemberId(si, dimtype.Account.Id, accountToTest) Then 'Some objects as shortcuts Dim originalCell As DataCell = args.NewDataCell Dim originalCellPk As DataCellPk = originalCell.DataCellPK 'Some objects needed to retrieve the Data from the origin Import Dim importCellPK As New DataCellPk(originalCellPk) importCellPK.OriginId = dimconstants.Import Dim sCubeName As String = brapi.Finance.Cubes.GetCubeInfo(si, importCellPK.CubeId).Cube.Name Dim importDataUnitPk As New DataUnitPk(importCellPK) Dim importDataBufferCellPk As New DataBufferCellPk(importCellPK) 'The input amount Dim dCellAmount As Decimal = args.NewDataCell.CellAmount 'To test before adjustment retrieve the import datacell Dim dataCellList As List(Of DataCell) = BRApi.Finance.Data.GetDataBufferDataCells(si, importDataUnitPk, importCellPK.ViewId, importDataBufferCellPk, False,True) If dataCellList.Count = 1 Then 'If there is a result add it to the amount to test dCellAmount += dataCellList(0).CellAmount End If 'Test the amount If dCellAmount > 1 Or dCellAmount < 0 Then 'Throw an error to prevent the save args.Cancel = True Throw New Exception("Account: " & environment.NewLine & "Value entered must be between 0% and 100%" & environment.NewLine) End If End If End If Return args.DefaultReturnValue Catch ex As Exception Throw ErrorHandler.LogWrite(si, New XFException(si, ex)) End Try End Function
I hope this helps
- 4 years ago
Christian's code to check a manual input before save and/or calculate is a good example of using the Save Data Event Handler. The Save Data Event Handler is an Event Handler that runs in order to track all save events in an application. The Save Data Event Handler does not necessarily have Api's ( BRApi's can be used ) but does use Args object references to various objects such as data cells. Since the Save Data Event Handler runs against any of the save events, it is important to understand what happens with the Save Data Event Handler when put under the bright lights of a production environment. Implementations come in all shapes and sizes and one size does not fit all. This is true for the Save Data Event Handler as well. Here are some things to consider when deciding to leverage Christian's code to begin your Save Data Event Handler journey.
1. Using a Single Account - In this example, Christian is using a single account to demonstrate the concept of checking the amount of a data cell to determine whether the save should happen or not. This absolutely works and works well. Here is something to think about: When you think about this single account, this single account is not the only dimension in the data cell. There are 19 Dimensions that make up a single data cell. For an example, you may have a Cube Model that contains 100 UD1's, 200 UD2's, and 10,000 UD3's which make up a valid data cell intersection combination with that single account. This is 200 million possible data cell combinations for this single account. If a Form was built with UD1, UD2, and UD3 as rows, and the single account in the Cube View POV (all available for manual input) each one of these data cell amounts would need to be evaluated to determine if they should be saved. This is one user that is cycling through 200 million data cells before completing a save command. Now imagine that you have 100 users simultaneously working within a variety of different Forms doing the same thing. Suggestion - Be aware on how the Forms are built and how many data cells that the Save Event Handler will have to process before it saves. Testing this process in a production type environment as others are interacting is important to understand the overall impact on the system. Again, no 1 implementation and environment is alike so parallel testing is important.
2. Limiting Rule Execution By Forms - In this example, Christian is showing how to execute the logic based on the Forms Origin. The logic will only execute on the data cells with Forms Origin
If args.NewDataCell.DataCellPK.OriginId = DimConstants.Forms
This allows a level of assurance that this logic will only run when a user is processing a Form using the Forms Origin. So when the user clicks on Save in a Form, it will execute the logic and evaluate the data cells to determine to save the data or not. This will happen for any Form in the application that is processed and the user clicks Save whether the Form was intended to use this logic or not. Therefore, it would be prudent to limit the Forms that you would like the Save Event Handler to execute on. Dim objBRApiForms As BRApiForms = BRApi.Forms.Metadata.GetForm.Form.Name.Equals("NameOfForm"). This is something to consider when introducing the Save Data Event Handler. Should it apply to all Forms or is it specific to a Form?
3. More Than 1 Account for Manual Input and Looping on More Than 1 Account - This certainly can be done. However, consider what was explained under item 1 above. There will be a multiplication factor depending on how many accounts for manual input and data cells evaluated. Another point to consider when building out Forms and how many data cells are available within the Form.
4. Using BRApi's to Cross Engines - BRApi's are very useful to cross OneStream Processing Engines. As common practice, it is best to use Api's that are provided within each Engine. As mentioned before, the Save Data Event Handler does not have Api's but does contain Args object references and BRApi's. In Christian's example, since there is no Api to use, we are using the BRApi to cross into the Finance Engine to get the Account Id. This is certainly needed in order to process this logic. The consideration here is how often is an user saving a Form and executing the logic to cross into the Finance Engine. Is it 1 person or 100 people simultaneously executing a Save and impacting the General servers? Something to monitor when testing.
Hope these considerations help when using this Business Rule. And remember TEST, TEST, TEST functionality and user interactions under production type environment to ensure a pleasant user experience. Christian is providing you with the power. It is up to you on how to use it. Consider these 4 items when implementing in a production environment.