In the picture: PPM > Portfolio Management > Financial Planning(Picture Courtesy: SAP)
My project had a requirement to add up actual values(actual and actual-manual) and copy to forecast values in the Financial Planning of the PPM Module. Even though this sounds very simple, anyone who knows PPM tables knows that it is more than what meets the eye.
I struggled a lot to find an apt way of achieving this. I tried many other processes like Function Module(FM) /RPM/FIN_PLAN_SAVE_DB. The problem with this FM was that all entries in the plan table belonging to a group had to be passed to this FM even when we had to update just one record in that group. I also explored the BADIs /RPM/EX_FIN_B_PLAN_BADI, /RPM/EX_FIN_PLAN, /RPM/FIN_CAP_PLAN . But I wanted something that can be called within an FM which updates the /RPM/FIN_PLAN table with plan details. Finally, while debugging I stumbled upon the API /rpm/cl_fin_cap_planning_api. This API was best suited for my requirement as I only had to pass the changed entry and it internally selects the rest of the plan entries in the group. I spent a lot of researching how to make use of this API specially to know how to pass the context to the API. I am writing this blog post to help my fellow developers.
The steps described in this blog post can also be used to update Capacity Planning tables.
Requirement: There are 2 views to capture actual cost – Actual(comes from ECC) and Actual-Manual(entered manually). The requirement is that the Forecast view should be calculated by adding the two costs – Actual and Actual-Manual.
This blog post is a step-by-step how-to guide to achieve this objective.
- Get guid from table /RPM/ITEM_D for the external_id in the input table(IT_PROJ)
- Get required fields into 1 table using join from /rpm/item_d /rpm/fin_cat, /rpm/fin_group /rpm/fin_plan
- Add the values of actual and actual-manual costs of corresponding months and categories
- Update the forecast costs using API. Use get_plan_info method to pass the context**. Call initialize_planning method and finally fin_groups_modify to update values. The API is well designed in the sense that only the changed fin_plan entries need to be passed and the API handles the rest.
** very crucial part..took me a while to figure out how to pass the context
- Very important to call the cl_inm_ppm_services=>save to commit work.
- Capture the messages and display.
I have given the required code of the RFC FM below. The FM takes one or more External_id(s) of the Project(/RPM/ITEM_D-EXTERNAL_ID) as the input, calculates the Forecast view and in turn updates the tables(/RPM/FIN_PLAN, /RPM/FIN_GROUP) for the same.
FUNCTION z_fin_calc . …………………………. "reference(s) DATA: lo_fin_cap_planning_api TYPE REF TO /rpm/cl_fin_cap_planning_api. "field-symbols FIELD-SYMBOLS: <fs_fin_plan> TYPE x_fin_planf, <fs_msg> TYPE /rpm/ts_messages. "select projects and process …………………………………………………….. "get api reference CALL METHOD /rpm/cl_fin_cap_planning_api=>get_instance RECEIVING rr_instance = lo_fin_cap_planning_api. IF lo_fin_cap_planning_api IS BOUND. "loop projects LOOP AT tb_item_d INTO s_item_d. CLEAR: tb_fin_group_api, tb_fin_plan_api. "populate context CLEAR s_context. s_context-portfolio_guid = s_item_d-portfolio_guid. s_context-parent_type = k_parent_type. "'RIH'. s_context-parent_guid = s_item_d-guid. s_context-object_type = k_object_type."'RIH'. s_context-object_guid = s_item_d-guid. "get plan info CLEAR: var_subrc, s_plan_info. CALL METHOD lo_fin_cap_planning_api->get_plan_info EXPORTING is_context = s_context * iv_language = iv_fin_cap = k_fin_cap "1 IMPORTING es_plan_info = s_plan_info et_msgs = tb_msgs ev_rc = var_subrc. APPEND LINES OF tb_msgs TO tb_msgs_item. CLEAR tb_msgs. "pass context CALL METHOD lo_fin_cap_planning_api->initialize_planning EXPORTING is_context = s_context iv_hierarchy_type = k_hierarchy_type iv_fin_cap = k_fin_cap "1 * iv_language = it_filter_data = tb_filter_data is_plan_info = s_plan_info * iv_portfolio_type = IMPORTING et_msgs = tb_msgs * es_mode = * . …………………………………………………….. "for every group AT END OF guid_g ##loop_atb_ok. "only if plan table is filled "update fin plan IF tb_fin_plan_api IS NOT INITIAL. "call api CALL METHOD lo_fin_cap_planning_api->fin_groups_modify EXPORTING iv_category_guid = var_cat_guid it_fin_groups = tb_fin_group_api it_fin_plan = tb_fin_plan_api iv_hierarchy_type = k_hierarchy_type iv_language = k_language is_plan_info = s_plan_info IMPORTING ev_rc = var_subrc et_msgs = tb_msgs. APPEND LINES OF tb_msgs TO tb_msgs_group. CLEAR tb_msgs. "save CALL METHOD cl_inm_ppm_services=>save( EXPORTING iv_check_only = /rpm/cl_co=>sk_false IMPORTING et_messages = tb_msgs ev_rejected = var_rejected ). APPEND LINES OF tb_msgs TO tb_msgs_group. CLEAR tb_msgs. "append project and group external ID UNASSIGN <fs_msg>. LOOP AT tb_msgs_group ASSIGNING <fs_msg>. <fs_msg>-objectid = s_item_d-external_id. ENDLOOP. UNASSIGN <fs_msg>. APPEND LINES OF tb_msgs_group TO etb_msgs. CLEAR tb_msgs_group. ENDIF. CLEAR: tb_fin_group_api, tb_fin_plan_api, s_fin_group_api. ENDAT. ENDLOOP. ENDLOOP. ENDIF. ENDFUNCTION.
To summarize, you learnt how to make use of std. SAP API /rpm/cl_fin_cap_planning_api to update /RPM/FIN_PLAN and /RPM/FIN_GROUP tables. Did this blog post help you, or answer at least some of your questions. Please share your feedback or thoughts in a comment 😊.