To create a Purchase Order programmatically in SAP, we use the BAPI:
BAPI_PO_CREATE1
This BAPI can be implemented in two ways:
- Custom ABAP Report - Write a program using SE38
- Direct Testing - Use SE37 (Function Builder) for testing
Method 1: Custom ABAP Report (SE38)
Complete Code Example
REPORT zpo_creation_using_bapi.
DATA: lt_poitem TYPE TABLE OF bapimepoitem,
lt_poitemx TYPE TABLE OF bapimepoitemx,
lt_return TYPE TABLE OF bapiret2,
ls_header TYPE bapimepoheader,
ls_headerx TYPE bapimepoheaderx,
lv_po_number TYPE bapivbeln.
START-OF-SELECTION.
" Fill Header Data
ls_header-doc_type = 'NB'. " Standard PO
ls_header-vendor = '1000'. " Vendor Number
ls_header-comp_code = '1000'. " Company Code
ls_header-purch_org = '1000'. " Purchase Organization
ls_header-pur_group = '001'. " Purchase Group
" Fill Header X-Structure (Change Indicators)
ls_headerx-doc_type = 'X'.
ls_headerx-vendor = 'X'.
ls_headerx-comp_code = 'X'.
ls_headerx-purch_org = 'X'.
ls_headerx-pur_group = 'X'.
" Fill Item Data
APPEND VALUE #( po_item = '00010'
material = 'MAT001'
plant = '1000'
quantity = '10'
net_price = '50' ) TO lt_poitem.
" Fill Item X-Structure (Change Indicators)
APPEND VALUE #( po_item = '00010'
material = 'X'
plant = 'X'
quantity = 'X'
net_price = 'X' ) TO lt_poitemx.
" Call BAPI to Create PO
CALL FUNCTION 'BAPI_PO_CREATE1'
EXPORTING
poheader = ls_header
poheaderx = ls_headerx
IMPORTING
exppurchaseorder = lv_po_number
TABLES
return = lt_return
poitem = lt_poitem
poitemx = lt_poitemx.
" Commit the Transaction
CALL FUNCTION 'BAPI_TRANSACTION_COMMIT'
EXPORTING
wait = 'X'.
" Display Results
IF lv_po_number IS NOT INITIAL.
WRITE: / 'Purchase Order Created:', lv_po_number.
ELSE.
WRITE: / 'PO Creation Failed. Check return messages.'.
ENDIF.
Key Data Structures
POHEADER (Header Data)
- DOC_TYPE: Document type (e.g., 'NB' for Standard PO)
- VENDOR: Vendor number
- COMP_CODE: Company code
- PURCH_ORG: Purchase organization
- PUR_GROUP: Purchase group
POHEADERX (Header Change Indicators)
- Mark fields with 'X' for data that should be processed
- Must correspond to filled fields in POHEADER
POITEM (Item Data)
- PO_ITEM: Item number (e.g., '00010')
- MATERIAL: Material number
- PLANT: Plant code
- QUANTITY: Order quantity
- NET_PRICE: Net price per unit
POITEMX (Item Change Indicators)
- Mark fields with 'X' for data that should be processed
- Must correspond to filled fields in POITEM
Method 2: Direct Testing using SE37
Step-by-Step Process with Visual Guide
Step 1: Access Function Builder
- Go to SE37 (Function Builder) or BAPI transaction
- Enter function module:
BAPI_PO_CREATE1
- Click Test/Execute (F8)
┌─────────────────────────────────────────────────────────────┐
│ Function Builder: Initial Screen │
├─────────────────────────────────────────────────────────────┤
│ Function Module: BAPI_PO_CREATE1 │
│ │
│ [Test/Execute] [Display] [Change] [Create] │
└─────────────────────────────────────────────────────────────┘
Step 2: Fill Header Data (POHEADER)
Navigate to POHEADER and fill mandatory fields:
Screen Layout:
┌─────────────────────────────────────────────────────────────┐
│ Test Function Module: BAPI_PO_CREATE1 │
├─────────────────────────────────────────────────────────────┤
│ Import Parameters: │
│ ├─ POHEADER [📁] <- Click to expand |
│ ├─ POHEADERX [📁] │
│ ├─ POADDRVENDOR [📁] │
│ ├─ TESTRUN [ ] │
│ │
│ Table Parameters: │
│ ├─ POITEM [📁] │
│ ├─ POITEMX [📁] │
│ ├─ RETURN [📁] │
└─────────────────────────────────────────────────────────────┘
POHEADER Fields to Fill:
┌─────────────────────────────────────────────────────────────┐
│ Structure POHEADER │
├─────────────────────────────────────────────────────────────┤
│ COMP_CODE : 1000 (Company Code) │
│ DOC_TYPE : NB (Document Type) │
│ VENDOR : 1000 (Vendor Number) │
│ PURCH_ORG : 1000 (Purchase Organization) │
│ PUR_GROUP : 001 (Purchase Group) │
│ CURRENCY : USD (Currency) │
│ DOC_DATE : 2024-01-15 (Document Date) │
└─────────────────────────────────────────────────────────────┘
Step 3: Set Header Indicators (POHEADERX)
Screen View:
┌─────────────────────────────────────────────────────────────┐
│ Structure POHEADERX │
├─────────────────────────────────────────────────────────────┤
│ COMP_CODE : X (Mark fields to be processed) │
│ DOC_TYPE : X │
│ VENDOR : X │
│ PURCH_ORG : X │
│ PUR_GROUP : X │
│ CURRENCY : X │
│ DOC_DATE : X │
└─────────────────────────────────────────────────────────────┘
Step 4: Fill Item Data (POITEM)
Table View:
┌────────────────────────────────────────────────────────────────────────────┐
│ Table POITEM │
├────────────────────────────────────────────────────────────────────────────┤
│ Row│PO_ITEM│MATERIAL│PLANT│STGE_LOC│QUANTITY│NET_PRICE│PRICE_UNIT│UNIT │
├────┼───────┼────────┼─────┼────────┼────────┼─────────┼──────────┼──────── ┤
│ 1 │ 00010 │ MAT001 │1000 │ 0001 │ 10 │ 50.00 │ 1 │ EA │
│ 2 │ 00020 │ MAT002 │1000 │ 0001 │ 5 │ 75.00 │ 1 │ EA │
└────┴───────┴────────┴─────┴────────┴────────┴─────────┴──────────┴─────── -┘
Step 5: Set Item Indicators (POITEMX)
Table View:
┌────────────────────────────────────────────────────────────────────────────┐
│ Table POITEMX │
├────────────────────────────────────────────────────────────────────────────┤
│ Row│PO_ITEM│MATERIAL│PLANT│STGE_LOC│QUANTITY│NET_PRICE│PRICE_UNIT│UNIT │
├────┼───────┼────────┼─────┼────────┼────────┼─────────┼──────────┼─────── ─┤
│ 1 │ 00010 │ X │ X │ X │ X │ X │ X │ X │
│ 2 │ 00020 │ X │ X │ X │ X │ X │ X │ X │
└────┴───────┴────────┴─────┴────────┴────────┴─────────┴──────────┴─────── ─┘
Step 6: Save Test Data
Save Dialog:
┌─────────────────────────────────────────────────────────────┐
│ Save Test Data │
├─────────────────────────────────────────────────────────────┤
│ Test Data Name: PO_CREATE_TEST_001 │
│ Description: Test data for PO creation │
│ │
│ [Save] [Cancel] │
└─────────────────────────────────────────────────────────────┘
Execution Process
Step 1: Setup Test Sequence
Navigation Path: SE37 → Function Module → Execute → Test Sequences
Test Sequence Setup Screen:
┌─────────────────────────────────────────────────────────────┐
│ Test Sequence Maintenance │
├─────────────────────────────────────────────────────────────┤
│ Sequence Name: PO_CREATION_SEQUENCE │
│ │
│ Function Modules in Sequence: │
│ ┌─────┬─────────────────────────────────────────────────────┐ │
│ │ No. │ Function Module │ │
│ ├─────┼─────────────────────────────────────────────────────┤ │
│ │ 1 │ BAPI_PO_CREATE1 │ │
│ │ 2 │ BAPI_TRANSACTION_COMMIT │ │
│ └─────┴─────────────────────────────────────────────────────┘ │
│ │
│ [Execute] [Save] [Test Data Directory] │
└─────────────────────────────────────────────────────────────┘
Step 2: Execute Test Sequence
Test Data Directory Screen:
┌─────────────────────────────────────────────────────────────┐
│ Test Data Directory │
├─────────────────────────────────────────────────────────────┤
│ Available Test Data: │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ ☑ PO_CREATE_TEST_001 - Test data for PO creation │ │
│ │ ☐ PO_CREATE_TEST_002 - Alternative test data │ │
│ │ ☐ PO_CREATE_TEST_003 - Vendor 2000 test data │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ [Execute] [Create] [Change] [Delete] │
└─────────────────────────────────────────────────────────────┘
Step 3: Execution Results
BAPI_PO_CREATE1 Results:
┌─────────────────────────────────────────────────────────────┐
│ Function Module Results: BAPI_PO_CREATE1 │
├─────────────────────────────────────────────────────────────┤
│ Export Parameters: │
│ EXPPURCHASEORDER: 4500000123 │
│ │
│ Return Messages: │
│ ┌─────┬──────┬────────────────────────────────────────────┐ │
│ │Type │ ID │ Message │ │
│ ├─────┼──────┼────────────────────────────────────────────┤ │
│ │ S │ ME │ Purchase order 4500000123 created │ │
│ │ S │ ME │ Item 00010 created │ │
│ │ S │ ME │ Item 00020 created │ │
│ └─────┴──────┴────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
BAPI_TRANSACTION_COMMIT Results:
┌─────────────────────────────────────────────────────────────┐
│ Function Module Results: BAPI_TRANSACTION_COMMIT │
├─────────────────────────────────────────────────────────────┤
│ Return Code: 000 │
│ Message: Transaction committed successfully │
│ │
│ Status: ✓ Purchase Order 4500000123 committed to database │
└─────────────────────────────────────────────────────────────┘
Step 4: Verification in ME23N
Display Purchase Order Screen:
┌─────────────────────────────────────────────────────────────┐
│ Display Purchase Order: 4500000123 │
├─────────────────────────────────────────────────────────────┤
│ Header Data: │
│ Vendor......: 1000 Doc Type.....: NB │
│ Company Code: 1000 Purch Org....: 1000 │
│ Created by..: USER001 Created on...: 15.01.2024 │
│ │
│ Items: │
│ ┌─────┬────────┬─────┬────────┬─────────┬─────────────────┐ │
│ │Item │Material│Plant│Quantity│Net Price│ Amount │ │
│ ├─────┼────────┼─────┼────────┼─────────┼─────────────────┤ │
│ │00010│ MAT001 │1000 │ 10 │ 50.00 │ 500.00 │ │
│ │00020│ MAT002 │1000 │ 5 │ 75.00 │ 375.00 │ │
│ └─────┴────────┴─────┴────────┴─────────┴─────────────────┘ │
│ Total: 875.00 │
└─────────────────────────────────────────────────────────────┘
Important Parameters Explained
Mandatory Header Fields
ls_header-comp_code = '1000'. " Company Code
ls_header-doc_type = 'NB'. " Document Type
ls_header-vendor = '1000'. " Vendor Number
ls_header-purch_org = '1000'. " Purchase Organization
ls_header-pur_group = '001'. " Purchase Group
X-Structure Concept
The X-structures (POHEADERX, POITEMX) are change indicators:
- 'X' = Field should be processed
- ' ' = Field should be ignored
BAPI_TRANSACTION_COMMIT
Always call this function after BAPI_PO_CREATE1 to:
- Commit the database transaction
- Make changes permanent
- Use
WAIT = 'X'
for synchronous processing
Error Handling and Troubleshooting
Return Message Analysis with Visual Examples
Success Scenario
┌─────────────────────────────────────────────────────────────┐
│ Return Messages Table │
├─────────────────────────────────────────────────────────────┤
│ Type│ID │Number│Message │
├─────┼───┼──────┼────────────────────────────────────────────┤
│ S │ME │ 022 │Purchase order 4500000123 created │
│ S │ME │ 055 │Item 00010 created │
│ S │ME │ 055 │Item 00020 created │
└─────┴───┴──────┴────────────────────────────────────────────┘
✓ Status: SUCCESS - PO Created Successfully
Error Scenario
┌─────────────────────────────────────────────────────────────┐
│ Return Messages Table │
├─────────────────────────────────────────────────────────────┤
│ Type│ID │Number│Message │
├─────┼───┼──────┼────────────────────────────────────────────┤
│ E │ME │ 025 │Vendor 9999 does not exist │
│ E │ME │ 030 │Material MAT999 not found │
│ W │ME │ 010 │Purchase organization not assigned │
└─────┴───┴──────┴────────────────────────────────────────────┘
✗ Status: ERROR - PO Creation Failed
Debug Screen Examples
BAPI Parameters Debug View
┌─────────────────────────────────────────────────────────────┐
│ Debugger: BAPI_PO_CREATE1 Parameters │
├─────────────────────────────────────────────────────────────┤
│ POHEADER Structure: │
│ ├─ COMP_CODE = '1000' │
│ ├─ DOC_TYPE = 'NB' │
│ ├─ VENDOR = '1000' │
│ ├─ PURCH_ORG = '1000' │
│ └─ PUR_GROUP = '001' │
│ │
│ POITEM Table (2 entries): │
│ ├─ Entry 1: PO_ITEM='00010', MATERIAL='MAT001' │
│ └─ Entry 2: PO_ITEM='00020', MATERIAL='MAT002' │
└─────────────────────────────────────────────────────────────┘
Best Practices
1. Data Validation
" Validate vendor exists
SELECT SINGLE lifnr FROM lfa1
INTO @DATA(lv_vendor)
WHERE lifnr = @ls_header-vendor.
IF sy-subrc <> 0.
MESSAGE 'Vendor does not exist' TYPE 'E'.
ENDIF.
2. Number Range Handling
" Let SAP assign PO number automatically
" Don't fill ls_header-po_number unless specific number needed
3. Transaction Control
" Always use BAPI_TRANSACTION_COMMIT
CALL FUNCTION 'BAPI_TRANSACTION_COMMIT'
EXPORTING
wait = 'X'.
" For error scenarios, use BAPI_TRANSACTION_ROLLBACK
IF error_occurred = abap_true.
CALL FUNCTION 'BAPI_TRANSACTION_ROLLBACK'.
ENDIF.
4. Multiple Items Handling
" Add multiple items
APPEND VALUE #( po_item = '00010' material = 'MAT001'
quantity = '10' net_price = '50' ) TO lt_poitem.
APPEND VALUE #( po_item = '00020' material = 'MAT002'
quantity = '5' net_price = '75' ) TO lt_poitem.
" Corresponding X-entries
APPEND VALUE #( po_item = '00010' material = 'X'
quantity = 'X' net_price = 'X' ) TO lt_poitemx.
APPEND VALUE #( po_item = '00020' material = 'X'
quantity = 'X' net_price = 'X' ) TO lt_poitemx.
Verification Steps
1. Check PO in Display Mode
- Transaction: ME23N
- Enter the created PO number
- Verify all data is correctly populated
2. Database Verification
" Check EKKO table for header data
SELECT SINGLE * FROM ekko
INTO @DATA(ls_ekko)
WHERE ebeln = @lv_po_number.
" Check EKPO table for item data
SELECT * FROM ekpo
INTO TABLE @DATA(lt_ekpo)
WHERE ebeln = @lv_po_number.
Common Use Cases
- Mass PO Creation: Process multiple POs from Excel files
- Automated Ordering: Create POs based on stock levels
- Integration: Connect external systems to SAP
- Workflow Integration: Automatic PO creation in approval workflows
Troubleshooting Tips
Issue: PO Not Created
- Check return messages in RETURN table
- Verify all mandatory fields are filled
- Ensure X-structures are properly set
Issue: Authorization Problems
- Check user has authorization for PO creation
- Verify company code and purchase organization access
Issue: Master Data Missing
- Ensure vendor master exists (LFA1)
- Verify material master exists (MARA)
- Check plant and storage location setup
No comments:
Post a Comment