How to check if there is initial value and duplicate entry? - abap

I have an ABAP program to add records into the database. I would like to check if there is the same identification number in the database and if so raise an error message. The second thing, if user passes the id field as empty I would like to raise an error message.
MY METHOD TO ADD RECORDS INTO DATABASE
METHOD add.
DATA: IT_E TYPE TABLE OF ZE.
DATA:WA_E TYPE ZE.
IF sy-subrc EQ 0.
WA_E-ID = C_ID.
WA_E-NAME = C_NAME.
APPEND wa_e TO it_e.
INSERT ZE FROM TABLE it_e.
CALL FUNCTION 'POPUP_TO_DISPLAY_TEXT'
EXPORTING
TITEL = 'Message2'
TEXTLINE1 = 'Record Added Successfully.'.
IF sy-subrc <> 0.
CALL FUNCTION 'POPUP_TO_DISPLAY_TEXT'
EXPORTING
TITEL = 'Message2'
TEXTLINE1 = 'YOu cant use this id no'.
ENDIF.
DATA : ref_obj TYPE REF TO LCL_E.
MAIN PART
START-OF-SELECTION.
IF ra_add EQ 'X'.
IF pa_id eq space.
CALL FUNCTION 'POPUP_TO_DISPLAY_TEXT'
EXPORTING
TITEL = 'Message2'
TEXTLINE1 = 'You cant pass id field empty'.
else.
CREATE OBJECT ref_obj
EXPORTING
im_id = pa_id
im_name = pa_name
CALL METHOD ref_obj->add.
endif.

For the first issue I would recommend to make a SELECT with the key before the INSERT to ensure that record exists in table, if it does display the message else make the INSERT. For the second issue you should use "IF lv_data IS INITIAL".

1)You can make the field mandatory using the keyword OBLIGATORY.
PARAMETERS : pa_id type c OBLIGATORY.
2) Try to retrieve the record from database using the id.if the sy-subrc <> 0 then insert the record ,else raise the error message.

Related

cmd_ei_api=>maintain_bapi to update kna1 table field (ICMSTAXPAY)

I have a requirement to update this field ICMSTAXPAY in KNA1 table using my custom report. So, I tried using cmd_ei_api=>maintain_bapi to update the table. But once I run the program, that particular field is not updated and I don't get any error messages too.
My logic:
Read the KNA1 entries.
Edit the required field to my value.
Pass mandatory data to HEADER for update.
Pass my new KNA1 entries to CENTRAL_DATA.
Read data from table:
CALL METHOD cmd_ei_api_memory=>get_global_kna1
EXPORTING
iv_kunnr = <lfs_final>-kunnr
IMPORTING
es_kna1_old = ls_old.
Change the value of field:
ls_old-icmstaxpay = 9.
MOVE-CORRESPONDING ls_old TO ls_customer-central_data-central-data.
Assign header data:
ls_customer-header-object_instance-kunnr = <lfs_final>-kunnr.
ls_customer-header-object_task = 'U'.
Add all the above to the master data structure:
APPEND ls_customer TO lt_customers[].
ls_master_data-customers = lt_customers[].
Pass the data and update to table:
cmd_ei_api=>initialize( ).
LOOP AT lt_customers INTO ls_customer.
cmd_ei_api=>lock( iv_kunnr = ls_customer-header-object_instance-kunnr ).
ENDLOOP.
" Update Customer with CMD_EI_API
CALL METHOD cmd_ei_api=>maintain_bapi
EXPORTING
iv_test_run = space
is_master_data = ls_master_data
IMPORTING
es_message_defective = ls_message_defective.
IF ls_message_defective IS INITIAL.
BREAK-POINT.
COMMIT WORK.
ELSE.
BREAK-POINT.
ENDIF.
LOOP AT lt_customers INTO ls_customer.
cmd_ei_api=>unlock( iv_kunnr = ls_customer-header-object_instance-kunnr ) .
ENDLOOP.
When I debug, I can see that the entry that is being fetched for update is the old entry that is present in the current memory.
Please let me know if i am doing something wrong while passing the value to the table.
You need including DATAX with X for all fields that you need change.
DATA: ls_datax TYPE cmds_ei_vmd_central_data_xflag.
ls_datax-icmstaxpay = 'X'.
MOVE ls_datax TO ls_customer-central_data-central-datax.
And thanx for your question, helped me with find this methody :)

Creating a range for a field from internal table using RTTS

