Skip to content

BAPI_PO_CREATE1

Create purchase orders programmatically — the standard BAPI for MM purchasing document creation.

Purpose

BAPI_PO_CREATE1 creates standard purchase orders (document type NB) and other purchasing document types. Like all write BAPIs, it requires BAPI_TRANSACTION_COMMIT after success and uses the checkbox structure pattern (POHEADERX, POITEMX) to indicate which fields to populate.

Signature (key parameters)

Parameter Direction Type Description
POHEADER Importing BAPIMEPOHEADER PO header data
POHEADERX Importing BAPIMEPOHEADERX Checkbox — flag fields to populate
POITEM Tables BAPIMEPOITEM Line items
POITEMX Tables BAPIMEPOITEMX Checkbox table for items
EXPHEADER Exporting BAPIMEPOHEADER Created PO number
RETURN Tables BAPIRET2 Messages

Checkbox structure pattern

Every field in POHEADER that you populate must also be set to 'X' in the corresponding field of POHEADERX. This tells the BAPI which fields to process — unset fields are ignored.

Example — create a standard PO

DATA: ls_header    TYPE bapimepoheader,
      ls_headerx   TYPE bapimepoheaderx,
      lt_items     TYPE STANDARD TABLE OF bapimepoitem,
      lt_itemsx    TYPE STANDARD TABLE OF bapimepoitemx,
      lv_po_number TYPE ekko-ebeln,
      lt_return    TYPE STANDARD TABLE OF bapiret2.

" Start from plant — find one with a valuation area and a material with description
" then derive company code and purchasing org from there to guarantee consistency
SELECT SINGLE m~matnr, m~werks, k~bukrs FROM marc AS m
  INNER JOIN mara AS a ON a~matnr = m~matnr
    AND a~mtart IN ('ROH', 'HALB', 'FERT', 'HAWA', 'VERP')
    AND a~pstat LIKE '%E%'
  INNER JOIN mbew AS b ON b~matnr = m~matnr AND b~bwkey = m~werks
  INNER JOIN makt AS t ON t~matnr = m~matnr AND t~spras = @sy-langu
  INNER JOIN t001k AS k ON k~bwkey = m~werks
  INTO @DATA(ls_mat).
IF sy-subrc <> 0.
  WRITE: / 'No suitable material/plant combination found — check MARC / MBEW / MAKT / T001K'.
  RETURN.
ENDIF.
DATA(lv_plant)    = ls_mat-werks.
DATA(lv_material) = ls_mat-matnr.

" Purchasing org assigned to the plant's company code
SELECT SINGLE ekorg FROM t024e
  WHERE bukrs = @ls_mat-bukrs
  INTO @DATA(lv_ekorg).
IF sy-subrc <> 0.
  WRITE: / 'No purchasing org for company code', ls_mat-bukrs, '— check T024E'.
  RETURN.
ENDIF.

SELECT SINGLE ekgrp FROM t024 INTO @DATA(lv_purgroup).
IF sy-subrc <> 0.
  WRITE: / 'No purchasing group found — check T024'.
  RETURN.
ENDIF.

" Vendor assigned to this purchasing org
SELECT SINGLE lifnr FROM lfm1
  WHERE ekorg = @lv_ekorg
  INTO @DATA(lv_vendor).
IF sy-subrc <> 0.
  WRITE: / 'No vendor found for purch org', lv_ekorg, '— check LFM1'.
  RETURN.
ENDIF.

" Header data
ls_header-comp_code = ls_mat-bukrs.
ls_header-doc_type  = 'NB'.
ls_header-vendor    = lv_vendor.
ls_header-purch_org = lv_ekorg.
ls_header-pur_group = lv_purgroup.
ls_header-doc_date  = sy-datum.

" Checkbox header — X = process this field
ls_headerx-comp_code = 'X'.
ls_headerx-doc_type  = 'X'.
ls_headerx-vendor    = 'X'.
ls_headerx-purch_org = 'X'.
ls_headerx-pur_group = 'X'.
ls_headerx-doc_date  = 'X'.

" Item data
APPEND VALUE #(
  po_item    = '00010'
  material   = lv_material
  plant      = lv_plant
  quantity   = '10'
  po_unit    = 'PC'
  net_price  = '25.00'
  price_unit = '1'
) TO lt_items.

" Checkbox item
APPEND VALUE #(
  po_item    = '00010'
  material   = 'X'
  plant      = 'X'
  quantity   = 'X'
  po_unit    = 'X'
  net_price  = 'X'
  price_unit = 'X'
) TO lt_itemsx.

CALL FUNCTION 'BAPI_PO_CREATE1'
  EXPORTING
    poheader  = ls_header
    poheaderx = ls_headerx
  IMPORTING
    exppurchaseorder = lv_po_number
  TABLES
    poitem   = lt_items
    poitemx  = lt_itemsx
    return   = lt_return.

" Check errors
LOOP AT lt_return INTO DATA(ls_msg) WHERE type CA 'EA'.
  WRITE: / ls_msg-type, ls_msg-message.
ENDLOOP.

IF sy-subrc <> 0.   " no errors in loop above = no E/A messages
  CALL FUNCTION 'BAPI_TRANSACTION_COMMIT' EXPORTING wait = abap_true.
  WRITE: / 'PO created:', lv_po_number.
ELSE.
  CALL FUNCTION 'BAPI_TRANSACTION_ROLLBACK'.
ENDIF.

Common pitfalls

Checkbox pattern is mandatory

If you set a field in POHEADER but not in POHEADERX, the field is silently ignored. Every field you want to transfer must have 'X' in both structures.

Always check RETURN before committing

Messages with TYPE = 'E' or 'A' indicate failure. A non-zero sy-subrc after the BAPI call is not reliable — always read the RETURN table.

  • Vendor number: Must be in internal format (10 digits with leading zeros). Selecting directly from LFM1 or LFA1 already gives internal format. Use CONVERSION_EXIT_ALPHA_INPUT if the user enters a short number.
  • Material number: Same — internal format with leading zeros. Selecting from MARC/MARA gives internal format directly.
  • Net price: Passed as a string-numeric value per PRICE_UNIT quantity.
  • Org-level consistency: The vendor must be assigned to the purchasing org (LFM1), and the plant must be assigned to the company code. Mismatched org values are the most common cause of header errors.

See also

Comments