cancel
Showing results for 
Search instead for 
Did you mean: 

Managed RAP application to create PurchaseOrder

10-06-2026 9:50 AM
RITZZ Explorer
319 views 5 comments Go to solution
0 Likes
Subscribe

I have created one managed RAP application to create PurchaseRequisition and store it in a custom table along with messages. 

Now I want to extend this application to create PurchaseOrder also and store it along with Vendor details in that same Z table. But I am facing some issue. is it possible to create PO using managed application with Unamanaged Save.

I am also attaching my code for the PR creation scenario.

Behavior Def

managed implementation in class zbp_i_pr_request unique;
strict ( 2 );

define behavior for ZI_PR_REQUEST alias PRReq
//persistent table zpr_request
lock master
authorization master ( instance )
//with additional save
//etag master <field_name>
with unmanaged save
{
create ( authorization : global );
update;
delete;
field ( readonly, numbering : managed ) ReqUuid;
field ( readonly ) Purchaserequisition, Message, Messagetype;

determination createPRAuto on save { create; }

mapping for zpr_request
{
ReqUuid                    = req_uuid;
Purreqdescription          = purreqdescription;
Purchaserequsitiontype     = purchaserequsitiontype;
Purchaserequisitionitem    = purchaserequisitionitem;
Purchaserequsitionitemtext = purchaserequsitionitemtext;
Plant                      = plant;
Material                   = material;
Deliverydate               = deliverydate;
Requestedquantity          = requestedquantity;
Baseunitisocode            = baseunitisocode;
Purchasinggroup            = purchasinggroup;
Purchaserequisition        = purchaserequisition;
Message                    = message;
Messagetype                = messagetype;
}
}

Global Class

CLASS zbp_i_pr_request DEFINITION PUBLIC ABSTRACT FINAL FOR BEHAVIOR OF zi_pr_request.
public section.
TYPES: BEGIN OF ty_pr_details,
pid        TYPE abp_behv_pid,
cid        TYPE abp_behv_cid,
pur_req    TYPE zpr_request-purchaserequisition,
req_uuid TYPE zpr_request-req_uuid,
END OF ty_pr_details.
CLASS-DATA purchase_requisition_details TYPE TABLE OF ty_pr_details.
protected section.
private section.

ENDCLASS.

CLASS zbp_i_pr_request IMPLEMENTATION.
ENDCLASS.

CreatePr method

METHOD createPRAuto.
    READ ENTITIES OF zi_pr_request  IN LOCAL MODE
        ENTITY PRReq
            ALL FIELDS WITH CORRESPONDING #( keys )
        RESULT DATA(lt_resquest).

    LOOP AT lt_resquest ASSIGNING FIELD-SYMBOL(<fs_req>).
      IF <fs_req>-Purchaserequisition IS NOT INITIAL.
        CONTINUE.
      ENDIF.

      DATA(lv_cid_hdr)  = |PRHDR_{ sy-tabix }|.
      DATA(lv_cid_item) = |PRITM_{ sy-tabix }|.

      MODIFY ENTITIES OF i_purchaserequisitiontp
          ENTITY PurchaseRequisition
            CREATE
              FIELDS ( purchaserequisitiontype PurReqnDescription )
              WITH VALUE #(
                ( %cid                     = lv_cid_hdr
                  PurchaseRequisitionType  = <fs_req>-Purchaserequsitiontype
                  PurReqnDescription       = <fs_req>-Purreqdescription ) )

            CREATE BY \_purchaserequisitionitem
              FIELDS ( purchaserequisitionitem plant material
                        purchasinggroup requestedquantity baseunit
                        deliverydate PurchaseRequisitionItemText )
              WITH VALUE #(
                ( %cid_ref = lv_cid_hdr
                  %target  = VALUE #(
                    ( %cid                      = lv_cid_item
                      PurchaseRequisitionItem    = <fs_req>-PurchaseRequisitionItem
                      Plant                      = <fs_req>-Plant
                      Material                   = <fs_req>-Material
                      PurchasingGroup            = <fs_req>-PurchasingGroup
                      RequestedQuantity          = <fs_req>-RequestedQuantity
                      BaseUnit                   = <fs_req>-BaseUnitISOCode
                      DeliveryDate               = <fs_req>-DeliveryDate
                      PurchaseRequisitionItemText = <fs_req>-Purchaserequsitionitemtext ) ) ) )

          MAPPED   DATA(lt_mapped)
          FAILED   DATA(lt_failed)
          REPORTED DATA(lt_reported).

      IF lt_failed IS INITIAL.

        READ TABLE lt_mapped-purchaserequisition
        INDEX 1
        INTO DATA(ls_mapped_pr).

        IF sy-subrc = 0.

          APPEND VALUE #(
          pid = ls_mapped_pr-%pid
          cid = ls_mapped_pr-%cid
          req_uuid = <fs_req>-ReqUuid
          ) TO zbp_i_pr_request=>purchase_requisition_details.

        ENDIF.

        <fs_req>-Messagetype = 'S'.
        <fs_req>-Message = 'PR creation initiated successfully'.
      ELSE.
        <fs_req>-Messagetype = 'E'.
        <fs_req>-Message = 'Error occured while creating PR'.
      ENDIF.

      MODIFY ENTITIES OF zi_pr_request IN LOCAL MODE
          ENTITY PRReq
              UPDATE FIELDS ( Message Messagetype )
              WITH VALUE #( ( %tky        = <fs_req>-%tky
                         Message     = <fs_req>-Message
                         MessageType = <fs_req>-Messagetype ) ).

    ENDLOOP.
  ENDMETHOD.