I want to create a function/custom class method that takes in 2 parameters:
1) IM_ITAB type ANY TABLE
2) IM_COMPONENT type STRING
and returns 1 parameter:
1) EX_RANGE type PIQ_SELOPT_T
So, algorithm is like this:
First of all, we check if the column with a component name at all exists
Then, we check that internal table is not empty.
Then, we loop through internal table assigning component and filling range table. Code is below.
METHODS compose_range_from_itab
IMPORTING
IM_ITAB type ANY TABLE
IM_COMPONENT type STRING
EXPORTING
EX_RANGE type PIQ_SELOPT_T.
...
METHOD compose_range_from_itab.
DATA: lo_obj TYPE REF TO cl_abap_tabledescr,
wa_range TYPE selopt,
lt_range TYPE piq_selopt_t.
FIELD-SYMBOLS: <fs_line> TYPE ANY,
<fs_component> TYPE ANY.
lo_obj ?= cl_abap_typedescr=>describe_by_data( p_data = im_itab ).
READ TABLE lo_obj->key TRANSPORTING NO FIELDS WITH KEY name = im_component.
IF sy-subrc IS INITIAL.
IF LINES( im_itab ) GT 0.
LOOP AT im_itab ASSIGNING <fs_line>.
ASSIGN COMPONENT im_component OF STRUCTURE <fs_line> TO <fs_component>.
wa_range-sign = 'I'.
wa_range-option = 'EQ'.
wa_range-low = <fs_component>.
APPEND wa_range TO lt_range.
ENDLOOP.
SORT lt_range BY low.
DELETE ADJACENT DUPLICATES FROM lt_range COMPARING low.
ex_range[] = lt_range[].
ENDIF.
ENDIF.
ENDMETHOD.
But I want to improve the method further. If the imported internal table has, let's say, 255 columns, then it will take longer to loop through such table. But I need only one column to compose the range.
So I want to get components of internal table, then choose only one component, create a new line type containing only that component, then create internal table with that line type and copy.
Here is the pseudo code corresponding to what I want to achieve:
append corresponding fields of im_itab into new_line_type_internal_table.
How can I "cut out" one component and create a new line type using RTTS?
You are overcomplicating everything, you don't need RTTS for that.
DEFINE make_range.
ex_range = VALUE #( BASE ex_range ( sign = 'I' option = 'EQ' low = &1 ) ).
END-OF-DEFINITION.
LOOP AT im_itab ASSIGNING FIELD-SYMBOL(<fs_line>).
ASSIGN COMPONENT im_component OF STRUCTURE <fs_line> TO FIELD-SYMBOL(<fs_field>).
CHECK sy-subrc = 0 AND <fs_field> IS NOT INITIAL.
make_range <fs_field>.
ENDLOOP.
And yes, as Sandra said, you won't gain any performance with RTTS, just the opposite.
Surprisingly, this variant turned out to be faster:
CLASS-METHODS make_range_variant_2
IMPORTING
sample TYPE table_type
column TYPE string
RETURNING
VALUE(result) TYPE range_type.
METHOD make_range_variant_2.
TYPES:
BEGIN OF narrow_structure_type,
content TYPE char32,
END OF narrow_structure_type.
TYPES narrow_table_type TYPE STANDARD TABLE OF narrow_structure_type WITH EMPTY KEY.
DATA narrow_table TYPE narrow_table_type.
DATA(mapping) =
VALUE cl_abap_corresponding=>mapping_table_value(
( kind = cl_abap_corresponding=>mapping_component srcname = column dstname = 'CONTENT' ) ).
DATA(mover) =
cl_abap_corresponding=>create_with_value(
source = sample
destination = narrow_table
mapping = mapping ).
mover->execute(
EXPORTING
source = sample
CHANGING
destination = narrow_table ).
LOOP AT narrow_table ASSIGNING FIELD-SYMBOL(<row>).
INSERT VALUE #(
sign = 'I'
option = 'EQ'
low = <row>-content )
INTO TABLE result.
ENDLOOP.
ENDMETHOD.
CL_ABAP_CORRESPONDING delegates to a kernel function for the structure-to-structure move, which apparently is faster than the ABAP-native ASSIGN COMPONENT [...] OF STRUCTURE [...] TO FIELD-SYMBOL [...]. The actual loop then seems to be faster because it uses fixed-name assignments.
Maybe somebody could verify.
I would not go for a Macro.
Data:
lr_data type ref to data.
FIELD-SYMBOLS:
<lv_component> TYPE any,
<ls_data> TYPE any.
CREATE DATA lr_data LIKE LINE OF im_itab.
ASSIGN lr_data->* TO <ls_data>.
"Check whether im_component exists
ASSIGN COMPONENT im_component OF STRUCTURE <ls_data> TO <lv_component>.
CHECK sy-subrc EQ 0.
LOOP AT im_itab INTO <ls_data>.
APPEND VALUE #( sign = 'I' option = 'EQ' low = <lv_component> ) TO ex_range.
ENDLOOP.

