In a typical CPG company, there are thousands of Trade Promotions/Trade Events are created & executed throughout the year. It’s quite a tedious job for the users to create these events manually. In order to manage time and effort effectively, a mass copy functionality is needed. SAP standard does provide this functionality via some configurations, but there would be some custom build scenarios which will not be copied. For example, new custom status profiles with special statuses were set up for our client which are not being copied using standard Mass copy job. To achieve the functionality of mass copy of the promotions which in statuses – Planned, Approved, Performed, Stopped & closed while extending the CBP Plans there needs to be custom enhancement along with the required system configuration.
In TMA3.0 & above – the CBP Plan can be extended either in the Calendar or the P&L view.
From the RA (Responsibility Area)
So once you try to extend ~ it would give a pop-up for the promotions of statuses which you would like to copy => here we would configure for Planned, Approved, Stopped, Closed etc. (based on the status profile of the Promotions)
Promotions are dependent on the responsibility area assigned to the user (& CBP Plan as well for the RAs assigned to a CBP Plan. And all the copied promotions would copy the copying promotion exactly (along with spends, Driver values, products, etc.) ~ only the date of the copied promo.
Also, make sure that the fund plan & funds are created for the year for which the CBP plan needs to be extended.
Many of the attributes like – Planning Customer, Sales Org, Trade Spends, Dates, etc. are copied from the source promotion to the copied promotion via standard SAP delivered functionality.
Apart from that, we need to make sure that the Trade Spend Values in the Planning Layout (from BW IP) are also copied across to the new promotion. After that user would make the necessary changes before finalizing the promotion & approving for execution. With the mass copy of the promotions (based on the selection as per the configuration setting), The planned/approved/stopped/performed/closed promotions would be copied into the extended year retaining the dame dates of the previous year and the status would be put in Draft. So that if any changes required can be put in.
- Plan extension can be done from calendar view or P&L view or from RA.
- Pop up with promotions statuses and types of promotions will be displayed.
- Based on the options selected by the user, the promotions get copied to the extended view.
- All the promotions copied to the new year will be in draft status.
- If no promotions are found, the only plan gets extended.
The TPM Custom Status Profile snapshot
Given below is a BADI/Enhancement Spots which may be used to achieve the functionality
There is a standard SAP implementation given which can be used or referenced to achieve our need here.
- Get the attributes of the plan.
* HSY BADI Implementation for CBP Plan Extension METHOD /jbpc/if_eh_extend_plan~extend_plan. DATA ls_planattr TYPE crms_mktpl_ol_attributes. DATA lr_mktproject_plan TYPE REF TO cl_crm_mktpl_ol_mktproject. DATA lv_wait_time TYPE /jbpc/wait_sec. DATA lv_status TYPE abap_bool . DATA lv_plan_guid TYPE cgpl_guid16. DATA lt_guid TYPE crmt_mktgs_guid. DATA lt_sel_options TYPE crmt_mktib_value. DATA lv_scn_guid TYPE cgpl_guid16 . DATA lv_scnplangroup TYPE cgpl_sem_plgrp. DATA lv_plan_year TYPE /jbpc/bp_year. DATA lv_scen_id TYPE crm_imp_object_id . DATA lr_applmanager TYPE REF TO cl_crm_mktgs_application_mgr. DATA lv_scen_guid TYPE sysuuid_x. DATA lr_scenarios TYPE REF TO /jbpc/cl_crm_mktpl_ol_scns. DATA lr_scenario TYPE REF TO /jbpc/cl_crm_mktpl_ol_scn. DATA lr_message_handler TYPE REF TO cl_crm_mktgs_msg_handler. DATA lv_msgtext TYPE string. lt_sel_options = ir_parameters->get_parameter_by_name( 'SEL_OPTION' )->get_values( ). lv_scn_guid = ir_parameters->get_parameter_by_name('SCN_GUID')->get_value( ). lv_scnplangroup = ir_parameters->get_parameter_by_name('PLANGROUP')->get_value( ). lv_plan_year = ir_parameters->get_parameter_by_name( 'SYNCH_YEAR' )->get_value( ). TRY. lr_mktproject_plan ?= get_marketing_project( ir_plan = ir_item ). CATCH cx_crm_mktib_application_impl. ENDTRY. lr_mktproject_plan->get_attributes( IMPORTING es_attributes = ls_planattr ). * release lock for scenario lv_scen_guid = /jbpc/cl_crm_jbp_common_api=>get_scenario_for_plan( iv_plan_guid = ls_planattr-guid ). CALL FUNCTION 'CONVERSION_EXIT_CGPLP_OUTPUT' EXPORTING input = lv_scen_guid IMPORTING output = lv_scen_id. lr_applmanager = lr_mktproject_plan->get_application_manager( ). lr_message_handler = lr_applmanager->get_message_handler( ). lr_scenarios ?= lr_applmanager->get_collection_for_type( iv_object_type = /jbpc/cl_crm_mktjbp_constants=>mkt_objtype_scenario ). APPEND lv_scen_guid TO lt_guid. lr_scenarios->load( lt_guid ). lr_scenario ?= lr_scenarios->get_item_by_guid( iv_guid = lv_scen_guid ). /jbpc/cl_extend_plan_api=>read_wait_time( EXPORTING iv_sales_org = ls_planattr-sales_org " Sales Organization ID iv_dis_channel = ls_planattr-dis_channel " Distribution Channel iv_division = ls_planattr-division " Division RECEIVING rv_wait_time = lv_wait_time ). " Extend Plan Wait Time CALL FUNCTION 'ZFM_JBPC_CBP_EXTEND_PLAN' STARTING NEW TASK 'Extend_Plan' CALLING processing_check ON END OF TASK EXPORTING it_sel_options = lt_sel_options iv_plan_guid = ls_planattr-guid iv_scenario_guid = lv_scn_guid iv_plangroup = lv_scnplangroup iv_plan_year = lv_plan_year. * CALL FUNCTION '/JBPC/CBP_EXTEND_PLAN' STARTING NEW TASK 'Extend_Plan' CALLING processing_check ON END OF TASK * EXPORTING * it_sel_options = lt_sel_options * iv_plan_guid = ls_planattr-guid * iv_scenario_guid = lv_scn_guid * iv_plangroup = lv_scnplangroup * iv_plan_year = lv_plan_year. WAIT UNTIL sv_process_status = abap_true UP TO lv_wait_time SECONDS. * provide a message that plan is being extended. IF sv_process_status = abap_false . MESSAGE i451(/jbpc/vvf_impl_msg) INTO lv_msgtext. lr_message_handler->add_message_symsg( iv_log_type = cl_crm_mktgs_msg_handler=>co_log_function ). ENDIF. ENDMETHOD.
2. Call FM by passing ZFM
- Get the plan instance.
- Get the scenario of the plan
- Call the global class method zcl_jbpc_cbp_extend_plan->extend_plan.
FUNCTION zfm_jbpc_cbp_extend_plan. DATA lt_plan_promo TYPE crmt_mktgs_guid. DATA lt_promotions_link TYPE /jbpc/tmktpl_tpm_link. DATA ls_sel_options TYPE crmt_gen_value . DATA lr_parameter TYPE REF TO cl_crm_mktib_action_parameter. DATA lt_sel_options TYPE crmt_mktib_value. DATA lr_plan TYPE REF TO cl_crm_mktpl_ol_mktproject. DATA lv_guid TYPE cgpl_guid16. DATA lv_scen_guid TYPE sysuuid_x. DATA lr_scenarios TYPE REF TO /jbpc/cl_crm_mktpl_ol_scns. DATA lr_scenario TYPE REF TO /jbpc/cl_crm_mktpl_ol_scn. DATA lv_scen_id TYPE crm_imp_object_id . DATA lr_application_mgr TYPE REF TO cl_crm_mktpl_application_mgr. DATA lr_plan_coll TYPE REF TO cl_crm_mktpl_ol_collection. DATA lt_guid TYPE crmt_mktgs_guid. DATA ls_attributes TYPE /jbpc/s_mktpl_ib_pln_attr. DATA lr_psm_asg_coll TYPE REF TO cl_crm_mktgs_asg_collection. DATA lr_psm_item TYPE REF TO /jbpc/cl_crm_mktpl_scn_psm_itm. * load plan instance. lr_application_mgr ?= cl_crm_mktpl_application_mgr=>get_instance( ). lr_plan_coll ?= lr_application_mgr->get_collection_for_type( iv_object_type = /jbpc/cl_crm_mktjbp_constants=>mkt_objtype_plan ). APPEND iv_plan_guid TO lt_guid. lr_plan_coll->load( lt_guid ). lr_plan ?= lr_plan_coll->get_item_by_guid( iv_guid = iv_plan_guid ). lr_plan->set_edit_mode( ). lr_plan->get_attributes( IMPORTING es_attributes = ls_attributes ). * *Get the scenario guid for the plan lv_scen_guid = /jbpc/cl_crm_jbp_common_api=>get_scenario_for_plan( iv_plan_guid = ls_attributes-guid ). * set sync date since the buffer is initial in a new session . /jbpc/cl_extend_plan_api=>set_sync_date( EXPORTING iv_sync_year = iv_plan_year " Planning Year iv_sales_org = ls_attributes-sales_org " Sales Organization ID iv_node_guid = ls_attributes-node_guid " GUID of Hierarchy Node iv_ra_guid = ls_attributes-ra_guid ). " Responsibility Area GUID * load scenario reference * lr_applmanager = lr_mktproject->get_application_manager( ). lr_scenarios ?= lr_application_mgr->get_collection_for_type( iv_object_type = /jbpc/cl_crm_mktjbp_constants=>mkt_objtype_scenario ). APPEND lv_scen_guid TO lt_guid. lr_scenarios->load( lt_guid ). lv_guid = lv_scen_guid. lr_scenario ?= lr_scenarios->get_item_by_guid( iv_guid = lv_guid ). lr_scenario->set_edit_mode( ). * * syn scenario lr_psm_asg_coll = lr_scenario->get_assignment_collection( iv_assignment_type = cl_crm_mktpl_constants=>asg_type_planning_sync_mgr ). IF lr_psm_asg_coll IS NOT BOUND. RETURN. ENDIF. * Get the planning synchronization item lr_psm_item ?= lr_psm_asg_coll->get_item_by_index( iv_index = 1 ). * * Call the Object Planning Synchronization Manager. IF lr_psm_item IS BOUND . * Synchronize BW data TRY. lr_psm_item->synchronize( i_force_change = abap_true iv_asynchronous = abap_false ). CATCH cx_crm_mktpl_imp_synchronize. RETURN. ENDTRY. ENDIF. lt_sel_options = it_sel_options . SORT lt_sel_options DESCENDING. " BW require the execution of planning event in a specific sequence. DATA: lr_obj TYPE REF TO zcl_jbpc_cbp_extend_plan. CREATE OBJECT lr_obj. *-- Copy promotions based on status. IF lt_sel_options IS NOT INITIAL. lr_obj->extend_plan( ir_plan = lr_plan it_sel_options = it_sel_options iv_plan_year = iv_plan_year iv_plan_guid = iv_plan_guid ). ENDIF. lr_application_mgr->save_and_commit( ). rv_result = abap_true . ENDFUNCTION.
METHOD extend_plan. DATA: lt_promotion_tab TYPE crmt_mktgs_guid. IF ir_plan IS BOUND. *-- Get Promotions from plan to extend get_promotions( EXPORTING ir_plan = ir_plan it_sel_options = it_sel_options iv_plan_year = iv_plan_year RECEIVING rt_promotion_tab = lt_promotion_tab ). *-- delete promotions by status. delete_promo_by_status( EXPORTING it_sel_options = it_sel_options CHANGING ct_promotion_tab = lt_promotion_tab ). *-- Copy Promotions copy_promotions( EXPORTING it_promotion_tab = lt_promotion_tab iv_plan_guid = iv_plan_guid ir_plan = ir_plan ). ENDIF. ENDMETHOD.
D. Get_Promotions method is called.
- Get the relevant campaign types
- Delete entries from the table based on promo types values selected
- If the value is CPY2, ALL – All promotions to be copied except canceled
- If the value is CPY2, EDL – Only EDLP & EDLC promos are selected
- If the value is CPY2, HIL – Only EDLP, EDLC, HILO promos are selected
- If the value is CPY2, OTH – Only Miscellaneous and Corporate promotions are selected
- Get all the promotions based on the campaign type selected for the plan year to the plan selected.
E. Delete_promo_by_status method is called by passing the promotions.
- Get the status of the promotions.
- Read the value selected from pop up
- If the value is CPY1, ALL – All status promos are selected except the rejected status
- If the value is CPY1, APR – Approved, Performed, Stopped and Closed status are selected
- If the value is CPY1,DRF – Copy only Draft and Planned status
F. COPY_PROMOTIONS method is called by passing the promotions & Plan id.
- Copy promotions by calling method zhsy_extend_plan_api=>copy_promotions
- Unlock the plan using FM DEQUEUE_ENQ_CGPL_PROJECT
- Link the promotions to calendar by using /jbpc/cl_extend_plan_api=>link_promotions.
G. Save and commit.
Concept of Lag:
In SAP TM, two sets of date ranges are provided: In-store dates and shipment dates. These are used across promotion planning and Customer Business Planning (CBP) for various processes such as
defaulting the dates on the promotion, moving consumption volume to shipment volume in promotion, moving the base consumption to shipment in CBP, etc.
SAP does provide Account defaults to be maintained in the system but these are defined per customer and do not allow for any product characteristic (e.g. season) to be part of the date default. These are defined by promotion type and duration which does not meet the business needs as the default of the date agnostic of promotions. Furthermore, these will not allow shifting of volume from consumption to shipment as these are promotion specific defaults.
The purpose of the LAG requirement is to provide an ability to the NA Controller Accounting Team to maintain the date defaults by season for a customer with an ability to upload the Lag rules. This specification will also consider the requirement to default the Shipment dates from the Instore dates on the promotion planning screen.
Custom Table Creation: Create a new Custom Table Z_CBP_LAG (with maintenance view) with the following fields. This would be primary table for the creation of Responsibility Areas in the CRM system.
|CLNT||Customer||Season||Lag Days||Year||Type||Wholesaler||Created By||Created On||Changed By||Changed On|
|<System Client>||<CRM Customer Hierarchy Node ID>||
<Multiple of 7>
|<CRM Customer Hierarchy Node ID>||
The business rule to fill this table is as follows:
- For a customer which is primarily a direct ship customer e.g. Publix, Costco, the table will contain the entries for the customer = Publix along with season, lag days, year, type = Regular and Wholesaler will be Blank
- For a customer which is an Indirect e.g. Walmart where the movement happens between Walmart and McLane the table will contain two entries.
Entry1: Customer= Walmart along with season, lag days, year, type = Regular, Wholesaler =<No Value>. This signifies within the Walmart Plan the expected date when Walmart will receive the goods from McLane
Entry2: Walmart along with season, lag days, year, and type = Wholesaler, Wholesaler= McLane. This signifies when Hershey is going to ship the product to McLane.
- For Customers where there is no consumption to shipment lag to be maintained and only default on promotion is required then the entry will be done with Type = Promo. This case may happen for McLane if in future there is a promotion required to be created.
- No Customer can have the type= Regular and Promo at the same time.
Default dates on promotion:
A User can create a promotion from two places. One when the user is in the CBP Plan. Two when the user is in the Promotion search screen and in a particular Responsibility Area. In either of these two cases when a user lands on the new promotion page the following should default
b) Responsibility Area
c) Season code from the responsibility Area.
The Instore dates can be manually populated or come from the selection in CBP screen
The following logic needs to be used for defaulting the Lag days:
- Based on the Customer Node, Season and Year (derived from Instore Start date) the Lag table Z_CBP_LAG must be read to find the Lag Days. By Default, the system needs to read the Lag type = Regular. If no rule is found then the Lag type = Promo must be read.
The Shipment Start and End Dates must be defaulted by the Lag days.
Shipment Start date = Instore Start Date – Lag days
Shipment End Date = Instore End Date – Lag days
- If no Lag type rule was defined then the Lag days must be treated as 0. This will cause the Shipment Start Date = Instore Start Date
Shipment end Date = Instore End Date
- If a user goes in and changes the Instore date (start or end date) the shipment dates should be recalculated.
- If a user makes a change to the Shipment dates (start or end) manually then in those cases a flag needs to be set on the promotion to indicate that the lag days are different from standard. Once this has been set even a reset of consumption dates by the user should not trigger the shipment date recalculation.
Given below is a BADI/Enhancement Spots which may be used to achieve the functionality
Enhancement Spot: CRM_MKTPL
- Badi Definition: CRM_MKTPL_OL_ASG
- Badi Definition: CRM_MKTPL_OL_OBJ
Default dates on promotion
When a new promotion is created, default the buying dates based on plan dates
1.Enhancement spot: CRM_MKTPL
DATERANGE = ASSIGNMENT_TYPE and
TPM = OBJECT_TYPE.
3. Method IF_EX_CRM_MKTPL_OL_ASG~CHECK_ATTRIBUTES, IF_EX_CRM_MKTPL_OL_ASG~SET_ATTRIBUTES_BEFORE are implemented to default the dates on promotion.
4. Get date values by using class cl_crm_mktpl_appl_base and method date_assign_read by passing the GUID.
5. Get header data using method get_header_assignment_item( ) from importing parameter ir_mktproject.
6. Pass the header ra_guid_ext to table /jbpc/mcrm_raatt to get the season.
7. Pass the customer, season, year and lag type to table zhsy_t_cbp_lag to get the lag days.
8. If the entry exists, then buying dates = plan dates – lag days.
9. If there is no entry in the table. Then set lag days as zero and set buying dates = plan dates.
10. Finally set the buying dates.
Set the flag before save
- Enhancement spot: CRM_MKTPL
- Filter values:
TPM = OBJECT_TYPE
- Method IF_EX_CRM_MKTPL_OL_OBJ~CHECK_BEFORE_SAVE is implemented to set the flag.
- Check the plan dates and buying dates are not equal to lag days then set the flag and save promotion.
- If buying start date is less than the current date, then through an error message “buying start date cannot be less than the current date” and don’t save the promotion.
As highlighted in the below screenshot, the dates are displayed using the log concept. default customer, season and Responsibility area are also displayed in the Trade Promotion.