Introduction: Recently we faced a scenario where it was required to create one more accounting document ( different document type) in ECC for CRM billing scenario and for a special case. There might be one question can come up why it was at all required and believe me that we had a same question. But business was very stringent due to one it’s special case and wanted to inherit this custom requirement with the standard process.
So we were left with no option and achieved same by exploring the requirement through ECC USER-EXIT/ CRM middleware BADI, automatically after the standard process gets completed.
Solution: We have middleware accounting BADI (BILL_ACC_IF) which will pass the data to ECC during accounting document creation from CRM billing. Let’s create one implementation and put code in method IF_EX_BILL_ACC_IF~ENRICH_ACC_DOCUMENT to populate changing parameter (extension table) CT_BAPICRMPAREX.
Please refer below code snippets to demonstrate the functionality:
For my requirement, it was required to pass Header, Item and conditions details. So I created three separate DDIC structures in CRM and ECC both.
CONSTANTS : lc_kschl TYPE kschl VALUE 'ZCND',
lc_billh_struct TYPE te_struc VALUE 'ZBILLING_H',
lc_billi_struct TYPE te_struc VALUE 'ZBILLING_I',
lc_billcnd_struct TYPE te_struc VALUE 'ZBILLING_CND'.
DATA : lt_cond_db TYPE prct_cond_du_tab,
ls_head_db TYPE prct_head_du.
* Get Item Net Value and Product ID
SELECT a~bdi_guid,
a~itemno_ext,
a~net_value,
a~product_descr,
b~product_id
FROM /1bea/crmb_bdi AS a
INNER JOIN comm_product AS b
ON a~product = b~product_guid
UP TO 1 ROWS
INTO @DATA(ls_crmb_bdi_pr)
WHERE a~bdi_guid = @is_item-be_item_guid.
ENDSELECT.
IF sy-subrc EQ 0.
CLEAR : ls_head_db, lt_cond_db.
* Get Pricing conditions values against each line item
CALL FUNCTION 'PRC_PRIDOC_SELECT_DB'
EXPORTING
iv_pd_guid = is_head-pridoc_guid
it_item_no = VALUE prct_item_no_t( ( is_item-be_item_guid ) )
IMPORTING
es_head_db = ls_head_db
et_cond_db = lt_cond_db
EXCEPTIONS
database_read_failure = 1
OTHERS = 2.
IF sy-subrc NE 0.
CLEAR ls_head_db.
ENDIF.
TRY.
DATA(lt_partner_std) = CORRESPONDING bill_acc_t_partner( lt_partner ).
* Populate condition type in conditions and pass it to the extension
DATA(ls_billing_cond) = VALUE zbilling_cnd( kposn = CONV kposn( is_item-be_item_no )
kschl = lc_kschl
kawrt = shift_left( lt_cond_db[ kschl = lc_kschl ]-kawrt )
kbetr = shift_left( lt_cond_db[ kschl = lc_kschl ]-kbetr )]
kwert = shift_left( lt_cond_db[ kschl = lc_kschl ]-kwert ) ).
ct_bapicrmparex[] = VALUE #( BASE ct_bapicrmparex[] ( be_head_no = cs_acc_achead-be_head_no
structure = lc_billcnd_struct
valuepart1 = CONV valuepart( ls_billing_cond ) ) ).
CATCH cx_sy_itab_line_not_found.
CLEAR: ls_billing_cond.
ENDTRY.
* Only populate below extension values if there is an 'ZCND' tax present at item level
IF ls_billing_cond IS NOT INITIAL.
* Header item would be append only once as this method is being triggered at item level
IF NOT line_exists( ct_bapicrmparex[ be_head_no = cs_acc_achead-be_head_no
structure = lc_billh_struct ] ).
* Populate Header value and pass it to the extension
DATA(ls_billing_header) = VALUE zbilling_h( vbeln = CONV #( |{ CONV vbeln_vf( |{ is_head-be_head_no ALPHA = OUT }| ) ALPHA = IN }| )
waerk = is_head-doc_currency
fkdat = is_head-pstng_date
bukrs = cs_acc_achead-comp_code
kunag = CONV kunag( |{ lt_partner_std[ partner_pft = '0001' ]-external_partner_number ALPHA = IN }| )
kurst = ls_head_db-kurst
xblnr = is_head-ref_doc_no ).
* In case of cancellation, we would need value date to determine fiscal year for original acc. document
IF is_head-obj_key_r IS NOT INITIAL.
DATA(lr_bdh_guid) = VALUE beart_bdh_guid( ).
SELECT transfer_date
FROM /1bea/crmb_bdh
UP TO 1 ROWS
INTO ls_billing_header-bill_transfer_dt
WHERE bdh_guid IN lr_bdh_guid
AND headno_ext = is_head-obj_key_r+0(10).
ENDSELECT.
IF sy-subrc NE 0.
CLEAR ls_billing_header-bill_transfer_dt.
ENDIF.
ENDIF.
ct_bapicrmparex[] = VALUE #( BASE ct_bapicrmparex[] ( be_head_no = cs_acc_achead-be_head_no
structure = lc_billh_struct
valuepart1 = CONV valuepart( ls_billing_header ) ) ).
ENDIF.
* Populate all item value and pass it to the extension
TRY .
DATA(lv_bus_area) = VALUE #( ct_acc_acgl09[ 1 ]-bus_area ).
CATCH cx_sy_itab_line_not_found.
CLEAR lv_bus_area.
ENDTRY.
DATA(ls_billing_item) = VALUE zbilling_i( vbeln = CONV #( |{ CONV vbeln_vf( |{ is_head-be_head_no ALPHA = OUT }| ) ALPHA = IN }| )
posnr = CONV posnr( is_item-be_item_no )
fkimg = shift_left( CONV char17( is_item-inv_qty ) )
meins = is_item-sales_unit
gsber = lv_bus_area
netwr = shift_left( CONV char21( ls_crmb_bdi_pr-net_value ) )
matnr = CONV matnr( ls_crmb_bdi_pr-product_id )
arktx = is_item-item_text ).
ct_bapicrmparex[] = VALUE #( BASE ct_bapicrmparex[] ( be_head_no = cs_acc_achead-be_head_no
structure = lc_billi_struct
valuepart1 = CONV valuepart( ls_billing_item ) ) ).
ENDIF.
CLEAR : ls_billing_header,
ls_billing_item,
ls_billing_cond.
ENDIF.
ENDIF.
We have BADI BADI_ACC_DOCUMENT and method : IF_EX_ACC_DOCUMENT~CHANGE (with below filter condition) in ECC which will process further to create accounting document.
Filter Value:
Value 1 : BEBD Comparator 1 : = (Equal) Filter : AWTYP
CONSTANTS : lc_msgtyp_e TYPE bapi_mtype VALUE 'E',
lc_msgtyp_a TYPE bapi_mtype VALUE 'A',
lc_aworg_crmb TYPE aworg VALUE 'CRMB',
lc_msgid TYPE symsgid VALUE 'ZMSG',
lc_msgno TYPE symsgno VALUE '000',
lc_billh_struct TYPE te_struc VALUE 'ZBILLING_H',
lc_billi_struct TYPE te_struc VALUE 'ZBILLING_I',
lc_billcnd_struct TYPE te_struc VALUE 'ZBILLING_CND'.
TYPES : ty_tt_bitem TYPE STANDARD TABLE OF zfp0_billing_item WITH DEFAULT KEY,
ty_tt_bcond TYPE STANDARD TABLE OF zfp0_billing_cond WITH DEFAULT KEY.
DATA: lt_billing_item TYPE STANDARD TABLE OF zfp0_billing_item,
lt_billing_cond TYPE STANDARD TABLE OF zfp0_billing_cond,
lt_return TYPE STANDARD TABLE OF bapiret2.
* Execution would be Only for CRM invoices
IF c_acchd-aworg EQ lc_aworg_crmb.
* Populate Billing Header, Item and conditions values from CRM
LOOP AT c_extension2 ASSIGNING FIELD-SYMBOL(<fs_extension2>).
CASE <fs_extension2>-structure.
WHEN lc_billh_struct.
DATA(ls_billing_header) = CONV zbilling_h( <fs_extension2>-valuepart1 ).
WHEN lc_billi_struct.
lt_billing_item = VALUE ty_tt_bitem( BASE lt_billing_item ( CONV zbilling_i( <fs_extension2>-valuepart1 ) ) ).
WHEN lc_billcnd_struct.
lt_billing_cond = VALUE ty_tt_bcond( BASE lt_billing_cond ( CONV zbilling_cnd( <fs_extension2>-valuepart1 ) ) ).
ENDCASE.
ENDLOOP.
IF ls_billing_header IS NOT INITIAL.
DATA(lt_vbrp) = CORRESPONDING vbrpvb_t( lt_billing_item[] ).
LOOP AT c_accit ASSIGNING FIELD-SYMBOL(<fs_accit>) WHERE werks IS NOT INITIAL.
DATA(ls_vbrp) = VALUE vbrpvb( werks = <fs_accit>-werks ).
MODIFY lt_vbrp FROM ls_vbrp TRANSPORTING werks WHERE werks IS INITIAL.
EXIT.
ENDLOOP.
DATA(lt_komv) = CORRESPONDING komv_t( lt_billing_cond[] ).
* Delete Extension fields after collecting in local internal table
* which would prevent execution of logic in case if method gets triggered again
DELETE c_extension2 WHERE structure EQ lc_billh_struct
OR structure EQ lc_billi_struct
OR structure EQ lc_billcnd_struct.
* Store all the changing paramter locally before calling below FM,
* Internally below FM would check and call ACCOUNTING DOCUMENT creation logic
* It removes the existing record and updates with the new details, which further create an error for Normal accounting posting
DATA(ls_acchd) = CORRESPONDING acchd( c_acchd ).
DATA(lt_accit) = CORRESPONDING accit_tab( c_accit ).
DATA(lt_acccr) = CORRESPONDING acccr_tab( c_acccr ).
DATA(lt_accwt) = CORRESPONDING accwt_tab( c_accwt ).
DATA(lt_acctx) = CORRESPONDING acctx_tab( c_acctx ).
DATA(lt_accfi) = CORRESPONDING accfi_t( c_accfi ).
CALL FUNCTION 'ZACCOUNT_DOC'
EXPORTING
is_vbrk = ls_billing_header
iv_billto_cntry = ls_billing_header-billto_cntry
iv_simulation = abap_true
TABLES
ct_cvbrp = lt_vbrp
ct_ckomv = lt_komv
ct_return = lt_return.
IF ( line_exists( lt_return[ type = lc_msgtyp_e ] ) OR line_exists( lt_return[ type = lc_msgtyp_a ] ) ).
* Append newly generated error in exisitng RETURN parameter
c_return[] = VALUE #( BASE c_return[] ( LINES OF lt_return ) ( type = lc_msgtyp_e
id = lc_msgid
number = lc_msgno ) ).
CLEAR lt_return.
ELSE.
* Call FM in update task to avoid confustion between creation of two accounting documents
* One with standard one and other additional document.
CLEAR lt_return.
CALL FUNCTION 'ZACCOUNT_DOC' IN UPDATE TASK
EXPORTING
is_vbrk = ls_billing_header
iv_billto_cntry = ls_billing_header-billto_cntry
iv_simulation = abap_false
TABLES
ct_cvbrp = lt_vbrp
ct_ckomv = lt_komv
ct_return = lt_return.
ENDIF.
* Fillup all the parameters stored locally befor FM call to proceed expected standard functionality
c_acchd = CORRESPONDING acchd( ls_acchd ).
c_accit = CORRESPONDING accit_tab( lt_accit ).
c_acccr = CORRESPONDING acccr_tab( lt_acccr ).
c_accwt = CORRESPONDING accwt_tab( lt_accwt ).
c_acctx = CORRESPONDING acctx_tab( lt_acctx ).
c_accfi = CORRESPONDING accfi_t( lt_accfi ).
ENDIF.
ENDIF.
Function module, ZACCOUNT_DOC will call internally BAPI_ACC_DOCUMENT _CHECK in simulation mode and BAPI_ACC_DOCUMENT_POST if needs to create a real document with the required information.
No comments:
Post a Comment