How to update Z fields with BAPI_OUTB_DELIVERY_CHANGE parameter EXTENSION2?

How to update Z fields with BAPI_OUTB_DELIVERY_CHANGE using EXTENSION2?
I tried to update some Z fields in LIKP table using the BAPI to update deliveries but after call it any changes wasn't made.
Any suggestions?
I found the BAdI - SMOD_V50B0001. I made an enhancement implementaction and in the method EXIT_SAPLV50I_010 (User Exit BAPI for Changes to Outbound Delivery) set the follow code.
METHOD if_ex_smod_v50b0001~exit_saplv50i_010.
CONSTANTS: lc_vbkok TYPE char5 VALUE 'VBKOK', "Enhance the structure for more z fields in LIKP
lc_vbpok TYPE char5 VALUE 'VBPOK', "Enhance the structure for more z fields in LIPS
lc_cs_vbkok TYPE char8 VALUE 'CS_VBKOK'.
DATA: lv_item TYPE posnr_vl.
FIELD-SYMBOLS: <lfs_fieldname> TYPE any.
LOOP AT extension2 INTO DATA(lw_extension2).
CASE lw_extension2-param.
"As a structure in row 0
WHEN lc_vbkok. "Fields for LIKP
ASSIGN (lc_cs_vbkok) TO FIELD-SYMBOL(<lfs_vbkok>).
IF <lfs_vbkok> IS ASSIGNED.
ASSIGN COMPONENT lw_extension2-field OF STRUCTURE <lfs_vbkok> TO <lfs_fieldname>.
IF <lfs_fieldname> IS ASSIGNED.
<lfs_fieldname> = lw_extension2-value.
ENDIF.
ENDIF.
"As a table from row 1 to n
WHEN lc_vbpok. "Fields for LIPS
MOVE lw_extension2-row TO lv_item.
READ TABLE ct_vbpok ASSIGNING FIELD-SYMBOL(<lfs_vbpok>) WITH KEY posnr_vl = lv_item.
IF sy-subrc = 0.
ASSIGN COMPONENT lw_extension2-field OF STRUCTURE <lfs_vbpok> TO <lfs_fieldname>.
IF <lfs_fieldname> IS ASSIGNED.
<lfs_fieldname> = lw_extension2-value.
ENDIF.
ENDIF.
ENDCASE.
ENDLOOP.
ENDMETHOD.
Enhace the structures VBKOK as well LIKP with appen structures to add new z fields and enhance the structure VBPOK as well LIPS for the same purpose.
Also take a look to the program LV50LF01 and would need to implement an additional enhancement point to keep the values.
After this a think that I got it.
METHOD m_update_delivery.
DATA: lw_header_data TYPE bapiobdlvhdrchg,
lw_header_control TYPE bapiobdlvhdrctrlchg,
lw_extension2 TYPE bapiext.
DATA: li_extension2 TYPE TABLE OF bapiext,
li_return TYPE TABLE OF bapiret2.
DATA: lv_delivery TYPE bapiobdlvhdrchg-deliv_numb.
lw_header_data-deliv_numb = p_w_output-delivery.
lw_header_control-deliv_numb = p_w_output-delivery.
lv_delivery = p_w_output-delivery.
lw_extension2-param = 'VBKOK'.
lw_extension2-field = 'ZZEXIDV'.
lw_extension2-value = p_w_output-value.
APPEND lw_extension2 TO li_extension2.
" Call BAPI to update delivery
CALL FUNCTION 'BAPI_OUTB_DELIVERY_CHANGE'
EXPORTING
header_data = lw_header_data
header_control = lw_header_control
delivery = lv_delivery
TABLES
extension2 = li_extension2
return = li_return.
READ TABLE li_return INTO DATA(lw_return)
WITH KEY type = c_e.
IF sy-subrc <> 0.
COMMIT WORK AND WAIT.
ENDIF.
ENDMETHOD.
You need to add BAPI_COMMIT after your BAPI function module.

Create dynamic ABAP internal table

