‎2008 Jul 03 11:48 AM
Hi all,
we process an extended version of DEBMAS01 IDoc on inbound and need to verify if the incoming IDoc does not contain outdated information already. Basically, we check if the underlying record was not yet changed in SAP based on change pointer BDCPS.
To achieve this we created a new process code that executes a new function module. This function module first retrieves the SAP kunnr of the DEBMAS01 and retrieves the record from KNA1. Afterwards we check if there any entries in BDCPS that are not yet processed. If so, we reject the IDoc. If not, we validate a specific version in KNA1 in addition against a custom field in DEBMAS01. At the end the standard function module IDOC_INPUT_DEBITOR to apply the information to KNA1.
Now, our problem is we need to lock the KNA1 record before we check for change pointers, otherwise the whole logic will not work if there happens a change at the same time. We tried to use enqueue/dequeue functions, but then the IDOC_INPUT_DEBITOR function module raises the error that the record is already locked. We also tried to update the KNA1 record before we check BDCPS, but unfortunately when IDOC_INPUT_DEBITOR is called the update gets committed and we loose the database lock.
Do you have any ideas how we could lock the record or another concept in mind? We don't want to copy IDOC_INPUT_DEBITOR and utilize as much standard as possible.
Many thanks for your input...we drive crazy here...especially as with a WAIT UP TO we cannot test the database LUWs as they are committed with a WAIT....
Cheers
Our custom function module:
FUNCTION Z_IDOC_INPUT_DEBITOR.
*"----
-
""Lokale Schnittstelle:
*" IMPORTING
*" VALUE(INPUT_METHOD) LIKE BDWFAP_PAR-INPUTMETHD
*" VALUE(MASS_PROCESSING) LIKE BDWFAP_PAR-MASS_PROC
*" VALUE(PI_XD99_USED) TYPE CHAR1 DEFAULT SPACE
*" VALUE(PI_KNVK_SPECIAL) TYPE CHAR1 DEFAULT SPACE
*" EXPORTING
*" VALUE(WORKFLOW_RESULT) LIKE BDWFAP_PAR-RESULT
*" VALUE(APPLICATION_VARIABLE) LIKE BDWFAP_PAR-APPL_VAR
*" VALUE(IN_UPDATE_TASK) LIKE BDWFAP_PAR-UPDATETASK
*" VALUE(CALL_TRANSACTION_DONE) LIKE BDWFAP_PAR-CALLTRANS
*" TABLES
*" IDOC_CONTRL STRUCTURE EDIDC
*" IDOC_DATA STRUCTURE EDIDD
*" IDOC_STATUS STRUCTURE BDIDOCSTAT
*" RETURN_VARIABLES STRUCTURE BDWFRETVAR
*" SERIALIZATION_INFO STRUCTURE BDI_SER
*" EXCEPTIONS
*" WRONG_FUNCTION_CALLED
*"----
-
DATA: zzfred like ZZFRED, "SFDC Extended Segment
i_e1kna1m like e1kna1m,
i_kna1 like kna1,
ls_idoc_data type edidd, "manipulierte IDOC DATA
lv_index type sy-tabix. "Index in table IDOC_DATA
DATA: i_CPIDENT like BDCPS-CPIDENT,
number_records type NUM.
Flag signals if customer already locked.
DATA: locked(1) type c value 'N'.
TABLES: bdcp,
bdcps.
*-------
*Sleep Pointer setzen, um LOCK auf Datensatz zu testen
WAIT UP TO 300 SECONDS.
*-------
LOOP AT IDOC_DATA.
CASE IDOC_DATA-segnam.
E1KNA1M
WHEN 'E1KNA1M'.
i_e1kna1m = IDOC_DATA-SDATA.
read table idoc_data into ls_idoc_data
with key segnam = IDOC_DATA-segnam.
lv_index = sy-tabix.
ZZFRED
WHEN 'ZZFRED'.
zzfred = IDOC_DATA-SDATA.
ENDCASE.
ENDLOOP.
<---------------------------------------------------------------------
Prüfen ob KUNNR übergeben wurde, sonst auf SFDC prüfen
und dann mit SFDC_ID die KUNNR aus SAP holen,
ansonsten eine neue SAP KUNNR erzeugen als nächst höhere freie Nr
IF i_e1kna1m-KUNNR eq '/'. "Kundennummer wurde nicht mit IDOC
"übergeben = '/' oder blank '' je nach
"Einstellung in INFA
SELECT SINGLE * FROM kna1 into i_kna1
WHERE sfdc_id = zzfred-sfdc_id.
IF sy-subrc eq 0. " Kunde gefunden in Kna1
IDOC Feld KUNNR den Wert aus Tabelle KNA1 zuweisen
i_e1kna1m-kunnr = i_kna1-kunnr.
ELSE.
neuen Wert für KUNNR erstellen und dann IDOC Segment zuweisen
i_e1kna1m-kunnr = '0000059376'. "
Code wechseln, so dass Wert
aus Tabelle ankommt
ENDIF. "sy-subrc
ENDIF. "Kunnr nicht gefüllt
KUNNR nun im manipulierten IDOC DATA Record vorhanden, aber noch nicht
an IDOC_DATA übertragen. Dies geschieht durch modify Anweisung folgend
i_e1kna1m-KUNNR = '0000059377'.
i_e1kna1m-STRAS = 'Hinterm Hornbach'.
manipulierte IDOC Daten übertragen
ls_idoc_data-sdata = i_e1kna1m. "man. Segment übertragen
modify idoc_data from ls_idoc_data index lv_index.
--------------------------------------------------------------------->
*------- Konto sperren KNA1 -
-
CALL FUNCTION 'ENQUEUE_EXKNA1'
EXPORTING
KUNNR = i_e1kna1m-kunnr
EXCEPTIONS
FOREIGN_LOCK = 1
SYSTEM_FAILURE = 2.
CASE SY-SUBRC.
WHEN 1.
LOCKED = 'Y'.
ROLLBACK WORK.
"MESSAGE E042 WITH kna1m-kunnr.
"von anderem Benutzer gesperrt
WHEN 2.
"MESSAGE E038. "Systemfehler
ROLLBACK WORK.
ENDCASE.
<---------------------------------------------------------------------
Nun prüfen, ob IDOC verarbeitet werden soll, hier auf Kriterien prüfen
SAP_VERSION prüfen
Change Pointer prüfen
Status für IDOC ändern (Bsp.: S.648 Buch)
*
if locked eq 'N'.
SELECT SINGLE * FROM kna1 into i_kna1
WHERE kunnr = i_e1kna1m-kunnr.
IF sy-subrc eq 0. " Kunde gefunden in Kna1
i_kna1-system_of_change = 'SFDC'.
update kna1 from i_kna1.
SELECT COUNT(*) INTO number_records
FROM BDCPS AS a INNER JOIN BDCP AS b
ON aCPIDENT = bCPIDENT
WHERE aPROCESS <> 'X' AND aMESTYPE = 'DEBMAS'
AND b~CDOBJID = i_e1kna1m-kunnr.
IF number_records > 0.
i_kna1-sap_version = i_kna1-sap_version + number_records.
EXIT.
ENDIF.
ENDSELECT.
IF zzfred-sap_version < i_kna1-sap_version
OR zzfred-sfdc_version < i_kna1-sfdc_version.
IDOC_STATUS-DOCNUM = IDOC_CONTRL-DOCNUM.
IDOC_STATUS-STATUS = '51'.
IDOC_STATUS-MSGTY = 'E'.
IDOC_STATUS-MSGID = 'ZE'.
IDOC_STATUS-MSGNO = '005'.
IDOC_STATUS-MSGV1 = i_e1kna1m-kunnr.
APPEND IDOC_STATUS.
WORKFLOW_RESULT = '99999'. "C_WF_RESULT_ERROR.
RETURN_VARIABLES-WF_PARAM = 'Error_IDOCs'.
RETURN_VARIABLES-DOC_NUMBER = IDOC_CONTRL-DOCNUM.
APPEND RETURN_VARIABLES.
EXIT.
ENDIF. "zzfred-sap_version
ENDIF. "sy-subrc
Und wenn abgelehnt, dann EXIT setzen, oder IF Bedingung, aber die
nachstehende Function 'IDOC_INPUT_DEBITOR' nicht ausführen
*
--------------------------------------------------------------------->
Wenn alles in Ordnung ist und IDOC nicht abgelehnt wird, dann Function
aufrufen, um IDOC verarbeiten zu lassen, allerdings mit den
manipulierten Daten.
CALL FUNCTION 'IDOC_INPUT_DEBITOR'
DESTINATION SPACE
EXPORTING
INPUT_METHOD = INPUT_METHOD
MASS_PROCESSING = MASS_PROCESSING
IMPORTING
WORKFLOW_RESULT = WORKFLOW_RESULT
APPLICATION_VARIABLE = APPLICATION_VARIABLE
IN_UPDATE_TASK = IN_UPDATE_TASK
CALL_TRANSACTION_DONE = CALL_TRANSACTION_DONE
TABLES
IDOC_CONTRL = IDOC_CONTRL
IDOC_DATA = IDOC_DATA
IDOC_STATUS = IDOC_STATUS
RETURN_VARIABLES = RETURN_VARIABLES
SERIALIZATION_INFO = SERIALIZATION_INFO
EXCEPTIONS
WRONG_FUNCTION_CALLED = 1
OTHERS = 2
.
rollback work.
------ Konto entsperren ---------------------------------------------*
CALL FUNCTION 'DEQUEUE_EXKNA1'
EXPORTING
KUNNR = i_e1kna1m-kunnr
EXCEPTIONS
SYSTEM_FAILURE = 1.
endif.
ENDFUNCTION.
‎2008 Jul 03 12:19 PM
Hi Maic,
Why not locking the KNA1, execute your checks, and then delocking the KNA1 just before you call the IDOC_INPUT_DEBITOR?
Regards,
John.
‎2008 Jul 03 2:36 PM
Yes, we did this already, but still somebody could change the record between we release the lock and the IDoc is processed in the standard module. Is there a way to get the lock and "pass" it into the module or better to say that the standard module can relock the record as it's the same transaction and user.