해당 공식문서를 학습한 내용임
How To Access Delivery Objects in S4H.pdf
트랜잭션 관리 패턴
/SCWM, /SCDL 클래스를 이용한 프로그래밍 시 적용
다음 순서대로 진행
- set warehouse
DATA: lo_tm TYPE REF TO /scwm/if_tm. "transaction manager
TRY.
lo_tm->set_whno_w_check( p_whno ).
CATCH /scwm/cx_tm_check INTO DATA(lx_whno).
MESSAGE lx_whno TYPE 'E'.
ENDTRY.
- Lock
- Update
- Check Errors
- - no error -> save
- - error occured -> rollback
예제 코드 : 딜리버리의 Customer field 수정
REPORT ZUPDATE_HEADER_EEW_DATA.
* This sample program shows how one an outbound delivery order (ODO)
* a customer specific field (Z_ZUSATZ) is filled/changed.
* The program does a locking and reading of the data
* it then changes the EEW field
* the program also contains error handling
* It also consideres validation errors
* based on if errors occurred or not it saves or rejects (ROLLBACK) the changes.
* The program uses the delivery service provider (SP).
* The program is ment to be used as a separate program, so not to be used inside
a BADI or
* other already running programs (as the setting of the warehouse/save/rollback
will destroy a running LUW/transaction)
* Note: The program is only for demo purpose. It is not ment for any
* productive usage.
DATA:
lo_sp TYPE REF TO /scdl/cl_sp_prd_out,
lo_message_box TYPE REF TO /scdl/cl_sp_message_box,
lo_tm TYPE REF TO /scwm/if_tm,
lt_a_head TYPE /scdl/t_sp_a_head,
lt_sp_k_head TYPE /scdl/t_sp_k_head,
ls_sp_k_head TYPE /scdl/s_sp_k_head,
lt_a_head_eew TYPE /scdl/t_sp_a_head_eew_prd,
lt_a_head_eew_out TYPE /scdl/t_sp_a_head_eew_prd,
ls_sp_action TYPE /scdl/s_sp_act_action,
lv_rejected TYPE boole_d,
lv_error_occured TYPE boole_d,
lv_validation_error_occured TYPE boole_d,
lt_return_codes TYPE /scdl/t_sp_return_code,
lt_validation_messages TYPE /scdl/dm_message_tab,
lt_messages TYPE /scdl/dm_message_tab.
FIELD-SYMBOLS:
<ls_a_head_eew> TYPE /scdl/s_sp_a_head_eew_prd,
<ls_messages> TYPE /scdl/dm_message_str.
* create service provider for processing delivery and and message box
* the service provider is not used here for a UI (so no attribute handler is used)
CREATE OBJECT lo_message_box.
CREATE OBJECT lo_sp
EXPORTING
io_message_box = lo_message_box
iv_doccat = /scdl/if_dl_doc_c=>sc_doccat_out_prd
iv_mode = /scdl/cl_sp=>sc_mode_classic.
* set warehouse that is used
lo_tm ?= /scwm/cl_tm_factory=>get_service( /scwm/cl_tm_factory=>sc_manager ).
lo_tm->set_whno( 'EWMZ' ).
* fill GUID of delivery header
CLEAR ls_sp_k_head.
ls_sp_k_head-docid = '00000000000100442833000000000000'.
APPEND ls_sp_k_head TO lt_sp_k_head.
* try to lock (also creates the delivery instance immediately)
clear lt_return_codes.
clear lv_rejected.
lo_sp->lock( EXPORTING
inkeys = lt_sp_k_head
aspect = /scdl/if_sp_c=>sc_asp_head
lockmode = /scdl/if_sp1_locking=>sc_exclusive_lock
IMPORTING
rejected = lv_rejected
return_codes = lt_return_codes ).
* check if any error occurred
READ TABLE lt_return_codes TRANSPORTING NO FIELDS WITH KEY failed = abap_true.
IF sy-subrc = 0 OR lv_rejected = abap_true.
lv_error_occured = abap_true.
ENDIF.
* if no error so far...
if lv_error_occured = abap_false.
* select customer fields EEW for the delivery
clear lt_return_codes.
clear lv_rejected.
lo_sp->select( EXPORTING
inkeys = lt_sp_k_head
aspect = /scdl/if_sp_c=>SC_ASP_HEAD_EEW_PRD
* OPTIONS
IMPORTING
outrecords = lt_a_head_eew
rejected = lv_rejected
return_codes = lt_return_codes ).
* check if any error occurred
READ TABLE lt_return_codes TRANSPORTING NO FIELDS WITH KEY failed = abap_true.
IF sy-subrc = 0 OR lv_rejected = abap_true.
lv_error_occured = abap_true.
ENDIF.
loop at lt_a_head_eew ASSIGNING <ls_a_head_eew>.
* now fill the customer specific field Z_ZUSATZ
<ls_a_head_eew>-Z_ZUSATZ = '1'.
endloop.
endif.
* if no error so far...
if lv_error_occured = abap_false.
* update customer fields EEW for the delivery
clear lt_return_codes.
clear lv_rejected.
lo_sp->update( EXPORTING
inrecords = lt_a_head_eew
aspect = /scdl/if_sp_c=>SC_ASP_HEAD_EEW_PRD
* OPTIONS
IMPORTING
outrecords = lt_a_head_eew_out
rejected = lv_rejected
return_codes = lt_return_codes ).
* check if any error occurred
READ TABLE lt_return_codes TRANSPORTING NO FIELDS WITH KEY failed = abap_true.
IF sy-subrc = 0 OR lv_rejected = abap_true.
lv_error_occured = abap_true.
ENDIF.
endif.
* if no error so far...
if lv_error_occured = abap_false.
* validate the delivery (also triggers determinations)
* this is an optional step. It is assumed in this example that if validation errors occur
* the delivery should not get saved.
* If also deliveries with validation errors (blocked status) should get saved,
* the error handling has to distinguish between validation errors and other errors
* validation error messages are in the message box and are not returned as REJECTED or RETURN_CODES
ls_sp_action-action_code = /scdl/if_bo_action_c=>sc_validate.
clear lt_return_codes.
clear lv_rejected.
lo_sp->execute( EXPORTING
aspect = /scdl/if_sp_c=>sc_asp_head
inkeys = lt_sp_k_head
inparam = ls_sp_action
action = /scdl/if_sp_c=>sc_act_execute_action
IMPORTING
outrecords = lt_a_head
rejected = lv_rejected
return_codes = lt_return_codes ).
* check if any error occurred
READ TABLE lt_return_codes TRANSPORTING NO FIELDS WITH KEY failed = abap_true.
IF sy-subrc = 0 OR lv_rejected = abap_true.
lv_error_occured = abap_true.
ENDIF.
endif.
* get all messages that occurred. Get the always as validation messages
* are also of interest
lt_messages = lo_message_box->get_messages( ).
* build two tables, one with validation messages and one with "real" errors
loop at lt_messages ASSIGNING <ls_messages> where consistency_message = abap_true.
append <ls_messages> to lt_validation_messages.
delete lt_messages.
endloop.
loop at lt_messages TRANSPORTING no fields where msgty ca 'EAX'.
lv_error_occured = abap_true.
exit.
endloop.
loop at lt_validation_messages TRANSPORTING no fields where msgty ca 'EAX'.
lv_validation_error_occured = abap_true.
exit.
endloop.
* now save delivery dependant on if error occurred or not.
* here validation errors are also considered. This depends on the business logic.
if lv_error_occured = abap_false and lv_validation_error_occured = abap_false.
clear lt_return_codes.
clear lv_rejected.
lo_sp->save( IMPORTING rejected = lv_rejected ).
* check if during save serious errors occurred.
IF lv_rejected = abap_true.
lv_error_occured = abap_true.
* if errors occurred then get the messages again
lt_messages = lo_message_box->get_messages( ).
ENDIF.
endif.
* now do a commit (here with wait) or rollback dependant on if errors occurred or not
if lv_error_occured = abap_false and lv_validation_error_occured = abap_false.
commit work and wait.
lo_tm->cleanup( ). "clear buffers and release locks
else.
rollback work.
lo_tm->cleanup( ). "clear buffers and release locks
endif.
* now for example, messages could be displayed
창고 세팅 부분
- GI Posting된 딜리버리는 수정하면 안됨(상태 확인 필요)
- /SCDL 서비스 프로바이더는 항상 BOPF, BO 인스턴스를 만들기에, 읽기만 할경우 다른 API 이용
- 수정기능도 제공
데이터 변경 저장하기
객체를 변경시, 저장하는 메서드를 호출함(보통 save)
한번만 호출해야함. 내부적으로 전기하는 로직이 있을 수 있기 떄문 (한 LUW에서)
적절한 메서드를 호출해야함.
딜리버리를 수정했으면 Shipping & Receiving을 저장, WT를 저장하는 메서드를 호출해야함.
에러가 발생하지 않았으면 Commit Work And Wait
Save 메서드를 통해 반영될 정보들이 커밋됨. Save 호출 안하면 변경 안됨. Commit 안해도 반영안됨
(여러 LUW를 모아 Save....)
Save 후 Cleanup( /SCWM/IF_TM. )해줘야 Lock이 풀림
딜리버리 잠금은 enqueue, dequeue 안됨. 클린업!
데이터 변경 롤백(Error LUW)
Rollback Work
Cleanup
IV_REASON = /SCMB/IF_SP_TRANSACTION=>SC_CLEANUP_END.
다음 LUW 실행
자주 불일치를 발생시키는 상황
D1바꾸고 D2(딜리버리) 바꾸다 오류남.
메세지 출력하고 화면으로 돌아감.
D3 바꾸고 저장하면 D1, D3 둘다 바뀜.
message into 아니면 Rollback, Cleanup 호출 불가(제어가 사용자에게 돌아가기 떄문)
메세지 사용하고 싶으면 메세지 컨테이너 또는 메세지 클래스 사용
D1이랑 D2 바꾸고 Commit Work 했더니 일부만 바뀜
Save 해야 함
D1이랑 D2 바꾸고 세이브 커밋한뒤....
클린업 잊지말기
세이브 여러번 실행하지 말기, 어떤 함수는 세이브를 내부에서 실행한다
업데이트 하고 CleanUp 안하면 락은 풀리지만 다른 사람 수정이 안보일 수 있다
세이브하면 커밋도 무조건 같이 해줘야함
팁
- LUW 시작 전 마다 CLEANUP(IV_REASON = END) and a ROLLBACK WORK 하기(뒤는 이전 LUW 정상 종료를 확신하지 못하면)
- LUW 안에서 LUW 만드는건 아닌지 신경쓰기
- Example: inside a BAdI implementation or modification you call a CLEANUP/SAVE or COMMIT WORK/ROLLBACK WORK).
- deliveries, HUs, warehouse tasks, and waves, for example
- 어떤 객체를 클린업할 것인지 신경쓰기
- 그냥 /SCWM/CL_TM => CLEANUP 쓰기
에러 헨들링 예제(상황에 따라)
*Exceptions in function calls:
CALL FUNCTION 'XYZ'
EXPORTING
....
IMPORTING
...
EXCEPTIONS
not_found = 1
wrong_input = 2.
"=> Handle error situation in case SY_SUBRC <> 0.
• Exceptions in method calls
TRY.
CALL METHOD ‘XYZ’
EXPORTING
...
RECEIVING
...
CATCH /scwm/cx_core .
"=> Handle exception situation here.
ENDTRY.
"Service provider calls
lo_message_box TYPE REF TO /scdl/cl_sp_message_box
(for delivery service providers only)
lo_servicepovider->update(
EXPORTING
...
IMPORTING
Outrecords = lt_outrecords
Rejected = lv_rejected
return_codes = lt_return_codes ).
"=> Handle error in case REJECTED = ‘X’ or if RETURN_CODES contains an entry where FAILED = ‘X’. Both
"cases need to be considered independent of each other.
"Details about the error reason can be retrieved from the message box. E.g.
lt_messages = lo_message_box->get_messages( ).
• Method calls with message instance
CALL METHOD lo_myclass->update
EXPORTING
...
IMPORTING
eo_message = lo_message
"=> Handle errors. LO_MESSAGE has to be checked if it contains E or A messages
• Combination of exceptions and messages
TRY.
/scwm/cl_xyz=>update(
EXPORTING
...
IMPORTING
...
eo_message = lo_message ).
CATCH /scwm/cx_error error INTO lx_error.
"=> Handle exception situation here.
ENDTRY.
"=> Handle errors. LO_MESSAGE has to be checked if it contains E or A messages
'SAP' 카테고리의 다른 글
[SAP] C_S4EWM_2023 취득 후기 (EWM Certifications Pass, 써티) (0) | 2025.04.11 |
---|---|
[EWM] Inbound Delivery Item Purchase Order 조회 방법 (0) | 2025.02.19 |
[EWM][ABAP] Canceled GI HU 조회 (0) | 2025.02.18 |
[EWM] 비즈니스 기능 구현 Basic 1편 - 스탠다드 기능 찾아가기 (0) | 2025.02.17 |
[SAP ABAP] Group By로 중복 체크하기 (0) | 2025.02.17 |