Hi Folks,
while tracking down an issue with not always properly working updates in the APO-system, I happened upon some SAP-code I don't quite understand – or don't know whether this might actually be an error worth raising an OSS-Message about.
Background:
We recently discovered that under certain circumstances, one important APO-quantity field doesn't get updated during the delivery-process triggered in SD via IDOCs (other fields do get updated as expected). When the triggering IDOC is the SAP standard SHPCON it works, if it's a Z-version, it doesn't. It seems that it's just one structure (IS_APOINF) which only has one field (ORIGIN) which controls the behaviour for this particular update of the APO-quantity-field: if this field is filled with 'A' (for goods movement) it works, if it's blank it doesn't. We were able to pinpoint this via debugging where we simply overrode the blank with 'A' in this field in the R/3-system before calling the APO-FM via RFC. The APO-updates then worked as expected.
We are on SAP_APPL 606 0013 SAPKH60613 with EHP6 after a rather big upgrade in early December 2014 from EHP0. From checking out some OSS-Notes where the impacted FMs are mentioned, it looks as if at least some of the code was added during this upgrade. Unfortunately, we are not able to pinpoint the exact time since when the issue occurs but from the information we have available it seems likely to have started with the upgrade but might have flown under the radar due to low traffic via the Z-IDOC. More items are being processed via this route now which is why issues have been noticed with the APO-quantities.
Tracking down the root-cause
Knowing which field to look for, I spend quite a lot of time debugging the process, searching for the proverbial needle in the haystack with the additional obstacle to first determine in which haystack to look for it. I compared what happens where for the standard-IDOC and our Z-version, noticing that most of the processing goes through the same SAP-standard routines. That way, I was eventually able to zoom in to where I think the processing of the Z-version loses the 'A' in IS_APOINF-ORIGIN.
Here is the relevant code in FM RV_COMMON_TABLE_UPDATE which gets processed in both cases:
CALL FUNCTION 'TH_IN_UPDATE_TASK'
IMPORTING
IN_UPDATE_TASK = LF_IN_UPDATE_TASK
EXCEPTIONS
ERROR_MESSAGE = 1
OTHERS = 2.
IF SY-SUBRC = 0 AND LF_IN_UPDATE_TASK = 0.
XVBBS[] = FXVBBS[].
YVBBS[] = FYVBBS[].
PERFORM VBBS_GLOBVAR_REFRESH ON ROLLBACK.
CALL FUNCTION 'RV_VBBE_AND_VBBS_BEARBEITEN' IN UPDATE TASK
EXPORTING
IS_APOINF = IS_APOINF
F_VBELN = F_VBELN
FXVBAK = FXVBAK
IV_VORGANG = VORGANG
IV_VBAK_MANDT = VBAK_MANDT
TABLES
FXVBBE = FXVBBE
FYVBBE = FYVBBE
FXVBBS = FXVBBS
FYVBBS = FYVBBS
FXVBPA = FXVBPA
FYVBPA = FYVBPA
FXAPOI = FXAPOI
FXVBAP = FXVBAP
FXVBUK = FXVBUK
FXLIPS = FXLIPS.
ELSE.
CALL FUNCTION 'RV_VBBE_BEARBEITEN'
EXPORTING
IS_APOINF = IS_APOINF
F_VBELN = F_VBELN
FXVBAK = FXVBAK
IV_VORGANG = VORGANG
IV_VBAK_MANDT = VBAK_MANDT
TABLES
FXVBBE = FXVBBE
FYVBBE = FYVBBE
FXVBPA = FXVBPA
FYVBPA = FYVBPA
FXAPOI = FXAPOI
FXVBAP = FXVBAP
FXVBUK = FXVBUK
FXLIPS = FXLIPS.
IS_APOINF-ORIGIN was previously set to 'A' regardless of the standard or Z-IDOC being processed.
This code, however, gets processed differently depending on the IDOC. For the standard IDOC, the local variable LF_IN_UPDATE_TASK is set to 1 which leads to the ELSE-code being processed – note that IS_APOINF gets exported to RV_VBBE_BEARBEITEN:
ELSE.
CALL FUNCTION 'RV_VBBE_BEARBEITEN'
EXPORTING
IS_APOINF = IS_APOINF
F_VBELN = F_VBELN
FXVBAK = FXVBAK
IV_VORGANG = VORGANG
IV_VBAK_MANDT = VBAK_MANDT
TABLES
FXVBBE = FXVBBE
FYVBBE = FYVBBE
FXVBPA = FXVBPA
FYVBPA = FYVBPA
FXAPOI = FXAPOI
FXVBAP = FXVBAP
FXVBUK = FXVBUK
FXLIPS = FXLIPS.
If this processing is executed, IS_APOINF-ORIGIN retains the 'A'.
For the Z-IDOC, LF_IN_UPDATE_TASK is set to 0 and the other FM is called – also exporting IS_APOINF – but 'IN UPDATE_TASK', so "shelved" for later processing:
IF SY-SUBRC = 0 AND LF_IN_UPDATE_TASK = 0.
XVBBS[] = FXVBBS[].
YVBBS[] = FYVBBS[].
PERFORM VBBS_GLOBVAR_REFRESH ON ROLLBACK.
CALL FUNCTION 'RV_VBBE_AND_VBBS_BEARBEITEN' IN UPDATE TASK
EXPORTING
IS_APOINF = IS_APOINF
F_VBELN = F_VBELN
FXVBAK = FXVBAK
IV_VORGANG = VORGANG
IV_VBAK_MANDT = VBAK_MANDT
TABLES
FXVBBE = FXVBBE
FYVBBE = FYVBBE
FXVBBS = FXVBBS
FYVBBS = FYVBBS
FXVBPA = FXVBPA
FYVBPA = FYVBPA
FXAPOI = FXAPOI
FXVBAP = FXVBAP
FXVBUK = FXVBUK
FXLIPS = FXLIPS.
The FM RV_VBBE_AND_VBBS_BEARBEITEN gets IS_APOINF as an optional import parameter passed with value and the 'A' is still visible at the start of the process:
FUNCTION RV_VBBE_AND_VBBS_BEARBEITEN.
*"----------------------------------------------------------------------
*"*"Update Function Module:
*"
*"*"Global Interface:
*" IMPORTING
*" VALUE(IS_APOINF) LIKE SHP_APOINF STRUCTURE SHP_APOINF
*" DEFAULT SPACE
*" VALUE(F_VBELN) LIKE VBAK-VBELN DEFAULT SPACE
*" VALUE(FXVBAK) LIKE VBAK STRUCTURE VBAK OPTIONAL
*" VALUE(IV_VORGANG) TYPE CHAR1 OPTIONAL
*" VALUE(IV_VBAK_MANDT) TYPE MANDT OPTIONAL
*" VALUE(IV_NO_CREATE_ORD) TYPE CHAR1 DEFAULT SPACE
*" TABLES
*" FXVBBE STRUCTURE VBBED
*" FYVBBE STRUCTURE VBBED
*" FXVBBS STRUCTURE VBBSD
*" FYVBBS STRUCTURE VBBSD
*" FXVBPA STRUCTURE VBPAVB
*" FYVBPA STRUCTURE VBPAVB OPTIONAL
*" FXAPOI STRUCTURE ATPFIELD OPTIONAL
*" FXVBAP STRUCTURE VBAPVB OPTIONAL
*" FXVBUK STRUCTURE VBUKVB OPTIONAL
*" FXLIPS STRUCTURE LIPSVB OPTIONAL
*"----------------------------------------------------------------------
CALL FUNCTION 'RV_VBBE_BEARBEITEN'
EXPORTING
F_VBELN = F_VBELN
FXVBAK = FXVBAK
IV_VORGANG = VORGANG
IV_VBAK_MANDT = VBAK_MANDT
TABLES
FXVBBE = FXVBBE
FYVBBE = FYVBBE
FXVBPA = FXVBPA
FXAPOI = FXAPOI
FXVBAP = FXVBAP
FXVBUK = FXVBUK.
As the first activitiy, FM RV_VBBE_BEARBEITEN gets called, but without exporting IS_APOINF as is done when this FM is called from RV_COMMON_TABLE_UPDATE. Before the FM gets called, IS_APOINF still contains 'A'.
For RV_VBBE_BEARBEITEN, IS_APOINF is also defined as optional with value and default SPACE.
*"----------------------------------------------------------------------
*"*"Update Function Module:
*"
*"*"Global Interface:
*" IMPORTING
*" VALUE(IS_APOINF) LIKE SHP_APOINF STRUCTURE SHP_APOINF
*" DEFAULT SPACE
*" VALUE(F_VBELN) LIKE VBAK-VBELN DEFAULT SPACE
*" VALUE(FXVBAK) LIKE VBAK STRUCTURE VBAK OPTIONAL
*" VALUE(IV_VORGANG) TYPE CHAR1 OPTIONAL
*" VALUE(IV_VBAK_MANDT) TYPE MANDT OPTIONAL
*" VALUE(IV_NO_CREATE_ORD) TYPE CHAR1 DEFAULT SPACE
*" TABLES
*" FXVBBE STRUCTURE VBBED
*" FYVBBE STRUCTURE VBBED
*" FXVBPA STRUCTURE VBPAVB
*" FYVBPA STRUCTURE VBPAVB OPTIONAL
*" FXAPOI STRUCTURE ATPFIELD OPTIONAL
*" FXVBAP STRUCTURE VBAPVB OPTIONAL
*" FXVBUK STRUCTURE VBUKVB OPTIONAL
*" FXLIPS STRUCTURE LIPSVB OPTIONAL
*"----------------------------------------------------------------------
VORGANG = IV_VORGANG.
VBAK_MANDT = IV_VBAK_MANDT.
PERFORM VBBE_BEARBEITEN.
IF IV_NO_CREATE_ORD IS INITIAL.
PERFORM VB_APO_CREATE_ORD.
ENDIF.
PERFORM VB_APO_PUT ON COMMIT LEVEL LEVEL_ATP.
IF NOT ( FXVBBE[] IS INITIAL AND FYVBBE[] IS INITIAL ).
PERFORM MEMORY_UPDATE ON COMMIT LEVEL LEVEL_ATP.
ENDIF.
PERFORM VBBE_BEARBEITEN_UPD_DB ON COMMIT LEVEL LEVEL_ATP.
PERFORM VBBE_GLOBVAR_REFRESH ON COMMIT LEVEL LEVEL_ATP_INIT.
PERFORM VBBE_GLOBVAR_REFRESH ON ROLLBACK.
* Register bgRFC send on commit (level > LEVEL_ATP)
CALL FUNCTION 'CIF_SEND_BGRFCUNIT_REGISTER'.
PERFORM VB_APO_REFRESH ON ROLLBACK.
ENDFUNCTION.
Within the processing, IS_APOINF is queried or passed to other FMs but not actively changed to another value as far as I can tell.
When this FM is processed for the Z-IDOC, the value of IS_APOINF shows as blank right at the start, most likely because it didn't get passed from the calling FM but is defined with a default value of SPACE. This will affect some processing within those called routines where IS_APOINF gets checked for 'A':
* to allow creation of in transit nodes for VMI batch items
* created at the same time as the goods issue.
IF is_apoinf-origin EQ 'A'
AND da_vbbe-updkz EQ updkz_new
AND da_vbbe-vbtyp EQ vbtyp_lino
AND da_vbbe-omeng EQ 0.
CALL FUNCTION 'CIF_VMISD_EXISTS'
EXPORTING
iv_kunnr = da_vbbe-kunnr
IMPORTING
ev_exists = lv_is_vmi_kunnr.
IF NOT lv_is_vmi_kunnr IS INITIAL
AND fxlips IS SUPPLIED.
READ TABLE fxlips
WITH KEY vbeln = da_vbbe-vbeln
posnr = da_vbbe-posnr
BINARY SEARCH.
IF sy-subrc IS INITIAL.
da_vbbe-omeng = da_vbbe-vmeng = fxlips-lgmng.
da_vbbe-apomobile = '4'. "prevent ERP update but allow APO
ENDIF.
ENDIF.
ENDIF.
But, what concerns me the most is the fact, that IS_APOINF has been set to SPACE when the processing is back in RV_VBBE_AND_VBBS_BEARBEITEN even though that FM never passed the field to RV_VBBE_BEARBEITEN. How can it be that an optional import parameter changes its value if it wasn't even passed into the called FM? Isn't that a rather big source for potential problems not just in this case but also more generally speaking?
Needless to say, once IS_APOINF is filled with space it never gets filled again after this sequence of FMs and the APO-processing doesn't properly work.
How best to proceed?
I'm planning to open an OSS-message about this, but would like to get some feedback from you first, mainly to get a better handle on whether this is an "oversight" by SAP or could have been intentionally programmed like this.
From past experience it's rather likely, that as soon as we mention the preceeding processing via a Z-IDOC, SAP-support will concentrate on what we might be doing wrong there instead of actually checking out the code already identified as potentially problematic (and I have saved many screenshots from debugging I could provide). Describing the necessary steps to reproduce the error - or even better: to watch it unfold during debugging! - in enough detail will also be rather time-consuming. Setting up working testcases in and by itself is a hassle for these tests, especially if the goal is to ensure that they are basically identical. Does anybody know of a "shortcut" to get somebody from SAP-development quickly involved in tackling an OSS-message, ideally via a conference call where screen-sharing is possible? Talking a developer through this would be a lot easier than trying to make somebody from SAP-support understand the technical details.
Thanks much for any feedback you can provide!
Cheers
Baerbel