1. Requirement
It is a common requirement to develop a report to show the relationship between sales order and customer PO, but sometimes we will get incorrect result or inconsistent relationship, let’s figure out the root cause.
If you don’t have problem, directly go to section 6 to check with the solution.
2. Symptom
- Customer PO number truncated.
- Customer PO missing.
- Customer PO incorrect.
3. Environment
This document is under SAP ERP 6.0 EHP7 with IDES on NetWeaver 7.42, and also verified on SAP S4/HANA 1511(S4Core 100 SP03) on NetWeaver 7.49.
4. Reproducing the Issue
4.1 Scenario A
Here we write down a simply report which the customer PO will be truncated.
TABLES: vbak.
SELECT-OPTIONS: s_vbeln FOR vbak-vbeln.
SELECT vbeln, bstnk
INTO TABLE @DATA(itab)
FROM vbak
WHERE vbak~vbeln IN @s_vbeln.
cl_demo_output=>display( itab[] ).
The customer PO Number in sales order
5085 is
AIT-432990-TEST-TRUNCATED, but our report shows that
AIT-432990-TEST-TRUN.
4.2 Scenario B
Here we write down a simply report which the customer PO will missing.
TABLES: vbak.
SELECT-OPTIONS: s_vbeln FOR vbak-vbeln.
SELECT vbak~vbeln, vbap~posnr, vbak~bstnk, vbkd~bstkd
INTO TABLE @DATA(itab)
FROM vbkd
INNER JOIN vbak
ON vbkd~vbeln EQ vbak~vbeln
INNER JOIN vbap
ON vbkd~vbeln EQ vbap~vbeln
AND vbkd~posnr EQ vbap~posnr
WHERE vbak~vbeln IN @s_vbeln.
cl_demo_output=>display( itab[] ).
The customer PO number in item
10 of sales order
5008 is
DG-27011997-4, but our report shows nothing.
4.3 Scenario C
Here we write down a simply report which the customer PO will be incorrect.
TABLES: vbak.
SELECT-OPTIONS: s_vbeln FOR vbak-vbeln.
SELECT vbak~vbeln, vbap~posnr, vbkd~bstkd_e
INTO TABLE @DATA(itab)
FROM vbkd
INNER JOIN vbak
ON vbkd~vbeln EQ vbak~vbeln
INNER JOIN vbap
ON vbkd~vbeln EQ vbap~vbeln
AND ( vbkd~posnr EQ vbap~posnr
OR vbkd~posnr EQ '' )
WHERE vbak~vbeln IN @s_vbeln.
cl_demo_output=>display( itab[] ).
The customer PO number in item
10 of sales order
5085 is
AIT-432990-TEST-TRUNCATED, but our report shows
AIT-432990-TEST-INCORRECT.
5. Reason and Prerequisites
5.1 Scenario A
For scenario A, we took
VBAK-BSTNK as customer PO number, we can navigate to another screen when double click on the customer PO number field of sales order overview.
There are two field in this screen named customer PO number,
VBAK-BSTNK with length
20 and
VBKD-BSTKD with length
35.
Considering the performance, we should use as less table as we can, so we may choose
VBAK-BSTNK if we forget to check the length of these two fields. When the length of customer PO number greater than
20, it will be truncated.
5.2 Scenario B
For scenario B, we would like to show customer PO number on item data, so we took
VBKD-BSTKD to join table
VBAP, although we could find the customer PO number in “
Order Data” of the item data, there is no corresponded data store in table
VBKD-BSTKD with item
10.
Try to change to customer PO number in “
Order Data” of the item data and then check the table
VBAP and
VBKD again, there are
four items in
VBAP, but only
two entries on table
VBKD.
In other words, customer PO from item data will be the same as header data
as default, and not store separately into table
VBKD, and will be duplicated
only if we change it within item data. That is to say, we can read item customer PO first, if there is no corresponded one, read the header customer PO instead.
5.3 Scenario C
For Scenario C, we may find
customer PO number within
overview screen, and see to
VBKD-BSTKD_E as
PO Number, since
VBKD-BSTKD shows as
PO Details in this screen.
6. Solution
Before we figure out the solution, we could go to standard function to check the standard logic how to select table VBKD within
SD_VBKD_ARRAY_READ.
SELECT * FROM VBKD INTO TABLE LB_VBKDVB
FOR ALL ENTRIES IN LT_VBKD_KEY
WHERE VBELN = LT_VBKD_KEY-VBELN
AND ( POSNR = LT_VBKD_KEY-POSNR OR
POSNR = POSNR_LOW )
ORDER BY PRIMARY KEY.
From previous three scenarios, we should know that there are three fields related to customer PO number,
VBAK-BSTNK,
VBKD-BSTKD,
VBKD-BSTKD_E, and
the table VBKD not always store each item.
Normally we should use
VBKD-BSTKD and should consider
POSNR as empty for item to get header data.
VBAK-BSTNK could use only for header, it could be used only for
better performance and the length
never greater than 20.
VBKD-BSTKD_E is for
ship-to party and
VBKD-BSTKD is for
sold-to party, there are different things, we should verify what they exactly are before we write the report.
Refer to standard function
SD_VBKD_ARRAY_READ, we can change our report as below.
TABLES: vbak.
SELECT-OPTIONS: s_vbeln FOR vbak-vbeln.
SELECT vbak~vbeln, vbap~posnr, vbak~bstnk, vbkd~bstkd, vbkd~bstkd_e
INTO TABLE @DATA(itab)
FROM vbkd
INNER JOIN vbak
ON vbkd~vbeln EQ vbak~vbeln
INNER JOIN vbap
ON vbkd~vbeln EQ vbap~vbeln
AND ( vbkd~posnr EQ vbap~posnr
OR vbkd~posnr EQ '' )
WHERE vbak~vbeln IN @s_vbeln.
cl_demo_output=>display( itab[] ).
From the result we found that there still some problem, no header customer PO, and the item customer PO will be duplicated.
The conclusion is that the standard logic will get the incorrect result if we change the customer PO number on item data, so we change our report again, and finally all the result correct.
TABLES: vbak.
SELECT-OPTIONS: s_vbeln FOR vbak-vbeln.
SELECT vbak~vbeln, vbkd~posnr, vbak~bstnk, vbkd~bstkd, vbkd~bstkd_e
INTO TABLE @DATA(itab)
FROM vbkd
INNER JOIN vbak
ON vbkd~vbeln EQ vbak~vbeln
WHERE vbak~vbeln IN @s_vbeln
AND vbkd~posnr EQ '000000'.
SELECT vbeln, posnr, ' ', ' ', ' '
APPENDING TABLE @itab
FROM vbap
WHERE vbeln IN @s_vbeln.
LOOP AT itab ASSIGNING field-symbol(<row>) WHERE posnr NE '000000'.
SELECT SINGLE bstkd bstkd_e
INTO (<row>-bstkd, <row>-bstkd_e)
FROM vbkd
WHERE vbeln EQ <row>-vbeln
AND posnr EQ <row>-posnr.
IF NOT sy-subrc IS INITIAL.
SELECT SINGLE bstkd bstkd_e
INTO (<row>-bstkd, <row>-bstkd_e)
FROM vbkd
WHERE vbeln EQ <row>-vbeln
AND posnr EQ '000000'.
ENDIF.
ENDLOOP.
cl_demo_output=>display( itab[] ).
7. Best Practice
- The correct field should be VBKD-BSTKD rather than VBAK-BSTNK for header data.
- Considering the performance, VBAK-BSTNK could be used only if the length never greater than 20.
- Always check corresponded POSNR for item data first, and don’t forget to check empty POSNR only if there is no corresponded item data, they are not a OR relationship.
8. Quotation
- Standard function SD_VBKD_ARRAY_READ