Financial Management Blogs by SAP
Get financial management insights from blog posts by SAP experts. Find and share tips on how to increase efficiency, reduce risk, and optimize working capital.
cancel
Showing results for 
Search instead for 
Did you mean: 
Thomas_Cayzerg
Product and Topic Expert
Product and Topic Expert
0 Kudos

Introduction

In many operational planning scenarios, companies need to leverage key-dates information to calculate their forecasted figures precisely.

The common reflex is to use a well-known spreadsheet application, embedding some easy-to-use and well documented date calculation functions.

But relying on spreadsheets for such critical and massive calculation process might be limitative for business execution.

In this blog, we will present you how you could leverage SAP Analytics Cloud Planning for modelling and writing business logic to serve such operational planning use cases.

 

Description of the business scenario

Let’s consider a simple business case where a company must forecast the terms of projects according to an estimated calendar.

Each projects controller would be responsible of a dedicated portfolio and would like to perform his own simulations based on dates assumptions.

A global page would be dedicated to collect planning assumptions of project step term, then a business logic would be executed to transposed them in a financial vision available for reporting.

Of-course, not-only dates assumptions can be collected this way and project referential might be enriched with more analytical details for reporting purpose (status, delay root cause, geography, …).

 

Designing the planning model

Login to your SAP Analytics Cloud tenant as a user with a planning professional role.

Go to Modeler menu with the left bar panel and click on Create new model tile:

Thomas_Cayzerg_0-1712654058722.png

Select the option Start with an empty model and click on the Create button:

Thomas_Cayzerg_1-1712654086335.png

Once the Model Structure workspace of the Modeler has opened, add a new dimension to manage the projects with the + button.

Call the new dimension “Project”, select Generic as type (to enrich the master data through the JavaScript API), and keep it private (just for our example). If you select public, choose a unique dimension Id over the tenant. Click on the Add button to create the new project dimension:

Thomas_Cayzerg_2-1712654116544.png

In the same manner, add a new Country dimension to your planning model.

Thomas_Cayzerg_3-1712654138961.png

Add a new measure with the + button, name it Amount and keep the default settings for type, aggregation and format:

Thomas_Cayzerg_4-1712654196532.png

Save your planning model with the Save button:

Thomas_Cayzerg_5-1712654219090.png

Name your model M_ProjectPlanning and save it into a dedicated folder you create with the new folder button:

Thomas_Cayzerg_6-1712654237196.pngThomas_Cayzerg_7-1712654254223.png

Edit the Project dimension table with the dedicated arrow button:

Thomas_Cayzerg_8-1712654272289.png

When the Project dimension worksheet has opened, create a new parent-child hierarchy from the right bar panel:

Thomas_Cayzerg_9-1712654296231.png

Give an ID and a description, then click on the Create button:

Thomas_Cayzerg_10-1712654312721.png

Create a new property from the right bar panel for handling the billing date; click the Create button to validate:

Thomas_Cayzerg_11-1712654329224.png

From the right bar panel, add a new property for handling the project’s country; click on Create to validate:

Thomas_Cayzerg_12-1712654353628.png

A new Geo Area property has been created. Possible property values are managed by SAP Analytics Cloud and can be downloaded with the info link:

Thomas_Cayzerg_13-1712654389191.png

Add two new properties "IsProject" and "IsMilestone" as single text values:

Thomas_Cayzerg_14-1712654410069.png

Thomas_Cayzerg_15-1712654432369.png

Definition of properties is now complete for our use case, but you can of course define more project properties to help characterization (manager, sub-region, intermediate dates, …) or facilitate the story navigation.

Copy the content of the below table without the header row, and paste it from the second row of the project members’ grid:

ID

Description

H1

Billing date

Country

Is Project

Is Milestone

ALL_PJT

All Projects

<root>

 

DE

 

 

PJT_AAAA

Project AAAA

ALL_PJT

 

AU

X

 

PJT_AAAA_001

PTC Storage Q3-2024

PJT_AAAA

2024-09-15

AU

 

X

PJT_AAAA_002

PTC Storage & Maintenance Q4-2024

PJT_AAAA

2024-12-15

AU

 

X

PJT_DDDD

Project DDDD

ALL_PJT

 

ES

X

 

PJT_DDDD_001

PTC Storage Q3-2024

PJT_DDDD

2024-09-20

ES

 

X

PJT_DDDD_002

PTC Storage & Maintenance Q4-2024

PJT_DDDD

2024-12-18

ES

 

X

PJT_HHHH

Project HHHH

ALL_PJT

 

BR

X

 

PJT_HHHH_001

PTC Storage & Maintenance Q4-2024

