BDC Program with OOABAP
Hi All,
This blog is all about to write BDC program with OOPs in ABAP. In one of my projects I got a requirement that while we creating a PO with respect to a quotation, the unused quotations of same RFQ should be marked as Rejected. To Implement this I found a BADI, unfortunately we don’t have BAPI’s to update quotations so we should opt BDC to update Quotations. usually BDC programs will be written by using two subroutines to fill BDCDATA internal table, one is for screen information and other one is for field name and value, the problem is that BADI class methods won’t allow perform and from statements, so we should write the same code in OOABAP.
So, what I did here is that simply I have converted those two subroutines into two methods in a class. Initially I created a Z_class in that I have create required attributes and methods. Please follow below steps you can understand.
Class Attributes
Class Methods
Class Methods Implementation
method BDC_DYNPRO.
wa_bdcdata–program = program. ” Program name
wa_bdcdata–dynpro = dynpro. ” Screen Number
wa_bdcdata–dynbegin = ‘X’. ” X
*** Append bdc table and clear work area
APPEND wa_bdcdata TO it_bdcdata.
CLEAR wa_bdcdata.
endmethod.
method BDC_FIELDVALUE.
wa_bdcdata–fnam = fnam. ” Field Name
wa_bdcdata–fval = fval. ” Field Value
APPEND wa_bdcdata TO it_bdcdata.
CLEAR wa_bdcdata.
endmethod.
Now I simply used this class in my BADI Class Method and solve the problem .
Here it is a sample code for BDC into OOABAP to update quotations Tcode ME47.
DATA: ob_bdc TYPE REF TO zcl_bdc_bps.
CREATE OBJECT ob_bdc.
TYPES: BEGIN OF t_ekko,
ebeln TYPE ekpo-ebeln,
END OF t_ekko,
BEGIN OF t_ekpo,
ebeln TYPE ekpo-ebeln,
ebelp TYPE ekpo-ebelp,
END OF t_ekpo.
data: it_ekko TYPE TABLE OF t_ekko,
it_ekpo TYPE TABLE OF t_ekpo,
it_message TYPE TABLE OF t_message,
it_bdcdata TYPE STANDARD TABLE OF bdcdata INITIAL SIZE 0,
it_bdc_messages TYPE STANDARD TABLE OF bdcmsgcoll INITIAL SIZE 0,
wa_message TYPE t_message,
wa_ekpo1 TYPE t_ekpo,
wa_ekko TYPE t_ekko,
wa_ekpo TYPE ekpo,
w_anfnr TYPE ekpo-anfnr,
w_submi TYPE ekko-submi,
w_mode(1) TYPE c VALUE ‘E’,
w_update(1) TYPE c VALUE ‘S’.
CLEAR wa_ekpo.
READ TABLE im_ekpo into wa_ekpo index 1.
IF sy-subrc EQ 0.
CLEAR w_submi.
SELECT SINGLE submi INTO w_submi FROM ekko WHERE ebeln = wa_ekpo-anfnr.
IF sy-subrc EQ 0.
SELECT ebeln FROM ekko INTO TABLE it_ekko WHERE submi = w_submi.
IF sy-subrc EQ 0.
SELECT ebeln ebelp FROM ekpo INTO TABLE it_ekpo
FOR ALL ENTRIES IN it_ekko
WHERE ebeln = it_ekko-ebeln.
delete it_ekko where ebeln = wa_ekpo-anfnr.
delete it_ekpo where ebeln = wa_ekpo-anfnr.
LOOP AT it_ekko INTO wa_ekko.
CLEAR:ob_bdc->it_bdcdata[].
*Populate BDC data to Maintain Quotation in ME47
CALL METHOD ob_bdc->bdc_dynpro
EXPORTING
program = ‘SAPMM06E’
dynpro = ‘0305’
dynbegin = ‘X’.
CALL METHOD ob_bdc->bdc_fieldvalue
EXPORTING
fnam = ‘BDC_CURSOR’
fval = ‘RM06E-ANFNR’.
CALL METHOD ob_bdc->bdc_fieldvalue
EXPORTING
fnam = ‘BDC_OKCODE’
fval = ‘/00’.
w_ebelp = wa_ekko-ebeln.
CONDENSE w_ebelp.
CALL METHOD ob_bdc->bdc_fieldvalue
EXPORTING
fnam = ‘RM06E-ANFNR’
fval = w_ebelp.
CLEAR:w_ebelp.
LOOP AT it_ekpo INTO wa_ekpo1 WHERE ebeln EQ wa_ekko-ebeln.
CALL METHOD ob_bdc->bdc_dynpro
EXPORTING
program = ‘SAPMM06E’
dynpro = ‘0323’
dynbegin = ‘X’.
CALL METHOD ob_bdc->bdc_fieldvalue
EXPORTING
fnam = ‘BDC_CURSOR’
fval = ‘RM06E-EBELP’.
CALL METHOD ob_bdc->bdc_fieldvalue
EXPORTING
fnam = ‘BDC_OKCODE’
fval = ‘/00’.
w_ebelp = w_ebelp + 10.
CONDENSE w_ebelp.
CALL METHOD ob_bdc->bdc_fieldvalue
EXPORTING
fnam = ‘RM06E-EBELP’
fval = w_ebelp.
CALL METHOD ob_bdc->bdc_dynpro
EXPORTING
program = ‘SAPMM06E’
dynpro = ‘0323’
dynbegin = ‘X’.
CALL METHOD ob_bdc->bdc_fieldvalue
EXPORTING
fnam = ‘BDC_CURSOR’
fval = ‘EKPO-EMATN’.
CALL METHOD ob_bdc->bdc_fieldvalue
EXPORTING
fnam = ‘BDC_OKCODE’
fval = ‘=DETA’.
CALL METHOD ob_bdc->bdc_fieldvalue
EXPORTING
fnam = ‘RM06E-EBELP’
fval = w_ebelp.
CALL METHOD ob_bdc->bdc_dynpro
EXPORTING
program = ‘SAPMM06E’
dynpro = ‘0311’
dynbegin = ‘X’.
CALL METHOD ob_bdc->bdc_fieldvalue
EXPORTING
fnam = ‘BDC_CURSOR’
fval = ‘RM06E-ANMNG’.
CALL METHOD ob_bdc->bdc_fieldvalue
EXPORTING
fnam = ‘EKPO-ABSKZ’
fval = ‘X’.
ENDLOOP.
CALL METHOD ob_bdc->bdc_fieldvalue
EXPORTING
fnam = ‘BDC_OKCODE’
fval = ‘=BU’.
refresh it_bdcdata.
it_bdcdata = ob_bdc->it_bdcdata.
CALL TRANSACTION c_me47 USING it_bdcdata
MODE w_mode
UPDATE w_update
MESSAGES INTO it_bdc_messages.
endloop.
Well, it's nice to see an attempt at object orientation, so kudos for that. You've used FOR ALL ENTRIES rather than INNER JOIN, which isn't good. In the vast majority of cases, INNER JOIN is more efficient that FOR ALL ENTRIES. You don't need to have the data in separate internal tables.
It's better to use the functional form when calling methods.
So: od_bdc->bdc_dynpro ( program = 'SAPMM06E' dynpro = '0323' dynbegin = 'X' ) or od_bdc->bdc_fieldvalue( fnam = 'BDC_CURSOR' fval = 'RM06E-EBELP' ).
Also, although the practice has been to use bdc_dynpro perhaps a more meaningful method name could be used?
Thanks for your valid comments..
Nice attempt to resolve. I agree with Matthew on his recommendations. Neverthless, this could be a perfect starting point for someone who needs to create a BDC in such space where only OOP is inevitable.
Thanks Sri..
Very informative Topic CD Raju
Thanks Hemanth..
OO approach for BDCs ,
Very thanks for adding a bit more to OO side of my ABAP Programming 🙂
Very good attempt in ABAP OOPs space.
Thanks Saurabh..
useful information... 🙂 🙂
Thanks Kumudwini..
Hi Raju,
Fanastic Blog!
Keep sharing. I will try to view all the blogs and implement in my project.
Thanks for sharing.
Regards,
Hari Suseelan
Thanks Hari..
Hi Raju,
You are welcome.
Regards,
Hari Suseelan
Hey Raju...Very usefull blog onBDCs with OO approach 🙂
Thanks Ranjit..
Excellent 🙂
Thanks Sai..
Very good OOABAP implementation indeed in BDC. Keep up the good work.
Thanks Lata..
Hi,
Actually you can declare this class local in report instead of se24. and you can sent multiple exporting parameters with using ':' .
Here is the example :
CLASS lcl_bdc DEFINITION.
PUBLIC SECTION.
METHODS : set_bdc_data
IMPORTING
i_pname TYPE bdc_prog OPTIONAL
i_dynnr TYPE bdc_dynr OPTIONAL
i_field TYPE fnam_____4 OPTIONAL
i_value TYPE bdc_fval OPTIONAL.
PROTECTED SECTION.
DATA : lt_bdcdata TYPE STANDARD TABLE OF bdcdata WITH DEFAULT KEY.
ENDCLASS. "lcl_bdc DEFINITION
*----------------------------------------------------------------------*
* CLASS lcl_bdc IMPLEMENTATION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_bdc IMPLEMENTATION.
METHOD set_bdc_data.
DATA : ls_bdcdata TYPE bdcdata.
IF i_pname NE space.
ls_bdcdata-program = i_pname. " Program name
ls_bdcdata-dynpro = i_dynnr. " Screen Number
ls_bdcdata-dynbegin = 'X'. " X
ELSE.
ls_bdcdata-fnam = i_field. " Field Name
ls_bdcdata-fval = i_value. " Field Value
ENDIF.
APPEND ls_bdcdata
TO lt_bdcdata.
ENDMETHOD. "set_bdc_data
ENDCLASS. "lcl_bdc IMPLEMENTATION
DATA : lo_bdc TYPE REF TO lcl_bdc.
START-OF-SELECTION.
CREATE OBJECT lo_bdc.
CALL METHOD lo_bdc->set_bdc_data :
EXPORTING
i_pname = 'SAPMM06E'
i_dynnr = '0305',
EXPORTING
i_field = 'BDC_OKCODE'
i_value = '/00'.
What benefit does a local class have over a global class? Surely having a global class facilitates re-use?
For a first timer, it is easier to copy,paste,compile with local class.
Local class facilitates first-use and global class facilitates re-use.
Start as you mean to go on, I say.
SE24 isn't exactly difficult to get to grips with. I started with global classes - it was quite a while before I did any local classes, since they are more complicated. I'd contend that it's easier to use SE24 for newbies.
Local class facilitates developing the same thing again and again and again.... 😉
Hi,
I think for very basic use there no need to create global object ( data, structure etc. ).
For this example, will you inherit other class from this? do you need to overwrite any method? This is simply changing perform to method.
This is my thought about diffirence between global and local declaration.
Also i wanted to give a example about writing code shorter, and usage of multi parameters with ':' .
A class to do BDC will be re-used. So you do it as a global class, where you will find classes that are re-usable. Whether it is subclass-able or not is irrelevant. In Java I write classes that will probably never be subclassed.
I don't see why even the most basic class shouldn't be global. It's not as though database space is at a premium. Global classes are easier and less work to create than local ones.
Methods are better than forms. Some kind of typing is enforced, and you have to name parameters.
I understand the use of :, but if you rewrite as a functional method, then you get shorter clearer code anyway.
I think having a BDC object is good!!
what will be better is to extend its functioanality
For example: Make it a singleton object
You wouldnt want to have another BDC object doing other things behind.
or you can gave a BDC factory etc..
Where to start will be to have an interface between them..
İf you make this a global class it should worth it:)
The Call Pattern or drag-and-drop from object list does not work with local class methods. It makes use of local classes harder.
Tolga,
I hope you would have understood why I created a Global Class for this purpose with Matthew's and Manish's good explanation. And addition their explanation, let me give you one more reason to create Global Class is that the above code is built in a BADI method and in method we can't define a class.
Hi Radju,
very nice aproach, but why stop at half the distance?
I had to build something quite similar and used standard class CL_CACS_BDC_CNTRL for the basic functionality. I found to my regret, that this class is final, otherwise i'd have jus inherited the methods. As it is, i use said class as an instance attribute and have added the rest in my class around it. OPEN_GROUP, CLOSE_GROUP and ADD_TRANSACTION complete the set.
By leaving OPEN_GROUP private and calling it from within, on first use of ADD_TRANSACTION i make sure, that no empty groups are created.
So, each instance of my class represents a bdc-group.
@Tolga Polat
for shorter code, especially when providing bdc data, i recommend the below document on advanced use of macros.
http://scn.sap.com/community/abap/blog/2012/10/28/use-macros-use-them-wisely
In my code this reads like this:
add_bdc_field 'BKPF-BUDAT' lv_hdat.
add_bdc_field 'BKPF-MONAT' lv_monat.
...
Best regards - Jörg
Thats a good idea Jörg:)
I agree with you
You could inherit and extend its functinality why leave it there
Macros are powerfulç good link
Hi Jörg,
I'm using macro too, looks like SM35 record result and we can define macro in method too
add_bdcdata_to_table : 'SAPMM06E' '0305' '' '',
'' '' 'BDC_OKCODE' '/00'.
I dont know CL_CACS_BDC_CNTRL, I will look.
Your approach to CL_CACS_BDC_CNTRL is a nice example of the power of composition. I've had to use it in the same circumstance - when for no really good reason, SAP have marked a class as final.
Thanks for pointing out the blog. Interesting reading, though I think in major development centres Rainer's approach of banning macros is eminently sensible. They're too easy to misuse and cause problems. I find that OO programming, with functional method calls, usually is sufficient to meet the criteria of:
Nice effort Raju!!
Regards,
Supratik
Thanks Supratik..
It seems great, But You can do much more better than this.
Regards,
Hai Wang
Thanks Hai Wang..
Looks useful !!
Thanks for Sharing 🙂
Thanks Chandra..
Nice doc..keep it up and keep rocking. 🙂
Regards,
Krishna Chaitanya.
Thanks Chaitanya...
Hii Raju,
Can u plz tell me the name of the BADI which u ve implemented for this to meet the requirement.
regards,
Smith
Hi Smith,
ME_PURCHDOC_POSTED is the BADI name.
Thanks
Raju
thank u..