Application Development and Automation Discussions
Join the discussions or start your own on all things application development, including tools and APIs, programming models, and keeping your skills sharp.
cancel
Showing results for 
Search instead for 
Did you mean: 
Read only

Create functional location with classification (BAPI)

Former Member
0 Likes
4,808

Hello everyone,

I want to create functional locations with classification (TA: IL01) by using BAPI functionality. Therefor I found functions BAPI_FUNCLOC_CREATE and BAPI_OBJCL_CREATE which work fine individually, but not by using both of them.

First I have to say that we use a customer exit which forces the user in IL01 to type in classicfication in every functional location. In the application this works fine but how to do this with BAPI?

(1) When I first use BAPI_OBJCL_CREATE for assigning class to the object I got the problem/error message that the object (func.loc) is not created yet.

(2) When I first use BAPI_FUNCLOC_CREATE for creating the func.loc., I got the problem with my customer exit message that classification has to be entered.

So what to do? 🙂

Regards

Michael Boguth

1 ACCEPTED SOLUTION
Read only

freek_cavens2
Participant
0 Likes
2,863

Hi Michael,

You will probably have to change your user exit so that it knows that the functional location is being created by the BAPI.  What I would do :

loop over functional locations to create.

  export variable to memory id for each functional location

  call bapi to create functional location.

  import variable from memory id in user exit.  If the value exists, skip check. The class assignment will be done later.

  free memory id.

  commit (so the functional location exists)

  call bapi to create class assignment.

  commit.

endloop.

Memory ID's are quite handy for this type of distinctions. SAP uses them in standard processes to determine whether the transaction was called directly or by workflow (by calling a business object method, where the memory id is set before the call transaction).

The only risk you have by doing it this way, is that you create a functional location and the class BAPI fails.  Then you would have to manually correct the data. 

Regards,

Freek

8 REPLIES 8
Read only

freek_cavens2
Participant
0 Likes
2,864

Hi Michael,

You will probably have to change your user exit so that it knows that the functional location is being created by the BAPI.  What I would do :

loop over functional locations to create.

  export variable to memory id for each functional location

  call bapi to create functional location.

  import variable from memory id in user exit.  If the value exists, skip check. The class assignment will be done later.

  free memory id.

  commit (so the functional location exists)

  call bapi to create class assignment.

  commit.

endloop.

Memory ID's are quite handy for this type of distinctions. SAP uses them in standard processes to determine whether the transaction was called directly or by workflow (by calling a business object method, where the memory id is set before the call transaction).

The only risk you have by doing it this way, is that you create a functional location and the class BAPI fails.  Then you would have to manually correct the data. 

Regards,

Freek

Read only

0 Likes
2,863

Hey Freek,

thanks for your help. I have to say that I never worked with Memory IDs 🙂

What do you mean with "export variable to memory id for each functional location"? Which variable do I have to export. The func.loc. number? Can you give me the abap statement for this?

And the creation by BAPI should be done in a Z-Program. So what do I have to change in the user exit? How can I difference between application and BAPI? With sy-tcode?

Regards

Michael

Read only

0 Likes
2,863

Hi Michael,

A memory ID is used to pass data between different programs in flow, where normally the data would be out of scope.  But you can also use it for scenario's like this.

This is how it is done :

In your Z-program, for each functional location that you create export for example the functional location id to a memory id.  This does not need to be an id, it can even be a simple 'X'.  You just need to pass a value to know that you came from the Z-program/BAPI.


EXPORT FUNCLOC from your_variable TO MEMORY ID 'FUNCLOC'.

In the user exit, import the value again.  If you find something in the memory, this means the call came from your Z-program, so you can skip the check


IMPORT FUNCLOC TO  your_variable FROM MEMORY ID 'FUNCLOC'.

if not your_variable is initial.

  skip check.

endif.

After processing the first BAPI, free the memory id again.


FREE MEMORY ID 'FUNCLOC'.

Further information on the syntax can be found in the SAP help.  It's rather easy to understand and use.

Regards,

Freek

Read only

0 Likes
2,863

Thanks Freek that worked fine 🙂 Nice hint!

But now I got another problem. I also want to insert some address data for the funcional location.

Therefor I found function 'ADDR_INSERT'.

CALL FUNCTION 'ADDR_INSERT'
     EXPORTING
       address_data     = gs_address_data
       address_group   = 'PM01'
       address_handle  = gd_address_handle
     IMPORTING
       address_data    = gs_address_data
       returncode        = gd_returncode
     TABLES
       error_table     = gt_error
     EXCEPTIONS
       address_exists  = 1
       parameter_error = 2
       internal_error     = 3
       OTHERS          = 4.

Unfortunately this function is not that easy to understand. I found out that address_group for functional location is always 'PM01'. I also inserted the address fields in gs_address_data. The adress handle looks like something temporary but I do not know how it has to be filled correctly? And even If I fill it correct, where do I get the address number then?

I found function ADDR_NUMBER_GET as well, but this is even more complicated than the other function.

