Quantcast
Channel: SCN : All Content - BOPF Application Framework
Viewing all 309 articles
Browse latest View live

BOPF-SADL Mapping – Demystifying Limitations

$
0
0

The series E2E: BOPF-SADL-GW-SAPUI5describes how to create an SAP Gateway service based on the Business Object Processing Framework (BOPF) by leveraging the mapping features of the Service Adaptation Description Language (SADL). We are glad to receive feedback and questions about this technology.

 

With this article I explain the most important limitations of this approach. I will also explain where these limitations come from, so you may have a better idea of what you can expect (not) to work in general. I assume that you already had a look at the “Map to Data Source” feature of the SAP NetWeaver Gateway Service Builder as described in E2E: BOPF-SADL-GW-SAPUI5 - Mapping an Entity Set.

 

Interested in some “History”?

SADL started out with the ambition to remove all “heavy” framework overhead for read-only scenarios. By doing so, SADL is an ultra-fast query engine which makes it possible to access and interactively page through millions of records with very short round-trip times. For instance, SADL provides the run time engine behind ALV and FPM on SAP HANA.

SADL uses BOPF’s metadata information to bypass the BOPF runtime for read-only scenarios. This is only possible if there is a static mapping between the structures used by the BOPF service manager API and the underlying database.

Today, SADL is no longer limited to read-only use cases, but it also offers support for modifying operations. SADL does not try to directly update data on the database, but delegates any modifying request to BOPF. This ensures the consistency of business data.

Although SADL supports modifying operations by delegation, it is important to keep in mind that the full use of SADL is generally limited to scenarios where it is possible to establish a static mapping of business object data to the database.

 

Limitations

So, what are the prerequisites for SADL to be able to map BOPF data directly to the database?

 

BO Nodes

  • The node’s database table must be maintained. Transient nodes in particular cannot be mapped.

  • No custom data access class (DAC) must be used. The following DAC classes are allowed: /BOBF/CL_DAC_TABLE and /BOBF/CL_DAC_LEGACY_TABLE (if available in your system). (Note that, if no DAC is maintained at the BO node, BOPF takes it from the BO header.)
  • The node must have only one node category.
    Node categories cannot be maintained in BOBX or in the Eclipse-based BOPF editor. If you created your BO with one of these tools, you only have one node category and you should not even bother about this concept as we discourage its use. The reason for the limitation is that SADL only supports static metadata for entities (here: BO nodes). BOPF’s node categories allow to model, for example, different associations per node category. From SADL’s perspective, this would mean that an entity’s metadata changes per entity instance.

 

If you need to expose a BOPF node which cannot be mapped by SADL, you will have to manually implement this in your service’s data provider class (DPC).

 

Node Attributes

  • The attribute must exist on the database table. Attributes of the transient structure cannot be mapped.
  • In case your BO uses the DAC /BOBF/CL_DAC_LEGACY_TABLE, the standard BOPF key fields (KEY, PARENT_KEY, ROOT_KEY) are transient and cannot be mapped.
    In this case, you cannot expose BOPF’s key fields in your service, but you have to use the key fields of the underlying database table. In my experience, this is what most applications do, anyway.

 

If you need to expose transient attributes you have to leave them unmapped. In addition, you have to redefine the entity set-specific implementation in your DPC. You can, for example, first call super (SADL’s generic implementation) and afterwards fill the missing values for the transient attributes. Take care not to flag such attributes as “sortable” or “filterable” in the property definition of the entity type.

 

Associations

  • Compositions, TO_ROOT, and TO_PARENT can be used – provided that their target node can be mapped (see above).
  • Other associations can be used if an attribute binding has been maintained for them. There is no check for the existence of an implementation class, but SADL assumes that the binding information is complete. If your association has binding information but the association is implemented in a way which deviates from the binding logic, wrong results may be returned by the SADL runtime.

 

If you need to map an association which cannot be handled by SADL, you will have to manually implement this in your DPC.

 

Authority Checks

SADL translates all authority checks into the WHERE-condition of a generated SELECT statement. This is a necessary precondition for efficiently processing requests for arbitrary pages of a given result set. Therefore, it must be possible to derive a WHERE-condition from BOPF’s metadata. This means:

  • The authority class must be able to return a SADL query condition provider. This is true if your BO uses /BOBF/CL_LIB_AUTHCHECK_W_QUERY or a subclass thereof. This class imposes certain constraints on how authorization checks can be implemented.

 

Miscellaneous Caveats

