Custom Function Module to retrieve accurate Pricing in SD for Customer and Material.
Of late, we have been focussing on HANA, UI5, Fiori and all the related new jargons. But in reality, a major percentage of clients are still in the classical database and they still have simple requirements of getting the right data. They might complain a little about performance or/and look and feel of their current ERP, but at the end of the day, they cannot be pissed off more than with the wrong report, output or data. So still today, our age old clients have the same age old secret desire to play with correct data only.
There are many situations where we need to find out the correct price of an Item(i.e. Material) for a Customer. The below custom Function Module, which we created, can be used as an API or as a utility FM to get the pricing details of a material; and can be called from any report program or enhancement as per the requirement.
The beauty here is, this FM takes only few information like the customer, material, and sales area details as input, but during the process of retrieval of pricing, we need much more information for which we have to fetch data from more than 20 tables, which is handled systematically inside this FM. Our idea is not to teach you how to create a custom FM, but to provide you a ready reference, in case you have a similar requirement in Pricing. Believe us, Pricing is a must in every SAP Project.
Even if you might not need this FM exactly, but we are positive, you would need many of the tables and standard function modules while working in some customization and in those instances, this article might help as a use case scenario for those tables and FMs.
Scope of the development
- Create a Function Module with the import and table parameters (shown below).
- Inside the FM use the detailed logic given below to fill the communication structure (Header structure KOMK and Item structure KOMP) which is very much important to get the accurate pricing from the FM PRICING.
- Call the standard FM ‘PRICING’ with the proper input. In the table parameter TKOMV of the FM PRICING, we can get all the condition type and their values
- After getting the output from the FM PRICING then prepare the output table for the custom FM to display them in the output.
Import parameter:
IM_KUNNR - Customer (KUNNR) IM_MATNR - Material (MATNR) IM_VKORG - Sales Organization (VKORG) IM_VTWEG - Distribution Channel (VTWEG) IM_SPART - Division (SPART) IM_KALVG - Document procedure (for determining pricing procedure) (KALVG) IM_MGLME - Quantity (MGLME) IM_VRKME - Sales unit (VRKME) IM_PRICING_DAT - Condition pricing date IM_RETURN_FLAG – Return flag IM_CDM - General Flag
Table parameter:
T_OUTTAB - Output table T_ERROR_MSG - Error message
Also Read: PO re-Price issue in BAPI_PO_CHANGE
Detailed Logic for the Function Module
- Create one Function Module with the above Import and Table parameters.
- Write the below logic inside the function module.
Call FM ‘PRICING_REFRESH’ to refresh the previous pricing if exist.
DATA : i_tkomk TYPE STANDARD TABLE OF komk, i_tkomv TYPE STANDARD TABLE OF komv INITIAL SIZE 0. CALL FUNCTION 'PRICING_REFRESH' TABLES tkomk = i_tkomk tkomv = i_tkomv.
Fill the Communication structure (Header structure KOMK and Item structure KOMP) which is very much important to get the accurate pricing from the FM PRICING.
Fill the Header Communication structure KOMK
Select all the fields from tables KNVV, MARA, MVKE and KNA1 and pass to the corresponding field of the header communication structure.
* Local data declaration DATA: lk_komk TYPE KOMK, lk_komp TYPE KOMP. MOVE-CORRESPONDING: MVKE TO lk_komk, (local structure type of KOMK) MARA TO lk_komk, KNVV TO lk_komk, KNA1 TO lk_komk. lk_komk-vkorg = im_vkorg. " Sales Org from Import parameter lk_komk-vkorgau = im_vkorg. " Sales Org from Import parameter lk_komk-vtweg = im_vtweg. " Distribution channel from Imp lk_komk-spart = im_spart. " Division from Import parameter lk_komk-kalvg = im_kalvg. " Document procedure
Select Pricing procedure
SELECT SINGLE kalsm " Pricing procedure INTO v_t683v_kalsm FROM t683v " Pricing Determination in Sales Docs. WHERE vkorg = p_im_vkorg " Sales Organisation AND vtweg = p_im_vtweg " Distribution Channel AND spart = p_im_spart " division AND kalvg = p_im_kalvg " customer’s document Pricing Procedure AND kalks = p_k_knvv-kalks. " customer’s Pricing Procedure lk_komk-kalsm = v_t683v_kalsm. " proper pricing procedure
Move the required fields from KNVV to the header structure
lk_komk-waerk = knvv-waers. " Currency lk_komk-hwaer = knvv-waers. " Currency * Get the company code SELECT SINGLE bukrs " Company code INTO v_bukrs FROM tvko " Organizational Unit: Sales Org WHERE vkorg = im_vkorg . lk_komk-bukrs = v_bukrs. " Company code
Move the required fields from KNA1 to the header structure
lk_komk-land1 = kna1-land1. " Country key lk_komk-aland = kna1-land1. " Country key lk_komk-regio = kna1-regio. " Region(State,country) lk_komk-land1_we = kna1-land1. lk_komk-aland_werk = kna1-land1. lk_komk-auart = ‘ZSOR’.
Select the region from table T001W
SELECT SINGLE region counc cityc INTO k_t001w FROM t001w WHERE werks = KNVV-werks. “ Plant from KNVV table lk_komk-wkreg = t001w-regio. lk_komk-wkcou = k_t001w-counc. lk_komk-wkcty = k_t001w-cityc.
Pass customer from Import parameter
lk_komk-kunnr = im_kunnr. " Customer Number lk_komk-kunwe = im_kunnr. " Ship-to party lk_komk-kunre = im_kunnr. " Bill-to party
Get the Head office A/C number from KNB1 table
SELECT SINGLE knrze FROM knb1 INTO v_knb1_knrze WHERE kunnr EQ im_kunnr AND bukrs EQ v_bukrs. IF v_knb1_knrze IS NOT INITIAL. lk_komk-knrze = v_knb1_knrze. " Head office A/C number ELSE. lk_komk-knrze = im_kunnr. " Head office A/C number ENDIF. lk_komk-kappl = ‘V’. " Application for SD Pricing * If Pricing date is Provided in the Input screen, then use that one IF im_pricing_dat IS NOT INITIAL. lk_komk-prsdt = im_pricing_dat. " pricing and exchange Date lk_komk-fbuda = im_pricing_dat. " Services rendered Date lk_komk-fkdat = im_pricing_dat. " Billing index & printout dt lk_komk-erdat = im_pricing_dat. " Record Created date lk_komk-audat = im_pricing_dat. " Doc Date(Received/Sent) * If Pricing date is not Provided , then use the Current date for Pricing ELSE. lk_komk-prsdt = sy-datum. “Pricing and exchange Date lk_komk-fbuda = sy-datum. “Services rendered Date lk_komk-fkdat = sy-datum. “Billing index & printout date lk_komk-erdat = sy-datum. “Record Created date lk_komk-audat = sy-datum. " Doc Date(Received/Sent) ENDIF. lk_komk-vbtyp = ‘C’. " SD document category lk_komk-werks = v_werks. " Plant lk_komk-zzp_caltyp = ‘P’. lk_komk-hityp_pr = ‘Z’. lk_komk-auart_sd = ‘ZSOR’. lk_komk-trtyp = ‘H’. lk_komk-kokrs = XYZ. “this is Controlling Area of the Client lk_komk-taxk1 = 1.
Also Check: Do all ABAPers know Fixed Point Arithmetic?
Get the Customer hierarchy Number
Data: li_cust_hierarchy TYPE STANDARD TABLE OF vbpavb INITIAL SIZE 0, CALL FUNCTION 'SD_CUSTOMER_HIERARCHY_PATH' EXPORTING customer = im_kunnr date = sy-datum htype = ‘Z’ sales_channel = im_vtweg sales_division = im_spart sales_org = im_vkorg TABLES hpath = li_cust_hierarchy * Read the table to get the customer hierrarchy 1 READ TABLE li_cust_hierarchy INTO lk_cust_hierarchy WITH KEY histunr = 1. IF sy-subrc EQ 0. Lk_komk-hienr01 = lk_cust_hierarchy-kunnr. ENDIF. * Read the table to get the customer hierrarchy 2 READ TABLE li_cust_hierarchy INTO lk_cust_hierarchy WITH KEY histunr = 2. IF sy-subrc EQ 0. lk_komk-hienr02 = lk_cust_hierarchy-kunnr. * Read the table to get the customer hierrarchy 3 READ TABLE li_cust_hierarchy INTO lk_cust_hierarchy WITH KEY histunr = 3. IF sy-subrc EQ 0. lk_komk-hienr03 = lk_cust_hierarchy-kunnr. ENDIF. * Read the table to get the customer hierarchy 4 READ TABLE li_cust_hierarchy INTO lk_cust_hierarchy WITH KEY histunr = 4. IF sy-subrc EQ 0. lk_komk-hienr04 = lk_cust_hierarchy-kunnr. ENDIF.
If the customer is supposed to receive retail pricing, check condition ZS22 to see if C2, CC and/or RX items should also be Retail Priced.
IF lk_komk-kalks = 'A' OR lk_komk-kalks = 'C' . * Check to see if the Customer is supposed to get Retail Pricing SELECT * FROM a904 INTO TABLE li_a904 WHERE kappl = c_kappl " Value 'V' AND kschl = c_kschlzs22 AND vkorg = lk_komk-vkorg AND vtweg = lk_komk-vtweg AND kunnr = lk_komk-kunnr AND kondm IN (c_cc, c_c2, c_rx ) AND datbi GE lk_komk-prsdt AND datab LE lk_komk-prsdt . IF sy-subrc = 0 . LOOP AT li_a904 INTO lk_a904 . * Check to make sure the conditions are not deleted SELECT SINGLE * FROM konp INTO lk_konp WHERE knumh = lk_a904-knumh AND loevm_ko = ' ' . IF sy-subrc EQ 0. * Set an 'X' if retail pricing should be executed. CASE lk_a904-kondm . WHEN c_c2 . MOVE c_charx TO lk_komk-zz_c2_retail . WHEN c_cc . MOVE c_charx TO lk_komk-zz_cc_retail . WHEN c_rx . MOVE c_charx TO lk_komk-zz_rx_retail . WHEN OTHERS. ENDCASE. ENDIF. ENDLOOP . ENDIF. CLEAR lk_konp. * Check the Chain for any MPGs not found at the Customer. IF lk_komk-zz_c2_retail IS INITIAL OR lk_komk-zz_cc_retail IS INITIAL OR lk_komk-zz_rx_retail IS INITIAL . SELECT * FROM a931 INTO TABLE li_a931 WHERE kappl = c_kappl " Value 'V' AND kschl = c_kschlzs22 AND vkorg = lk_komk-vkorg AND vtweg = lk_komk-vtweg AND hienr02 = lk_komk-hienr02 AND kondm IN (c_cc, c_c2, c_rx ) AND datbi GE lk_komk-prsdt AND datab LE lk_komk-prsdt . IF sy-subrc = 0 . LOOP AT li_a931 INTO lk_a931 . * Check to make sure the conditions are not deleted SELECT SINGLE * FROM konp INTO lk_konp WHERE knumh = lk_a931-knumh AND loevm_ko = ' ' . IF sy-subrc EQ 0. * Set an 'X' if retail pricing should be executed. CASE lk_a931-kondm . WHEN c_c2 . MOVE c_charx TO lk_komk-zz_c2_retail . WHEN c_cc . MOVE c_charx TO lk_komk-zz_cc_retail . WHEN c_rx . MOVE c_charx TO lk_komk-zz_rx_retail . WHEN OTHERS. ENDCASE. ENDIF. ENDLOOP . ENDIF. ENDIF. ENDIF.
* Check to see if the Zero Percent Flag should not apply to this customer Check the Sold-to.
CLEAR lk_konp. SELECT SINGLE * FROM a918 INTO lk_a918 WHERE kappl = c_kappl AND kschl = c_kschlzszp AND vkorg = lk_komk-vkorg AND vtweg = lk_komk-vtweg AND kunnr = lk_komk-kunnr AND datbi GE lk_komk-prsdt AND datab LE lk_komk-prsdt . IF sy-subrc = 0 . * Check to make sure the conditions are not deleted SELECT SINGLE * FROM konp INTO lk_konp WHERE knumh = lk_a918-knumh AND loevm_ko = ' ' . IF sy-subrc EQ 0. lk_komk-zzzero_perc_flx = c_charx. ENDIF. ENDIF. * If the flag is not set, check the Chain IF lk_komk-zzzero_perc_flx = ' ' . * Check the Chain SELECT SINGLE * FROM a935 INTO lk_a935 WHERE kappl = c_kappl AND kschl = c_kschlzszp AND vkorg = lk_komk-vkorg AND vtweg = lk_komk-vtweg AND hienr02 = lk_komk-hienr02 AND datbi GE lk_komk-prsdt AND datab LE lk_komk-prsdt . IF sy-subrc = 0 . * Check to make sure the conditions are not deleted SELECT SINGLE * FROM konp INTO lk_konp WHERE knumh = lk_a935-knumh AND loevm_ko = ' ' . IF sy-subrc EQ 0. lk_komk-zzzero_perc_flx = c_charx. ENDIF. ENDIF. ENDIF. * Check the Customer Group if the zero percent flag is not filled IF lk_komk-zzzero_perc_flx = ' ' . * Check the Customer Group SELECT SINGLE * FROM a906 INTO lk_a906 WHERE kappl = c_kappl AND kschl = c_kschlzszp AND vkorg = lk_komk-vkorg AND vtweg = lk_komk-vtweg AND kdgrp = lk_komk-kdgrp AND datbi GE lk_komk-prsdt AND datab LE lk_komk-prsdt. IF sy-subrc = 0 . CLEAR lk_konp. * Check to make sure the conditions are not deleted SELECT SINGLE * FROM konp INTO lk_konp WHERE knumh = lk_a906-knumh AND loevm_ko = ' ' . IF sy-subrc EQ 0. lk_komk-zzzero_perc_flx = c_charx. ENDIF. ENDIF. ENDIF.
Fill the Item Communication structure KOMP
Move the corresponding field of MVKE and MARA to the item communication structure.
MOVE-CORRESPONDING: MVKE TO lk_komp, MARA TO lk_komp. IF im_vrkme IS NOT INITIAL. “ From Import parameter lk_komp-meins = im_vrkme. lk_komp-lagme = im_vrkme. lk_komp-vrkme = im_vrkme. lk_komp-kmein = im_vrkme. ELSE. lk_komp-vrkme = mara-meins. lk_komp-meins = mara-meins. lk_komp-lagme = mara-meins. lk_komp-kmein = mara-meins. ENDIF. lk_komp-mglme = im_mglme. " Quantity From Import parameter lk_komp-kpein = im_mglme. " Quantity lk_komp-werks = v_werks. " Plant lk_komp-bwkey = knvv-vwerk. " Plant
* Get the vendor from theSource List SELECT lifnr " Vendor Number FROM eord " Purchasing Source List INTO lv_lifnr UP TO 1 ROWS WHERE matnr = p_p_im_matnr AND werks = p_v_werks AND flifn = c_flag AND vdatu LE sy-datum AND bdatu GE sy-datum. ENDSELECT lk_komp-zzvendor = lv_lifnr. " Vendor lk_komp-kposn = '000010’. " Condition item number lk_komp-matnr = im_matnr. " Material Number lk_komp-pmatn = im_matnr. " Material Number lk_komp-zzdemand_matnr = im_matnr. lk_komp-mgame = im_mglme. " Quantity lk_komp-prsok = ’X’. " Pricing is OK lk_komp-umvkz = 1. " Numerator for conversion lk_komp-umvkn = 1. " Denominator for Conversion lk_komp-taxm1 = 1. " Tax classification material lk_komp-use_multival_attr = ‘X’. " Use Multivalue Attributes lk_komp-zzbismt = mara-bismt. lk_komp-zzmtpos = mvke-mtpos. lk_komp-wkreg = t001w-regio. " Region lk_komp-kursk = 1. lk_komp-prsfd = ’X’. " Carry out pricing lk_komp-evrwr = ’X’. " Determine cost lk_komp-prodh1 = mvke-prodh+0(4). " Product Hierarchy1 lk_komp-prodh2 = mvke-prodh+4(4). " Product Hierarchy2 lk_komp-prodh3 = mvke-prodh+8(4). " Product Hierarchy3 lk_komp-zzprodh2 = mvke-prodh+8(3). lk_komp-zzprodh2+3(1) = 0. lk_komp-zzprodh3 = mvke-prodh+8(4). lk_komp-zzvkorg = im_vkorg. “ From import parameter lk_komp-zzmmsta = marc-mmsta. " Material Status lk_komp-prctr = marc-prctr. " profit centre lk_komp-zzndc10 = mean-ean11.
* Get the Default item category for the document
CALL FUNCTION 'RV_VBAP_PSTYV_DETERMINE' EXPORTING t184_auart = ‘ZSOR’ " ZSOR value t184_mtpos = mvke-mtpos t184_uepst = ' ' t184_vwpos = ' ' vbap_pstyv_i = ' ' IMPORTING vbap_pstyv = lv_pstyv EXCEPTIONS eintrag_nicht_da = 1 pstyv_nicht_erlaubt = 2 OTHERS = 3. IF sy-subrc EQ 0. * Sales document item category lk_komp-pstyv = lv_pstyv. * Get the Schedule line item number SELECT ettyp INTO lv_ettyp FROM tvepz UP TO 1 ROWS WHERE pstyv = lv_pstyv. ENDSELECT. IF sy-subrc EQ 0 . * Get the Purchase Order type SELECT SINGLE bsart FROM tvep INTO lv_bsart WHERE ettyp = lv_ettyp. IF sy-subrc EQ 0. * Set the indicator showing a dropship item IF NOT lv_bsart IS INITIAL. lk_komp-zzdscdisc = c_charx. " Value 'X'. ENDIF. ENDIF. ENDIF. ENDIF.
* Clear active price methods, net indicator, program and super net each time those are moved during MOVE CORRESPONDING.
CLEAR: lk_komp-zzkschl , lk_komp-zznetbill , lk_komp-zzsupernet , lk_komp-zzprog_cd , lk_komp-zzkschl_ret , lk_komp-vabme , lk_komp-tragr .
* Finally pass the Communication structure to call the Standard FM PRICING and get the accurate Pricing Values
CALL FUNCTION 'PRICING' EXPORTING calculation_type = ‘C’ " Carry out new Pricing comm_head_i = lk_komk comm_item_i = lk_komp IMPORTING comm_head_e = lk_komk comm_item_e = lk_komp “ change value will be returned TABLES tkomv = i_tkomv EXCEPTIONS OTHERS = 0.
After execution of the standard FM PRICING.
All the condition type and their corresponding values will be populated in the table parameter of the PRICING FM.
Output from standard Order
Sample output of the FM after execution.
The output which is prepared from the table parameter TKOMV of the standard FM PRICING.
Do not miss this: Ready Reckoner for SAP Developers. SD, MM, FI flow and tables for ABAPers.
Function Modules and Tables to Remember that are used in this Z function Module
Function Modules:
- ‘PRICING_REFRESH’ called before calling the FM ‘PRICING’ to refresh the Pricing values if anything exists.
- KNVV_SINGLE_READ to get the Customer Master Sales Data
- MARA_SINGLE_READ to get the Material master data
- MVKE_SINGLE_READ to get the Sales Data for Material
- RV_VBAP_PSTYV_DETERMINE to get the item category
- SD_CUSTOMER_HIERARCHY_PATH to get the customer hierarchy
- PRICING to get the customer and material Pricing
- SD_CONDTAB_SELECT to get the start date and end date of the condition record number to populate in the output.
Table used to get the Accurate Pricing of Customer and material:
KONH | T001W | MVKE | A935 |
KNVV | MARM | KONP | A906 |
MARA | T683V | A904 | TVEP |
MARC | KNA1 | A931 | TVEPZ |
MEAN | KNB1 | A918 | LFA1 |
Point to remember
Either we have to populate all the fields of the communication structure (Header and Item) manually that are populated in the standard USER Exits or some how we have to call the below USER Exits to get the accurate pricing of the Customer and material.
- USEREXIT_PRICING_PREPARE_TKOMK
- USEREXIT_PRICING_PREPARE_TKOMP.
We know you do not want to see 100 of lines of codes on our blog. But being a technical blog, sometimes we take the liberty to flood you with ABAP codes and syntax. . Please bear with us. This FM is an outcome of a request from a genuine reader. Since one of our readers was getting benefitted offline, therefore we thought of publishing it so that, few other ABAPers in need might get some lead and help at the time of distress.
The custom FM might look simple and straight forward, but while trying to figure out the logic and build them, it took quite some time for us. Hope, you would not have to spend that many hours if you have a similar requirement.
So…What Do You Think?
Now we want to hear from you.
Do you think, this article explaining some custom logic for Pricing in helpful?
Whether you feel it is helpful or not, in either case, please leave a quick comment below.
Are you Fiori Ready? Check this end to end Fiori Implementation.