Save_modfied method

DATA: lt_pr_request_as TYPE STANDARD TABLE OF zpr_request.

IF create-prreq IS NOT INITIAL.
  lt_pr_request_as = CORRESPONDING #( create-prreq MAPPING FROM ENTITY ).
  INSERT zpr_request FROM TABLE @LT_pr_request_as.

  LOOP AT zbp_i_pr_request=>purchase_requisition_details INTO DATA(purchase_reqn_via_eml) WHERE  pid IS NOT INITIAL .
    CONVERT KEY OF i_purchaserequisitiontp FROM purchase_reqn_via_eml-pid TO DATA(ls_pr_key1).
    DATA(lv_pr) = condense( |{ ls_pr_key1-PurchaseRequisition ALPHA = OUT }| ).
    DATA(lv_message) = |PR Number { lv_pr } created successfully|.
    UPDATE zpr_request SET purchaserequisition = @LV_pr,
                           message = @LV_message
                           WHERE req_uuid = @Purchase_reqn_via_eml-req_uuid.
  ENDLOOP.
ENDIF.

Now how can I adjust the PO creation logic? is it possible so?

ABAP RESTful Application Programming Model ABAP Development SAP S/4HANA Cloud ABAP Environment ABAP Cloud SAP S/4HANA Cloud Public Edition 

0 Likes
View Entire Topic
AlexandrePassarelli
Contributor

Hi,

Yes, it is possible. Your PR pattern (EML call in a determination on save, keep the %pid, CONVERT KEY in save_modified) works the same way for purchase orders with the released BO I_PurchaseOrderTP_2. I checked the BDEFs on an S/4HANA 2025 system (read-only). Please compare them on your release.

What matters in the BDEF

  • I_PurchaseOrderTP_2 is an interface over R_PurchaseOrderTP: unmanaged, strict ( 2 ), late numbering on the root and on every child entity, no draft. So, like the PR, inside your determination you only get a %pid. The PO number only comes out via CONVERT KEY in your save phase.
  • The item cannot be created directly (use create is commented out on the item). It can only be created through the association: CREATE BY \_PurchaseOrderItem.
  • Mandatory fields from R_PurchaseOrderTP: PurchaseOrderType and Supplier on the header, Plant on the item.
  • The item exposes PurchaseRequisition and PurchaseRequisitionItem, so you can create the PO with a reference to the PR you already created in the same app.
  • It is C1-released for ABAP Cloud on 2025. On your system, check the API State tab in ADT.

Sketch for the determination (built from the BDEF, not executed):

MODIFY ENTITIES OF i_purchaseordertp_2
  ENTITY PurchaseOrder
    CREATE FIELDS ( PurchaseOrderType CompanyCode PurchasingOrganization
                    PurchasingGroup Supplier )
    WITH VALUE #( ( %cid                   = lv_cid_po_hdr
                    PurchaseOrderType      = 'NB'
                    CompanyCode            = lv_bukrs
                    PurchasingOrganization = lv_ekorg
                    PurchasingGroup        = <fs_req>-Purchasinggroup
                    Supplier               = <fs_req>-Supplier ) )
    CREATE BY \_PurchaseOrderItem
    FIELDS ( Material Plant OrderQuantity PurchaseOrderQuantityUnit
             PurchaseRequisition PurchaseRequisitionItem )
    WITH VALUE #( ( %cid_ref = lv_cid_po_hdr
                    %target  = VALUE #( ( %cid                    = lv_cid_po_item
                                          Material                = <fs_req>-Material
                                          Plant                   = <fs_req>-Plant
                                          OrderQuantity           = <fs_req>-Requestedquantity
                                          PurchaseOrderQuantityUnit = lv_unit
                                          PurchaseRequisition     = <fs_req>-Purchaserequisition
                                          PurchaseRequisitionItem = <fs_req>-Purchaserequisitionitem ) ) ) )
  MAPPED DATA(lt_po_mapped)
  FAILED DATA(lt_po_failed)
  REPORTED DATA(lt_po_reported).