While SADL is being heavily used within new SAP applications, there are still scenarios which have not received much attention, so far.

  • BOPF Dependent Objects have not been in focus, yet. Some scenarios may not work in all aspects with SADL. So if you use them, you should be aware that you are an early adopter in this area.
  • Since BOPF offers a lot of flexibility, it is not always feasible to programmatically detect all situations where metadata in the BOPF configuration model might be misleading with regard to the BO’s actual run-time behavior. In addition, BOPF supports add-ons and plugins which can change pretty much every aspect of BOPF’s original behavior. SADL does not check for such extensions as it would not be practical to disable SADL mapping as soon as an extension is detected.
  • If you use SADL’s feature of implicit view building as described in the example in E2E: BOPF-SADL-GW-SAPUI5 - Implicit View Building, you will not be able to update fields which have been joined from other BO nodes to the leading node. In the example, this is the case for the fields PRODUCTNAME and SUPPLIERNAME. If you need to update such a field, you will have to update it at its original entity.
  • SADL reads data by bypassing BOPF’s buffer. Keep this in mind if you use BOPF’s service manager API in your service implementation. If you re-use SADL’s generic implementation for reading data of an entity set after having made changes via BOPF, SADL might read outdated data.

 

BOPF vs. Stateless Services

There is a natural conflict between some BOPF BOs which have been optimized for traditional SAPGUI or WebDynpro applications on the one hand, and modern web-based applications using stateless services on the other hand. Some framework optimizations which have been introduced for traditional applications can turn into a bourdon for modern architectures.

 

In a stateless context, you would like to post only small updates with each service call. You might want to “activate” your object only after a series of modifications which would not make much sense each on their own. You would like to be able to save an incomplete version (“draft”) of your document and continue working on it later – knowing that the existence of your draft prevents the original document from being modified in the background.

 

On the other hand, a classic BOPF BO – if it has been developed with only session-based applications in mind – may refuse to save any business data as long as it is not in a “consistent state”. Inconsistencies are only temporarily allowed within the current ABAP session. For the time of the current session, BOPF locks instances against parallel changes.

 

A stateless service request is answered by an ABAP session. The next request creates a new session. Any locks acquired in the first session are lost as soon as it ends. In addition, some updates may fail because of save-preventing BOPF validations.

 

The cheap answer to this problem is: Only use a BOPF BO in a stateless service after you have verified that it is suitable for the scenarios you are targeting. Especially BOs with strict consistency checks or save-preventing validations are likely to cause issues.

However, at SAP we are working on a better solution to bridge the gap between classic applications and the world of stateless UIs. Stay tuned!


How to trigger lock action from odata gateway

$
0
0

Dear experts,

 

Now I have a lock action which is created by framework in BO.

BOBF action.PNG

I'd like to call method do_action() to trigger it from function import in odata gateway

do action.PNG

But I got an application error in the method do_action() of class /BOBF/CL_TRA_SERVICE_MGR.

dump.PNG

Based on my understanding for code, it only allows to trigger action with category object specific. But lock action is a kind of special action, so it can't be triggered by calling do_action()?

ac.png

Is anybody who can confirm that lock action can't be triggered like this and explain the reason? And anybody know how to trigger lock action in another way?

 

Thanks and Regards,

Emily

How to prevent the creation of a node?

$
0
0

Hi,

 

we try to connect a service which offers the possibility to prevent the manual creation of a node.

 

As a first try we used a determination which is called at creation and set et_failed_key by debugger but this did not work.

 

Better ideas?

 

Regards, Jürgen

BAPI calls in BOPF Actions how-to ?

$
0
0

Hello Experts,

could you pelase clarify, what is the proper way to call BAPIs from BO actions ? I'm doing a BAPI call in my action, which creates a document. After in AFTER_COMMIT determination when saving the transaction, I want to start a workflow, and add GOS attachments to the document created by the BAPI call, but this document not become persistent. What I know, that BOPF does the commit work automatically and the changes to BOPF data are done in an UPDATE task.

May I call BAPI_TRANSACTION_COMMIT in my BO action, or maybe use SET UPDATE TASK LOCAL statement before calling the BAPI? I do not want to "crash" the BOPF phase model with my own commits. The slave transaction manager is for the opposite case as far as I understood, where we do not want to allow the BOPF to commit, so does not apply. Any advice is welcome .

Thank you

Attila

Triggering a second transaction

$
0
0

Hi experts,

 

Is there a way to trigger a second save transaction from within a determination?  We are facing a situation where, when saving to a BOPF table, another standard table has to be maintained. 

 

In a normal situation we can control the two updates via the BOPF commit, but because of some unfortunate circumstances, the standard table has to be updated via an RFC call.  This means that the update of the standard table is already committed before the BOPF commit has succeeded, leaving room for inconsistencies between the two tables. The user should receive an error message if any of the two updates failed.

