Application Development Blog Posts
Learn and share on deeper, cross technology development topics such as integration and connectivity, automation, cloud extensibility, developing at scale, and security.
cancel
Showing results for 
Search instead for 
Did you mean: 
ceeshi
Discoverer
38,045

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

2 Comments
Labels in this area