PJT_HHHH

2024-12-10

BR

 

X

PJT_HHHH_002

PTC Storage & Maintenance Q4-2025

PJT_HHHH

2025-12-15

BR

 

X

PJT_XXXX

Project XXXX

ALL_PJT

 

CA

X

 

PJT_XXXX_001

Holdback - Hydro Quebec Testing

PJT_XXXX

2024-06-30

CA

 

X

PJT_XXXX_002

Holdback - Hydro Quebec Testing 2

PJT_XXXX

2024-09-30

CA

 

X

PJT_YYYY

Project YYYY

ALL_PJT

 

PL

X

 

PJT_YYYY_001

Punch-List Holdback

PJT_YYYY

2024-10-15

PL

 

X

PJT_YYYY_002

Punchlist Holdback

PJT_YYYY

2025-03-20

PL

 

X

 

Thomas_Cayzerg_17-1712654529896.png

Click on the Save button to save the model:

Thomas_Cayzerg_18-1712654570487.pngThomas_Cayzerg_19-1712654579197.png

From the right bar panel, click on the info button and the Download locations link:

Thomas_Cayzerg_20-1712654598619.png

Open the downloaded Supported_locations.csv file with Excel.

Select the columns B and C and copy them:

Thomas_Cayzerg_21-1712654642385.png

Paste the columns to a new worksheet and remove the data/duplicates with the Excel menu:

Thomas_Cayzerg_22-1712654659993.png

Thomas_Cayzerg_24-1712654689193.png

Thomas_Cayzerg_25-1712654709871.png

Copy the content of the columns A and B:

Thomas_Cayzerg_26-1712654731734.png

Edit the Country dimension table from the SAC Modeler:

Thomas_Cayzerg_27-1712654748498.png

Paste the content of the clipboard starting at the row 2 to populate the members’ grid:

Thomas_Cayzerg_28-1712654769937.png

Add a new parent-child hierarchy from the right bar panel:

Thomas_Cayzerg_29-1712654800783.png

Thomas_Cayzerg_31-1712654821383.png

Add a new dimension member for handling the global world position:

Thomas_Cayzerg_32-1712654843018.pngThomas_Cayzerg_33-1712654855645.png

Attach the Global and Unassigned members to the root node of the hierarchy.

Attach all other countries to the Global node:

Thomas_Cayzerg_34-1712654891275.png

Thomas_Cayzerg_35-1712654913171.png

Click on the Save button to save the model.

Open the Date dimension table:

Thomas_Cayzerg_36-1712654940681.png

Modify the Dimension Table properties to set the default booking behavior to unassigned and the default date hierarchy to Year, Month:

Thomas_Cayzerg_37-1712654964430.png

Save the planning model.

Add a new measure named “Probability” to the model measures list.

Set scale as Percent with a precision of 2 digits, set Exception aggregation to Average for all dimensions as Exception:

Thomas_Cayzerg_38-1712654997012.png

Add a new measure named “ExpectedYear” to the model measures list.

Set it as integer, with Max as exception aggregation and none as unit:

Thomas_Cayzerg_39-1712655025777.png

By copying ExpectedYear measure from the 3 dots menu, create two new measures “ExpectedMonth” and “ExpectedDay” in the same way:

Thomas_Cayzerg_40-1712655049895.png

Thomas_Cayzerg_41-1712655079708.png

Save the model when finish.

Thomas_Cayzerg_42-1712655103124.png

Our planning model is now ready to be used through SAC stories.

 

Creating a planning story

From the modeler view, create a new canvas story:

Thomas_Cayzerg_43-1712655152089.png

Insert a new table object into the canvas:

Thomas_Cayzerg_44-1712655178546.png

The new table should be automatically linked to your planning model M_ProjectPlanning.

From the builder panel, arrange the table structure to get Projects in rows and Version and Measures in columns:

Thomas_Cayzerg_45-1712655206843.png

Select all the available measures and sort them to get Probability at the end:

Thomas_Cayzerg_46-1712655228795.png

Thomas_Cayzerg_47-1712655247406.png

Thomas_Cayzerg_48-1712655259532.png

Right click the Actual version and copy it to a new Plan version:

Thomas_Cayzerg_49-1712655279499.pngThomas_Cayzerg_50-1712655291817.png

Publish the new private version Plan version as public version Plan:

Thomas_Cayzerg_51-1712655311709.pngThomas_Cayzerg_52-1712655321761.pngThomas_Cayzerg_53-1712655330593.png

Select the columns 2 to 6 in the table and hide them:

Thomas_Cayzerg_54-1712655345177.png