The current idea is to work with a status variable in the BOPF node:

- transaction 1 = BOPF update + commit; status = update pending;  for changed made by user

- transaction 2 = standard table update + commit; status = active; via determination after load, for all records where status = update pending.

 

I could trigger the second save via the transaction manager instance from the FPM application controller, but the BOPF model should also work from outside the FPM application.

 

I'm aware that this approach is not optimal.  Any other strategies to tackle this problem are welcome

 

Thanks in advance!

 

Kind regards,

Bjorn

BOPF Transaction Management

$
0
0

Hello experts,

 

is it possible to retrieve data from an bopf object, after save the transaction with pattern "save and exit"?

Bild 10.png

Using /BOBF/IF_TRA_SERVICE_MANAGER will dump because the transaction state is "finished".

 

Bild 20.png

 

But how can i clear the transaction or get a new one or rather read data from an bopf-object?

 

Changing the transaction pattern is not an option, because this is a standard implementation.

 

Thanks for your help!

 

Regards,

Thomas Deubel

Add customer action to the standard BOPF

$
0
0

Hello, experts!

Can I add my own action to stadart BOPF and execute it after standard action?

My task is to add new action into BOPF /SRMSMC/BO_SEV. That action will send the file to Sourcing after action "Complete" for evaluation of supplier. Action "Complete' is not ready for enhancement in that BOPF-object.

 

Please help me.

Additional driver person is created for preliminary data creation in offline form scenario

$
0
0

I have couple of offline forms for incident and near-miss recording, having sections to capture driver details for the vehicle involved cases. They are based on standard EHHSS_INCIDENT business object.

 

Problem arises when we have more than one driver persons with 'External' Person group (i.e. not an employee, so no Person Number). I create a row for involved person node with preliminary data updating person group and create person role, person initial, person statement node rows accordingly and updating driver details to respective vehicle asset node. The party key ID for such involved persons is auto-generated starting with an 'I' (like I00000631) instead of 'A' in case of an employee.

 

The row count of person involved node remains consistent with what I am intending to do till the end of persistent class STORE_DATA method where I am coding. However, after service manager SAVE() method at very end, I check in pre-exit of PERSON_GROUP determination and find that there are additional (duplicate) driver person created for 'External' Person group cases only and that too only for second such driver person onwards (not for first driver person). We have other sections on the form with other involved person roles like Reporting Person, Injured Person, Treatment Provider etc. but such discrepancy does not happen anywhere else.

 

This is a bit strange and I am yet to figure out where it is going wrong: my persistent class code or somewhere within service manager SAVE() method for any reason.

 

Please let me know if there is anything in BOPF that may drive this behavior. I am putting my code snippet below for better understanding:

 

    LOOP AT <ls_interf_str>-inv_pers-vehicle_drivers  REFERENCE INTO l_driver.    "Start of Driver Person Loop
      CLEAR: ls_driver_key_refs.
      zl_index = sy-tabix.
      lv_person_exist  = abap_false.
      lv_create_hr  = abap_false.
      lv_pers_no = l_driver->person_data-person_initial-person_number.
      lv_first_name = l_driver->person_data-person_initial-first_name.
      lv_last_name  = l_driver->person_data-person_initial-last_name.
      cl_ehhss_aif_inc_person_helper=>get_party_key_by_person_number(
        EXPORTING
          iv_person_number =  lv_pers_no "Personnel Number
          iv_first_name =  lv_first_name"First Name of Driver
          iv_last_name =  lv_last_name"Last Name of Driver
        IMPORTING
          ev_hr_per_exists = lv_person_exist"Driver Exist
          ev_party_key = ls_veh_dri_party_key"Combined Party ID
          ev_create_hr = lv_create_hr"HR data exist
      ).
      IF lv_person_exist = abap_true AND lv_create_hr = abap_true.
    "If an existing employee - this case works fine
    .
    .
    .
      ELSE.

*-----------------------------------------------------------------------------------------

* Invalid Personnel Number - unable to read the data by the proxy ( create person Initial)

*-----------------------------------------------------------------------------------------

* create  driver person - Combined Party ID is initial

     IF lv_driver_added EQ abap_false.
        lo_inv_pers = lo_root_node->get_subnode_by_key( if_ehhss_inc_c=>sc_association-root-person_involved ).
        lr_s_person_involved ?= lo_inv_pers->create_empty_row( ).
        lo_inv_pers->insert_and_focus( lr_s_person_involved ).
        lr_s_person_involved ?= lo_inv_pers->get_current_row( ).
        "Update Person Group
        IF l_driver->person_data-per_group IS NOT INITIAL.
              lr_s_person_involved->per_group = l_driver->person_data-per_group.
        ENDIF.
        CALL METHOD lo_inv_pers->update
          EXPORTING
                ir_s_update_row   = lr_s_person_involved
          RECEIVING
                rv_success          = lv_success.