So my question, isn't there any easier way to insert a news address to a functional location, and if not how do I have to do this with the named functions?

Regards

Michael

Read only

0 Likes
2,863

Hi Michael,

This is a method that will do this for you.  Your address group will be 'PM01' I suppose (you can check table TSAD7).  For the address reference, check table TSADRV to find the correct table for your object. 

The data types of the parameters are :

data: lv_address_group type ad_group.
     data: lv_address_reference type addr_ref.
     data: lv_address_data type addr1_data.
     data: lv_address_number type ad_addrnum.

You call it like this (you'll have to choose your own class name, off course) :


CALL METHOD zcl_central_address_handler=>CREATE_ADDRESSNR
       EXPORTING
*       address_handle    = lv_address_handle
         address_group     = lv_address_group
         address_reference = lv_address_reference
       IMPORTING
         address_number    = lv_address_number
       CHANGING
         address_data      = lv_address_data.

the exception zcx_central_address_handler will also be unknown in your system.  You can replace it by cx_root or create your own.


**********************************************************************************************
* This method creates an address type 1 in central address management.
* Importing parameters: address_group: valid address group (table TSAD7)
*                       address_reference: valid address reference (table TSADRV)
*                       address_data: data about the address to be created
* Exporting parameter: address_number
************************************************************************************************
     data: address_handle type ad_handle.

     data: errors type standard table of addr_error.

*    * Return-code
     data: rc_insert type ad_retcode.

     data: rc_number_get type NRRETURN.
     data: rc_memory_save type SYSUBRC.

* Specify an address handler.
* The handler is used to refer to the address in local memory (function group SZA0S)
   address_handle = 'ADDRESS_HANDLE'.

* Store the address in the local memory. (cfr function group SZA0S)
     call function  'ADDR_INSERT'
          exporting  address_data    = address_data
                      address_group   = address_group
                      address_handle  = address_handle
          importing  address_data    = address_data
                      returncode      = rc_insert
          tables     error_table     = errors
          exceptions address_exists  = 1
                      parameter_error = 2
                      internal_error  = 3
                      others          = 4.
     if sy-subrc <> 0 or rc_insert = 'E'.
       raise exception type zcx_central_address_handler.
     endif.

* Generate an address number for the address
     call function  'ADDR_NUMBER_GET'
          exporting  address_handle           = address_handle
                       address_reference        = address_reference
          importing  address_number           = address_number
                       returncode_numberrange   = rc_number_get
          exceptions address_handle_not_exist = 1
                       internal_error           = 2
                      parameter_error          = 3.
     if sy-subrc <> 0 or rc_number_get = 'E'.
       raise exception type zcx_central_address_handler.
     endif.


* Store the address from the local memory into the database
     call function  'ADDR_MEMORY_SAVE'
          exceptions address_number_missing  = 1
                      person_number_missing   = 2
                      internal_error          = 3
                      database_error          = 4
                      reference_missing       = 5.
     if sy-subrc <> 0.
       raise exception type zcx_central_address_handler.
     endif.

* Clear the local memory
     call function 'ADDR_MEMORY_CLEAR'
          exceptions unsaved_data_exist = 1
                       internal_error     = 2.
     if sy-subrc <> 0.
       raise exception type zcx_central_address_handler.
     endif.


endmethod.

Regards,

Freek

Read only

0 Likes
2,863

Thanks again Freek, that helped me. I'm now getting an address inserted in ADRC, but I do not get to link it with the functional location.

I work like this now.

(1) Creating Functional location by inherit from superior functional location

(2) Creating Classification

(3) Creating Address

(4) Changing Functional location

As far as I can see it, it is not possible to enter cost center and address when using the "inheriting function" by creating functional location? Or is there any hint? So I first create them with some basis data and after that update them. This works fine for costcenter but not with address.

I made the address creating like this:

FORM create_address  CHANGING cd_address_number LIKE gd_address_number.

   DATA: ls_address_data      LIKE addr1_data,
         ls_address_reference LIKE  addr_ref,
         ld_address_handle    LIKE szad_field-handle,
         ld_rc_insert         LIKE szad_field-returncode,
         ls_error             LIKE addr_error,
         lt_error             LIKE TABLE OF ls_error,
         ld_rc_get            LIKE inri-returncode.


* Adress-Handle füllen
   MOVE 'ADDRESS_HANDLE'    TO ld_address_handle.

* Adress-Referenz füllen
   MOVE 'IFLOT'             TO ls_address_reference-appl_table.
   MOVE 'TPLNR'             TO ls_address_reference-appl_field.
   MOVE 'PM01'              TO ls_address_reference-addr_group.
   CONCATENATE '800' gd_funcloc
     INTO ls_address_reference-appl_key.

* Adressdaten füllen
   MOVE gs_data-name1       TO ls_address_data-name1.
   MOVE gs_data-street      TO ls_address_data-street.
   MOVE gs_data-post_code1  TO ls_address_data-post_code1.
   MOVE gs_data-city1       TO ls_address_data-city1.
   MOVE gs_data-country     TO ls_address_data-country.


* Adresse erzeugen
   CALL FUNCTION 'ADDR_INSERT'
     EXPORTING
       address_data    = ls_address_data
       address_group   = 'PM01'
       address_handle  = ld_address_handle
     IMPORTING
       address_data    = ls_address_data
       returncode      = ld_rc_insert
     TABLES
       error_table     = lt_error
     EXCEPTIONS
       address_exists  = 1
       parameter_error = 2
       internal_error  = 3
       OTHERS          = 4.

* Adressnummer holen
   CALL FUNCTION 'ADDR_NUMBER_GET'
     EXPORTING
       address_handle           = ld_address_handle
       address_reference        = ls_address_reference
     IMPORTING
       address_number           = cd_address_number
       returncode_numberrange   = ld_rc_get
     EXCEPTIONS
       address_handle_not_exist = 1
       internal_error           = 2
       parameter_error          = 3
       OTHERS                   = 4.

* Adresse sichern
   CALL FUNCTION 'ADDR_MEMORY_SAVE'
     EXCEPTIONS
       address_number_missing = 1
       person_number_missing  = 2
       internal_error         = 3
       database_error         = 4
       reference_missing      = 5
       OTHERS                 = 6.

* Adressspeicher leeren
   CALL FUNCTION 'ADDR_MEMORY_CLEAR'
     EXCEPTIONS
       unsaved_data_exist = 1
       internal_error     = 2
       OTHERS             = 3.


ENDFORM.                    "create_address

and changing functional location like this:

FORM change_tp USING    ud_funcloc        LIKE gd_funcloc
                         ud_address_number LIKE gd_address_number.

   DATA: ls_itob        TYPE bapi_itob,
         ls_itob_fl     TYPE bapi_itob_fl_only,
         ls_itobx       TYPE bapi_itobx,
         ls_itob_flx    TYPE bapi_itob_fl_onlyx,
         ls_return      TYPE bapiret2,
         ls_cust_return TYPE bapiret2,
         ld_funcloc_int TYPE bapi_itob_parms-funcloc_int.


   MOVE gd_funcloc         TO ld_funcloc_int.
* Kostenstelle
   MOVE gs_data-costcenter TO ls_itob-costcenter.
   MOVE 'X'                TO ls_itobx-costcenter.
* Adressnummer füllen
   MOVE ud_address_number  TO ls_itob-read_adrnr.
   MOVE 'X'                TO ls_itobx-read_adrnr.



* Technischen Platz ändern
   CALL FUNCTION 'BAPI_FUNCLOC_CHANGE'
     EXPORTING
       functlocation     = ld_funcloc_int
       data_general      = ls_itob
       data_generalx     = ls_itobx
       data_specific     = ls_itob_fl
       data_specificx    = ls_itob_flx
     IMPORTING
       data_general_exp  = ls_itob
       data_specific_exp = ls_itob_fl
       return            = ls_return.


   IF ls_return IS INITIAL.
     CLEAR ls_cust_return.
     ls_cust_return-type        = 'I'.
     ls_cust_return-id          = 'ZPM'.
     ls_cust_return-number      = '022'.
     ls_cust_return-message_v1  = ud_funcloc.
     PERFORM fill_msglist USING ls_cust_return.

   ELSE.
*   Message-Liste aufbereiten
     PERFORM fill_msglist  USING ls_return.
   ENDIF.


   CLEAR ls_return.
* Commit Work
   CALL FUNCTION 'BAPI_TRANSACTION_COMMIT'
     EXPORTING
       wait   = abap_true
     IMPORTING
       return = ls_return.

* Message-Liste aufbereiten
   PERFORM fill_msglist  USING ls_return.


ENDFORM.                    "change_tp

So can you tell me where is the error?

Regards

Michael

Read only

Former Member
0 Likes
2,863

Hello again,

ok I now found out the reason for that looking at OSS note 333988.

These interface parameters are always identical for the same object, irrespective of whether writing or reading BAPIS are involved. However, since certain attributes can be read but not set, the interface for writing BAPIs contains some attributes that are not processed, even though they are provided by the person calling up the function.

In order to make these attributes clear to the person calling up the function, they have been assigned the prefix READ:

  • General attributes that are read-only:

           DATA_GENERAL-READ_CRDAT : Date created

           DATA_GENERAL-READ_CRNAM : Created by

           DATA_GENERAL-READ_CHDAT : Date changed

           DATA_GENERAL-READ_CHNAM : Changed by

          DATA_GENERAL-READ_ADRNR : Key number of address

So this does not work. I'm now getting some work-around by filling the address with batch input record. It works fine, but I do not prefer a mix of bapi and batch input. So does anyone got an other idea how to fill address in functional location?

Regards

Michael

Read only

0 Likes
2,863

Hi Michael,

I haven't found a suitable function that does this.  Only people with the same problem as you.  you could try to update the ILOA-ADRNR field directly, though changing SAP tables is not recommended.  You could try it with one though.  If it works and does not cause inconsistencies, you might be lucky.

Regards,

Freek