一、QM检验批UD之后,还有后悔药吗?
在QM UD之前发现错误,只要用MBST冲销原始物料凭证就可以取消检验批,然后再重新收货,重新检验,但是在QM UD之后(使用决策之后),发现原检验数据或者原收货凭证有错,必须取消或重检,就不能用MBST,怎么办呢? 一开始没弄明白,在论坛里找寻答案,却一直迷惑不解,到最后发现自己是被误导了。
在使用决策已经做出后,SAP的标准设置就只给一个QA12(更改使用决策)来处理,但在实际使用QA12时却发现,它只能改变决策代码,对库存过账已经无能为力了。意味着对最具实质性的库存过账错误,QA12是无能为力的,这就是我一直迷惑不解的地方。
后来在SAP论坛QM区,有一位给出了曲线救国的方案:先MM02, 维护检验类型08(勾上活动),然后用MB1B 344 先转到冻结库存,跟着 349 从冻结到质检库存。 但当我对新产生的检验批做新的使用决策时,发现检验库存只能退回给采购订单,无法退给生产订单! 只能解决采购收货的决策失误问题,生产收货失误问题仍是未能解决。
经过多次测试,终于得到了解决方法,对于生产收货的质量使用决策失误,处理方法是非常简单 的,完全用不到这个曲线救国的方法: 在UD之后,检验库存已完全过账到非限制库存,这时纠正库存过账错误,用 MB1B 102或122 (特别注意把那个库存类型 X 删掉,即由默认的检验库存改为非限制库存, 122会多出强制要求输入移动原因码),把相应批次的生产收货冲销掉就可以了。同时用QA12, 去改一下相应检验批的使用决策代码。如果要重新收货检验,就是再做正 常的 MB31 101 收货了。 对于非生产收货的使用决策失误,则仍可应用曲线救国的方法,也可用跟生产收货反冲相似的方法反冲过账):
- 物料主档里维护08检验类型是必要的,因为如果没有,后面就不能生成新的检验批。 而MB1B 344 (非限制到冻结)是可选的,这是为了实际中一发现出错,就先从非限制放到冻 结,以防止在处理错误的过程中,货物却被发走了的情况出现。 如果一发现错误,就用 322 (非限制到质检) 就不用 344 了。
- MB1B 349 (冻结到质检),如果用了 344 就必须用349了。 ?如果在物料主档里维护了08检 验类型,这时(322时也一样)就会产生检验批,但是默认 情况下,08类型的检验批,其对应的检验计划用途是9,所以在只维护了1或5的检验计划的情况 下,会提示质量检验未准备好。这时并不需要维护用途9的检验计划, 只需要去改一下检验批的默认检验计划用途即可。 对于QM的UD, 按常理,本来就应该谨慎而为之,因为,一旦做出完全合格的决定,由质检库存转 到了非限制库存,如果未能及时发现出错,则货物很可能被发给客户, 这样的质量成本将会很高。 但是无论如何,SAP已经考虑到了尽量多的可能性,甚至TC:BS22 都已经准备好让客户修改控制 状态,还有什么不能改的呢?(用BS22,可以让已做UD的检验批, 仍可以更改检验结果值,虽然这完全违背检验的常理)
二、取消UD方法
1、 适用业务
通常检验批作完检验结果录入后,最后一步就是做UD判断,这一步的内容主要包括两方面:选定UD代码,表示检验将作如何的判定,如A表示接受,R表示拒绝,A1表示让步接受…;另外就是做库存转移,就是将检验状态的库存移为非限制状态的库存(有的企业称为判良品)或者转为冻结库存,甚至如果是破坏性检验还要做样品消耗过账,当然有的企业还可以做物料降级使用(即309移动)。实质上QM真正和后勤其他模块集成的也就是库存转移这一步。既然有集成,往往也就很能会出现错误,比如在KEE项目上生产完工的入库检验(04),当完工报工确认(CO11N),系统自动入库,即产生相应的检验批(此时库存先入为检验状态),品管部再作检验,做后续的判定。那么此时很有可能会发生生产误报工,而到导致品管也跟着误操作,事后发现时,只能采用反冲销的方法解决。问题来了,大家都知道SAP的事务通常都有反冲销的作业,如报工取消CO13,物料凭证取消MBST…恰恰UD判定的没有提供。仔细想想,也是,UD判定本来就如包公判案一样,泼出去的水且能收回…当然无能如何,人总会有犯错的时候,估计包公也有办错案反悔的时候吧:)。
也许有人会想到直接MBST或作诸如322移动的过账,这种方法不可行,因为一旦QM质量检验激活,不可以手工作321或322的过账,会有如下图错误消息。要想这样做只能取消激活QM视图(不过如果有其他质检库存时,还不能取消激活)。汇总以上方案如下,
1)直接MBST时会有如下错误,不可行
2)也可以不通过MBST而通过MB01、MB31或MIGO直接冲销,记得库存类型的X删掉,但如果是生产自动完工入库的则没法使用,因为需使用CO13取消报工和过账.
3)直接MB1B作322时会有如下错误,
4)有一种复杂的方法,就是要先激活08的检验类型,再用344(非限制到冻结)再349(冻结到检验),不过这种方法太复杂;
综上所述,无论哪种方案虽能解决问题,但都有缺陷,不是最完美的解决方案。到SAP Notes一查,其实SAP也提供了相应的解决方案,下面就谈谈该解决方案是如何取消UD的。
2、 业务流程
流程倒是比较简单:检验结果录入→UD判定→取消UD判定
3、 举例
比如在KEE项目上生产完工的入库检验(04),当完工报工确认(CO11N),系统自动入库,即产生相应的检验批(此时库存先入为检验状态),品管部再作检验,做后续的判定。那么此时很有可能会发生生产误报工,而到导致品管也跟着误操作,事后发现时,只能采用反冲销的方法解决。
二、操作说明
根据SAP notes 74638 和175842的说明,步骤如下,
1、 notes 74638里的程序zqevac40导入系统,并激活,执行如下,
分析一下这个程序,实际上就是取消UD 代码,并给检验批设置取消状态。
2、 Notes 175842的程序RQEVAC50导入系统,并激活,执行如下,
该程序实际上就是做反冲销凭证的操作,也许有人会有疑问,不是直接MBST不可以吗,而这支程序就可以?没错SAP在程序里做了手脚,主要是下面这段程序,
SAP 在过账前将QM 检验类型激活的变量清空,过账后又加上,原来在这儿…注:这不会修改质量视图的数据!!
理论上有了上面两支程序就足以解决问题,但唯一的缺点是两支程序是分别执行的,显得不太友好和专业。需要增强一下。
3、 运用增强QEVA0008,在UD界面里增加取消UD的按钮,并调用上面两支程序,如下图,
至此,所有的功能已加好,下面我们来测试一下这个功能的效果,找一笔已经作了UD的检验批,UD取消前的状态如下,
UD取消后的状态,注意状态变化,表明是成功运行了,如下图:
三、SAP Notes 74638—取消检验批UD判定
参考SAP Notes 74638的程序ZQEVAC40
效果:
代码:
* Program Name :
* Descriptions :
* T-Code :
* Updates Tables :
* Input Parameters :
* Output Parameters :
* Return Codes :
* Special Logic :
* Includes :
************************************************************************
* Modification Log
************************************************************************
* Date Ver. Programmer Descriptions
* -------- ---- ------------ -------------------------------------------
* 2020 6.25 xxx Create
*
************************************************************************
REPORT ZQMRTEST.
***********************************************************************
* Tables Definitions
************************************************************************
*TABLES:.
************************************************************************
* Data Definitions
************************************************************************
CONSTANTS: g_flag TYPE c VALUE 'X'.
DATA: gs_qals LIKE qals,
gs_qave LIKE qave.
************************************************************************
* Includes Module
************************************************************************
************************************************************************
* Selection Screen
************************************************************************
PARAMETERS: p_qplos LIKE qals-prueflos OBLIGATORY.
************************************************************************
* Initialization
************************************************************************
INITIALIZATION.
************************************************************************
* At Selection Screen
************************************************************************
AT SELECTION-SCREEN.
PERFORM check_data.
************************************************************************
* At Selection Screen Output
************************************************************************
AT SELECTION-SCREEN OUTPUT.
************************************************************************
* Report Format
************************************************************************
TOP-OF-PAGE.
END-OF-PAGE.
************************************************************************
* Main Process
************************************************************************
START-OF-SELECTION.
PERFORM ud_to_rel.
END-OF-SELECTION.
*&---------------------------------------------------------------------*
*& Form CHECK_DATA
*&---------------------------------------------------------------------*
FORM check_data.
"检查是否存在检验批
CALL FUNCTION 'QPSE_LOT_READ'
EXPORTING
i_prueflos = p_qplos
IMPORTING
e_qals = gs_qals
EXCEPTIONS
no_lot = 1
OTHERS = 2.
IF sy-subrc NE 0.
MESSAGE e102(qa) WITH p_qplos.
ENDIF.
"检验批枷锁
CALL FUNCTION 'ENQUEUE_EQQALS1'
EXPORTING
prueflos = p_qplos
EXCEPTIONS
foreign_lock = 1
system_failure = 2
OTHERS = 3.
IF sy-subrc NE 0.
MESSAGE e007(qa) WITH '有人' p_qplos.
ENDIF.
"UD状态检查
CALL FUNCTION 'QAST_STATUS_CHECK'
EXPORTING
i_objnr = gs_qals-objnr
i_status = 'I0218'
EXCEPTIONS
status_not_activ = 1
OTHERS = 2.
IF sy-subrc NE 0.
MESSAGE e102(qv) WITH p_qplos.
ENDIF.
"检验批UD资料
CALL FUNCTION 'QEVA_UD_READ'
EXPORTING
I_PRUEFLOS = p_qplos
IMPORTING
E_QAVE = gs_qave
EXCEPTIONS
qave_not_found = 1
OTHERS = 2.
ENDFORM. "CHECK_DATA
*&---------------------------------------------------------------------*
*& Form UD_TO_REL
*&---------------------------------------------------------------------*
FORM ud_to_rel.
"REL核发状态生效
PERFORM status_change USING 'I0002' g_flag.
"STIC检验完成状态失效
PERFORM status_change USING 'I0216' space.
"ICCO已完成所有检验状态失效
PERFORM status_change USING 'I0217' space.
"UD已做出检验结果判定状态失效
PERFORM status_change USING 'I0218' space.
"值更改
CLEAR: gs_qals-stat14,gs_qals-stat35.
CLEAR: gs_qave-vauswahlmg,
gs_qave-vwerks,
gs_qave-versionam,
gs_qave-vcodegrp,
gs_qave-vcode,
gs_qave-vbewertung,
gs_qave-versioncd,
gs_qave-vfolgeakti,
gs_qave-qkennzahl.
CALL FUNCTION 'QEVA_UD_UPDATE' IN UPDATE TASK
EXPORTING
qals_new = gs_qals
qave_new = gs_qave.
IF sy-subrc = 0.
COMMIT WORK.
MESSAGE '检验批已取消UD判定' TYPE 'S'.
ELSE.
ROLLBACK WORK.
MESSAGE '检验批未做任何修改' TYPE 'E'.
ENDIF.
ENDFORM. "UD_TO_REL
*&---------------------------------------------------------------------*
*& Form STATUS_CHANGE
*&---------------------------------------------------------------------*
FORM status_change USING in_status in_flag.
DATA: lt_status LIKE TABLE OF jstat,
ls_status LIKE LINE OF lt_status.
IF gs_qals-objnr IS INITIAL.
MESSAGE e013(qv).
ENDIF.
ls_status-stat = in_status.
IF in_flag IS INITIAL.
ls_status-inact = g_flag.
ENDIF.
APPEND ls_status TO lt_status.CLEAR ls_status.
CALL FUNCTION 'STATUS_CHANGE_INTERN'
EXPORTING
objnr = gs_qals-objnr
TABLES
status = lt_status
EXCEPTIONS
object_not_found = 1
status_inconsistent = 2
status_not_allowed = 3
OTHERS = 4.
ENDFORM. "STATUS_CHANGE
QEVA0008
木叶飞舞之处,火亦生生不息
四、SAP Notes 175842—取消检验批的库存过账
参考SAP Notes 175842的程序RQEVAC50
效果:
已存货过账:
取消存货过账:
代码:
************************************************************************
* Program Name :
* Descriptions :
* T-Code :
* Updates Tables :
* Input Parameters :
* Output Parameters :
* Return Codes :
* Special Logic :
* Includes :
************************************************************************
* Modification Log
************************************************************************
* Date Ver. Programmer Descriptions
* -------- ---- ------------ -------------------------------------------
* 2020 7.3 xxx Create
*
************************************************************************
REPORT ZQMRTEST MESSAGE-ID QA.
TYPES:
T_MKPF_TAB LIKE MKPF OCCURS 0,
T_MSEG_TAB LIKE MSEG OCCURS 0.
PARAMETERS:
PRUEFLOS LIKE QALS-PRUEFLOS OBLIGATORY MEMORY ID QLS. "nspection Lot
DATA:
G_MSGV1 LIKE SY-MSGV1,
G_QALS LIKE QALS,
G_QALS_LEISTE LIKE QALS,
G_QAMB_TAB TYPE QAMBTAB,
G_QAMB_VB_TAB TYPE QAMBTAB,
G_MKPF_TAB TYPE T_MKPF_TAB,
G_MSEG_TAB TYPE T_MSEG_TAB,
G_SUBRC LIKE SY-SUBRC.
START-OF-SELECTION.
PERFORM ENQUEUE_QALS USING PRUEFLOS
G_SUBRC.
IF NOT G_SUBRC IS INITIAL.
MESSAGE ID SY-MSGID TYPE 'S' NUMBER SY-MSGNO
WITH SY-MSGV1 SY-MSGV2 SY-MSGV3 SY-MSGV4.
SUBMIT (SY-REPID) VIA SELECTION-SCREEN.
ENDIF.
PERFORM READ_QALS USING PRUEFLOS
G_QALS
G_QALS_LEISTE
G_SUBRC.
IF NOT G_SUBRC IS INITIAL.
MESSAGE ID 'QA' TYPE 'S' NUMBER '102'
WITH PRUEFLOS.
SUBMIT (SY-REPID) VIA SELECTION-SCREEN.
ENDIF.
PERFORM CHECK_LOT USING G_QALS
G_SUBRC.
IF NOT G_SUBRC IS INITIAL.
CASE G_SUBRC.
WHEN 256.
G_MSGV1 = 'Lot & does not refer to a material doc'.
WHEN 128.
G_MSGV1 = 'Material & is serialized'.
REPLACE '&' WITH G_QALS-MATNR INTO G_MSGV1.
WHEN 64.
G_MSGV1 = 'Lot & is not stock relevant'.
WHEN 32.
G_MSGV1 = 'Lot &: No stock transferred'.
WHEN 16.
G_MSGV1 = 'Lot & is cancelled'.
WHEN 8.
G_MSGV1 = 'Lot & is archived'.
WHEN 4.
G_MSGV1 = 'Lot & is blocked'.
WHEN 2.
G_MSGV1 = 'Lot & is HU managed'.
ENDCASE.
REPLACE '&' WITH PRUEFLOS INTO G_MSGV1.
MESSAGE ID '00' TYPE 'S' NUMBER '208'
WITH G_MSGV1.
SUBMIT (SY-REPID) VIA SELECTION-SCREEN.
ENDIF.
PERFORM READ_QAMB USING G_QALS
G_QAMB_TAB
G_SUBRC.
IF NOT G_SUBRC IS INITIAL.
MESSAGE ID 'QA' TYPE 'S' NUMBER '068'
WITH PRUEFLOS.
SUBMIT (SY-REPID) VIA SELECTION-SCREEN.
ENDIF.
PERFORM READ_MKPF USING G_QAMB_TAB
G_MKPF_TAB
G_SUBRC.
IF NOT G_SUBRC IS INITIAL.
MESSAGE ID SY-MSGID TYPE 'S' NUMBER SY-MSGNO
WITH SY-MSGV1 SY-MSGV2 SY-MSGV3 SY-MSGV4.
SUBMIT (SY-REPID) VIA SELECTION-SCREEN.
ENDIF.
PERFORM CHECK_MKPF USING G_MKPF_TAB
G_SUBRC.
IF NOT G_SUBRC IS INITIAL.
MESSAGE ID 'QA' TYPE 'S' NUMBER '068'
WITH PRUEFLOS.
SUBMIT (SY-REPID) VIA SELECTION-SCREEN.
ENDIF.
PERFORM READ_MSEG USING G_MKPF_TAB
G_MSEG_TAB
G_SUBRC.
IF NOT G_SUBRC IS INITIAL.
MESSAGE ID SY-MSGID TYPE 'S' NUMBER SY-MSGNO
WITH SY-MSGV1 SY-MSGV2 SY-MSGV3 SY-MSGV4.
SUBMIT (SY-REPID) VIA SELECTION-SCREEN.
ENDIF.
PERFORM CHECK_MSEG USING G_MSEG_TAB
G_QAMB_TAB
G_SUBRC.
IF NOT G_SUBRC IS INITIAL.
MESSAGE ID 'QA' TYPE 'S' NUMBER '068'
WITH PRUEFLOS.
SUBMIT (SY-REPID) VIA SELECTION-SCREEN.
ENDIF.
PERFORM CREATE_GOODS_MOVEMENT USING G_QALS
G_MSEG_TAB
G_SUBRC.
IF NOT G_SUBRC IS INITIAL.
MESSAGE ID 'QA' TYPE 'S' NUMBER '068'
WITH PRUEFLOS.
SUBMIT (SY-REPID) VIA SELECTION-SCREEN.
ENDIF.
PERFORM POST_GOODS_MOVEMENT.
PERFORM POST_DATA USING G_QALS
G_QALS_LEISTE
G_QAMB_TAB
G_QAMB_VB_TAB
G_SUBRC.
IF NOT G_SUBRC IS INITIAL.
MESSAGE ID SY-MSGID TYPE 'S' NUMBER SY-MSGNO
WITH SY-MSGV1 SY-MSGV2 SY-MSGV3 SY-MSGV4.
SUBMIT (SY-REPID) VIA SELECTION-SCREEN.
ELSE.
COMMIT WORK AND WAIT.
G_MSGV1 = 'inspection lot &'.
REPLACE '&' WITH PRUEFLOS INTO G_MSGV1.
MESSAGE ID '00' TYPE 'S' NUMBER '368'
WITH 'Stock posting reversed for ' G_MSGV1.
SUBMIT (SY-REPID) VIA SELECTION-SCREEN.
ENDIF.
*----------------------------------------------------------------------*
* Form ENQUEUE_QALS *
*----------------------------------------------------------------------*
* Los sperren *
*----------------------------------------------------------------------*
FORM ENQUEUE_QALS USING P_PRUEFLOS LIKE QALS-PRUEFLOS
P_SUBRC LIKE SY-SUBRC.
CLEAR: P_SUBRC.
CALL FUNCTION 'ENQUEUE_EQQALS1'
EXPORTING
PRUEFLOS = P_PRUEFLOS
EXCEPTIONS
FOREIGN_LOCK = 1
SYSTEM_FAILURE = 2
OTHERS = 3.
P_SUBRC = SY-SUBRC.
ENDFORM. " ENQUEUE_QALS
*----------------------------------------------------------------------*
* Form READ_QALS *
*----------------------------------------------------------------------*
* Pr邦flos lesen *
*----------------------------------------------------------------------*
FORM READ_QALS USING P_PRUEFLOS LIKE QALS-PRUEFLOS
P_QALS LIKE QALS
P_QALS_LEISTE LIKE QALS
P_SUBRC LIKE SY-SUBRC.
CLEAR: P_SUBRC.
CALL FUNCTION 'QPSE_LOT_READ'
EXPORTING
I_PRUEFLOS = P_PRUEFLOS
I_RESET_LOT = 'X'
IMPORTING
E_QALS = P_QALS
EXCEPTIONS
NO_LOT = 1.
P_SUBRC = SY-SUBRC.
IF P_SUBRC IS INITIAL.
P_QALS_LEISTE = P_QALS.
ELSE.
CLEAR: P_QALS,
P_QALS_LEISTE.
ENDIF.
ENDFORM. " READ_QALS
*----------------------------------------------------------------------*
* Form CHECK_LOT *
*----------------------------------------------------------------------*
* Pr邦flos pr邦fen *
*----------------------------------------------------------------------*
FORM CHECK_LOT USING P_QALS LIKE QALS
P_SUBRC LIKE SY-SUBRC.
DATA:
L_STAT LIKE JSTAT,
L_STAT_TAB LIKE JSTAT OCCURS 0 WITH HEADER LINE.
P_SUBRC = 256.
*/No reference to material document
IF P_QALS-ZEILE IS INITIAL.
EXIT.
ELSE.
P_SUBRC = 128.
ENDIF.
*/Serialized Material
IF NOT P_QALS-SERNP IS INITIAL.
EXIT.
ELSE.
P_SUBRC = 64.
ENDIF.
*/BERF
CALL FUNCTION 'STATUS_CHECK'
EXPORTING
OBJNR = P_QALS-OBJNR
STATUS = 'I0203'
EXCEPTIONS
STATUS_NOT_ACTIVE = 2.
IF NOT SY-SUBRC IS INITIAL.
EXIT.
ELSE.
P_SUBRC = 32.
ENDIF.
*/BTEI & BEND
CLEAR L_STAT. CLEAR L_STAT_TAB. REFRESH L_STAT_TAB.
L_STAT-STAT = 'I0219'. APPEND L_STAT TO L_STAT_TAB. "BTEI
L_STAT-STAT = 'I0220'. APPEND L_STAT TO L_STAT_TAB. "BEND
CALL FUNCTION 'STATUS_OBJECT_CHECK_MULTI'
EXPORTING
OBJNR = P_QALS-OBJNR
TABLES
STATUS_CHECK = L_STAT_TAB.
IF L_STAT_TAB[] IS INITIAL.
EXIT.
ELSE.
P_SUBRC = 16.
ENDIF.
*/LSTO & LSTV
CLEAR L_STAT. CLEAR L_STAT_TAB. REFRESH L_STAT_TAB.
L_STAT-STAT = 'I0224'. APPEND L_STAT TO L_STAT_TAB. "LSTO
L_STAT-STAT = 'I0232'. APPEND L_STAT TO L_STAT_TAB. "LSTV
CALL FUNCTION 'STATUS_OBJECT_CHECK_MULTI'
EXPORTING
OBJNR = P_QALS-OBJNR
TABLES
STATUS_CHECK = L_STAT_TAB.
IF NOT L_STAT_TAB[] IS INITIAL.
EXIT.
ELSE.
P_SUBRC = 8.
ENDIF.
*/ARSP & ARCH & REO1 & REO2 & REO3
CLEAR L_STAT. CLEAR L_STAT_TAB. REFRESH L_STAT_TAB.
L_STAT-STAT = 'I0225'. APPEND L_STAT TO L_STAT_TAB. "ARSP
L_STAT-STAT = 'I0226'. APPEND L_STAT TO L_STAT_TAB. "ARCH
L_STAT-STAT = 'I0227'. APPEND L_STAT TO L_STAT_TAB. "REO3
L_STAT-STAT = 'I0228'. APPEND L_STAT TO L_STAT_TAB. "REO2
L_STAT-STAT = 'I0229'. APPEND L_STAT TO L_STAT_TAB. "REO1
CALL FUNCTION 'STATUS_OBJECT_CHECK_MULTI'
EXPORTING
OBJNR = P_QALS-OBJNR
TABLES
STATUS_CHECK = L_STAT_TAB.
IF NOT L_STAT_TAB[] IS INITIAL.
EXIT.
ELSE.
P_SUBRC = 4.
ENDIF.
*/SPER
CALL FUNCTION 'STATUS_CHECK'
EXPORTING
OBJNR = P_QALS-OBJNR
STATUS = 'I0043'
EXCEPTIONS
STATUS_NOT_ACTIVE = 2.
IF SY-SUBRC IS INITIAL.
EXIT.
ELSE.
P_SUBRC = 2.
ENDIF.
*/HUM
CALL FUNCTION 'STATUS_CHECK'
EXPORTING
OBJNR = P_QALS-OBJNR
STATUS = 'I0443'
EXCEPTIONS
STATUS_NOT_ACTIVE = 2.
IF SY-SUBRC IS INITIAL.
EXIT.
ELSE.
P_SUBRC = 0.
ENDIF.
ENDFORM. " CHECK_LOT
*----------------------------------------------------------------------*
* Form READ_QAMB *
*----------------------------------------------------------------------*
* QAMBs lesen *
*----------------------------------------------------------------------*
FORM READ_QAMB USING P_QALS LIKE QALS
P_QAMB_TAB TYPE QAMBTAB
P_SUBRC LIKE SY-SUBRC.
CLEAR: P_SUBRC.
SELECT * FROM QAMB INTO TABLE P_QAMB_TAB
WHERE PRUEFLOS = P_QALS-PRUEFLOS
AND TYP = '3'.
P_SUBRC = SY-SUBRC.
ENDFORM. " READ_QAMB
*----------------------------------------------------------------------*
* Form READ_MKPF *
*----------------------------------------------------------------------*
* Read material document header *
*----------------------------------------------------------------------*
FORM READ_MKPF USING P_QAMB_TAB TYPE QAMBTAB
P_MKPF_TAB TYPE T_MKPF_TAB
P_SUBRC LIKE SY-SUBRC.
DATA:
BEGIN OF L_MKPF_KEY_TAB OCCURS 0,
MBLNR LIKE MKPF-MBLNR,
MJAHR LIKE MKPF-MJAHR,
END OF L_MKPF_KEY_TAB.
DATA:
L_QAMB LIKE QAMB,
L_MKPF LIKE MKPF,
L_TRTYP LIKE T158-TRTYP VALUE 'A',
L_VGART LIKE T158-VGART VALUE 'WQ',
L_XEXIT LIKE QM00-QKZ.
P_SUBRC = 4.
LOOP AT P_QAMB_TAB INTO L_QAMB.
L_MKPF_KEY_TAB-MBLNR = L_QAMB-MBLNR.
L_MKPF_KEY_TAB-MJAHR = L_QAMB-MJAHR.
COLLECT L_MKPF_KEY_TAB.
ENDLOOP.
LOOP AT L_MKPF_KEY_TAB.
CALL FUNCTION 'ENQUEUE_EMMKPF'
EXPORTING
MBLNR = L_MKPF_KEY_TAB-MBLNR
MJAHR = L_MKPF_KEY_TAB-MJAHR
EXCEPTIONS
FOREIGN_LOCK = 1
SYSTEM_FAILURE = 2
OTHERS = 3.
IF NOT SY-SUBRC IS INITIAL.
L_XEXIT = 'X'.
EXIT.
ENDIF.
CLEAR: L_MKPF.
CALL FUNCTION 'MB_READ_MATERIAL_HEADER'
EXPORTING
MBLNR = L_MKPF_KEY_TAB-MBLNR
MJAHR = L_MKPF_KEY_TAB-MJAHR
TRTYP = L_TRTYP
VGART = L_VGART
IMPORTING
KOPF = L_MKPF
EXCEPTIONS
ERROR_MESSAGE = 1.
IF NOT SY-SUBRC IS INITIAL.
L_XEXIT = 'X'.
EXIT.
ELSE.
APPEND L_MKPF TO P_MKPF_TAB.
ENDIF.
ENDLOOP.
IF NOT L_XEXIT IS INITIAL.
EXIT.
ELSE.
P_SUBRC = 0.
ENDIF.
ENDFORM. " READ_MKPF
*----------------------------------------------------------------------*
* Form READ_MSEG *
*----------------------------------------------------------------------*
* MSEGs lesen *
*----------------------------------------------------------------------*
FORM READ_MSEG USING P_MKPF_TAB TYPE T_MKPF_TAB
P_MSEG_TAB TYPE T_MSEG_TAB
P_SUBRC LIKE SY-SUBRC.
DATA:
L_MKPF LIKE MKPF,
L_MSEG_TAB LIKE MSEG OCCURS 0 WITH HEADER LINE,
L_TRTYP LIKE T158-TRTYP VALUE 'A',
L_XEXIT LIKE QM00-QKZ.
P_SUBRC = 4.
LOOP AT P_MKPF_TAB INTO L_MKPF.
CLEAR: L_MSEG_TAB. REFRESH: L_MSEG_TAB.
CALL FUNCTION 'MB_READ_MATERIAL_POSITION'
EXPORTING
MBLNR = L_MKPF-MBLNR
MJAHR = L_MKPF-MJAHR
TRTYP = L_TRTYP
*/ ZEILB = P_ZEILE
*/ ZEILE = P_ZEILE
TABLES
SEQTAB = L_MSEG_TAB
EXCEPTIONS
ERROR_MESSAGE = 1.
IF NOT SY-SUBRC IS INITIAL.
L_XEXIT = 'X'.
EXIT.
ELSE.
APPEND LINES OF L_MSEG_TAB TO P_MSEG_TAB.
ENDIF.
ENDLOOP.
IF NOT L_XEXIT IS INITIAL.
EXIT.
ELSE.
*/ XAuto-Zeilen und Chargenzustands#nderung werden gel#scht
DELETE P_MSEG_TAB WHERE XAUTO NE SPACE
OR BWART EQ '341'
OR BWART EQ '342'.
P_SUBRC = 0.
ENDIF.
ENDFORM. " READ_MSEG
*----------------------------------------------------------------------*
* Form CREATE_GOODS_MOVEMENT *
*----------------------------------------------------------------------*
* Warenbewegung anlegen *
*----------------------------------------------------------------------*
FORM CREATE_GOODS_MOVEMENT USING P_QALS LIKE QALS
P_MSEG_TAB TYPE T_MSEG_TAB
P_SUBRC LIKE SY-SUBRC.
DATA:
L_LMENGEZUB LIKE QALS-LMENGEZUB,
L_LMENGEGEB LIKE QALS-LMENGEZUB,
L_MBQSS LIKE MBQSS,
L_IMKPF LIKE IMKPF,
L_IMSEG LIKE IMSEG,
L_IMSEG_TAB LIKE IMSEG OCCURS 1,
L_EMKPF LIKE EMKPF,
L_EMSEG LIKE EMSEG,
L_EMSEG_TAB LIKE EMSEG OCCURS 1,
L_MSEG LIKE MSEG,
L_MSEG_TAB LIKE MSEG OCCURS 1,
L_TCODE LIKE SY-TCODE VALUE 'QA11',
L_TABIX LIKE SY-TABIX VALUE 1,
L_XSTBW LIKE T156-XSTBW.
CLEAR: P_SUBRC.
*/QAMB initialisieren
CALL FUNCTION 'QAMB_REFRESH_DATA'.
*/Kopf f邦llen
L_IMKPF-BLDAT = SY-DATLO.
L_IMKPF-BUDAT = SY-DATLO.
L_IMKPF-BKTXT = 'Cancellation of QM UD postings'.
*/Urspr邦ngliche zu buchende Menge merken + inkrementieren
L_LMENGEZUB = P_QALS-LMENGEZUB.
L_LMENGEGEB = P_QALS-LMENGE01
+ P_QALS-LMENGE02
+ P_QALS-LMENGE03
+ P_QALS-LMENGE04
+ P_QALS-LMENGE05
+ P_QALS-LMENGE06
+ P_QALS-LMENGE07
+ P_QALS-LMENGE08
+ P_QALS-LMENGE09.
*/Zeilen aufbauen
L_MSEG_TAB[] = P_MSEG_TAB[].
LOOP AT L_MSEG_TAB INTO L_MSEG.
MOVE-CORRESPONDING L_MSEG TO L_MBQSS.
MOVE-CORRESPONDING L_MBQSS TO L_IMSEG.
*/ Referenzbeleg 邦bergeben, falls Bestellnummer gef邦llt
IF NOT L_MSEG-EBELN IS INITIAL.
MOVE: L_MSEG-LFBNR TO L_IMSEG-LFBNR,
L_MSEG-LFBJA TO L_IMSEG-LFBJA,
L_MSEG-LFPOS TO L_IMSEG-LFPOS.
ENDIF.
MOVE L_MSEG-KDAUF TO L_IMSEG-KDAUF.
MOVE L_MSEG-KDPOS TO L_IMSEG-KDPOS.
MOVE L_MSEG-PS_PSP_PNR TO L_IMSEG-PS_PSP_PNR.
*/ Umlagerungsfelder setzen
MOVE:
L_MSEG-UMMAT TO L_IMSEG-UMMAT,
L_MSEG-UMWRK TO L_IMSEG-UMWRK,
L_MSEG-UMLGO TO L_IMSEG-UMLGO,
L_MSEG-UMCHA TO L_IMSEG-UMCHA.
*/ Storno-Beleg setzen
MOVE: L_MSEG-MJAHR TO L_IMSEG-SJAHR,
L_MSEG-MBLNR TO L_IMSEG-SMBLN,
L_MSEG-ZEILE TO L_IMSEG-SMBLP.
*/ Falsch gef邦llte Felder initialisieren
CLEAR: L_IMSEG-MBLNR,
L_IMSEG-MENGE,
L_IMSEG-MEINS.
*/ Bewegungsart lesen
SELECT SINGLE XSTBW FROM T156 INTO L_XSTBW
WHERE BWART = L_IMSEG-BWART.
IF NOT SY-SUBRC IS INITIAL.
P_SUBRC = 4.
EXIT.
ENDIF.
*/ Werk/Lagerort f邦llen
IF P_QALS-STAT11 IS INITIAL.
IF L_XSTBW IS INITIAL.
MOVE P_QALS-LAGORTVORG TO L_IMSEG-LGORT.
ELSE.
MOVE P_QALS-LAGORTVORG TO L_IMSEG-UMLGO.
ENDIF.
ENDIF.
IF L_XSTBW IS INITIAL.
MOVE P_QALS-WERKVORG TO L_IMSEG-WERKS.
ELSE.
MOVE P_QALS-WERKVORG TO L_IMSEG-UMWRK.
ENDIF.
*/ Zus#tzliche Felder
MOVE P_QALS-MENGENEINH TO L_IMSEG-ERFME.
"MOVE P_GRUND TO L_IMSEG-GRUND.
"MOVE P_ELIKZ TO L_IMSEG-ELIKZ.
*/ Kennzeichen Storno-Buchung setzen
MOVE 'X' TO L_IMSEG-XSTOB.
MOVE P_QALS-PRUEFLOS TO L_IMSEG-QPLOS.
APPEND L_IMSEG TO L_IMSEG_TAB.
IF P_QALS-STAT11 IS INITIAL.
ADD L_IMSEG-ERFMG TO L_LMENGEZUB.
SUBTRACT L_IMSEG-ERFMG FROM L_LMENGEGEB.
ELSE.
IF L_IMSEG-KZBEW EQ SPACE
AND L_IMSEG-WERKS NE SPACE
AND L_IMSEG-LGORT NE SPACE
AND L_IMSEG-UMWRK NE SPACE
AND L_IMSEG-UMLGO NE SPACE
AND L_IMSEG-WERKS EQ L_IMSEG-UMWRK
AND L_IMSEG-UMLGO EQ L_IMSEG-UMLGO.
*/ Dummy Buchung bei WE-Sperrbestand & Stichprobe
ELSE.
ADD L_IMSEG-ERFMG TO L_LMENGEZUB.
SUBTRACT L_IMSEG-ERFMG FROM L_LMENGEGEB.
ENDIF.
ENDIF.
ENDLOOP.
IF NOT P_QALS-STAT11 IS INITIAL.
*/ Bei WE-Sperrbestand und Stichprobenbuchung Zeilen tauschen
DO.
READ TABLE L_IMSEG_TAB INDEX SY-INDEX INTO L_IMSEG.
IF SY-SUBRC IS INITIAL
AND L_IMSEG-KZBEW EQ SPACE
AND L_IMSEG-WERKS NE SPACE
AND L_IMSEG-LGORT NE SPACE
AND L_IMSEG-UMWRK NE SPACE
AND L_IMSEG-UMLGO NE SPACE
AND L_IMSEG-WERKS EQ L_IMSEG-UMWRK
AND L_IMSEG-UMLGO EQ L_IMSEG-UMLGO.
IF SY-TABIX NE L_TABIX.
DELETE L_IMSEG_TAB INDEX SY-TABIX.
INSERT L_IMSEG INTO L_IMSEG_TAB INDEX L_TABIX.
L_TABIX = L_TABIX + 1.
ELSE.
L_TABIX = L_TABIX + 1.
CONTINUE.
ENDIF.
ELSEIF SY-SUBRC IS INITIAL.
CONTINUE.
ELSE.
EXIT. "from do
ENDIF.
ENDDO.
ENDIF.
*/QM deaktivieren
CALL FUNCTION 'QAAT_QM_ACTIVE_INACTIVE'
EXPORTING
AKTIV = SPACE.
*/Buchen
CALL FUNCTION 'MB_CREATE_GOODS_MOVEMENT'
EXPORTING
IMKPF = L_IMKPF "L_IMKPF-BUDAT可修改过账日期
XALLP = 'X'
XALLR = 'X'
CTCOD = L_TCODE
XQMCL = ' '
IMPORTING
EMKPF = L_EMKPF
TABLES
IMSEG = L_IMSEG_TAB
EMSEG = L_EMSEG_TAB.
*/QM wieder aktivieren
CALL FUNCTION 'QAAT_QM_ACTIVE_INACTIVE'
EXPORTING
AKTIV = 'X'.
*/Buchung auswerten
IF L_EMKPF-SUBRC GT 1.
IF L_EMKPF-MSGID NE SPACE.
*/ Fehler auf Kopfebene
MESSAGE ID L_EMKPF-MSGID TYPE 'S'
NUMBER L_EMKPF-MSGNO
WITH L_EMKPF-MSGV1 L_EMKPF-MSGV2
L_EMKPF-MSGV3 L_EMKPF-MSGV4.
SUBMIT (SY-REPID) VIA SELECTION-SCREEN.
ELSE.
*/ Fehler auf Zeilenebene (Ausgabe des ersten Fehlers)
LOOP AT L_EMSEG_TAB INTO L_EMSEG.
IF L_EMSEG-MSGID NE SPACE.
MESSAGE ID L_EMSEG-MSGID TYPE 'S'
NUMBER L_EMSEG-MSGNO
WITH L_EMSEG-MSGV1 L_EMSEG-MSGV2
L_EMSEG-MSGV3 L_EMSEG-MSGV4.
SUBMIT (SY-REPID) VIA SELECTION-SCREEN.
ENDIF.
ENDLOOP.
ENDIF.
ENDIF.
LOOP AT L_EMSEG_TAB INTO L_EMSEG.
CALL FUNCTION 'QAMB_COLLECT_RECORD'
EXPORTING
LOTNUMBER = P_QALS-PRUEFLOS
DOCYEAR = L_EMKPF-MJAHR
DOCNUMBER = L_EMKPF-MBLNR
DOCPOSITION = L_EMSEG-MBLPO
TYPE = '7'.
ENDLOOP.
*/Sonderkorrektur f邦r Frei-An-Frei & WE-Sperr-An-We-Sperr
IF NOT P_QALS-STAT11 IS INITIAL.
IF P_QALS-LMENGE04 EQ L_LMENGEGEB.
ADD P_QALS-LMENGE04 TO L_LMENGEZUB.
SUBTRACT P_QALS-LMENGE04 FROM L_LMENGEGEB.
ENDIF.
ELSEIF P_QALS-INSMK IS INITIAL.
IF P_QALS-LMENGE01 GE L_LMENGEGEB
AND NOT P_QALS-LMENGE01 IS INITIAL.
ADD L_LMENGEGEB TO L_LMENGEZUB.
SUBTRACT L_LMENGEGEB FROM L_LMENGEGEB.
ENDIF.
ENDIF.
CLEAR: P_QALS-STAT34,
P_QALS-MATNRNEU,
P_QALS-CHARGNEU,
P_QALS-LMENGE01,
P_QALS-LMENGE02,
P_QALS-LMENGE03,
P_QALS-LMENGE04,
P_QALS-LMENGE05,
P_QALS-LMENGE06,
P_QALS-LMENGE07,
P_QALS-LMENGE08,
P_QALS-LMENGE09.
P_QALS-LMENGEZUB = L_LMENGEZUB.
IF NOT L_LMENGEGEB IS INITIAL.
P_SUBRC = 4.
ENDIF.
ENDFORM. " CREATE_GOODS_MOVEMENT
*----------------------------------------------------------------------*
* Form POST_GOODS_MOVEMENT *
*----------------------------------------------------------------------*
* Warenbewegung buchen *
*----------------------------------------------------------------------*
FORM POST_GOODS_MOVEMENT.
CALL FUNCTION 'MB_POST_GOODS_MOVEMENT'.
ENDFORM. " POST_GOODS_MOVEMENT
*----------------------------------------------------------------------*
* Form POST_DATA *
*----------------------------------------------------------------------*
* QM-Daten verbuchen *
*----------------------------------------------------------------------*
FORM POST_DATA USING P_QALS LIKE QALS
P_QALS_LEISTE LIKE QALS
P_QAMB_TAB TYPE QAMBTAB
P_QAMB_VB_TAB TYPE QAMBTAB
P_SUBRC LIKE SY-SUBRC.
DATA:
L_STAT LIKE JSTAT,
L_STAT_TAB LIKE JSTAT OCCURS 0,
L_QAMB LIKE QAMB,
L_UPDKZ LIKE QALSVB-UPSL VALUE 'U'.
*/QAMBs umsetzen (7 = VE-Buchung storniert)
LOOP AT P_QAMB_TAB INTO L_QAMB.
L_QAMB-TYP = '7'.
APPEND L_QAMB TO P_QAMB_VB_TAB.
ENDLOOP.
*/BERF & BTEI zur邦cknehmen
CLEAR L_STAT. CLEAR L_STAT_TAB.
L_STAT-INACT = 'X'.
L_STAT-STAT = 'I0219'. APPEND L_STAT TO L_STAT_TAB. "BTEI
L_STAT-STAT = 'I0220'. APPEND L_STAT TO L_STAT_TAB. "BEND
CALL FUNCTION 'STATUS_CHANGE_INTERN'
EXPORTING
OBJNR = P_QALS-OBJNR
TABLES
STATUS = L_STAT_TAB
EXCEPTIONS
ERROR_MESSAGE = 1.
IF SY-SUBRC <> 0.
MESSAGE ID SY-MSGID TYPE 'S' NUMBER SY-MSGNO
WITH SY-MSGV1 SY-MSGV2 SY-MSGV3 SY-MSGV4.
SUBMIT (SY-REPID) VIA SELECTION-SCREEN.
ENDIF.
*/Pr邦flos aktualisieren
CALL FUNCTION 'QPL1_UPDATE_MEMORY'
EXPORTING
I_QALS = P_QALS
I_UPDKZ = L_UPDKZ.
CALL FUNCTION 'QPL1_INSPECTION_LOTS_POSTING'
EXPORTING
I_MODE = '1'.
CALL FUNCTION 'STATUS_UPDATE_ON_COMMIT'.
*/QAMB initialisieren
CALL FUNCTION 'QAMB_REFRESH_DATA'.
PERFORM UPDATE_QAMB ON COMMIT.
P_SUBRC = 0.
ENDFORM. " POST_DATA
*----------------------------------------------------------------------*
* Form UPDATE_QAMB *
*----------------------------------------------------------------------*
* Update auf QAMB *
*----------------------------------------------------------------------*
FORM UPDATE_QAMB.
CALL FUNCTION 'QEVA_QAMB_CANCEL' IN UPDATE TASK
EXPORTING
T_QAMB_TAB = G_QAMB_VB_TAB.
ENDFORM. " UPDATE_QAMB
*----------------------------------------------------------------------*
* Form CHECK_MSEG *
*----------------------------------------------------------------------*
* MSEGs pr邦fen *
*----------------------------------------------------------------------*
FORM CHECK_MSEG USING P_MSEG_TAB TYPE T_MSEG_TAB
P_QAMB_TAB TYPE QAMBTAB
P_SUBRC LIKE SY-SUBRC.
DATA:
L_MSEG_STOR_TAB LIKE MSEG OCCURS 0 WITH HEADER LINE.
CLEAR: P_SUBRC.
*/Zeilen bereits storniert?
SELECT MBLNR MJAHR ZEILE SMBLN SJAHR SMBLP
FROM MSEG INTO CORRESPONDING FIELDS OF TABLE L_MSEG_STOR_TAB
FOR ALL ENTRIES IN P_MSEG_TAB
WHERE SMBLN EQ P_MSEG_TAB-MBLNR
AND SJAHR EQ P_MSEG_TAB-MJAHR
AND SMBLP EQ P_MSEG_TAB-ZEILE.
IF SY-SUBRC IS INITIAL.
LOOP AT L_MSEG_STOR_TAB.
DELETE P_MSEG_TAB WHERE MBLNR = L_MSEG_STOR_TAB-SMBLN
AND MJAHR = L_MSEG_STOR_TAB-SJAHR
AND ZEILE = L_MSEG_STOR_TAB-SMBLP.
DELETE P_QAMB_TAB WHERE MBLNR = L_MSEG_STOR_TAB-SMBLN
AND MJAHR = L_MSEG_STOR_TAB-SJAHR
AND ZEILE = L_MSEG_STOR_TAB-SMBLP.
ENDLOOP.
IF P_MSEG_TAB[] IS INITIAL.
P_SUBRC = 4.
EXIT.
ENDIF.
ENDIF.
ENDFORM. " CHECK_MSEG
*----------------------------------------------------------------------*
* Form CHECK_MKPF *
*----------------------------------------------------------------------*
* Materialbelege pr邦fen (Wurde durch VE-Buchung Pr邦fllos erzeugt?*
*----------------------------------------------------------------------*
FORM CHECK_MKPF USING P_MKPF_TAB TYPE T_MKPF_TAB
P_SUBRC LIKE SY-SUBRC.
DATA:
L_MKPF_TAB TYPE T_MKPF_TAB.
CLEAR: P_SUBRC.
SELECT MBLNR FROM QAMB INTO CORRESPONDING FIELDS OF TABLE L_MKPF_TAB
FOR ALL ENTRIES IN P_MKPF_TAB
WHERE MBLNR EQ P_MKPF_TAB-MBLNR
AND MJAHR EQ P_MKPF_TAB-MJAHR
AND TYP = '1'.
IF SY-SUBRC IS INITIAL.
P_SUBRC = 4.
ENDIF.
ENDFORM. " CHECK_MKPF