* create  driver person initial

        lo_inv_pers_initial = lo_inv_pers->get_subnode_by_key( if_ehhss_inc_c=>sc_association-person_involved-person_initial ).
        lr_s_person_initial ?= lo_inv_pers_initial->create_empty_row( ) .

 

        IF   l_driver->person_data-person_initial-first_name IS NOT INITIAL
              OR l_driver->person_data-person_initial-last_name IS NOT INITIAL
              OR l_driver->person_data-person_initial-telephone_number IS NOT INITIAL
              OR l_driver->person_data-person_initial-email IS NOT INITIAL
              OR l_driver->person_data-person_initial-person_number IS NOT INITIAL.

 

 

          IF l_driver->person_data-person_initial-first_name IS  INITIAL
              OR l_driver->person_data-person_initial-last_name IS INITIAL.
            lv_otr = cl_wd_utilities=>get_otr_text_by_alias( alias = 'EHHSS_UI_INC_COMMON/UNKNOWN_PERSON' language = <ls_interf_str>-meta_data-langu ).
            lr_s_person_initial->last_name    = lv_otr.
          ELSE.
            lr_s_person_initial->first_name = l_driver->person_data-person_initial-first_name.
            lr_s_person_initial->last_name = l_driver->person_data-person_initial-last_name.

 

 

          ENDIF.

 

          lr_s_person_initial->telephone_number = l_driver->person_data-person_initial-telephone_number.
          lr_s_person_initial->email = l_driver->person_data-person_initial-email.

 

          lo_inv_pers_initial->insert( lr_s_person_initial ).

 

          "Statement
          IF l_driver->person_data-statem_of_pers-text IS NOT INITIAL AND l_driver->person_data-statem_of_pers-text NE space.
            lo_driver_stmt = lo_inv_pers->get_subnode_by_key( if_ehhss_inc_c=>sc_association-person_involved-person_statem ).

 

            lr_s_driver_stmt ?= lo_driver_stmt->create_empty_row( ) .
            lr_s_driver_stmt->text = l_driver->person_data-statem_of_pers-text.
            lr_s_driver_stmt->per_stat_date = <ls_interf_str>-basicinfo-start_date.

 

            IF <ls_interf_str>-basicinfo-start_time IS NOT INITIAL.
              CLEAR lv_ehfnd_time.
              CALL FUNCTION 'CONVERSION_EXIT_THHMM_INPUT'
                EXPORTING
                  input = <ls_interf_str>-basicinfo-start_time  
                IMPORTING
                  output   = lv_ehfnd_time
                EXCEPTIONS
                  time_invalid = 1
                  OTHERS    = 2.
              IF sy-subrc EQ 0.
                lr_s_driver_stmt->per_stat_time = lv_ehfnd_time.
              ENDIF.
            ENDIF.
            lo_driver_stmt->insert( lr_s_driver_stmt ).
          ENDIF.

* Create driver person role

          lo_veh_inv_pers_role = lo_inv_pers->get_subnode_by_key( if_ehhss_inc_c=>sc_association-person_involved-person_role ).

 

          lr_s_veh_driver_role ?= lo_veh_inv_pers_role->create_empty_row( ).
          lr_s_veh_driver_role->role = if_ehhss_inc_impl_c=>sc_person_role-vehicle_driver.
          lr_s_veh_driver_role->key_ref = lr_s_veh_driver_role->parent_key.
          lo_veh_inv_pers_role->insert( lr_s_veh_driver_role ).
          APPEND ls_veh_dri_party_key TO lt_veh_party_keys.

 

          "To update Driver under vehicle
          ls_driver_key_refs-driver_ref_key = lr_s_veh_driver_role->parent_key.
          ls_driver_key_refs-create_hr  = lv_create_hr.
          ls_driver_key_refs-exist_hr   = lv_person_exist.
          APPEND ls_driver_key_refs TO lt_driver_key_refs.
        ELSE.
          lo_inv_pers->delete( ).
        ENDIF.
        ENDIF.
      ENDIF.
      CLEAR:  lr_s_person_involved, lr_s_veh_driver_role, lr_s_driver_stmt, ls_driver_key_refs,
      lr_s_person_initial, ls_party_roles, ls_driver_key_refs, ls_veh_dri_party_key.
    ENDLOOP.   "End of Driver Person Loop

