How To Report Cross Comp Stock
How To Report Cross Comp Stock
How To Report Cross Comp Stock
1 Business Scenario
Current stock reporting in BW (e. g. InfoCube 0IC_C03) doesnt offer the possibility to report on stock in transit that is created via purchase orders/sales orders (Cross company stock in transit - movement types 101 and 643 for cross company).
2 Introduction
Current extractors like 2LIS_03_BF cannot report on this as the material movements come with normal movement types (101) that are also used by stock transfers with company external customers/vendors. Such information could only be deliverd by 2LIS_03_BF due to the posting logic. If the purchase orders history (table EKBE) is additionally read in the extraction process (purchase orders with item category 0) then this information could be obtained. But his solution is not feasible as this would lead into big performance problems. Therefore we prefer a solution that extracts cross company stock directly into BW. This extrator transfers information displayed with R/3 transaction MB5T (Display of stock in transit) into BW. This data can be loaded as a daily snapshot into an ODS (for less data amount and preferred reporting on single records) or InfoCube (for many data and preferred reporting on aggregated data) and then be combined with 0IC_C03 in a MultiProvider scenario for consolidated stock reporting.1
R/3:
Creation of DDIC structures, etc. Creation of function module extractor, etc. Creation of DataSource DataSource testing and comparison with MB5T
BW:
Creation of missing InfoObjects Creation of InfoSource, ODS and update rules Creation of a sample query Date Source replication; creation of transfer rules and data extraction from R/3 Query testing and comparison with MB5T Creation of a Multi Provider and Multi Provider Query Query testing of consolidated stock reporting
1. Steps in R/3
1. Creation of DDIC structures, etc.
1. ZCUM_STRUC_TRANSIT
2. ZSTOCK_TRANSIT
3. ZSTOCK_TRANSIT_SEL
4. Type-Pool ZCON
TYPE-POOL zcon. * Field names CONSTANTS: zcon_gc_fn_material zcon_gc_fn_pstyp zcon_gc_fn_budat zcon_gc_fn_plant * Ranges constants CONSTANTS: zcon_gc_sign_include zcon_gc_option_equal TYPE TYPE TYPE TYPE rsfieldnm rsfieldnm rsfieldnm rsfieldnm VALUE VALUE VALUE VALUE 'MATNR', 'PSTYP', 'BUDAT', 'WERKS'.
1. Function group ZZ_STOCK_TRANSIT 2. Funtion module Z_STOCK_TRANSIT_DATE a) Global data FUNCTION-POOL ZZ_STOCK_TRANSIT. TYPE-POOLS: SBIWA, RSAP, SRSC, RSAOT, RSAZT, ZCON. types: begin of po_num, ebeln type ebeln, bsart type bsart, INCO1 type inco1, INCO2 type inco2, wkurs type wkurs, "MESSAGE-ID ..
b) Import parameters
c) Tables parameters
d) Exceptions
e) Source code FUNCTION z_stock_transit_date. *"---------------------------------------------------------------------*"*"Local interface: *" IMPORTING *" REFERENCE(I_REQUNR) TYPE SRSC_S_IF_SIMPLE-REQUNR *" REFERENCE(I_DSOURCE) TYPE SRSC_S_IF_SIMPLE-DSOURCE OPTIONAL *" REFERENCE(I_MAXSIZE) TYPE SRSC_S_IF_SIMPLE-MAXSIZE OPTIONAL *" REFERENCE(I_INITFLAG) TYPE SRSC_S_IF_SIMPLE-INITFLAG OPTIONAL *" REFERENCE(I_READ_ONLY) TYPE SRSC_S_IF_SIMPLE-READONLY OPTIONAL *" TABLES
IF NOT i_initflag IS INITIAL. gt_select = i_t_select[]. gt_fields = i_t_fields[]. PERFORM budat_validate CHANGING gt_select. ELSE. * transfer selection parameters in ranges PERFORM range_fill USING CHANGING PERFORM range_fill USING CHANGING PERFORM range_fill USING CHANGING PERFORM range_fill USING CHANGING zcon_gc_fn_material gt_select lr_material. zcon_gc_fn_plant gt_select lr_plant. zcon_gc_fn_pstyp gt_select lr_pstyp. zcon_gc_fn_budat gt_select lr_budat. i_maxsize lr_material lr_plant lr_pstyp lr_budat gt_sel_fields e_t_data[].
*&---------------------------------------------------------------------* *& Include LZZ_STOCK_TRANSITF0B * *&---------------------------------------------------------------------* FORM build_range USING iv_sign iv_option iv_low iv_high CHANGING cr_range
DATA: lp_data TYPE REF TO data. FIELD-SYMBOLS: <ls_fields> <ls_range> <lv_sign> <lv_option> <lv_low> <lv_high> <lv_fieldname> TYPE TYPE TYPE TYPE TYPE TYPE TYPE ANY, ANY, ANY, ANY, ANY, ANY, ANY.
TO TO TO TO
DATA: ls_select TYPE srsc_s_select. DATA: lt_select TYPE srsc_t_select. DATA: ls_return TYPE bapiret2. DATA: lv_tabix TYPE sytabix.
lt_select = ct_select. SORT lt_select BY fieldnm. DELETE lt_select WHERE fieldnm NE zcon_gc_fn_budat. DESCRIBE TABLE lt_select. IF sy-tfill > 1. MESSAGE e113(zstocktransit) WITH zcon_gc_fn_budat RAISING error_passed_to_mess_handler. * Selection parameter & only allows one value ENDIF. READ TABLE lt_select INTO ls_select WITH KEY fieldnm = zcon_gc_fn_budat. IF sy-subrc NE 0. MESSAGE e114(zstocktransit) WITH zcon_gc_fn_budat RAISING error_passed_to_mess_handler. * Parameter & is mandatory ENDIF. IF NOT ls_select-low IS INITIAL AND NOT ls_select-high IS INITIAL AND ls_select-low NE ls_select-high . MESSAGE e115(zstocktransit) WITH zcon_gc_fn_budat. * For parameter & no intervall is allowed ENDIF. READ TABLE ct_select INTO ls_select WITH KEY fieldnm = zcon_gc_fn_budat. lv_tabix = sy-tabix. IF NOT ls_select-high IS INITIAL. CLEAR: ls_select-high. ENDIF. ls_select-option = 'LE'. MODIFY ct_select FROM ls_select INDEX lv_tabix. ENDFORM. " budat_validate
g) Include LZZ_STOCK_TRANSITF0C *&---------------------------------------------------------------------* *& Include LZZ_STOCK_TRANSITF0C * *&---------------------------------------------------------------------* FORM check_relevance USING it_ekbe TYPE SORTED TABLE
READ TABLE it_ekbe TRANSPORTING NO FIELDS WITH KEY (lv_ebelnfield) = iv_ebeln (lv_ebelpfield) = iv_ebelp BINARY SEARCH. IF sy-subrc NE 0. CLEAR: cv_relevant. EXIT. ELSE. lv_start = sy-tabix. ENDIF. LOOP AT it_ekbe INTO ls_ekbe FROM lv_start. IF ls_ekbe-ebeln NE iv_ebeln OR ls_ekbe-ebelp NE iv_ebelp. EXIT. ENDIF. MOVE: ls_ekbe-ebeln TO ls_cum-ebeln, ls_ekbe-ebelp TO ls_cum-ebelp. CASE ls_ekbe-vgabe. WHEN '1'. * goods receipt IF ls_ekbe-shkzg EQ 'S'. * normal goods receipt ADD ls_ekbe-menge TO ls_cum-wemng. ELSE. * reversal ls_ekbe-menge = ls_ekbe-menge * -1. ADD ls_ekbe-menge TO ls_cum-wemng. ENDIF. WHEN '6'. * goods issue IF ls_ekbe-shkzg EQ 'H'. * normal goods issue ADD ls_ekbe-menge TO ls_cum-wamng. ELSE. * reversal ls_ekbe-menge = ls_ekbe-menge * -1. ADD ls_ekbe-menge TO ls_cum-wamng. ENDIF. ENDCASE. ENDLOOP. IF ls_cum-wamng <> ls_cum-wemng. cv_relevant = 'X'. cv_wamng = ls_cum-wamng. cv_wemng = ls_cum-wemng. ELSE. CLEAR: cv_relevant. ENDIF.
ENDFORM.
" check_relevence
h) Include LZZ_STOCK_TRANSITF0D *&---------------------------------------------------------------------* *& Include LZZ_STOCK_TRANSITF0D * *&---------------------------------------------------------------------* *&---------------------------------------------------------------------* *& Form data_selection_transit_date *&---------------------------------------------------------------------* FORM data_selection_transit_date USING iv_maxsize ir_material TYPE STANDARD TABLE ir_plant TYPE STANDARD TABLE ir_pstyp TYPE STANDARD TABLE ir_budat TYPE STANDARD TABLE it_sel_fields TYPE STANDARD TABLE CHANGING ct_data TYPE STANDARD TABLE. FIELD-SYMBOLS: <ls_data> <ls_budat> <lv_low> STATICS: lt_sel_fields lt_t001 lt_ekbe TYPE TYPE TYPE zstock_transit_sel, ANY, ANY. fieldname, t001 bukrs, ekbe ebeln ebelp zekkn vgabe gjahr belnr buzei,
TYPE STANDARD TABLE OF TYPE SORTED TABLE OF WITH UNIQUE KEY TYPE SORTED TABLE OF WITH UNIQUE KEY
lv_datapakid_counter lv_cursor lv_tabix lv_wamng lv_wemng lv_relevant DATA: lt_fields lt_data lr_plant lr_ebeln lr_ebelp lt_mara ls_mara lt_transit_data ls_transit_data ls_t001 lv_budat l_bsakz l_ccomp.
TYPE TYPE TYPE TYPE TYPE TYPE TYPE TYPE TYPE TYPE TYPE TYPE
sytabix, cursor, sytabix, menge_d, menge_d, char1. srsc_t_fields, zstock_transit_sel, werks_d, ebeln, ebelp, mara matnr, mara, zstock_transit, zstock_transit, t001, datum, ekko-bsakz,
STANDARD TABLE OF RANGE OF RANGE OF RANGE OF SORTED TABLE OF WITH UNIQUE KEY
DATA: lp_data TYPE REF TO data. ***************************************************************** CREATE DATA lp_data LIKE LINE OF ir_budat.
ASSIGN lp_data->* TO <ls_budat>. ASSIGN COMPONENT 'LOW' OF STRUCTURE <ls_budat> TO <lv_low>. * IF lt_sel_fields IS INITIAL. adjust selected fields to your requirements
USING CHANGING
SELECT * FROM t001 INTO TABLE lt_t001. ENDIF. IF lv_datapakid_counter IS INITIAL. OPEN CURSOR WITH HOLD lv_cursor FOR SELECT (lt_sel_fields) FROM ekko INNER JOIN ekpo ON ekko~mandt = ekpo~mandt AND ekko~ebeln = ekpo~ebeln WHERE ekko~ebeln IN lr_ebeln AND ekpo~ebelp IN lr_ebelp * AND mb_mdbs~etenr IN lr_etenr AND ekpo~matnr IN ir_material AND ekpo~werks IN ir_plant AND ekpo~pstyp IN ir_pstyp AND ekpo~loekz EQ space * AND mb_mdbs~elikz eq space AND ekpo~bstyp EQ 'F' AND ekko~reswk <> space. IF sy-subrc NE 0. MESSAGE e103(zstocktransit) RAISING no_more_data. * No data found ENDIF. ENDIF. FETCH NEXT CURSOR INTO CORRESPONDING FIELDS OF TABLE PACKAGE SIZE lv_cursor lt_data iv_maxsize.
IF sy-subrc <> 0. CLOSE CURSOR lv_cursor. MESSAGE e103(zstocktransit) RAISING no_more_data. ENDIF. lv_datapakid_counter = lv_datapakid_counter + 1. SELECT * FROM INTO TABLE FOR ALL ENTRIES IN WHERE mara lt_mara lt_data matnr EQ lt_data-matnr.
READ TABLE ir_budat INTO <ls_budat> INDEX 1. lv_budat = <lv_low>. SORT lt_data BY ebeln ebelp.
* the entries from EKBE are needed because we want to know the transit * stock per posting date SELECT * FROM ekbe INTO TABLE lt_ekbe FOR ALL ENTRIES IN lt_data WHERE ebeln EQ lt_data-ebeln AND ebelp EQ lt_data-ebelp AND ( vgabe EQ '1' OR vgabe EQ '6' ) AND budat IN ir_budat. LOOP AT lt_data ASSIGNING lv_tabix = sy-tabix. CLEAR: lv_relevant. * <ls_data>.
move EKPO-MENGE to field BSTMG from the transfer structure MOVE <ls_data>-menge TO <ls_data>-bstmg. CLEAR <ls_data>-menge. form SET_CCOMP complies with function module MMPUR_SET_CCOMP which is available with release 470
* *
10
Determine posting logic for document item. IF <ls_data>-bsakz = 'T' OR l_ccomp = '1'. l_bsakz = 'T'. ELSE. l_bsakz = space. ENDIF. Delete if not requested IF l_bsakz = 'T'. DELETE lt_data. CLEAR l_ccomp. CONTINUE. ENDIF. calculates WEMNG and WAMNG using the entries in EKBE if WEMNG <> WAMNG -> lv_relevant = 'X' PERFORM check_relevance USING lt_ekbe <ls_data>-ebeln <ls_data>-ebelp CHANGING lv_relevant lv_wamng lv_wemng. IF lv_relevant IS INITIAL. DELETE lt_data INDEX lv_tabix. CONTINUE. ENDIF. READ TABLE lt_mara INTO ls_mara WITH KEY matnr = <ls_data>-matnr BINARY SEARCH. CLEAR ls_transit_data. MOVE-CORRESPONDING <ls_data> TO ls_transit_data. ls_transit_data-budat = lv_budat. ls_transit_data-meins = ls_mara-meins. ls_transit_data-attyp = ls_mara-attyp. ls_transit_data-bsttyp = 'A'. ls_transit_data-menge = lv_wamng - lv_wemng.
* *
adjustment NETWR to quantity in transit <ls_data>-netwr = ls_transit_data-menge * <ls_data>-netwr / <ls_data>-bstmg. ls_transit_data-menge = ls_transit_data-menge * <ls_data>-umrez / <ls_data>-umren. READ TABLE lt_t001 INTO ls_t001 WITH KEY bukrs = <ls_data>-bukrs BINARY SEARCH. IF ls_t001-waers NE <ls_data>-waers. IF <ls_data>-kufix IS INITIAL. CLEAR <ls_data>-wkurs. ENDIF. CALL FUNCTION 'CONVERT_TO_LOCAL_CURRENCY' EXPORTING date = sy-datum foreign_amount = <ls_data>-netwr foreign_currency = <ls_data>-waers local_currency = ls_t001-waers rate = <ls_data>-wkurs IMPORTING local_amount = ls_transit_data-dmbtr.
11
*&---------------------------------------------------------------------* *& Form set_ccomp *&---------------------------------------------------------------------* FORM set_ccomp USING im_plant1 im_plant2 im_bsakz CHANGING ch_ccomp. DATA: l_same_company_code TYPE xfeld. CONSTANTS: bsakz_norm bsakz_tran VALUE VALUE ' ', 'T'.
CHECK ch_ccomp IS INITIAL. CHECK NOT im_plant1 IS INITIAL. CHECK NOT im_plant2 IS INITIAL. PERFORM compare_company_codes USING CHANGING IF l_same_company_code IS INITIAL. CASE im_bsakz. WHEN bsakz_norm. ch_ccomp = '2'. WHEN bsakz_tran. ch_ccomp = '1'. ENDCASE. ELSE. ch_ccomp = '1'. ENDIF. ENDFORM. " set_ccomp im_plant1 im_plant2 l_same_company_code.
*&---------------------------------------------------------------------* *& Form compare_company_codes *&---------------------------------------------------------------------* FORM compare_company_codes USING im_plant1 im_plant2 CHANGING ex_same_company_code. DATA: l_bukrs1 l_bukrs2 l_t001w l_t001w_ext l_t001k TYPE TYPE TYPE TYPE TYPE bukrs, bukrs, t001w, t001w_ext, t001k. t001w l_t001w werks = im_plant1. t001k l_t001k bwkey = l_t001w-bwkey.
SELECT SINGLE * FROM INTO WHERE IF sy-subrc EQ 0. SELECT SINGLE * FROM INTO WHERE IF sy-subrc NE 0. RAISE error. ENDIF.
12
IF l_t001k-bukrs IS INITIAL. RAISE error. ENDIF. l_bukrs1 = l_t001k-bukrs. ENDIF. SELECT SINGLE * FROM INTO WHERE IF sy-subrc EQ 0. SELECT SINGLE * FROM INTO WHERE IF sy-subrc NE 0. RAISE error. ENDIF. IF l_t001k-bukrs IS INITIAL. RAISE error. ENDIF. l_bukrs2 = l_t001k-bukrs. ENDIF. IF l_bukrs1 EQ l_bukrs2. ex_same_company_code = 'X'. ELSE. ex_same_company_code = ' '. ENDIF. ENDFORM. i) Include LZZ_STOCK_TRANSITF0F *&---------------------------------------------------------------------* *& Include LZZ_STOCK_TRANSITF0F * *&---------------------------------------------------------------------* *&---------------------------------------------------------------------* *& Form field_list_build *&---------------------------------------------------------------------* FORM field_list_build USING it_fields TYPE srsc_t_fields CHANGING ct_fields TYPE ANY TABLE. DATA: lr_fields DATA: lt_fields DATA: ls_fields TYPE RANGE OF TYPE TYPE fieldname. srsc_t_fields. srsc_s_fields. " compare_company_codes t001w l_t001w werks = im_plant2. t001k l_t001k bwkey = l_t001w-bwkey.
LOOP AT it_fields INTO ls_fields. PERFORM build_range USING zcon_gc_sign_include zcon_gc_option_equal ls_fields-fieldnm space CHANGING lr_fields. ENDLOOP. PERFORM get_fields USING CHANGING USING CHANGING 'EKKO' lr_fields lt_fields. 'EKPO' lr_fields lt_fields.
PERFORM get_fields
SORT lt_fields BY fieldnm. DELETE ADJACENT DUPLICATES FROM lt_fields COMPARING fieldnm. ct_fields = lt_fields. ENDFORM. " field_list_build
j) Include LZZ_STOCK_TRANSITF0G
13
TYPE STANDARD TABLE OF fieldname. TYPE srsc_s_fields. TYPE fieldname. TYPE srsc_t_fields. REF TO data.
FIELD-SYMBOLS: <ls_range> TYPE ANY, <lv_low> TYPE ANY. CREATE DATA lp_data LIKE LINE OF cr_fields. ASSIGN lp_data->* TO <ls_range>. ASSIGN COMPONENT 'LOW' OF STRUCTURE <ls_range> TO <lv_low>. SELECT fieldname FROM dd03l APPENDING TABLE ct_fields WHERE tabname = iv_tabname AND fieldname IN cr_fields. LOOP AT cr_fields INTO <ls_range>. READ TABLE ct_fields INTO ls_field WITH KEY fieldnm = <lv_low>. IF sy-subrc EQ 0. CONCATENATE iv_tabname '~' ls_field-fieldnm INTO ls_field-fieldnm. MODIFY ct_fields FROM ls_field INDEX sy-tabix. DELETE TABLE cr_fields FROM <ls_range>. ENDIF. ENDLOOP. ENDFORM. " get_fields
k) Include LZZ_STOCK_TRANSITF0R *&---------------------------------------------------------------------* *& Include LZZ_STOCK_TRANSITF0R * *&---------------------------------------------------------------------* FORM range_fill USING iv_selfield it_seltab TYPE srsc_t_select CHANGING er_range TYPE STANDARD TABLE.
DATA: lp_data TYPE REF TO data. DATA: ls_seltab TYPE srsc_s_select. FIELD-SYMBOLS: <ls_line> TYPE ANY. CREATE DATA lp_data LIKE LINE OF er_range. ASSIGN lp_data->* TO <ls_line>. LOOP AT it_seltab INTO ls_seltab WHERE fieldnm = iv_selfield. PERFORM build_range USING ls_seltab-sign ls_seltab-option ls_seltab-low ls_seltab-high CHANGING er_range. ENDLOOP. ENDFORM. 3. Message class ZSTOCKTRANSIT " range_fill
14
15
16
Please note that the company code is the company code from the supplying plant. Also the quantity and value belongs to the supplying plant/company code. The value is determined by the purchase order value. In the inter company stock transfer (coverd by 2LIS_03_BF) the value is determined with the valuation price of the receiving plant.
17
2. Steps in BW
18
19
20
21
1. InfoSource Z_STOCK_TRANSIT_DATE
2. ODS ZCCSTOCK
22
3. Update rules
There is a complete 1:1 Mapping. Please set the key figures to Addition 3. Creation of a sample query
23
HOW TO REPORT ON CROSS COMPANY STOCK TRANSFER 4. Date Source replication; creation of transfer rules and data extraction from R/3
1. Replication of DataSource Z_STOCK_TRANSIT_DATE 2. Creation of transfer rules Not every field gets assigned from the DataSource, if further fields for reporting are required, enhancements or modifications can be done easily.
3. Data extraction - Scheduler At least the selection criteria posting date has to be provided. Otherwhise the extractor will give an error if no selection criteria are handed over. Please note that by restricting 0ITM_CAT with 0 only the cross company stock in transit gets extracted. Restrictions with 7 gives the inter company stock in transit back. No selections restrict the complete stock in transit.3
Please note that in same cases this restriction doesnt help. See comment
24
As we have here a snapshot scenario update mode Full Update is the only supported one. This means that no duplicated uploads with the same posting date should be executed.
1. Query ZZMB5T
* * * * *
of PO's should be selected. This is just for backwards compatibility with callers which do not use the separated flags. Please note that with cross-system movements, PO's with UB-logic (formerly PSTYP = 7) can also have PSTYP = 0. Therefore, this criteria is not usable any more. IF NOT xpstyp[] IS INITIAL. IF '0' IN xpstyp OR '3' IN xpstyp. i_cross_company = 'X'. ENDIF. IF '7' IN xpstyp. i_non_cross_company = 'X'. ENDIF. ENDIF.
in function module MB_ADD_TRANSFER_QUANTITY that is used in transaction MB5T. In such cases the similar logic * Delete if not requested IF ( l_bsakz = 'T' AND i_non_cross_company IS INITIAL ) OR ( l_bsakz = space AND i_cross_company IS INITIAL ). DELETE xmdbs. CONTINUE. ENDIF.
from this function module has to be implemented in the extractor. 2004 SAP AMERICA, INC. AND SAP AG
25
2. Transaction MB5T
Together with InfoCube 0IC_C03 the defined ODS object can be part of a MultiProvider. The most common objects like material, plant and posting date can be defined as matching characteristics.
26
4 Additional Information
This scenario requires at lest BW 3.0B and R/3 4.7.
27