Drill to the leaf level of the project dimension by right clicking the Project dimension header:

Thomas_Cayzerg_55-1712655364873.png

Add projects properties Billing date and Country to rows:

Thomas_Cayzerg_56-1712655381039.pngThomas_Cayzerg_57-1712655390903.pngThomas_Cayzerg_58-1712655404793.png

Save the story as “S_ProjectPlanning” in the same folder as the planning model:

Thomas_Cayzerg_59-1712655432055.png

From the right builder panel, filter the Country dimension to the unassigned member:

Thomas_Cayzerg_60-1712655469961.png

Do the same for the Date dimension (it should be the case by default):

Thomas_Cayzerg_61-1712655496927.png

Save the story from the story menu.

Now, every data entered with this story table is described by project, version and measure only.

Populate some Actuals values in the table and publish them:

Thomas_Cayzerg_62-1712655557148.png

Thomas_Cayzerg_63-1712655573441.png

Feed expected dates information for the Plan and the associated probability:

Thomas_Cayzerg_64-1712655592385.png

Publish the Plan assumptions when you are done.

 

Simplify user experience for planning with dates

Instead of changing each expected project date individually in the story, we would like to manage it through a simple user interface.

The Datepicker widget is a custom widget, that helps to work this way (if the widget is not available on your tenant, ask your admin to download and install it from https://github.com/SAC-Custom-Widgets/datepicker).

From the story designer, insert a new custom widget Datepicker in your canvas:

Thomas_Cayzerg_65-1712655661885.png

Then insert a new text label before the date widget and set its value to “Expected Date:”:

Thomas_Cayzerg_66-1712655680674.png

Add two more labels upon the former as “Selected Project:” and “Please select a project…”:

Thomas_Cayzerg_67-1712655697726.png

Rename the Datepicker_1 widget instance to “Datepicker_SelectProject” and the Text_3 instance to “Text_SelectProject” in the Outline section of the left bar panel:

Thomas_Cayzerg_68-1712655724105.png

Add a global variable for handling the planning model from the Scripting area of the Outline view:

Thomas_Cayzerg_69-1712655740907.png

Select the model M_ProjectPlanning and rename the model variable accordingly before clicking the done button:

Thomas_Cayzerg_70-1712655761511.png

Add a new script global variable from the outline view and rename it “gProjectId”:

Thomas_Cayzerg_71-1712655786857.png

Thomas_Cayzerg_73-1712655812459.png

Add a new function on Table_1 for handling the selection event:

Thomas_Cayzerg_74-1712655828281.png

Copy and paste the following code to the function:

// Retrieve current table selection
var select = Table_1.getSelections();

// Extract selected project id
var project_id = select[0].Project.substring("[Project].[H1].&[".length, select[0].Project.length-1);

// Retrieve member from the Planning model
var vproject = M_ProjectPlanning.getMember("Project", project_id);

// Set project desc to the UI
Text_SelectProject.applyText(vproject.description);

// Retrieve selected project data
var year_data = Table_1.getDataSource().getData({Version: 'public.Plan', CustomDimension1: 'ExpectedYear', Project: select[0].Project });
var month_data = Table_1.getDataSource().getData({Version: 'public.Plan', CustomDimension1: 'ExpectedMonth', Project: select[0].Project });
var day_data = Table_1.getDataSource().getData({Version: 'public.Plan', CustomDimension1: 'ExpectedDay', Project: select[0].Project });

// Build a JavaScript Date variable from YYYY MM DD
var vdate = new Date(Number.parseInt(year_data.rawValue), Number.parseInt(month_data.rawValue)-1, Number.parseInt(day_data.rawValue));

// Set the data to the UI
Datepicker_SelectProject.setDateVal(vdate);

// Store the select project id for further operation
gProjectId = select[0].Project;

 

Save you story and test it in View mode:

When you click on a row in the projects table, the date widget must now present the full expected date:

Thomas_Cayzerg_75-1712655908771.png

Go back to the story in edit mode (close the browser View tab).

Add a new function to the DatePicker_SelectProject instance by clicking the fx symbol:

Thomas_Cayzerg_76-1712655936256.png

Copy and paste the following JavaScript code to your new function:

// Local variable for handling boolean result
var bresult = false;

// Retrieve new date value
var vdate = this.getDateVal();

// Write to the dates measures in the table
bresult = Table_1.getPlanning().setUserInput({ 'Version': 'public.Plan', '@MeasureDimension': 'ExpectedYear', 'Project': gProjectId }, vdate.getFullYear().toString());
bresult = Table_1.getPlanning().setUserInput({ 'Version': 'public.Plan', '@MeasureDimension': 'ExpectedMonth', 'Project': gProjectId }, (vdate.getUTCMonth()+1).toString());
bresult = Table_1.getPlanning().setUserInput({ 'Version': 'public.Plan', '@MeasureDimension': 'ExpectedDay', 'Project': gProjectId }, (vdate.getUTCDate()+1).toString());

// Submit the data to the backend
if(bresult) {
       bresult = Table_1.getPlanning().submitData();
}

 

Save the story and execute it in View mode.

Select a project and modify the date value directly in the datepicker widget using the displayed calendar.

The new date must now be written to the selected project:

Thomas_Cayzerg_77-1712656132155.png

You are now able to change every project expected date from a nice visual widget using this method.

As usually in SAC Planning, you can revert your changes with the Version management button or the History list:

Thomas_Cayzerg_78-1712656151330.png

 

More planning KPIs based on dates

Calculating some additional KPIs like the expected delay in days per project could be something useful to forecast additional costs.

Reopen the M_ProjectPlanning model from the main left bar menu:

Thomas_Cayzerg_79-1712656186974.png

Navigate to the Calculations Workspace:

Thomas_Cayzerg_80-1712656205405.png

Add a new calculated measure with the + button and name it “ExpectedDelay”:

Thomas_Cayzerg_81-1712656221594.png

Copy and paste the following formula to the editor:

([ExpectedYear]*31556926 + [ExpectedMonth]*2629743 + [ExpectedDay]* 86400 - (INT(TONUMBER(SUBSTRING([d/Project].[p/BillingDate] ,0 ,4 )))*31556926 + INT(TONUMBER(SUBSTRING([d/Project].[p/BillingDate] ,5 ,2 )))*2629743 + INT(TONUMBER(SUBSTRING([d/Project].[p/BillingDate] ,8 ,2 ))) * 86400)) / 86400

We calculate the difference between the expected date and the Billing date property in seconds, then convert it in days (1 day = 86.400 sec). The behavior is equivalent to the standard DateDiff function but applied to measures and properties values (vs date members).

Define the unit type by typing Day as a new label:

Thomas_Cayzerg_82-1712656274037.png

Set the scale to none and the decimal places to 2:

Thomas_Cayzerg_83-1712656288732.png

Save the model when finish:

Thomas_Cayzerg_84-1712656304331.png

Reopen the S_ProjectPlanning story in edit mode and go the first page, select the Table_1 widget.

Open the Measures filter in Column and add the Expected Delay measure to the selection:

Thomas_Cayzerg_85-1712656323603.png

Save the story and open it in view mode.

You must now be able to display the Expected Delay KPI in the table:

Thomas_Cayzerg_86-1712656342680.png

When you change the expected date from the Datepicker widget, the expected delay is recalculated dynamically:

Thomas_Cayzerg_87-1712656361694.png

 

Financial logic based on dates

SAP Analytics Cloud can help you to go further with date-based operations by transforming your delay assumptions into a financial vision.

We wanted to see the impact of costs over time periods and geography to analyze delay shifting effects and its financial impact.

For such a purpose, we are going to define a business logic based on a Data Action.

Open the story S_ProjectPlanning in edit mode and add a new canvas page:

Thomas_Cayzerg_88-1712656410598.png

Add a new table widget from the menu and set Project and Country in rows, Version and Date in columns; filter on Amount measure:

Thomas_Cayzerg_89-1712656425594.png

Add a new table filter to exclude the Unassigned Country and do the same for the Date dimension:

Thomas_Cayzerg_90-1712656442986.png

Thomas_Cayzerg_91-1712656455174.png

Save the story with the save button.

Keeping the story tab, open a new tab in your browser to SAP Analytics Cloud.

Go to the Data Actions menu and click on the Create New Data Action tile:

Thomas_Cayzerg_92-1712656478931.png

Name the Data Action and attach it to your planning model M_ProjectRisk; save the Data Action:

Thomas_Cayzerg_93-1712656497881.png

Add a new copy step from the main menu:

Thomas_Cayzerg_94-1712656515784.png

Position the filters appropriately to retrieve Actuals amounts from the input page, i.e. Country and Date as unassigned and All Projects:

Thomas_Cayzerg_95-1712656529934.png

Add a new Advanced Formulas Step:

Thomas_Cayzerg_96-1712656548273.png

Name it “Calculate Plan”.

Add new parameters from the top menu:

Thomas_Cayzerg_97-1712656564683.png

Add a parameter for the list of dates:

Thomas_Cayzerg_98-1712656581072.png

And add a parameter for the list of projects:

Thomas_Cayzerg_99-1712656598626.png

Open the Script view of the Calculate Plan step and paste the following script code:

//-----------------------------------------------------------------------------------
//Set Configurations Definitions for the Advanced Formulas.
//-----------------------------------------------------------------------------------
CONFIG.TIME_HIERARCHY = CALENDARYEAR
CONFIG.GENERATE_UNBOOKED_DATA = OFF

//-----------------------------------------------------------------------------------
//The data region against which the formulas will be executed.
//-----------------------------------------------------------------------------------
MEMBERSET [d/Measures] = ("Amount", "ExpectedYear", "ExpectedMonth", "ExpectedDay", "Probability")
MEMBERSET [d/Country] = "#"
MEMBERSET [d/Date] = BASEMEMBER([d/Date].[h/YM] , %Dates%)
MEMBERSET [d/Project] = BASEMEMBER([d/Project].[h/H1], %Projects%)

INTEGER @EXPECT_YEAR
INTEGER @EXPECT_MONTH

//-----------------------------------------------------------------------------------
//Calculation and Data Writing
//-----------------------------------------------------------------------------------

FOREACH [d/Project]

       @EXPECT_YEAR = RESULTLOOKUP([d/Measures]="ExpectedYear", [d/Date]="000000")
       @EXPECT_MONTH= RESULTLOOKUP([d/Measures]="ExpectedMonth", [d/Date]="000000")

       IF YEAR([d/Date])=@EXPECT_YEAR AND MONTH([d/Date])=@EXPECT_MONTH THEN
              DATA([d/Measures]="Amount", [d/Country]=[d/Project].[p/Country]) = RESULTLOOKUP([d/Measures]="Amount", [d/Date]="000000")
              DATA([d/Measures]="Probability", [d/Country]=[d/Project].[p/Country]) = RESULTLOOKUP([d/Measures]="Probability", [d/Date]="000000")
       ENDIF

ENDFOR // Project

 

Use the Validate button to ensure, that no error is found:

Thomas_Cayzerg_100-1712656736934.png

You can switch to Visual mode to analyze the code of the Calculate Plan step:

Thomas_Cayzerg_101-1712656757015.png

For each single project, the script checks to expected date value and copy the amount and the probability to the appropriate date period and country member.

 

Add a new advanced formulas step to clear the actual figures we copied on the first step.

Name it “Clear Actuals”:

Thomas_Cayzerg_102-1712656785060.png

Paste the following script code in the script view:

//-----------------------------------------------------------------------------------
//Set Configurations Definitions for the Advanced Formulas.
//-----------------------------------------------------------------------------------
CONFIG.TIME_HIERARCHY = CALENDARYEAR
CONFIG.GENERATE_UNBOOKED_DATA = OFF

//-----------------------------------------------------------------------------------
//The data region against which the formulas will be executed.
//-----------------------------------------------------------------------------------
MEMBERSET [d/Measures] = "Amount"
MEMBERSET [d/Country] = "#"
MEMBERSET [d/Date] = "000000"
MEMBERSET [d/Project] = BASEMEMBER([d/Project].[h/H1] , %Projects%)

//-----------------------------------------------------------------------------------
//Calculation and Data Writing
//-----------------------------------------------------------------------------------
DELETE()

Validate and save the data action with the Save button:

Thomas_Cayzerg_103-1712656869776.png

Back to the story S_ProjectPlanning in edit mode, add a new data action trigger:

Thomas_Cayzerg_104-1712656886373.png

Name the trigger and select the Data Action created before; you can add page or story filter to preselect the execution context for target Version, Date and Project values:

Thomas_Cayzerg_105-1712656906689.png

Save the story.

You can test immediately the Data Action by clicking the arrow button.

Select the dates 2024 / 2025, and all the projects, click the Run button:

Thomas_Cayzerg_106-1712656928140.png

Thomas_Cayzerg_107-1712656939621.png

Once the execution finished, the table is refreshed with the calculated values:

Thomas_Cayzerg_108-1712656955162.png

Use the hierarchy selection, story filters and formatting options to drill into the calculated data by month, project and country:

Thomas_Cayzerg_109-1712656973540.png

New assumption can be made on the projects delays in the first page and the plan simulation can be recalculated on demand before publishing it.

More advanced presentation can also be set, like displaying over a geo map:

Thomas_Cayzerg_110-1712656999680.png

 

Conclusion

This simple project planning example lets you understand how SAP Analytics Cloud can be configured for managing dates-based planning scenario with few concepts.

Interoperability between the modeler, the story and the data action is key to handle on-the-fly calculations or user triggered business logic.

We hope that would now extend this example to your own use cases and more easily fill the gap between operational planning based on dates and financial reporting.