****-------------------------------------------------------------------------------------------------------

 

    LOOP AT lt_vehicle REFERENCE INTO l_vehicle.   "Start of Vehicle Loop
      zl_pass_index = sy-tabix.
    .
    .
    .
      READ TABLE lt_driver_key_refs INTO ls_driver_key_refs INDEX zl_pass_index.   
      IF sy-subrc EQ 0.   "Driver Added
        READ TABLE lt_veh_party_keys INTO ls_veh_dri_party_key INDEX zl_pass_index.
        IF sy-subrc EQ 0.   "Driver Added with Person Number - Employee
          IF ls_driver_key_refs-create_hr EQ abap_true AND ls_driver_key_refs-exist_hr EQ abap_true.
            lr_s_vehicle->driver_id  = ls_veh_dri_party_key-id_combined.
          ELSE.
            READ TABLE <ls_interf_str>-inv_pers-vehicle_drivers  REFERENCE INTO l_driver INDEX zl_pass_index.
            IF sy-subrc EQ 0.
              IF ls_veh_dri_party_key-id_combined IS NOT INITIAL.
                lr_s_vehicle->driver_id     = ls_veh_dri_party_key-id_combined.
              ELSE.   "Driver Added as External Person
                CLEAR: lr_s_person_involved, lr_s_veh_driver_role, lv_role_found.
                lo_inv_pers = lo_root_node->get_subnode_by_key( if_ehhss_inc_c=>sc_association-root-person_involved ).
                zl_count = lo_inv_pers->count( ).
                WHILE lo_inv_pers->has_more_rows( ) = abap_true.   "Get auto ID from Involved Person Node
                  lr_s_person_involved ?= lo_inv_pers->get_next_row( ).
                  IF lr_s_person_involved->key eq ls_driver_key_refs-driver_ref_key.
                    lr_s_vehicle->driver_id   = lr_s_person_involved->id.
                    EXIT.
                  ENDIF.
                ENDWHILE.
              ENDIF.
              lr_s_vehicle->driver_fi_name= l_driver->person_data-person_initial-first_name.
              lr_s_vehicle->driver_last_name  = l_driver->person_data-person_initial-last_name.
              CONCATENATE   l_driver->person_data-person_initial-first_name
                            l_driver->person_data-person_initial-last_name
                     INTO   zl_driver_name
              SEPARATED BY  space.
              lr_s_vehicle->driver_name   =  zl_driver_name.
              lr_s_vehicle->driver_email  = l_driver->person_data-person_initial-email.
              lr_s_vehicle->driver_tel_num= l_driver->person_data-person_initial-telephone_number.
            ENDIF.
          ENDIF.
          lv_driver_id  = ls_veh_dri_party_key-id_combined.
        ENDIF.
      ENDIF.

      .

   .   
      lo_inv_veh->insert_and_focus( lr_s_vehicle ).

      .

      .

      CLEAR:  lr_s_person_involved, lr_s_person_details, lr_s_veh_driver_role,
              ls_r_pers_role_rev_key, lv_role_found, lr_s_person_initial.
      lo_inv_pers = lo_root_node->get_subnode_by_key( if_ehhss_inc_c=>sc_association-root-person_involved ).
      zl_count = lo_inv_pers->count( ).

      "Setting Vehicle key into Driver Role node's key_ref field and Involved Person key as parent key for

      "person_role_rev_for_key node under vehicle

      WHILE lo_inv_pers->has_more_rows( ) = abap_true.
        lr_s_person_involved ?= lo_inv_pers->get_next_row( ).
        IF ( lr_s_person_involved->id eq lv_driver_id AND lv_driver_id IS NOT INITIAL ) or
           ( lr_s_person_involved->key eq ls_driver_key_refs-driver_ref_key ).
          lv_role_found = abap_true.
        ELSE.
          lo_inv_pers_details = lo_inv_pers->get_subnode_by_key( if_ehhss_inc_c=>sc_association-person_involved-person_detail ).
          zl_count = lo_inv_pers_details->count( ).
          WHILE lo_inv_pers_details->has_more_rows( ) = abap_true.
            lr_s_person_details ?= lo_inv_pers_details->get_next_row( ).
            IF lr_s_person_details->id eq lv_driver_id AND lv_driver_id IS NOT INITIAL AND lr_s_person_details->parent_key eq lr_s_person_involved->key.
              lv_role_found = abap_true.
              EXIT.
            ENDIF.
          ENDWHILE.
          IF lv_role_found ne abap_true.
            lo_inv_pers_initial = lo_inv_pers->get_subnode_by_key( if_ehhss_inc_c=>sc_association-person_involved-person_initial ).
            zl_count = lo_inv_pers_initial->count( ).
            WHILE lo_inv_pers_initial->has_more_rows( ) = abap_true.
              lr_s_person_initial ?= lo_inv_pers_initial->get_next_row( ).
              IF lr_s_person_initial->id eq lv_driver_id AND lv_driver_id IS NOT INITIAL AND lr_s_person_initial->parent_key eq lr_s_person_involved->key.
                lv_role_found = abap_true.
                EXIT.
              ENDIF.
            ENDWHILE.
          ENDIF.
        ENDIF.
        IF lv_role_found ne abap_true.
          CONTINUE.
        ENDIF.
        lo_veh_inv_pers_role = lo_inv_pers->get_subnode_by_key( if_ehhss_inc_c=>sc_association-person_involved-person_role ).
        zl_count = lo_veh_inv_pers_role->count( ).
        WHILE lo_veh_inv_pers_role->has_more_rows( ) = abap_true.
          lr_s_veh_driver_role ?= lo_veh_inv_pers_role->get_next_row( ).
          IF  lr_s_veh_driver_role->role EQ if_ehhss_inc_impl_c=>sc_person_role-vehicle_driver AND
              lr_s_veh_driver_role->parent_key EQ lr_s_person_involved->key .
                lr_s_veh_driver_role->key_ref = lr_s_vehicle->key.
                lo_veh_inv_pers_role->update( lr_s_veh_driver_role ).
          ENDIF.
        ENDWHILE.
        READ TABLE lt_driver_key_refs INTO ls_driver_key_refs INDEX zl_pass_index.  "zl_index.
        IF sy-subrc EQ 0.
          lo_pers_role_rev_key = lo_inv_veh->get_subnode_by_key( if_ehhss_inc_c=>sc_association-vehicle-person_role_rev_for_key ).
          ls_r_pers_role_rev_key ?= lo_pers_role_rev_key->create_empty_row( ).
          ls_r_pers_role_rev_key->key_ref = lr_s_vehicle->key.
          ls_r_pers_role_rev_key->role   = if_ehhss_inc_impl_c=>sc_person_role-vehicle_driver.
          ls_r_pers_role_rev_key->parent_key = lr_s_person_involved->key.
          lo_pers_role_rev_key->insert( ls_r_pers_role_rev_key ).
        ENDIF.
        CLEAR: lr_s_person_involved, lr_s_person_details, lr_s_veh_driver_role,
               ls_r_pers_role_rev_key, lv_role_found, lr_s_person_initial.
      ENDWHILE.
      CLEAR: lv_driver_id, lr_s_person_involved, lr_s_veh_driver_role, lv_role_found.
    ENDLOOP.   "End of Vehicle Loop

