...
Create the Calculation Base filter for a Rebate Record
in Pricefx Studio, edit the logic BonusOnSales
Create a new element "CalculationBase" in which you will create the filter.
Example 1. Code of Element "CalculationBase", with Calculation Context "Rebate Record"
Code Block import net.pricefx.common.util.CalendarUtil.TimePeriod import net.pricefx.common.util.CalendarUtil.TimeUnit /* The CalculationBase filter will be used for Rebate Allocation process. We redefine the default filter here, because we want to use different end date. Otherwise we would not need to change it. */ calculationBase.clear() calculationBase.include(out.CustomerGroup) calculationBase.include(out.ProductGroup) calculationBase.include( new TimePeriod(out.StartDate, out.EndDateOrToday, TimeUnit.DAY) ) /* this date field will be later redefined in the Rebate Allocation process, but if we set it up here, we can use see the effect of this filter already in the RR detail screen, under sub-screen "Calculation Base" */ calculationBase.setDateFieldName("InvoiceDate") api.trace("calculationBase", api.jsonEncode(calculationBase)) //TODO comment out in production code //api.trace("calculationBase.dump", calculationBase.dump()) //if you want to verify the DateFieldValue
the variable "calculationBase" is created automatically and is pre-populated by a datamart filter based on the out-of-the-box inputs of the Rebate Record (like startDate, customerGroup, …).
But there’s a chance you will need to change it based on specific needs of your project implementation. In our case we change it simply because we need to simulate different "Today".
Test the logic in Studio:
Switch the Context to "Rebate Record"
In RebateRecordName enter ID of your RR, on top of which you will test the execution.
the CalculationDate will simulate Today
Note: if your dialog show also "Target Date", you can ignore it, because the Calculation Date will be used as value of
api.targetDate()
Figure 2. Setup of Parameters for Test of the Rebate Record logic
Test the Logic, and review the content of the CalculationBase filter
Figure 3. Results of Test of the Rebate Record logic
Figure 4. Traced detail of CalculationBase filter
Deploy the logic to the partition
...
You need a column in the Datamart, where you will store the allocated Rebate money amount of every Transaction line
Figure 5. Datamart field settings - new field "Rebate"
add money column "Rebate" to your Datamart "Transactions"
The field must be owned by (must belong to) the Datamart (i.e. the Owner field will be empty), otherwise the Dataload process will not be able to write into it the result of the logic.
set Label of the column to "Rebate"
Note: After click on the "Add Field" button, the new field appears at the end of the list, which can be on another page, if your Datamart has many fields.
datatype of the column should be "Money"
move the column just after the InvoicePrice column. This is not needed from technical perspective, but it will give you better feeling about the flow of the calculation.
remember, the allocated Rebate will have impact on the size of the Margin, so you must reflect it in the Margin calculation
change the Expression of the Margin column to "InvoicePrice - Rebate - Cost"
Deploy the Datamart
Create the Allocation logic
Navigate to Administration → Logics → Analytics
Make a new logic – name it "RebateAllocation", Valid After 2000-01-01, Active
Create new element, name it "Rebate". This is intentionally exactly the name of column in the Datamart because the result will be mapped to the Rebate column in the Datamart.
keep Calculation Context as "Row". Remember, this will be a Row logic used in the Calculation Dataload, which iterates the Transactions one by one.
Ensure the result of the element is visible - again, that’s important, to be able to map the calculated rebate value back to the Datamart.
Example 4. Code of Element "Rebate"
Code Block /* read data from Transaction row */ def trxPreviousRebate = api.userEntry("Rebate") ?: 0.0 def trxInvoicePrice = api.userEntry("InvoicePrice") ?: 0.0 //def transactionId = api.userEntry("TransactionId") if (api.isSyntaxCheck()) return /* read data from the Rebate Record */ def rebateRecord = api.currentItem() if (api.isDebugMode()) { // ONLY for testing purposes rebateRecord = api.find("RR",0,1,"uniqueName")?.getAt(0) } def rrActualSales = rebateRecord?.attribute1 def rrActualRebate = rebateRecord?.attribute2 /* api.logInfo("RR vs TransactionID", (rebateRecord?.uniqueName ?: "") + " vs " + transactionId) */ if (!(null in [rrActualSales,rrActualRebate,trxInvoicePrice])) { return trxPreviousRebate + rrActualRebate * (trxInvoicePrice / rrActualSales) } else { api.addWarning("Cannot calculate Rebate for RR:" + rebateRecord?.uniqueName + " because either RR's ActualSales, RR's ActualRebate" + " or TX Invoice Price is empty." ) return null }
values from the Datamart rows are read in the same way as in Row logics in DL Calculationswe do not want to proceed, if the logic was executed just to collect the definitions of the input fields.
api.currentItem()
returns the RR being processed. For testing purposes, you can temporarily find some existing saved RR, for exampleapi.find("RR",0,1,"uniqueName")?.getAt(0)
, because in Test Logic mode, theapi.currentItem()
returns null.each line of a Datamart has the field Warnings, where you can see those messages after the calculation process is over.you must consider the previously (already) calculated rebate of the Transaction row, because several of your Rebate Records might need to allocate the money into the same Transaction row. That’s quite common business scenario.
Test the logic:
For the test, you will have to temporarily read the Rebate Record directly from the table of Rebate Records, but be sure to comment it out after you’re done with testing.
On Parameters tab:
Figure 6. Setup of Parameters for Test of the "allocation" Logic
click on Generate Parameters to see the inputs Rebate and InvoicePrice, you’re using. This is not necessary for the test itself, but good to verify, that they’re coming up correctly, as it’s needed in the DataLoad later.
Select Datamart context
Select your Datamart Transactions
fill in the ID of the Datamart row, on which you will test. If you cannot see this field, then re-select the Datasource name field (even if you have only one)
Set targetDate to the date, which you would like to use as "today"
click "Test Logic"
Verify the calculated Rebate for your selected Transactions, if it is what you would expect. Warning: the numbers on the screenshots are only illustrative
Figure 7. Results of Test of the "allocation" Logic
ensure your results are correct
why do you see the Warning, even if the code works?
review the content of the _ROW_. What does it contain?
Remember to comment out the testing code - the direct reading of Rebate Record from table
Deploy the logic to the partition
...
Navigate to Analytics DataManager Data Loads
Add new DataLoad:
Click on Add Data Load
Figure 8. Adding new DataLoad
Enter the Label "Rebate Allocation"
Set Type to "Calculation
And click Add.
Warning: Your new Dataload is added to the END of the table, so there’s a chance you cannot see it right away.
Also, your new Dataload will likely show an error because of missing Target, but that’s what you will set in the next steps
Edit the detail of the new Dataload:
click on the name of the new Data Load, to open its detail screen.
Figure 9. List of DataLoads with the newly added DataLoad
Setup the Options:
Figure 10. Setup of DataLoad’s OPTIONS
untick the "Incremental"
for the "Target" select your Datamart.
No filters needed (on the "Target" tab)
Remember – this is an Allocation process (not common enrichment) – so the filter, which transactions will be used, is taken from the Rebate Record’s "Calculation Base" filter
Setup the Calculation:
Open the "Calculation" tab
Figure 11. Configuration of DataLoad’s logics and field mappings
Logic/Formula section
For "Logic" – select your "RebateAllocation" logic. Once you do it, the content of Formula Fixed Inputs, Source Field Mapping, and Target fields should get populated.
Source Field Mapping section
Verify the Source Field Mapping, if it came up automatically correctly. If the "Input" field name (defined in the logic) is the same as the datamart "Field" name, the mapping comes up automatically. Otherwise ensure, that you’ve set it up.
Target Fields section
ensure, that your displayed logic element "Rebate" shows up here. Also, the checkbox next to "Rebate" must be checked, otherwise the result will not be mapped to the Datamart row.
Feeder Formula section
select your "Feeder" logic. Your 2 input parameters "StartDate" and "EndDate" should appear.
Set the StartDate to 2020-01-01 and EndDate to 2020-12-31.
Save the Data Load
Click on Run Data Load to execute the allocation process.
Note: Later you can schedule this DataLoad to run regularly, or it can be executes from Integration Manager.
Navigate back to the Schedule tab
Refresh the Job/Task Tracking, until the process is done (Ready).
Click on the "Info" icon (located at the end of the line) and review all the Messages:
You should be able to find a line describing, how many Transaction rows were affected by the process, for example:
Target rowset has 99 rows after calculation [RebateAllocation[1280]]
also, in the performance log (down in the Messages), you should see, how many times your logic RebateAllocation was executed, something like this:
103.14 4% ░░░░░░░░░░ 99 │ ├── RebateAllocation
Verify the results in the Datamart
Figure 12. Datamart with Rebate allocated to the appropriate Transactions
Check values of the Rebate column of those Transactions
Review the range of Invoice Dates, if it matches the CalculationBase filter from the Rebate Record
Check Customer Group and Product Group, if they match to those selected on the Rebate Record
Reset of Rebate column value to zero:
our Allocation process expected to have the Rebate column empty (or zero), before it starts, because we might need to allocate rebate from more Rebate Records into the same Transaction row. So, we cannot simply override the Rebate by every Allocation logic call.
For you it means, that you need to ensure, that the Rebate column will be empty (or zero) before the Allocation Data Load starts.
To set the Rebate column to zero manually (quite helpful when you want to re-test the Rebate Allocation again), you can use the Mass Edit operation on the DataRows screen.
Figure 13. Reseting the Rebate value column to 0 using the Mass Edit functinality
...