On selection screen, the user needs to insert a table name, and I need to get first 3 fields from that table and display them in an ALV for the output. What I understand from reading tutorials is that I need to call method cl_alv_table_create=>create_dynamic_table, but I don't know how to create the fieldcatalog.
DATA: t_newtable TYPE REF TO data,
t_fldcat TYPE lvc_t_fcat,
CALL METHOD cl_alv_table_create=>create_dynamic_table
EXPORTING
it_fieldcatalog = t_fldcat
IMPORTING
ep_table = t_newtable.
I assume that the table name which user enters is a data dictionary table (like SFLIGHT). If yes, then you can generate the field catalog as follows.
data : it_tabdescr type abap_compdescr_tab,
wa_tabdescr type abap_compdescr.
data : ref_table_descr type ref to cl_abap_structdescr.
ref_table_descr ?= cl_abap_typedescr=>describe_by_name( p_table ).
it_tabdescr[] = ref_table_descr->components[].
loop at it_tabdescr into wa_tabdescr.
clear wa_fieldcat.
wa_fieldcat-fieldname = wa_tabdescr-name .
wa_fieldcat-datatype = wa_tabdescr-type_kind.
wa_fieldcat-inttype = wa_tabdescr-type_kind.
wa_fieldcat-intlen = wa_tabdescr-length.
wa_fieldcat-decimals = wa_tabdescr-decimals.
append wa_fieldcat to it_fieldcat.
endloop.
Here, "p_table" is the selection screen parameter containing the table
name.

Why INSERT into internal table fails?

I have a Problem with ABAP. I have the following code from a book:
METHOD make_reservation.
DATA: license_plate TYPE zcars-license_plate,
reservation_wa LIKE LINE OF reservation_tab,
reservation_num TYPE i,
mess TYPE string.
reservation_num = lines( reservation_tab ).
SELECT license_plate FROM zcars INTO (license_plate) WHERE category = category.
LOOP AT reservation_tab
TRANSPORTING NO FIELDS
WHERE license_plate = license_plate
AND NOT ( date_from > date_to OR date_to < date_from ).
ENDLOOP.
IF sy-subrc <> 0.
reservation_wa-reservation_id = reservation_num + 1.
reservation_wa-customer_id = customer.
reservation_wa-license_plate = license_plate.
reservation_wa-date_from = date_from.
reservation_wa-date_to = date_to.
INSERT reservation_wa INTO TABLE reservation_tab.
IF sy-subrc <> 0.
CONCATENATE license_plate ' reserved!' INTO mess.
MESSAGE mess TYPE 'I'.
ELSE.
MESSAGE 'internal error!' TYPE 'I' DISPLAY LIKE 'E'.
LEAVE PROGRAM.
ENDIF.
RETURN.
ENDIF.
ENDSELECT.
RAISE EXCEPTION TYPE zcx_no_car_available.
ENDMETHOD.
the problem is the line INSERT reservation_wa INTO TABLE reservation_tab. which does not run correctly and I always get sy-subrc <> 0. This results to the message "internal error!"
now my question: I tired to debug it, but I cant find the reason why this statement does not insert the data. How can I find out a detailed error message what went wrong with this SQL statement?
This snipplet tests for not equal 0:
INSERT reservation_wa INTO TABLE reservation_tab.
IF sy-subrc <> 0.
CONCATENATE license_plate ' reserved!' INTO mess.
MESSAGE mess TYPE 'I'.
ELSE.
MESSAGE 'internal error!' TYPE 'I' DISPLAY LIKE 'E'.
LEAVE PROGRAM.
ENDIF.
I always prefer to test for equality (that's easier to read). The similar coding for your code:
INSERT reservation_wa INTO TABLE reservation_tab.
IF sy-subrc = 0.
MESSAGE 'internal error!' TYPE 'I' DISPLAY LIKE 'E'.
LEAVE PROGRAM.
ELSE.
CONCATENATE license_plate ' reserved!' INTO mess.
MESSAGE mess TYPE 'I'.
ENDIF
In plain text: If the insert is successful (return code == 0), then report an error. If the insert is not successful, then inform about the correct reservation.
I don't know your exact requirement, but it seems you mix up the if/else branch in your code.
In ABAP, sy-subrc == 0 always means success. Your code seems to have a problem since the success is associated with any other value.
If you put a breakpoint in your code just before the insert, you'll be able to check that the insertion was a success.
You can check the possible return values of an instruction by putting the cursor on it and using the F1 key. this will launch the help/documentation.
Regards