Attach File to BO Folder method fails to upload for certain plants in offline form scenario

$
0
0

Hi All,

 

I have couple of offline forms for incident and near-miss recording, based on standard EHHSS_INCIDENT business object.

 

I am calling  attach_file_to_bo_folder method of class to attach uploaded offline form file to BO node:

 

lo_attachment_node = lo_root_node->get_subnode_by_key( iv_assoc_key = if_ehhss_inc_c=>sc_association-root-att_document
                                                                                       iv_edit_mode = /bobf/if_conf_c=>sc_edit_exclusive ).

cl_ehhss_aif_inc_helper=>attach_file_to_bo_folder(
           EXPORTING
             io_attachment_node = lo_attachment_node
             iv_att_folder_id         = if_ehhss_inc_c=>sc_association-root-att_document_rev_for_key
             iv_key_ref                = lr_s_root->key
             iv_node_key_ref       = if_ehhss_inc_c=>sc_node-root
             is_form                   = is_form
             iv_filename              = iv_filename
             iv_file_content         = iv_filecontent
             io_service_manager = lo_service_manager
             iv_document_action = if_ehhss_inc_c=>sc_action-att_document-upload_document_in_bg
             iv_save_data           = iv_save_data
           IMPORTING
              ev_attach_rejected = lv_rejected
              ev_conf_key          = lv_attachment_reference  ).


However, the method cannot insert the attachment row into the lo_attachment_node node above and ends up raising cx_ehhss_aif_comn_exception for certain plants. It works for all others.


How come the method functionality be affected by form content? I can see that it uses file content when creating the file attributes structure for the attachment folder but the problem occurs even before when it tries to insert data into attachment node within this method.


Why it fails to work in certain cases whereas the values of parameters passed into this method are similar in all cases?


Please help.



Determinations: Logic of "Request Nodes" Configuration

$
0
0

One question concerning request nodes of a determination:

Our BO has (among others) a parent-child hierarchy Root - Item - Sub Iten. There is an item determnation with the following "Request Nodes" configuration:

 

     Item - Update

     Sub Item - Create, Update

 