" keep the ROOT %pid, not the item %pid
IF lt_po_failed IS INITIAL.
  APPEND VALUE #( pid      = lt_po_mapped-purchaseorder[ 1 ]-%pid
                  cid      = lv_cid_po_hdr
                  req_uuid = <fs_req>-ReqUuid ) TO zbp_i_pr_request=>purchase_order_details.
ENDIF.

And in save_modified, same as your PR loop:

LOOP AT zbp_i_pr_request=>purchase_order_details INTO DATA(ls_po) WHERE pid IS NOT INITIAL.
  CONVERT KEY OF i_purchaseordertp_2 FROM ls_po-pid TO DATA(ls_po_key).
  " ls_po_key-PurchaseOrder -> update your Z table (PO number + Supplier)
ENDLOOP.

Where it usually breaks

Because R_PurchaseOrderTP is strict ( 2 ), a contract violation in the calling code becomes a BEHAVIOR_CONTRACT_VIOLATION dump instead of a message. The reasons that apply here (texts from SNAPT):

  • MISSING_CID: every create needs a unique %cid. Use separate prefixes for PO header and item, as you did with PRHDR_ / PRITM_.
  • CONVERT_KEY_NOT_MAPPED: CONVERT KEY got a %pid that was never mapped to a final number. Typical causes: passing the item %pid to CONVERT KEY OF i_purchaseordertp_2, or converting after the PO save failed.
  • EMPTY_UPDATE: if you later update the PO, each update record needs at least one non-key field flagged in %control.

Two more things to check:

  • A missing mandatory field (PurchaseOrderType, Supplier, Plant) can show up as runtime error BEHAVIOR_MANDATORY_FIELD.
  • Authorization: the PO checks M_BEST_BSA, M_BEST_EKG, M_BEST_EKO and, on the item, M_BEST_WRK. Note that the API documentation (KTD) names them M_BST_*, which do not exist in TOBJ.

If it still fails, could you share the exact error: the runtime error name and the reason line from ST22, or the content of FAILED / REPORTED after the MODIFY? Then we can narrow it down.

RITZZ
Explorer
Thanks for your answer. I am getting one issue. { "error": { "code": "06/275", "message": "Purchase requisition , item 00010, does not exist", "@SAP__common.longtextUrl": "../../../../default/iwbep/common/0001/T100Longtexts(MessageClass='06',MessageNumber='275',Variable1='',Variable2='00010',Variable3='',Variable4='')/Documentation", "@SAP__common.ExceptionCategory": "Provider_Application_Error", "details": [ { "code": "MEPO/001", "message": "Purchase order item 00010 still contains faulty schedule lines", "@SAP__common.Severity": "error", "@SAP__common.numericSeverity": 4 } ], "innererror": { "ErrorDetails": { "@SAP__common.Application": { "ComponentId": "BC-ESI-ESF-GW", "ServiceRepository": "SRVD", "ServiceId": "ZSD_PR_REQUEST", "ServiceVersion": "0001" }, "@SAP__common.TransactionId": "C83CB3D2A1420060E006AC128DB7C532", "@SAP__common.Timestamp": "20261007055004.275678", "@SAP__common.ErrorResolution": { "Analysis": "Use ADT feed reader \"SAP Gateway Error Log\" or run transaction /IWFND/ERROR_LOG on SAP Gateway hub system and search for entries with the timestamp above for more details", "Note": "See SAP Note 1797736 for error analysis (https://service.sap.com/sap/support/notes/1797736)" } } } } }
AlexandrePassarelli
Contributor
0 Likes
@RITZZ thanks for testing. This one is on my sketch: it passed fs_req-Purchaserequisition, which is still empty at that point, so 06/275 ("Purchase requisition &, item &, does not exist") came with Variable1 empty. MEPO/001 is only a summary message; the real cause is the message before it. I checked the source on S/4HANA 2025 (read-only): a PO that references a PR created in the same save cannot work. (1) The PR number is only assigned in the PR's adjust_numbers. (2) The PO checks the reference with MEREQS_EBAN_LOOKUP, which reads EBAN from the database, where the PR only exists after COMMIT. (3) That check runs in the PO's finalize, before any adjust_numbers. What works: save the PR first, as today, then create the PO in a later request, e.g. an action on ZI_PR_REQUEST that reads the real PR number from your Z table (MODIFY ENTITIES OF i_purchaseordertp_2 is allowed there, COMMIT ENTITIES is not). With the reference, the schedule line takes the delivery date from the PR; without it, send a schedule line with date and quantity. Note: a failed EBAN lookup stays cached until MEREQS_REFRESH, and I_PurchaseRequisitionTP is not C1-released on 2025, so the PR part will not compile in ABAP Cloud.