This document explains how to achieve actual material cost during stock transfers when the freight charges and other cost are finalized before delivery goods issue and this is applicable for Materials with moving average price in case of Standard Price this will be posted to Price Difference account
The Freight charges and other costs (Loading, Unloading and other charges) are captured in shipment cost document before Delivery Post Goods Issue
Freight charges are finalized either based on Quantity or Fixed, Charges may to finalized in foreign currency
Also Read: SAP MM Certification Preparation Guide
Material Inventory Valuation to be posted delivery line item wise even if does have batch split quantities
For the above business requirement below Process, Configuration and development change needs to be carried out
Process flow to be followed
Step :1 MM Configuration
Configuration to enable Delivery Cost Conditions for Stock Transfers
Enter for the Combination of Schema Group Purchasing Organization, STO Doc Type, Supplying Plant, Assign Calculation Schema
Based on above Configuration Delivery Cost Condition Types are defaulted in stock transfer document
Step : 2 LE-TRA Configuration
Configuration to capture Freight and other charges for Material Cost Inventorization
Ensuring you have configured Shipment and Shipment Cost for Stock Transfer Deliveries, follow steps from Section “Transfer the shipment costs into the condition types of the purchase order” from note 427944.
Ensure you have configured Shipment item categories to capture vendor wise charges / Cost in Shipment Cost Document and changed shipment item category settlement as per below
Step : 3 Modification in Function Module : SD_SCD_PO_ITEM_DELIVERY_COSTS
Create an implicit enhancement at the end of form LEINRF2N. internal tables BETB[] and SBETB[] need to be modified. Replace the Vendor (LIFNR) and total Value (KWERT & KWRFW) based on the associated Shipment Cost Document SCD_NEW-FKNUM based on Mapping Table Maintained for Delivery Cost.
Create a Mapping Table to Pass Values from shipment cost document item categories to PO condition type
Copy table SBETB and BETB into other internal tables where the original data can be stored e.g.
COPY_BETB & COPY_SBETB. Replace the value of LIFNR & KWERT using the logic from table Shipment Cost Item data (VFKP) table.
Pass SCD_NEW-FKNUM to VFKP-FKNUM, get the following VFKP-PARVW(Shipment Partner Function)
VFKP-FKPTY (Shipment Item Category)
VFKP-EXT1 (Shipment Doc)
VFKP-TDLNR (Partner for each stage)
Since the total value (KWERT & KWRFW) is already calculated and kept in original internal table COPY_BETB, put the same in the newly modified table BETB []- KWERT & BETB []- KWRFW.
Sample Code
Shipment Cost Inventorization
CALL FUNCTION 'SD_SCD_PO_ITEM_DELIVERY_COSTS'
EXPORTING
i_vbeln = xebefu-vbeln_vl
i_vbelp = xebefu-vbelp_vl
i_budat = budat
i_waers = xebefu-waers
i_wkurs = ekko-wkurs "PO conversion rate <693957
i_kufix = lf_kufix "N980402
i_local = t001-waers "PO local currency <693957
TABLES
e_vtfkla = te_vtfkla
EXCEPTIONS
OTHERS = 01.
IF sy-subrc EQ 0.
LOOP AT te_vtfkla WHERE netwr NE 0.
* Gesamtkosten pro Lieferant merken (mit Menge)
CLEAR: ts_bnk. " 376476
READ TABLE ts_bnk WITH KEY lifnr = te_vtfkla-tdlnr
BINARY SEARCH.
IF sy-subrc EQ 0.
ts_bnk-menge = ts_bnk-menge + xebefu-lamng.
ts_bnk-netwr = ts_bnk-netwr + te_vtfkla-netwr.
CLEAR: ts_bnk-netwr_t,
ts_bnk-lgmng,
ts_bnk-kcmeng,
ts_bnk-kcmeng_vme.
MODIFY ts_bnk INDEX sy-tabix.
ELSE.
ts_bnk-menge = ts_bnk-menge + xebefu-lamng.
ts_bnk-netwr = ts_bnk-netwr + te_vtfkla-netwr.
ts_bnk-lifnr = te_vtfkla-tdlnr.
ts_bnk-netwr_t = te_vtfkla-netwr_t.
ts_bnk-lgmng = te_vtfkla-lgmng.
ts_bnk-kcmeng = te_vtfkla-kcmeng.
IF xebefu-umrez IS NOT INITIAL.
ts_bnk-kcmeng_vme = ts_bnk-kcmeng * xebefu-umren /
xebefu-umrez.
ENDIF.
INSERT ts_bnk INDEX sy-tabix.
ENDIF.
ENDLOOP.
ENDIF.
ENDLOOP.
*&--logic for fixed quantity
ELSEIF delivery = 'X'.
CHECK i_vbeln NE space.
LOOP AT xbbefu.
REFRESH te_vtfkla.
* Begin N980402
* If exchange rate handling is active the actual exchange rate
* has to be used for GR.
* N1387559 ekko-kufix should be considered for GR legal req
lf_kufix = ekko-kufix.
*End N980402
CALL FUNCTION 'SD_SCD_PO_ITEM_DELIVERY_COSTS'
EXPORTING
i_vbeln = i_vbeln
i_vbelp = i_vbelp
i_budat = budat
i_waers = ekko-waers
i_wkurs = ekko-wkurs "PO conversion rate <693957
i_kufix = lf_kufix "N980402
i_local = t001-waers "PO local currency <693957
TABLES
e_vtfkla = te_vtfkla
EXCEPTIONS
OTHERS = 01.
IF sy-subrc EQ 0.
IF te_vtfkla[] IS NOT INITIAL.
SELECT * FROM lips INTO CORRESPONDING FIELDS OF TABLE it_lips
FOR ALL ENTRIES IN te_vtfkla[] WHERE vbeln = te_vtfkla-vbeln AND
posnr = te_vtfkla-posnr.
IF sy-subrc = 0.
SORT it_lips BY vbeln posnr.
ENDIF.
ENDIF.
LOOP AT te_vtfkla WHERE netwr NE 0.
* Gesamtkosten pro Lieferant merken (mit Menge)
CLEAR: ts_bnk. " 376476
* Begin N907632
CLEAR ls_lips.
READ TABLE it_lips INTO is_lips WITH KEY vbeln = te_vtfkla-vbeln
posnr = te_vtfkla-posnr.
IF sy-subrc = 0.
MOVE-CORRESPONDING is_lips TO ls_lips.
ENDIF.
IF xbbefu-erfme NE ls_lips-vrkme.
IF ls_lips-umvkn IS NOT INITIAL.
lf_lfimg = ls_lips-lfimg * ls_lips-umvkz / ls_lips-umvkn.
ENDIF.
IF xbbefu-umrez IS NOT INITIAL.
lf_lpomg = lf_lfimg * xbbefu-umren / xbbefu-umrez.
ENDIF.
IF lf_lpomg GT maxmenge.
lf_lpomg = 0.
ENDIF.
ELSE.
lf_lpomg = ls_lips-lfimg.
ENDIF.
* For items with batch split, retain exisiting logic
IF lf_lpomg IS INITIAL.
lf_lpomg = xbbefu-glmng.
ENDIF.
* End N907632
READ TABLE ts_bnk WITH KEY lifnr = te_vtfkla-tdlnr
BINARY SEARCH.
IF sy-subrc EQ 0.
ts_bnk-menge = ts_bnk-menge + lf_lpomg. "N907632
ts_bnk-netwr = ts_bnk-netwr + te_vtfkla-netwr.
CLEAR: ts_bnk-netwr_t,
ts_bnk-lgmng,
ts_bnk-kcmeng,
ts_bnk-kcmeng_vme.
MODIFY ts_bnk INDEX sy-tabix.
ELSE.
ts_bnk-menge = ts_bnk-menge + lf_lpomg. "N907632
ts_bnk-netwr = ts_bnk-netwr + te_vtfkla-netwr.
ts_bnk-lifnr = te_vtfkla-tdlnr.
ts_bnk-netwr_t = te_vtfkla-netwr_t.
ts_bnk-lgmng = te_vtfkla-lgmng.
ts_bnk-kcmeng = te_vtfkla-kcmeng.
IF xbbefu-umrez IS NOT INITIAL.
ts_bnk-kcmeng_vme = ts_bnk-kcmeng * xbbefu-umren /
xbbefu-umrez.
ENDIF.
INSERT ts_bnk INDEX sy-tabix.
ENDIF.
ENDLOOP.
ENDIF.
ENDLOOP.
ENDIF.
ELSEIF delivery = abap_true.
CHECK i_vbeln NE space.
LOOP AT xbbefu.
REFRESH te_vtfkla.
* Begin N980402
* If exchange rate handling is active the actual exchange rate
* has to be used for GR.
* N1387559 ekko-kufix should be considered for GR legal req
lf_kufix = ekko-kufix.
*End N980402
CALL FUNCTION 'SD_SCD_PO_ITEM_DELIVERY_COSTS'
EXPORTING
i_vbeln = i_vbeln
i_vbelp = i_vbelp
i_budat = budat
i_waers = ekko-waers
i_wkurs = ekko-wkurs "PO conversion rate <693957
i_kufix = lf_kufix "N980402
i_local = t001-waers "PO local currency <693957
TABLES
e_vtfkla = te_vtfkla
EXCEPTIONS
OTHERS = 01.
IF sy-subrc EQ 0.
IF te_vtfkla[] IS NOT INITIAL.
SELECT * FROM lips INTO CORRESPONDING FIELDS OF TABLE it_lips
FOR ALL ENTRIES IN te_vtfkla[] WHERE vbeln = te_vtfkla-vbeln AND
posnr = te_vtfkla-posnr.
IF sy-subrc = 0.
SORT it_lips BY vbeln posnr.
ENDIF.
ENDIF.
LOOP AT te_vtfkla WHERE netwr NE 0.
* Gesamtkosten pro Lieferant merken (mit Menge)
CLEAR: ts_bnk. " 376476
* Begin N907632
CLEAR ls_lips.
READ TABLE it_lips INTO is_lips WITH KEY vbeln = te_vtfkla-vbeln
posnr = te_vtfkla-posnr.
IF sy-subrc = 0.
MOVE-CORRESPONDING is_lips TO ls_lips.
ENDIF.
IF xbbefu-erfme NE ls_lips-vrkme.
IF ls_lips-umvkn IS NOT INITIAL.
lf_lfimg = ls_lips-lfimg * ls_lips-umvkz / ls_lips-umvkn.
ENDIF.
IF xbbefu-umrez IS NOT INITIAL.
lf_lpomg = lf_lfimg * xbbefu-umren / xbbefu-umrez.
ENDIF.
IF lf_lpomg GT maxmenge.
lf_lpomg = 0.
ENDIF.
ELSE.
lf_lpomg = ls_lips-lfimg.
ENDIF.
* For items with batch split, retain exisiting logic
IF lf_lpomg IS INITIAL.
lf_lpomg = xbbefu-glmng.
ENDIF.
* End N907632
READ TABLE ts_bnk WITH KEY lifnr = te_vtfkla-tdlnr
BINARY SEARCH.
IF sy-subrc EQ 0.
ts_bnk-menge = ts_bnk-menge + lf_lpomg. "N907632
ts_bnk-netwr = ts_bnk-netwr + te_vtfkla-netwr.
CLEAR: ts_bnk-netwr_t,
ts_bnk-lgmng,
ts_bnk-kcmeng,
ts_bnk-kcmeng_vme.
MODIFY ts_bnk INDEX sy-tabix.
ELSE.
ts_bnk-menge = ts_bnk-menge + lf_lpomg. "N907632
ts_bnk-netwr = ts_bnk-netwr + te_vtfkla-netwr.
ts_bnk-lifnr = te_vtfkla-tdlnr.
ts_bnk-netwr_t = te_vtfkla-netwr_t.
ts_bnk-lgmng = te_vtfkla-lgmng.
ts_bnk-kcmeng = te_vtfkla-kcmeng.
IF xbbefu-umrez IS NOT INITIAL.
ts_bnk-kcmeng_vme = ts_bnk-kcmeng * xbbefu-umren /
xbbefu-umrez.
ENDIF.
INSERT ts_bnk INDEX sy-tabix.
ENDIF.
ENDLOOP.
ENDIF.
ENDLOOP.
ELSE.
EXIT.
ENDIF.
IF ts_bnk[] IS NOT INITIAL.
***********************************************************
*CUSTOM LOGIC
***********************************************************
IMPORT w_fknum FROM MEMORY ID 'YFKNUM'.
FREE MEMORY ID 'YFKNUM'.
CLEAR it_yfkpty.
SELECT kschl
parvw
fkpty INTO TABLE it_yfkpty FROM
yyv_lifnr_fkpty.
CLEAR it_vfkp.
SELECT fknum
fkpos
fkpty
bukrs
netwr
knumv
parvw
tdlnr
INTO TABLE it_vfkp FROM vfkp
WHERE fknum = w_fknum.
IF it_vfkp[] IS NOT INITIAL.
SELECT knumv
kposn
vbeln
posnr
netwr
INTO TABLE it_vfsi FROM vfsi
FOR ALL ENTRIES IN it_vfkp
WHERE knumv = it_vfkp-knumv AND
vbeln = i_vbeln AND
posnr in ( i_vbelp, space ). "SR0001++
* posnr = i_vbelp. "SR0001--
ENDIF.
REFRESH ts_bnk_copy[].
SORT it_yfkpty BY kschl.
SORT it_vfkp BY fkpty parvw.
SORT ts_bnk BY lifnr.
SORT it_vfsi BY knumv posnr. "SR0001++
* SORT it_vfsi BY knumv. "SR0001--
TYPES:BEGIN OF ty_lips_f,
vbeln TYPE vbeln_vl,
posnr TYPE posnr_vl,
lfimg TYPE lfimg,
END OF ty_lips_f.
DATA:lv_total TYPE lfimg,
lt_lips_f TYPE STANDARD TABLE OF ty_lips_f.
SELECT vbeln
posnr
LFIMG
FROM lips
INTO TABLE lt_lips_f
WHERE vbeln = i_vbeln.
IF sy-subrc eq 0.
CLEAR:lv_total.
LOOP AT lt_lips_f INTO DATA(lw_lips_f).
lv_total = lv_total + lw_lips_f-lfimg.
ENDLOOP.
DATA(lt_lips_t) = lt_lips_f[].
DELETE lt_lips_t WHERE posnr IS INITIAL.
SORT lt_lips_t BY posnr.
DELETE ADJACENT DUPLICATES FROM lt_lips_t COMPARING posnr.
DATA(lv_lines) = lines( lt_lips_t ).
CLEAR:lw_lips_f.
READ TABLE lt_lips_t INTO lw_lips_f INDEX lv_lines.
IF sy-subrc EQ 0 AND i_vbelp EQ lw_lips_f-posnr .
DATA(lv_posnr) = lw_lips_f-posnr.
ENDIF.
ENDIF.
LOOP AT betb.
READ TABLE it_yfkpty INTO is_yfkpty WITH KEY kschl = betb-kschl BINARY SEARCH.
IF sy-subrc EQ 0.
READ TABLE it_vfkp INTO is_vfkp WITH KEY fkpty = is_yfkpty-fkpty
parvw = is_yfkpty-parvw BINARY SEARCH.
IF sy-subrc EQ 0.
READ TABLE ts_bnk WITH KEY lifnr = is_vfkp-tdlnr BINARY SEARCH.
IF sy-subrc EQ 0.
ts_bnk_copy-lifnr = ts_bnk-lifnr.
ts_bnk_copy-menge = ts_bnk-menge.
CLEAR is_vfsi.
* READ TABLE it_vfsi INTO is_vfsi WITH KEY knumv = is_vfkp-knumv BINARY SEARCH. "SR0001--
******************************Begin Of Change By SR0001++**********************
"Splitting the Shipping charges for Header to all Line items Shippment for Header
READ TABLE it_vfsi INTO is_vfsi WITH KEY
knumv = is_vfkp-knumv posnr = i_vbelp BINARY SEARCH.
IF is_vfsi-netwr IS INITIAL.
READ TABLE it_vfsi INTO is_vfsi WITH KEY
knumv = is_vfkp-knumv posnr = space BINARY SEARCH.
IF sy-subrc eq 0.
CLEAR:lw_lips_f.
READ TABLE lt_lips_f INTO lw_lips_f with key
vbeln = i_vbeln posnr = i_vbelp.
IF sy-subrc eq 0.
IF lv_total is NOT INITIAL.
"Calculating the Shippment Charges
PERFORM shippment_del_cost_change IN PROGRAM ysd_e_subforms
USING lw_lips_f-lfimg
lv_total
i_vbeln
lv_posnr
CHANGING is_vfsi-netwr if FOUND.
ENDIF.
ENDIF.
ENDIF.
ENDIF.
******************************End Of Change By SR0001++**********************
ts_bnk_copy-netwr = is_vfsi-netwr.
ts_bnk_copy-netwr_t = is_vfsi-netwr.
* ts_bnk_copy-NETWR = ts_bnk-netwr.
* ts_bnk_copy-NETWR_T = ts_bnk-netwr_t.
ts_bnk_copy-lgmng = ts_bnk-lgmng.
ts_bnk_copy-kcmeng = ts_bnk-kcmeng.
ts_bnk_copy-kcmeng_vme = ts_bnk-kcmeng_vme.
IF is_vfsi-netwr = '0.00'
AND is_vfkp-netwr = '0.00'.
" do nothing.
elseIF ts_bnk_copy-netwr = '0.00'
AND ts_bnk_copy-netwr_t = '0.00'.
ts_bnk_copy-netwr = ts_bnk-netwr.
ts_bnk_copy-netwr_t = ts_bnk-netwr_t.
ENDIF.
APPEND ts_bnk_copy.
ENDIF.
ENDIF.
ENDIF.
ENDLOOP.
REFRESH ts_bnk[].
ts_bnk[] = ts_bnk_copy[].
**********************************************************
*CUSTOM LOGIC
**********************************************************
data : lv_tabix type sy-tabix.
SORT it_yfkpty BY kschl.
SORT it_vfkp BY fkpty parvw.
SORT ts_bnk BY lifnr.
read table betb INDEX 1.
if sy-subrc = 0.
delete sbetb where ebeln eq betb-ebeln and ebelp eq betb-ebelp .
endif.
LOOP AT betb WHERE ebelp EQ ebelp
AND bnktk NE space.
* AND kwert EQ 0.
* sind mehrere Konditionen vorhanden, wird solange mit den
* gefundenen Spediteuren aufgef¸llt, wie es geht;
* es kann nat¸rlich sein, dafl nicht gen¸gend Konditionen
* gepflegt sind, wer weifl das schon
*=================================================================================
clear lv_tabix.
READ TABLE it_yfkpty INTO is_yfkpty WITH KEY kschl = betb-kschl BINARY SEARCH.
IF sy-subrc EQ 0.
READ TABLE it_vfkp INTO is_vfkp WITH KEY fkpty = is_yfkpty-fkpty
parvw = is_yfkpty-parvw BINARY SEARCH.
IF sy-subrc EQ 0.
READ TABLE ts_bnk WITH KEY lifnr = is_vfkp-tdlnr BINARY SEARCH.
IF sy-subrc EQ 0.
lv_tabix = sy-tabix.
* READ TABLE ts_bnk WITH KEY lifnr = is_vfkp-tdlnr BINARY SEARCH.
ENDIF.
ELSE.
betb-kwert = 0.
betb-kwrfw = 0.
* betb-frwmg = 0.
* betb-frwwr = 0.
* betb-frwfr = 0.
MODIFY betb.
CONTINUE.
ENDIF.
ELSE.
CONTINUE.
ENDIF.
*=================================================================================
* READ TABLE ts_bnk INDEX 1.
* IF sy-subrc NE 0.
* EXIT.
* ENDIF.
*=================================================================================
IF ts_bnk-menge NE 0. " 376476
IF ts_bnk-kcmeng NE 0.
IF ekko-bsakz = bsakz-tran AND delivery = 'X' AND
i_vbeln NE space.
* Umlagerungsbestellung: Nachschublieferung mit Chargensplit
IF ts_bnk-kcmeng_vme IS NOT INITIAL.
betb-kwert = ts_bnk-netwr_t * i_menge / ts_bnk-kcmeng_vme.
ENDIF.
ELSE.
* Normalbestellung: Anlieferung mit Chargensplit
IF ts_bnk-menge IS NOT INITIAL AND ts_bnk-kcmeng IS NOT INITIAL.
betb-kwert = ( ts_bnk-netwr_t * i_menge * ts_bnk-lgmng )
/ ( ts_bnk-menge * ts_bnk-kcmeng ).
ENDIF.
ENDIF.
ELSE.
* ohne Chargen
IF ts_bnk-menge IS NOT INITIAL.
betb-kwert = ts_bnk-netwr * i_menge / ts_bnk-menge. " 376476
ENDIF.
ENDIF.
ELSE. " 376476
CLEAR: betb-kwert. " 376476
ENDIF. " 376476
betb-kwrfw = betb-kwert.
* den Nettowert in separatem feld zum Proportionaliseren und
* abspeichern in EKBZ an WE ¸bergeben (mit zugehˆriger Menge)
IF ts_bnk-kcmeng_vme NE 0.
betb-vnetw = ts_bnk-netwr_t. "in Bestellw‰hrung
betb-vmeng = ts_bnk-kcmeng_vme. "in Lagermengeneinheit
ELSE.
betb-vnetw = ts_bnk-netwr. "in Bestellw‰hrung
betb-vmeng = ts_bnk-menge.
ENDIF.
* Lieferant ¸bernehmen
betb-lifnr = ts_bnk-lifnr.
IF ekko-waers NE t001-waers.
* Umrechnen in Hausw‰hrung
IF budat IS INITIAL.
budat = sy-datlo.
ENDIF.
* If exchange rate handling is active the actual exchange rate
* has to be used for GR.
* N1387559 ekko-kufix should be considered for GR legal req
IF ekko-kufix NE space. "N980402 N1387559
CALL FUNCTION 'CONVERT_TO_LOCAL_CURRENCY'
EXPORTING
date = budat
foreign_amount = betb-kwert
foreign_currency = ekko-waers
local_currency = t001-waers
type_of_rate = kurstyp
rate = ekko-wkurs
IMPORTING
local_amount = betb-kwert.
ELSE.
CALL FUNCTION 'CONVERT_TO_LOCAL_CURRENCY'
EXPORTING
date = budat
foreign_amount = betb-kwert
foreign_currency = ekko-waers
local_currency = t001-waers
type_of_rate = kurstyp
IMPORTING
local_amount = betb-kwert.
ENDIF.
ENDIF.
MODIFY betb.
* Transportkosten merken
MOVE-CORRESPONDING betb TO sbetb.
APPEND sbetb.
IF lv_tabix gt 0.
DELETE ts_bnk INDEX lv_tabix.
ENDIF.
ENDLOOP.
ENDIF.
ENDIF.
ENDENHANCEMENT.
From the above code the Vendor code is populated to the delivery cost condition type and the shipment cost values are posted to material inventory valuation line item wise
Additional Validation required
- Delivery PGI not allowed in case delivery has reference of Shipment document unless shipment cost document is created with out a null value
- In case of PGI reversal, Ensure Shipment Cost Document should not be deleted if created.
Step 4. Vendor Payment
Using MIRO you can make vendor payments based on Stock transfer order number using delivery cost option within allowed tolerance