There is a (root) action creating an item and a sub item instance ath the same time. With the given configuration the determination is not executed though "Sub Item - Create" is marked.

When I change the configuration to

 

     Item - Create, Update

     Sub Item - Create, Update

 

the determination is executed.

Waht is the logic behind this? I did not find detailed documentation explaining that.

 

Thank you for you input,

Klaus

How to create a web portal for users providing no direct access for users to the sap system

$
0
0

I have a requirement in order to create a web portal for the SAP TM which user can give the  input and the  details as output (with no direct sap access)

I am new to SAP TM system , How can we get the link between FU , Container , FW .Please share some SAP TM materials if any one can help me on this

$
0
0

I am new to SAP TM system , How can we get the link between FU , Container , FW .Please share some SAP TM materials  if any one can help me on this

No Offense Intended

$
0
0

Hello,

 

I am exploring this technology along with other SAP offerings and the question I have is this.

 

Why should I and my development staff spend the time and effort learning this technology? 

How to Batch Input Freight Order

$
0
0

Hi experts:

 

    I want to batch input created freight order using an excel file, is there any standard function or API to do this ?

    or, can I use BOPF Service Manager (DO_ACTION) method to do this ?

Text collection BOPF not supporting '

$
0
0

Hello All,

 

In Our BOPF application we have a message box where we can write the message and the message is stored by using the standard  BO /BOBF/TEXT_collection.

The issue is customer had kept some text with ' < ' symbol , for which BOPF understood that it as a SAP script tag and as it is not supported tag it is going for the dump .Please see the below images.

 

IMage1.png

IMage2.png

Difficult part is before Saving in the database table it should dump Because currently when I tried to replicate the issue I am getting a dump before saving in the database ,But don't know how it is saved for the customer .

 

So now my issue is I need to delete this text from the standard table /BOBF/D_TXCCON. Is any standard Report or archiving program available .

 

Regards,

Partha


How to unlock object in BOBF?

$
0
0

Hello experts!

1) I have a question. When I call retrieve with parameter iv_edit_mode = /bobf/if_conf_c=>sc_edit_exclusive    it's mean, that i lock this data. After that I make some changes.

When will object unlocked? After commit?

 

 

2) Also I have found code like this:

 

retrieve

    iv_edit_mode = /bobf/if_conf_c=>sc_edit_exclusive

 

modify

 

retrieve

   iv_edit_mode = /bobf/if_conf_c=>sc_edit_read_only

 

And comment for last call is: "unlock data". Is it meat, when we call retrieve with iv_edit_mode = /bobf/if_conf_c=>sc_edit_read_only , that object will be unlocked?

Change the Risk Tab in Risk Assessment module editable .

$
0
0

Working on Risk Assessment module of SAP .Its uses FPM and BOPF technologies.I need to enable all the fields on the attach screen as editable after clicking on the risk tab.Kindly if some can help me in suggesting any solution to achieve this.

BOPF Customize Issue (TM Freight Order Side)

$
0
0

Hi experts:

 

    I want to add a customize tab-strip in FO side:

  

    step1: Customize business object  /SCMTMS/TOR and add a customized NODE using  TCODE: /BOBF/CUST_UI.

 

    step2:. In customized UI mode, create customizing configuration and add a UIBB: FPM_FORM_UIBB_GL2  using my own configuration.

               feeder class and FBI view:

               3.png4.png      

    step3. Add my own element in the FORM page, and set them as input field:

   1.png

    My problem is: in NWBC, when I test and see my customize tab-strip ready, but the fields can not be inputted, why ?

    2.png

Run-Time-Error when save customize table strip data in freight order

$
0
0

Hi BOPF Expert,

 

   I add a customize table strip in freight order side, and it's base on a customize node in BOBX creation.

   in this table strip customize area, after i entry input fields and click SAVE button, a run-time-error occurs.

 

   QQ截图20160813171711.png

 

   check ST22 see:

 

   QQ1截图20160813172314.png

    check abap program side:     

     QQ截图201eeeeee60813172708.png

      please advice, many thank.

Integration of BOPF Business Objects and Existing Applications (Part 2/2)

$
0
0

In the first part of this article a sequence diagram has been discussed showing the interaction between an existing legacy application and BOPF business objects during the save phase of a common transaction. In addition to this, an implementation example of the legacy application's save sequence is now provided.

 

Master Transaction Manager - Implementation Example

   " --- 1. execute some application specific logic ---------------

   " ...

 

   " --- 2. add pre-commit logic for BOPF objects -----------------

   DATA(lo_message_container) = /bobf/cl_frw_factory=>get_message( ).

 

   " 2.1 set update task local

   " if this can't be set in your scenario, use COMMIT WORK AND WAIT later on to ensure,

   " that the changes done in the transaction are written to the database before the next session continues

   SET UPDATE TASK LOCAL.

 

   " 2.2 get slave transaction manager

   DATA(lo_slave_manager) = /bobf/cl_tra_trans_mgr_factory=>get_slave_transaction_manager( ).

 

   " 2.3 FINALIZE phase to prepare BOPF objects to be saved

   lo_slave_manager->finalize(

     IMPORTING

       eo_message          = DATA(lo_finalize_message)

       et_rejecting_bo_key = DATA(et_rejecting_bo_key)

       ev_rejected         = DATA(ev_rejected) ).

   lo_message_container->add( lo_finalize_message ).

 

   " 2.3.1 AFTER_FAILED_SAVE phase in case that a BO rejects the save

   IF ev_rejected = abap_true.

     " allow BOPF objects to cleanup changes that happend while the failed finalization phase

     lo_slave_manager->after_failed_save(

       IMPORTING

         eo_message = DATA(lo_after_failed_message) ).

     lo_message_container->add( lo_after_failed_message ).

     " as at least one BOPF objects has reject the save, thus the save process must be canceled

     " return messages (depending on the legacy application)

     lo_message_container->get_messages( IMPORTING et_message = DATA(lt_message) ).

     RETURN.

   ENDIF.

 

   " 2.4 CHECK_BEFORE_SAVE to check the BOPF BOs if they can be saved at all

   lo_slave_manager->check_before_save(

     IMPORTING

       eo_message          = DATA(lo_before_save_message)

       et_rejecting_bo_key = et_rejecting_bo_key

       ev_rejected         = ev_rejected ).

   lo_message_container->add( lo_before_save_message ).

 

   " 2.4.1 AFTER_FAILED_SAVE:  phase in case that a BO rejects the save

   IF ev_rejected = abap_true.

     " allow BOPF objects to make things undone that happend due to finalization

     lo_slave_manager->after_failed_save(

       IMPORTING

         eo_message = lo_after_failed_message ).

     lo_message_container->add( lo_after_failed_message ).

     " as at least one BOPF objects has reject the save, the save process must be canceled

     " return messages (depending on the legacy application)

     lo_message_container->get_messages( IMPORTING et_message = lt_message ).

     RETURN.

   ENDIF.

 

   " 2.5 ADJUST_NUMBERS: Invoke BOPF BOs that use late numbering

   lo_slave_manager->adjust_numbers(

       IMPORTING

         eo_change  = DATA(lo_adjust_num_change)

         eo_message = DATA(lo_adjust_num_message) ).

   lo_message_container->add( lo_adjust_num_message ).

 

   " 2.6 ON_NUMBERS_ADJUSTED: Invoke BOPF BOs that spread the numbers to other locations within the BO

   lo_slave_manager->on_numbers_adjusted(

       EXPORTING

         io_change  = lo_adjust_num_change

       IMPORTING

         eo_message = DATA(lo_adjusted_num_message) ).

   lo_message_container->add( lo_adjusted_num_message ).

 

   " 2.7 DO_SAVE

   lo_slave_manager->do_save(

     IMPORTING

       et_rejecting_bo_key = DATA(lv_rejecting_bo_key)

       eo_message          = DATA(lo_do_save_message)

       ev_rejected         = ev_rejected ).

   lo_message_container->add( lo_do_save_message ).

 

   IF ev_rejected = abap_true.

     " Save has been rejected - rollback the transaction and raise a dump

     ROLLBACK WORK.

     " return messages (depending on the legacy application)

     lo_message_container->get_messages( IMPORTING et_message = lt_message ).

     RETURN.

   ENDIF.

 

   " --- 3. commit work ----------------------------------------------

   " register dummy update task to ensure that all BOPF locks are released

   CALL FUNCTION '/BOBF/TRA_DUMMY_UPDATE_TASK' IN UPDATE TASK.

   COMMIT WORK.

 

   " --- 4. add post-commit logic for BOPF objects ----------------

 

   " 4.1 AFTER_SUCCESSFUL_SAVE

   lo_slave_manager->after_successful_save(

      IMPORTING

        eo_message = DATA(lo_after_save_message) ).

   lo_message_container->add( lo_after_save_message ).

 

   " --- 5. execute some application specific logic

   " ...

 

   " --- 6. return messages

   " return messages (depending on the legacy application)

   lo_message_container->get_messages( IMPORTING et_message = lt_message ).

   RETURN.

Viewing all 309 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>