当前位置:   article > 正文

SAP 银企直连基本开发过程及常用增强总结

sap 银企直连基本开发过程及常用增强总结

一、银企直连介绍
银企直联是一种新的网上银行系统与企业的财务软件系统在线直接联接的接入方式。银企直联通过因特网或专线连接方式,实现了银行和企业计算机系统的有机融合和平滑对接。企业通过财务系统的界面就可直接完成对银行账户以及资金的管理和调度,进行信息查询、转账支付等各项业务操作。同时,银企直联可以为企业在财务系统中开发和定制个性化功能提供支持,具有信息同步、高效简便、个性服务和安全可靠的鲜明特色。银企直联能够做到与企业计算机系统的对接,方便的完成企业系统的与银行有关的交易。

SAP银企直连一般有两种:自开发和EPIC
共同点:
A、通过事物代码SM59配置RFC端口与银行前置机的连接,
B、相同的通信过程:

(1)SAP服务器向前置机发送报文

(2)前置机将报文发送至银行服务器

(3)银行服务器响应收到的请求报文,返回响应报文

(4)前置机收到响应报文后发送给sap服务器,SAP服务器解析报文

不同银行sap与前置机交互步骤不同,大部分只有以上四个步骤,有部分银行会有签到或加密的过程,该操作一般在前置机完成。

1、EPIC介绍
SAP银行企业直连,英文全称:Electronic Payment Integration(For China),简称EPIC,是SAP中国为本地化的需求开发的一款产品,以银企直连为支撑,主要解决了三个主要的业务问题:付款,收款,对账。事务代码为EPIC_PROC;付款主要 围绕应付账款的支付处理以及银行账户间调拨的处理,一般可用来管理对公付款,对私付款以及内部公司之间或者本公司间的头寸调拨。收款部主要以银行回单为处 理对象,可用来处理应收账款的清帐以及代扣代缴业务的过账处理。对账部分以银行对账单为处理对象,涉及到了对账单管理以及银企对账的处理。而银企直连指的 是通过网络,直接将ERP系统与银行的系统连接起来,这样整个数据的处理中可以做到不落地,有效提高处理效率,避免人工引起的差错,同时可以使得一些关键 的业务数据在系统中得到及时的体现。
操作界面:

2、 基本配置
基本配置步骤
1>首先激活银企直联业务功能;
2>Sap业务配置,银企直联对业务顾问的要求很高,配置繁琐,业务顾问会提供详尽的配置文档;
3>银行前置机安装(前置机IP地址要确定,且为静态IP),银行测试环境,银行接口等材料获取
4>Sap与前置机建立连接,sm59
5>开发平台为:EPIC_PROC,所有的开发都是在这个tcode下进行的
6>开发点为:epic_proc环境—>更改定制—>电子支付集成定义银行通信详细信息—>实施类
7>功能:付款(批量支付,单笔支付,代发工资),余额查询,交易明细查询,银行回单获取,付款结果查询,工资代发结果查询

详细配置说明
1>通信类型配置:Tcode:epic_proc环境—>更改定制—>电子支付集成

2>定义详细通信信息

对话框参数结构为对话框输入结构,次数示例为回单,回单对话框参数为系统标准格式,其他查询类配置对话框参数结构可以自定义
输出结构参数为报文输出结构,回单类型为系统标准结构,其他查询类型接口可以自定义输出结果参数。

3>定义银行通信步骤(部分银行需要)
遇特殊银行(如浦发银行、上海银行、杭州银行)一次业务通信会与前置机两个服务器通信;或者是需要手动发送至前置机签名,再将签名结果发送至银行,就需要定义通信步骤。其SM59也需要配置两个连接

4>SM59配置
SM59事物代码下,创建‘到外部服务器的HTTP连接’:

5>接口开发
事务代码SE24进行实施类开发,系统中默认有五家银行的例子,可参考该代码实施:

3、实施步骤
接口实施类中一般有以下几个方法:

Create_Request:创建请求报文

这里dialog参数即为通信详细信息配置中的对话框参数结构,主要传递对话框参数,如历史余额查询日期

第一个位置中为构建发送报文信息。从系统中取得发送报文必要的信息,这里仍然为Abap类型的结构,根据银行接口文档中报文示例,将Abap结构转换为XML报文。TRANSFORMATION在事物代码STRANS中维护一般通过Strans构建发送报文。也可以手工拼接报文。
Process_response:解析响应报文

这里是将接收到的报文进行解析,首先将XML格式报文转换,转为Abap可以处理的结构,再在PERFOMR_POST_RESP_XSLT_PROC中进行读取,将报文中的信息解析到输出结构中。
Adjust_HTTP_REQUEST:发送前对报文进行调整
当报文结构较为特殊时,一般在此方法中对报文格式进行调整。通过如下方式取得报文:

Adjust_HTTP_RESPONSE:解析前对响应报文进行调整
当需要对收到的响应报文进行处理时,可在此方法中进行操作。

二、报文生成的几种方式
(1)DMEE生成
DMEE中通常配置付款报文,通过事务代码DMEE创建对应树结构:

树格式如下:

该格式为报文的树形结构,根据接口文档中字段属性可对应至付款结构的相应字段,当F110运行付款建议时,会生成付款文件,当选择付款数据发送至银行时,在接口中会将付款文件转换为XML格式报文。
排序字段(关键字段,付款条目处理时相当于主键)设置

节点属性:

名称即为报文字段名称,长度中可设置节点长度,以及类型,当为金额或日期、时间等字段时,可选择转换功能,将字段转换为对应的格式;
状态,节点状态可为空或1、2;为空时,节点值可空,不做校验;为1时节点值不能为空;为2时节点值为空即在报文中不现实;若遇多种付款保文,且报文字段不一致时,可通过状态,结合出口做更改。

通常使用‘常量’、‘结构字段’、‘退出模块’等属性;
常量:即为固定值,一般客户号、操作员号、操作员密码等为常量
结构字段:即为DMEE_PAYM_IF_TYPE结构中的字段

该结构中包含基本的收付款方信息。
退出模块:节点值需要做判断处理时,一般选择退出模块;例如同行跨行、同城异地付款标识。

(2)Strans生成
Strans为最常用的XML数据与ABAP数据转换方式:不仅可以将ABAP对象转换为XML报文,也可以将XML报文转换为ABAP数据。示例如下:
<xsl:transform xmlns:xsl=“http://www.w3.org/1999/XSL/Transform” xmlns:sap=“http://www.sap.com/sapxsl” xmlns:asx=“http://www.sap.com/abapxml” exclude-result-prefixes=“asx” version=“1.0”>

<xsl:strip-space elements="*"/>
<xsl:output encoding=“gbk” indent=“no” omit-xml-declaration=“yes”/>
<xsl:template match="/asx:abap/asx:values/PARAMETERS">

<transaction>
  <itemsPrevious>
    <itemsPreviousRequest>
      <itemsPreviousRequestHeader>
       <language>
         <xsl:value-of select="LANGUAGE"/>
       </language>
       <clientTime>
         <xsl:value-of select="CLIENTTIME"/>
       </clientTime>
       <logonPart>
        <userID>
          <xsl:value-of select="USERID"/>
        </userID>
        <userPassword>
          <xsl:value-of select="USERPASS"/>
        </userPassword>
        <operatorID>
          <xsl:value-of select="OPERATORID"/>
        </operatorID>

       </logonPart>
        <batchID>
          <xsl:value-of select="BATCHID"/>
        </batchID>
        <transPatches>
          <xsl:value-of select="TRANSPATCHS"/>
        </transPatches>
      </itemsPreviousRequestHeader>
      <itemsPreviousRequestBody>
        <itemsPreviousRequestRecord>
          <clientPatchID>
            <xsl:value-of select="CLIENTPATCHID"/>
          </clientPatchID>
          <accountNo>
            <xsl:value-of select="ACCOUNTNO"/>
          </accountNo>
          <startTime>
            <xsl:value-of select="STARTTIME"/>
          </startTime>
          <endTime>
            <xsl:value-of select="ENDTIME"/>
          </endTime>
          <startPatches>
            <xsl:value-of select="STARTPATCHS"/>
          </startPatches>
          <requestPatches>
            <xsl:value-of select="REQUESTPATCHES"/>
          </requestPatches>
        </itemsPreviousRequestRecord>
      </itemsPreviousRequestBody>
    </itemsPreviousRequest>
  </itemsPrevious>
</transaction>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54

</xsl:template>
</xsl:transform>

XMLàABAP数据时遇到需要解析XML标签的属性,可在标签路径中加‘@属性名’可解析属性

关于带命名空间的xml,若命名空间为一致的,可采用replace方式去掉命名空间
XML转换为ABAP数据示例:
<xsl:transform xmlns:xsl=“http://www.w3.org/1999/XSL/Transform” xmlns:sap=“http://www.sap.com/sapxsl” version=“1.0”>
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<asx:abap xmlns:asx=“http://www.sap.com/abapxml” version=“1.0”>
asx:values

      <INFO>
        <RSPCOD>
          <xsl:value-of select="FOX/SIGNONMSGSRSV1/SONRS/STATUS/CODE"/>
        </RSPCOD>
        <RSPMSG>
          <xsl:value-of select="FOX/SIGNONMSGSRSV1/SONRS/STATUS/SEVERITY"/>
        </RSPMSG>
        <TOTALNUM>
          <xsl:value-of select="FOX/SECURITIES_MSGSRSV1/SCUSTSTMTTRNRS/SCUSTSTMTRS/TRANLIST/@MORE"/>
        </TOTALNUM>
        <ACTACN>
          <xsl:value-of select="FOX/SECURITIES_MSGSRSV1/SCUSTSTMTTRNRS/SCUSTSTMTRS/ACCTFROM/ACCTID"/>
        </ACTACN>
        <NAME>
          <xsl:value-of select="FOX/SECURITIES_MSGSRSV1/SCUSTSTMTTRNRS/SCUSTSTMTRS/ACCTFROM/NAME"/>
        </NAME>
        <BANKDESC>
          <xsl:value-of select="FOX/SECURITIES_MSGSRSV1/SCUSTSTMTTRNRS/SCUSTSTMTRS/ACCTFROM/BANKDESC"/>
        </BANKDESC>
      </INFO>
      <ITEMS>
        <xsl:for-each select="FOX/SECURITIES_MSGSRSV1/SCUSTSTMTTRNRS/SCUSTSTMTRS/TRANLIST/STMTTRN">

          <ITEM>
            <RSPMSG>
              <xsl:value-of select="MEMO"/>
            </RSPMSG>

            <TRANSID>
              <xsl:value-of select="ATTACHINFO"/>
            </TRANSID>
            <TXNDATE>
              <xsl:value-of select="DTACCT"/>
            </TXNDATE>
            <TXNAMT>
              <xsl:value-of select="TRNAMT"/>
            </TXNAMT>
            <ACCTBAL>
              <xsl:value-of select="BALAMT"/>
            </ACCTBAL>
            <USEINFO>
              <xsl:value-of select="PURPOSE"/>
            </USEINFO>
            <TRNCUR>
              <xsl:value-of select="CURRENCY"/>
            </TRNCUR>
            <DIRECTION>
              <xsl:value-of select="TRNTYPE"/>
            </DIRECTION>
            <FBUSPARTER>
              <xsl:value-of select="CORRELATE_NAME"/>
            </FBUSPARTER>
            <FBANKNAME>
              <xsl:value-of select="CORRELATE_BANKNAME"/>
            </FBANKNAME>
            <FACCOUNT_NUMBER>
              <xsl:value-of select="CORRELATE_ACCTID"/>
            </FACCOUNT_NUMBER>

            <TBUSPARTER>
              <xsl:value-of select="CORRELATE_NAME"/>
            </TBUSPARTER>
            <TBANKNAME>
              <xsl:value-of select="CORRELATE_BANKNAME"/>
            </TBANKNAME>
            <TACCOUNT_NUMBER>
              <xsl:value-of select="CORRELATE_ACCTID"/>
            </TACCOUNT_NUMBER>
          </ITEM>
        </xsl:for-each>
      </ITEMS>
    </RESPONSE>
  </asx:values>
</asx:abap>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74

</xsl:template>
</xsl:transform>

(3)手动拼接
XML报文也可理解为String字符串,因此可以用concatenate拼接报文:

CONCATENATE ‘dse_sessionId=’ gv_token ‘&opName=queryHistoryCurrentListNEW1_1Op&reqData=’
‘<?xml version="1.0" encoding="GBK"?>’
‘’
‘’
‘’ ls_requ_mapping_source_data-serialno ‘’
‘’ sy-datum ‘’
‘’
‘’ ls_requ_mapping_source_data-acno ‘’
‘’ ls_requ_mapping_source_data-qsrq ‘’
‘’ ls_requ_mapping_source_data-zzrq ‘’
‘0.00’
‘9999999999.99’
‘’
‘’
‘’ INTO ev_request_message_string.
当遇到非XML格式报文时,也可采用拼接方式,例如JSON或其他格式的报文。

采用concatenate拼接时,可能会遇到乱码问题,可将String转换为XString一般可解决该问题。

"字符串转换:STRING->XSTRING

CALL FUNCTION 'SCMS_STRING_TO_XSTRING'
  EXPORTING
    TEXT     = EV_REQUEST_MESSAGE_STRING
  • 1
  • 2
  • 3
  •   MIMETYPE = ' '
      ENCODING = '8404'
    IMPORTING
      BUFFER   = EV_REQUEST_MESSAGE_XSTRING
    EXCEPTIONS
      FAILED   = 1
      OTHERS   = 2.
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    IF SY-SUBRC <> 0.
  • Implement suitable error handling here
    ENDIF.

三、常用增强
1、Ukey校验增强
增强点:EPIC_VALIDATION_CONTROL
参考代码:
METHOD if_epic_security_token_control~validate_with_security_token.

IF  sy-tcode = 'EPIC_PROC' AND iv_bctyp = '010'.


  INCLUDE ole2incl.

  DATA win32 TYPE ole2_object.
  DATA lv_identity TYPE string.
  DATA lv_sn TYPE string.
  DATA lv_query_rslt TYPE token_auth_table.
  DATA lv_encryption TYPE c LENGTH 32.
  DATA lv_result TYPE i VALUE 40.
  DATA lv_answer.
  DATA lv_pin TYPE pvarfield.
  DATA lv_pin_code TYPE string.
  DATA lv_is_pin_pass TYPE abap_bool.
  DATA lv_error_type TYPE i VALUE 0.
  DATA lv_pin_failed TYPE abap_bool VALUE abap_true.
  DATA lv_pin_failed_times TYPE i VALUE 1.
  DATA gv_is_validation_passed TYPE c.
  DATA ls_message LIKE LINE OF ct_messages.
  DATA: lv_dummy TYPE string.
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  •  IF sy-batch = 'X'."后台JOB不做UKEY检查
    
    • 1
  •    ev_pass = abap_true.
    
    • 1
  •    RETURN.
    
    • 1
  •  ENDIF.
    
    CONSTANTS lv_c_bool_false TYPE i VALUE 0.
    ev_pass = abap_true.
    
    
    ev_pass = abap_false.
    
    CREATE OBJECT win32 'USBIdentifier.USBIdentifierClass'.
    
    CALL METHOD OF
      win32
        'openToken_call' = lv_result.
    IF lv_result = lv_c_bool_false.
      ev_pass = abap_false.
      lv_error_type = 1.
    ELSEIF lv_result = 40.
      CLEAR gv_is_validation_passed.
      ev_pass = abap_false.
      MESSAGE e106(epic_validation_msg) INTO lv_dummy.
      MOVE-CORRESPONDING sy TO ls_message.
      APPEND ls_message TO ct_messages.
      RETURN.
    ELSE.
      IF gv_is_validation_passed EQ abap_true.
        CALL METHOD OF win32 'closeDevice_call' = lv_result.
        CALL METHOD OF win32 'closeToken_call' = lv_result.
        ev_pass = abap_true.
        RETURN.
      ENDIF.
      CALL METHOD OF
        win32
          'openDevice_call' = lv_result.
      IF lv_result = lv_c_bool_false.
        CLEAR gv_is_validation_passed.
        ev_pass = abap_false.
        lv_error_type = 2.
    
      ELSE.
        CALL METHOD OF
          win32
            'getUsbTokenNumber_call' = lv_sn.
    
        TRANSLATE lv_sn TO UPPER CASE.
    
        SELECT SINGLE * INTO lv_query_rslt
            FROM scurty_tokn_vldt
            WHERE sn = lv_sn
            AND  username = sy-uname .
    
        IF sy-dbcnt <> 1.
          CLEAR gv_is_validation_passed.
          ev_pass = abap_false.
          lv_error_type = 3.
    
        ELSE.
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56

----————————————————UKEY重复输入修正start----————————————————
DATA lw_ztcm021 TYPE ztcm021 .
SELECT SINGLE * FROM ztcm021 INTO lw_ztcm021 WHERE upnam = sy-uname AND udat = sy-datum.
IF sy-subrc = 0.
ev_pass = abap_true.
RETURN.
ENDIF.
----————————————————UKEY重复输入修正 end----————————————————
CALL FUNCTION ‘CALL_USB_KEY_PIN_SCREEN’
EXPORTING
io_win32 = win32
IMPORTING
ev_is_pin_pass = lv_is_pin_pass.

        IF lv_is_pin_pass = abap_true.
          CALL METHOD OF
            win32
              'getUserIdentity_call' = lv_identity.

          CALL FUNCTION 'MD5_CALCULATE_HASH_FOR_CHAR'
            EXPORTING
              data           = lv_identity
            IMPORTING
              hash           = lv_encryption
            EXCEPTIONS
              internal_error = 1
              OTHERS         = 2.
          SELECT SINGLE * INTO lv_query_rslt
            FROM scurty_tokn_vldt
            WHERE password = lv_encryption
            AND  username = sy-uname .
          IF sy-dbcnt = 1.
            ev_pass = abap_true.
            gv_is_validation_passed = abap_true.
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

----————————————————UKEY重复输入修正start----————————————————
lw_ztcm021-upnam = sy-uname.
lw_ztcm021-udat = sy-datum.
lw_ztcm021-utime = sy-uzeit.
INSERT ztcm021 FROM lw_ztcm021.
----————————————————UKEY重复输入修正 end----————————————————
ELSE.
CLEAR gv_is_validation_passed.
ev_pass = abap_false.
lv_error_type = 5.

          ENDIF.
        ENDIF.

      ENDIF.
    ENDIF.
  ENDIF.


  CALL METHOD OF win32 'closeDevice_call' = lv_result.
  CALL METHOD OF win32 'closeToken_call' = lv_result.
  CASE lv_error_type .
    WHEN 1.
      MESSAGE e101(epic_validation_msg) INTO lv_dummy.
      MOVE-CORRESPONDING sy TO ls_message.
      APPEND ls_message TO ct_messages.
      CLEAR gv_is_validation_passed.
      ev_pass = abap_false.
    WHEN 2.
      MESSAGE e102(epic_validation_msg) INTO lv_dummy.
      MOVE-CORRESPONDING sy TO ls_message.
      APPEND ls_message TO ct_messages.
      CLEAR gv_is_validation_passed.
      ev_pass = abap_false.
    WHEN 3.
      MESSAGE e103(epic_validation_msg) INTO lv_dummy.
      MOVE-CORRESPONDING sy TO ls_message.
      APPEND ls_message TO ct_messages.
      CLEAR gv_is_validation_passed.
      ev_pass = abap_false.
    WHEN 4.
      MESSAGE e104(epic_validation_msg) INTO lv_dummy.
      MOVE-CORRESPONDING sy TO ls_message.
      APPEND ls_message TO ct_messages.
      CLEAR gv_is_validation_passed.
      ev_pass = abap_false.
    WHEN 5.
      MESSAGE e105(epic_validation_msg) INTO lv_dummy.
      MOVE-CORRESPONDING sy TO ls_message.
      APPEND ls_message TO ct_messages.
      CLEAR gv_is_validation_passed.
      ev_pass = abap_false.
    WHEN OTHERS.
  ENDCASE.
ELSE.
  ev_pass = abap_true.
ENDIF.
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46

2、审批流增强
增强点:EPIC_APPROVAL_CONTROL
审批流配置表:

审批记录表:

采用标准审批功能,用自定义配置表,支持多人同时审批:

创建审批流,并推送给对应审批人:
METHOD if_epic_badi_approval_control~get_possible_approvers.

DATA: ls_item LIKE LINE OF it_items,
ls_approver LIKE LINE OF et_possible_approvers,
lv_approver_level TYPE fprl_level,
lv_approver_tier TYPE int4,
lf_valid_approver TYPE flag.

DATA: lt_tiers TYPE STANDARD TABLE OF ty_tier_assignment,
ls_tier LIKE LINE OF lt_tiers.

DATA: ls_user_address TYPE addr3_val.

----------------------------------------------------------------------
DATA lt_ztcm008 TYPE STANDARD TABLE OF ztcm008.
DATA lt_ztcm008_check TYPE STANDARD TABLE OF ztcm008.
DATA ls_ztcm008 TYPE ztcm008.
DATA lt_items LIKE it_items.
DATA lv_lines TYPE i.
DATA lv_userid LIKE ls_approver-userid.

DATA lt_ztcm010 TYPE STANDARD TABLE OF ztcm010.
DATA ls_ztcm010 TYPE ztcm010.
-----------------Add By HAND_HR 20180611-------------------------------
DATA:lt_ztcm061 TYPE STANDARD TABLE OF ztcm061,
ls_ztcm061 TYPE ztcm061.

  • DATA:lt_ztcm008 TYPE STANDARD TABLE OF ztcm008,

  •   ls_ztcm008 TYPE ztcm008.
    
    • 1

    DATA:lv_wrbtr TYPE wrbtr.
    -----------------END---------------------------------------------------

    lt_items = it_items.

    IF lt_items IS NOT INITIAL.

    SELECT * FROM ztcm010
    INTO TABLE lt_ztcm010
    FOR ALL ENTRIES IN lt_items
    WHERE bukrs = lt_items-bukrs.

    SORT lt_ztcm010 BY zappnum.
    ----------------Add By HAND_HR 20180611--------------------------------

    SELECT * FROM ztcm061 INTO TABLE lt_ztcm061
    FOR ALL ENTRIES IN lt_items
    WHERE zapprsign = lt_items-guid.
    SELECT * FROM ztcm008 INTO TABLE lt_ztcm008 FOR ALL ENTRIES IN lt_ztcm061
    WHERE zstep = lt_ztcm061-zstep
    AND zapprover = lt_ztcm061-zapprover.
    ----------------END----------------------------------------------------
    ENDIF.

    DELETE ADJACENT DUPLICATES FROM lt_ztcm010 COMPARING zappnum.
    DESCRIBE TABLE lt_ztcm010 LINES lv_lines.
    IF lv_lines NE 1.
    MESSAGE e000(zepic_msg).
    *没有找到正确的审批流
    ENDIF.
    SORT lt_ztcm008 BY wrbtr.
    READ TABLE lt_ztcm008 INTO ls_ztcm008 INDEX 1.
    lv_wrbtr = ls_ztcm008-wrbtr.
    LOOP AT lt_ztcm008 INTO ls_ztcm008 WHERE wrbtr NE lv_wrbtr.
    MESSAGE e000(zepic_msg).
    *没有找到正确的审批流
    ENDLOOP.
    READ TABLE lt_ztcm010 INTO ls_ztcm010 INDEX 1.
    ----------------Add By HAND_HR 20180611--------------------------------
    "生成所有审批条目

    SORT lt_ztcm061 BY zstep zapprover.
    DELETE ADJACENT DUPLICATES FROM lt_ztcm061 COMPARING zstep zapprover…
    LOOP AT lt_ztcm061 INTO ls_ztcm061 WHERE zactflg = ‘X’.

    lv_userid = ls_ztcm061-zapprover.
    ls_approver-userid = lv_userid.
    APPEND ls_approver TO et_possible_approvers.

  •  ENDIF.
    
    • 1

    ENDLOOP.

ENDMETHOD.

创建审批记录,并提交审批结果:
METHOD if_epic_badi_approval_control~check_release_possible.

CLEAR: ef_release_possible.

----------------------------------------------------------------------

DATA lt_ztcm008 TYPE STANDARD TABLE OF ztcm008.
DATA lt_ztcm010 TYPE STANDARD TABLE OF ztcm010.
DATA ls_ztcm008 TYPE ztcm008.
DATA ls_ztcm010 TYPE ztcm010.

  • DATA:ls_approver LIKE LINE OF et_possible_approvers.
    DATA lv_userid LIKE ls_ztcm008-zapprover.
    -----------------Add By HAND_HR 20180611-------------------------------
    DATA:lt_ztcm061 TYPE STANDARD TABLE OF ztcm061,
    ls_ztcm061 TYPE ztcm061.
    DATA:lt_ztcm061_check TYPE STANDARD TABLE OF ztcm061,
    ls_ztcm061_check TYPE ztcm061.
    DATA:lv_wrbtr TYPE wrbtr.
    DATA:lv_zstep TYPE ztcm061-zstep.
    -----------------END---------------------------------------------------

SELECT SINGLE * FROM ztcm010 INTO ls_ztcm010 WHERE bukrs = is_item-bukrs.

SELECT * FROM ztcm008
INTO TABLE lt_ztcm008
WHERE zappnum = ls_ztcm010-zappnum.

SORT lt_ztcm008 BY zappnum wrbtr.

LOOP AT lt_ztcm008 INTO ls_ztcm008 WHERE zappnum = ls_ztcm010-zappnum AND wrbtr >= is_item-wrbtr.
EXIT.
ENDLOOP.

IF sy-subrc NE 0.
RETURN.
ENDIF.
----------------Add By HAND_HR 20180611--------------------------------
SELECT * FROM ztcm061
INTO TABLE lt_ztcm061_check
WHERE zapprsign = is_item-guid.
IF sy-subrc <> 0 .
"生成所有审批条目
SORT lt_ztcm008 BY wrbtr zstep.

  • LOOP AT lt_items INTO ls_item.
    CLEAR:ls_ztcm061,lv_wrbtr.
    ls_ztcm061-bukrs = is_item-bukrs. "公司代码
    ls_ztcm061-zapprsign = is_item-guid. "审批组标识
    LOOP AT lt_ztcm008 INTO ls_ztcm008 WHERE wrbtr >= is_item-wrbtr.
    ls_ztcm061-zstep = ls_ztcm008-zstep.
    lv_wrbtr = ls_ztcm008-wrbtr.
    EXIT.
    ENDLOOP.
    IF lv_wrbtr IS NOT INITIAL.
    LOOP AT lt_ztcm008 INTO ls_ztcm008 WHERE wrbtr = lv_wrbtr .
    CLEAR:ls_ztcm061-zactflg.
    IF ls_ztcm008-zstep = ‘1’.
    ls_ztcm061-zactflg = ‘X’. "审批激活标识
    lv_userid = ls_ztcm008-zapprover.
    ENDIF.
    ls_ztcm061-zapprover = ls_ztcm008-zapprover."审批人
    ls_ztcm061-zstep = ls_ztcm008-zstep."审批步骤
    ls_ztcm061-zdate = sy-datum. "日期
    ls_ztcm061-ztime = sy-uzeit. "时间
    APPEND ls_ztcm061 TO lt_ztcm061.
    ENDLOOP.
    ENDIF.

    MODIFY ztcm061 FROM TABLE lt_ztcm061.
    ELSE.
    LOOP AT lt_ztcm061_check INTO ls_ztcm061_check WHERE zactflg = ‘X’.
    lv_zstep = ls_ztcm061_check-zstep.
    IF sy-uname = ls_ztcm061_check-zapprover."下一级审批
    IF ls_ztcm061_check-zdate = sy-datum AND ls_ztcm061_check-ztime = sy-uzeit.
    lv_userid = ls_ztcm061_check-zapprover.
    EXIT.
    ENDIF.
    CLEAR:ls_ztcm061_check-zactflg.
    ls_ztcm061_check-zapprres = ‘A’.

     "更新审批结果
     UPDATE ztcm061
     SET zapprres = ls_ztcm061_check-zapprres
         zapdate  = sy-datum
         zaptime  = sy-uzeit
     WHERE bukrs     = ls_ztcm061_check-bukrs
       AND zapprsign = ls_ztcm061_check-zapprsign
       AND zstep     = ls_ztcm061_check-zstep
       AND zapprover = sy-uname.
     "更新审批激活标识
     UPDATE ztcm061
     SET zactflg  = ls_ztcm061_check-zactflg
     WHERE bukrs     = ls_ztcm061_check-bukrs
       AND zapprsign = ls_ztcm061_check-zapprsign
       AND zstep     = ls_ztcm061_check-zstep.
     LOOP AT  lt_ztcm061_check INTO ls_ztcm061_check WHERE zstep = lv_zstep + 1.
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
  •      IF sy-subrc = 0.
        lv_userid = ls_ztcm061_check-zapprover.
        ls_ztcm061_check-zactflg = 'X'.
        UPDATE ztcm061
      SET zactflg  = ls_ztcm061_check-zactflg
      WHERE bukrs     = ls_ztcm061_check-bukrs
        AND zapprsign = ls_ztcm061_check-zapprsign
        AND zstep     = ls_ztcm061_check-zstep
        AND zapprover = ls_ztcm061_check-zapprover .
      ENDLOOP.
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
  •      ENDIF.
    ELSE.
      lv_userid = ls_ztcm061_check-zapprover.
    ENDIF.
    
    • 1
    • 2
    • 3
    • 4

    ENDLOOP.

    ENDIF.

    IF lv_userid IS INITIAL .
    ef_release_possible = abap_true.
    RETURN.
    ENDIF.

ENDMETHOD.

实现效果:
在款项处理页签,提交审批后,对应的审批人,可在款项审批界面看到需要审批的款项记录,若同级审批人为一人,则默认为审批人,若同级有多人审批,则可选择担当审批人之后批准付款;操作如下:选择付款条目à点击有待分组à有待审批;会提示用户是否担当审批人,选择是之后,对改付款条目进行审批。

若有其他审批人时,会提示错误:

3、回单认领增强
增强点:EPIC_EBR_PRPS

根据付款中DOC1R匹配回单并认领过账

DATA lv_belnr TYPE belnr_d.
DATA lt_belnr TYPE tt_belnr.
DATA ls_epic_ebr_doc_info TYPE LINE OF epic_t_ebr_document_info.
DATA lt_bkpf TYPE STANDARD TABLE OF bkpf.
DATA ls_bkpf TYPE bkpf.
DATA lt_ref_bkpf TYPE STANDARD TABLE OF bkpf.
DATA lt_bseg TYPE STANDARD TABLE OF bseg.
DATA ls_bseg TYPE bseg.
DATA ls_ebr_document_info TYPE LINE OF epic_t_ebr_document_info.
DATA ls_v_ebr_hdr TYPE epic_v_ebr_hdr.
DATA lv_filter_gjahr TYPE gjahr.
DATA lv_part_id TYPE epic_ebr_part_id.
FIELD-SYMBOLS <fs_ebr_doc_info> TYPE LINE OF epic_t_ebr_document_info.
DATA LV_BUKRS LIKE is_ebr_hdr-BUKRS.

CLEAR et_epic_ebr_doc_info.

DATA:lw_belnr LIKE LINE OF lt_belnr,
     l_butxt  TYPE butxt_eb,
     l_gjahr  TYPE gjahr.

CLEAR l_butxt.
SELECT SINGLE
  bank_remark
INTO l_butxt
FROM epic_v_ebr_hdr
WHERE ebr_id = is_ebr_hdr-ebr_id.
IF strlen( l_butxt ) = 16.
  lw_belnr-belnr  = l_butxt+4(10).
  l_gjahr+0(2) = '20'.
  l_gjahr+2(2) = l_butxt+14(2).

  APPEND lw_belnr TO lt_belnr.

ELSEIF strlen( l_butxt ) > 16.
  lw_belnr-belnr  = l_butxt+4(10).
  l_gjahr+0(2) = '20'.
  l_gjahr+2(2) = l_butxt+16(2).

  APPEND lw_belnr TO lt_belnr.
ENDIF.
LV_BUKRS = l_butxt+0(4).
CHECK lt_belnr IS NOT INITIAL.
IF l_gjahr IS  INITIAL.
  lv_filter_gjahr = sy-datum(4).
ELSE.
  lv_filter_gjahr = l_gjahr.
ENDIF.
CLEAR: lt_bkpf, lt_ref_bkpf.
SELECT
  *
  FROM bkpf
  INTO TABLE lt_bkpf FOR ALL ENTRIES IN lt_belnr
  WHERE belnr = lt_belnr-belnr
   AND  bukrs = LV_BUKRS"is_ebr_hdr-bukrs
   AND  gjahr = lv_filter_gjahr.

CHECK lt_bkpf IS NOT INITIAL.
DATA lv_shkzg TYPE shkzg.
IF is_ebr_hdr-direction =  cl_epic_ebr_util=>gc_outgoing.
  lv_shkzg = cl_epic_ebr_util=>gc_debit.
ELSE.
  lv_shkzg = cl_epic_ebr_util=>gc_credit.
ENDIF.

SELECT
  *
  FROM bseg
  INTO TABLE lt_bseg
  FOR ALL ENTRIES IN lt_bkpf
  WHERE belnr = lt_bkpf-belnr
  AND   gjahr = lt_bkpf-gjahr
  AND   bukrs = lt_bkpf-bukrs
  AND   shkzg = lv_shkzg.

CHECK lt_bseg IS NOT INITIAL.
LOOP AT  lt_bseg INTO ls_bseg.
  CLEAR: ls_ebr_document_info ,lv_part_id.
  IF ls_bseg-koart EQ 'K'.
    lv_part_id     = ls_bseg-lifnr.
  ELSEIF ls_bseg-koart EQ 'D'.
    lv_part_id     = ls_bseg-kunnr.
  ELSEIF ls_bseg-koart EQ 'S'.
    lv_part_id     =  ls_bseg-hkont.
  ENDIF.

  READ TABLE et_epic_ebr_doc_info ASSIGNING <fs_ebr_doc_info>
                                  WITH KEY bukrs = ls_bseg-bukrs  belnr = ls_bseg-belnr
                                           gjahr = ls_bseg-gjahr  part_type = ls_bseg-koart
                                           part_id = lv_part_id.
  IF sy-subrc EQ 0.
    <fs_ebr_doc_info>-wrbtr = <fs_ebr_doc_info>-wrbtr + ls_bseg-wrbtr.
    <fs_ebr_doc_info>-dmbtr = <fs_ebr_doc_info>-dmbtr + ls_bseg-dmbtr.
  ELSE.
    ls_ebr_document_info-belnr      = ls_bseg-belnr.
    ls_ebr_document_info-gjahr      = ls_bseg-gjahr.
    ls_ebr_document_info-part_type  = ls_bseg-koart.
    ls_ebr_document_info-part_id    = lv_part_id.
    ls_ebr_document_info-wrbtr      = ls_bseg-wrbtr.
    ls_ebr_document_info-dmbtr      = ls_bseg-dmbtr.
    READ TABLE lt_bkpf INTO ls_bkpf WITH KEY belnr = ls_bseg-belnr
                                             gjahr = ls_bseg-gjahr
                                             bukrs = ls_bseg-bukrs.
    IF sy-subrc EQ 0.
      ls_ebr_document_info-budat    = ls_bkpf-budat.
    ENDIF.
    ls_ebr_document_info-waers      = ls_bkpf-waers.
    ls_ebr_document_info-bukrs      = ls_bkpf-bukrs.
    APPEND ls_ebr_document_info TO et_epic_ebr_doc_info.
  ENDIF.
ENDLOOP.
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96

Unsupported image type.

4、自定义字段
在付款条目中,用户需要添加一些客制化信息,因此可以通过向标准表FRPL_ITEM中添加字段实现。

增强点:EPIC_EXTENSIBILITY_CONTROL
在FPRL_ITAM中添加字段

运行F110时,赋值

新增的字段在DMEE中结构中是不存在的,需要通过出口获取;根据结构中的DOC1R,分别从reguh regup找到fprl_item对应的条目;继而获取到对应的新增字段的值。
在DMEE出口中获取新增的字段出口代码:

*"----------------------------------------------------------------------
"“本地接口:
*” IMPORTING
*" VALUE(I_TREE_TYPE) TYPE DMEE_TREETYPE_ABA
*" VALUE(I_TREE_ID) TYPE DMEE_TREEID_ABA
*" VALUE(I_ITEM)
*" VALUE(I_PARAM)
*" VALUE(I_UPARAM)
*" EXPORTING
*" REFERENCE(O_VALUE)
*" REFERENCE(C_VALUE)
*" REFERENCE(N_VALUE)
*" REFERENCE(P_VALUE)
*" TABLES
*" I_TAB
*"----------------------------------------------------------------------
*{ INSERT ECDK901724 1
DATA ls_item TYPE dmee_paym_if_type.

  • DATA lv_bank_number TYPE string.
  • DATA lv_bank_key TYPE string.
  • DATA lv_zbnky TYPE string.
  • DATA:lv_zarte TYPE ztcm004-zarte.
  • DATA lv_ubnkl TYPE dmee_paym_if_type-fpayhx-ubnkl.
    DATA:lv_zzdescr TYPE fprl_item-zzdescr.
    DATA:lv_bukrs TYPE fprl_item-bukrs.
    DATA:lv_belnr TYPE fprl_item-vblnr_pay.
    DATA:lv_gjahr TYPE fprl_item-gjahr.
    DATA ls_bapireturn1 TYPE bapireturn1.
    DATA:lt_reguh TYPE TABLE OF reguh.
    DATA:ls_reguh TYPE reguh.
    DATA:lt_regup TYPE TABLE OF regup.
    DATA:lt_fprl_item TYPE TABLE OF fprl_item.
    DATA:ls_fprl_item TYPE fprl_item.
    DATA:lv_subrc TYPE n.

DATA lv_meg TYPE string.
DATA lv_str TYPE string.
IF i_item IS NOT INITIAL.
ls_item = i_item.
ENDIF.
lv_bukrs = ls_item-fpayh-doc1r+0(4).
lv_belnr = ls_item-fpayh-doc1r+4(10).
lv_gjahr = ls_item-fpayh-doc1r+14(4).

  • CALL FUNCTION ‘BAPI_COMPANYCODE_GET_PERIOD’

" 读取相关的FPRL_ITEM,即EPIC相关的待付款项数据
SELECT * FROM reguh INTO CORRESPONDING FIELDS OF TABLE lt_reguh
WHERE laufd = ls_item-fpayh-laufd
AND laufi = ls_item-fpayh-laufi
AND xvorl = ls_item-fpayh-xvorl
AND zbukr = ls_item-fpayh-zbukr
AND vblnr = lv_belnr
AND zaldt = ls_item-fpayh-zaldt.

ASSERT lines( lt_reguh ) <= 1.
IF lt_reguh IS NOT INITIAL.
READ TABLE lt_reguh INTO ls_reguh INDEX 1.

SELECT * FROM regup INTO CORRESPONDING FIELDS OF TABLE lt_regup
  WHERE laufd = ls_reguh-laufd
    AND laufi = ls_reguh-laufi
    AND xvorl = ls_reguh-xvorl
    AND zbukr = ls_reguh-zbukr
    AND lifnr = ls_reguh-lifnr
    AND kunnr = ls_reguh-kunnr
    AND empfg = ls_reguh-empfg
    AND vblnr = ls_reguh-vblnr.

"读取所有待付款项FPRL_ITEM
SELECT  * FROM fprl_item INTO CORRESPONDING FIELDS OF TABLE lt_fprl_item
  FOR ALL ENTRIES IN lt_regup
  WHERE bukrs = lt_regup-bukrs
   AND  belnr = lt_regup-belnr
   AND  gjahr = lt_regup-gjahr
   AND  buzei = lt_regup-buzei.
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

ENDIF.
IF lt_fprl_item IS NOT INITIAL.
LOOP AT lt_fprl_item INTO ls_fprl_item.
c_value = ls_fprl_item-zzdescr.
ENDLOOP.
ENDIF.

5、EPIC付款界面添加按钮
操作对象:CL_EPIC_PI_UIL

在PBO_INIT_SCREEN方法中找到
SET HANDLER _event_toolbar FOR gr_grid.
双击_event_toolbar跳转至添加Toolbar按钮,此时通过转换为可修改模式,通过菜单栏:编辑à增强操作à显示隐式增强选项;找到增强点

在最下方代码中,在灰色箭头行创建增强代码:

添加完毕后激活程序。
添加成功效果:在款项处理工具栏会有新添加的按钮。

2、添加事件处理逻辑
同上一步添加增强的方法一样,我们在_EVENT_USER_COMMAND方法中添加该按钮的处理事件:

可通过直接写处理逻辑,也可添加新方法处理事务;这里添加新方法处理事务:

创建新方法后,继续创建增强,并添加处理逻辑。

6、更改发票凭证付款方式
在EPIC中更付款方式时,系统会校验发票凭证和供应商主数据中是否维护该付款方式,一般发票凭证上不会带有付款方式;那么当用户将付款方式改为供应商主数据中不存在的付款方式时,系统会提示错误。因此通过更改发票凭证付款方式,实现对付款方式的更改。

通过其他程序调用FI_DOCUMENT_CHANGE更改凭证中的付款方式字段;之后再在EPIC中修改;此时在校验付款方式时,可在凭证中找到;便可成功修改为供应商中未维护的付款方式。

7、原因代码替代
当使用现金和银行科目过账时必须指定原因代码来代表此现金流入或流出对应的现金流量表项目。这样通过直接法可以跟踪每笔现金和银行业务的流动情况,得到现金流量表。这种出示现金流量表的方式要求每笔现金和银行科目过账都必须由财务人员判断并分配一个原因代码,并且要求企业现金和银行收支业务必须按现金流量表项目分开,不能混合,从而保证记账时在行项目上分清现金流的原因代码。

事物代码:GGB1

  •   FORM U201                                                     *
    
    • 1
  •   银企直联原因代码替代出口                                       *
    
    • 1

FORM u201 USING e_rstgr TYPE bseg-rstgr.
DATA lv_msg TYPE string.
DATA gv_belnr TYPE bseg-belnr.
DATA gv_belnr_loop TYPE bseg-belnr.
IF ( bkpf-tcode = ‘F110’) AND ( sy-tcode NE ‘FB02’ AND sy-tcode NE ‘FB03’ AND sy-tcode NE ‘FBL1N’ AND sy-tcode NE ‘FBL3N’)." AND ( sy-uname = ‘HAND_ZML’ OR sy-uname = ‘HAND_ZCY’ ).

DATA fnam    LIKE bdcdata-fnam.
FIELD-SYMBOLS: <fs_ausz3> TYPE ausz_clr_tab.
FIELD-SYMBOLS: <fs_ausz3w> LIKE LINE OF <fs_ausz3>.
DATA lt_bseg TYPE STANDARD TABLE OF bseg WITH HEADER LINE.
DATA lt_bseg_invo TYPE STANDARD TABLE OF bseg WITH HEADER LINE.
DATA lt_ztcm009 TYPE STANDARD TABLE OF ztcm009 WITH HEADER LINE.
DATA lt_payrq TYPE STANDARD TABLE OF payrq WITH HEADER LINE.
DATA lv_rstgr LIKE e_rstgr.
"获取内存中,EPIC的原始凭证数据,因该内存是SESSION级的,只能在同一会话窗口中获取,故不会有不同人同时操作而乱掉的情况
fnam = '(SAPF110S)XAUSZ3[]'.
ASSIGN (fnam) TO <fs_ausz3>.
IF sy-subrc = 0.
  IF <fs_ausz3> IS NOT INITIAL.
    CLEAR lv_rstgr.

    READ TABLE <fs_ausz3> ASSIGNING <fs_ausz3w> INDEX 1.
    IF  <fs_ausz3w> IS NOT INITIAL.
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

*1.(一) 根据屏幕字段 FPRL_ITEM-BELNR ,到表BSEG中,当 FPRL_ITEM-GJAHR = BSEG-GJAHR,FPRL_ITEM-BUKRS = BSEG-BUKRS 时,找到 BSEG-BELNR
*(二)判断第一个数字是否为 8 ,如果不是8,则继续 步骤2
*(三)如果是8,取BSEG-REBZG:1)如果此字段为空,则定位到 BSEG-AUGBL = FPRL_ITEM-BELNR,当 FPRL_ITEM-GJAHR = BSEG-GJAHR,FPRL_ITEM-BUKRS = BSEG-BUKRS 且 BSEG-SHKZG = H 时,取 BSEG-BELNR

  • 2)若此字段不为空,且开头为8,则重复(三)

  • 3)若此字段不为空,且开头不为8,则定位到 BSEG-BELNR = 此 BSEG-REBZG,且 FPRL_ITEM-GJAHR = BSEG-GJAHR,FPRL_ITEM-BUKRS = BSEG-BUKRS 时
    CLEAR gv_belnr.

       IF <fs_ausz3w>-belnr(1) = '8'.
         gv_belnr_loop = <fs_ausz3w>-belnr.
         DO 10 TIMES.
           SELECT SINGLE * FROM bseg INTO lt_bseg
           WHERE gjahr = <fs_ausz3w>-gjahr AND bukrs = <fs_ausz3w>-bukrs AND belnr = gv_belnr_loop AND shkzg = 'H'.
           IF sy-subrc = 0.
             IF lt_bseg-rebzg IS INITIAL .
               SELECT SINGLE * FROM bseg INTO lt_bseg_invo
                  WHERE gjahr = <fs_ausz3w>-gjahr AND bukrs = <fs_ausz3w>-bukrs AND augbl = gv_belnr_loop AND shkzg = 'H'.
               IF sy-subrc = 0.
                 gv_belnr = lt_bseg_invo-belnr.
                 EXIT.
               ENDIF.
             ELSEIF lt_bseg-rebzg(1) = '8'.
               gv_belnr_loop = lt_bseg-rebzg.
             ELSEIF lt_bseg-rebzg(1) NE '8'.
               gv_belnr = lt_bseg-rebzg.
               EXIT.
             ENDIF.
           ENDIF.
         ENDDO.
    
       ENDIF.
    
       IF gv_belnr IS INITIAL .
         gv_belnr = <fs_ausz3w>-belnr.
       ENDIF.
    
       SELECT * FROM bseg INTO TABLE lt_bseg
         WHERE gjahr = <fs_ausz3w>-gjahr AND bukrs = <fs_ausz3w>-bukrs AND belnr = gv_belnr." AND shkzg = 'S'.
       IF lt_bseg[] IS NOT INITIAL.
         READ TABLE lt_bseg WITH KEY  shkzg = 'S'.
         IF sy-subrc = 0.
    
           SORT lt_bseg BY shkzg DESCENDING wrbtr DESCENDING.
           READ TABLE lt_bseg INDEX 1.
           SELECT SINGLE * FROM ztcm009 INTO lt_ztcm009 WHERE hkont = lt_bseg-hkont.
           IF sy-subrc = 0.
             CASE bseg-shkzg.
               WHEN 'H'.
                 lv_rstgr = lt_ztcm009-rstgr.
               WHEN 'S'.
    
               WHEN OTHERS.
             ENDCASE.
    
           ENDIF.
    
         ELSE.
           CASE bseg-shkzg.
             WHEN 'H'.
               lv_rstgr = '124'.
             WHEN 'S'.
    
             WHEN OTHERS.
           ENDCASE.
         ENDIF.
    
    
       ELSE.
         SELECT * FROM payrq INTO TABLE lt_payrq
            WHERE zbukr = <fs_ausz3w>-bukrs AND keyno = <fs_ausz3w>-belnr.
         LOOP AT lt_payrq WHERE cpudt(4) = <fs_ausz3w>-gjahr.
           IF lt_payrq-zbukr = lt_payrq-bukrs.
    
             CASE bseg-shkzg.
               WHEN 'H'.
                 lv_rstgr = '402'.
               WHEN 'S'.
                 lv_rstgr = '401'.
               WHEN OTHERS.
             ENDCASE.
    
           ELSE.
    
             CASE bseg-shkzg.
               WHEN 'H'.
                 lv_rstgr = '222'.
               WHEN 'S'.
    
               WHEN OTHERS.
             ENDCASE.
    
           ENDIF.
           EXIT.
         ENDLOOP.
       ENDIF.
    
       e_rstgr = lv_rstgr.
     ENDIF.
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90

    ENDIF.
    ENDIF.

  • ELSEIF bkpf-tcode = ‘F111’ .

  • IF bkpf-bvorg IS NOT INITIAL AND bseg-hkont >= ‘1002000000’ AND bseg-hkont <= ‘1002999999’.

  •  CASE bseg-shkzg.
    
    • 1
  •    WHEN 'S'.
    
    • 1
  •      e_rstgr = '311'.
    
    • 1
  •    WHEN 'H'.
    
    • 1
  •      e_rstgr = '222'.
    
    • 1
  •    WHEN OTHERS.
    
    • 1
  •  ENDCASE.
    
    • 1
  • ELSEIF bkpf-bvorg IS INITIAL AND bseg-hkont NE ‘1012100001’ AND bseg-hkont >= ‘1002000000’ AND bseg-hkont <= ‘1002999999’.

  •  CASE bseg-shkzg.
    
    • 1
  •    WHEN 'S'.
    
    • 1
  •      e_rstgr = '401'.
    
    • 1
  •    WHEN 'H'.
    
    • 1
  •      e_rstgr = '402'.
    
    • 1
  •    WHEN OTHERS.
    
    • 1
  •  ENDCASE.
    
    • 1
  • ENDIF.
    ENDIF.

ENDFORM. "U100

---------------------------------------------------------------------

  •   FORM u202                                                     *
    
    • 1

---------------------------------------------------------------------

  •   Reads the cost-center from the CSKS table .                   *
    
    • 1

---------------------------------------------------------------------
FORM u202 USING bool_data TYPE gb002_015.

  • DATA lv_msg TYPE string.
  • lv_msg = ‘进入原因代码完全凭证替代’.
  • MESSAGE lv_msg TYPE ‘S’.
  • CONCATENATE 'tcode = ’ bool_data-bkpf-tcode INTO lv_msg.
  • MESSAGE lv_msg TYPE ‘S’.
    DATA:
    i_field(50).
    DATA:
    ls_bseg TYPE bseg .
    FIELD-SYMBOLS: <fs_l_regup> TYPE regup .

i_field = ‘(SAPF111S)REGUP’.
ASSIGN (i_field) TO <fs_l_regup>.

DATA lv_stat TYPE string."状态
DATA lw_bseg TYPE bseg.
DATA lw_hkont_s TYPE hkont.
DATA lw_hkont_h TYPE hkont.
IF bool_data-bkpf-tcode = ‘F111’ AND ( sy-tcode NE ‘FB02’ AND sy-tcode NE ‘FB03’ AND sy-tcode NE ‘FBL1N’ AND sy-tcode NE ‘FBL3N’).
*01 BKPF-TCODE = ‘F111’

  • 每行 BSEG-HKONT 前四位等于 ‘1002’ 且 BSEG-HKONT 不等于 ‘1012100001’ 时
  • BSEG-SHKZG = ‘S’ 时
  • RSTGR = ‘401’
  • BSEG-SHKZG = ‘H’ 时
  • RSTGR = ‘402’

*02 BKPF-TCODE = ‘F111’

  • BSEG-SHKZG = ‘S’ 且 BSEG-HKONT = ‘1012100001’ 时
  • BSEG-SHKZG = ‘H’ 的 RSTGR = ‘111’

*03 BKPF-TCODE = ‘F111’

  • BSEG-SHKZG = ‘S’ AND BSEG-HKONT 前四位不等于 ‘1002’ 时
  • BSEG-SHKZG = ‘H’ 的 RSTGR = ‘222’

*04

  • BSEG-SHKZG = ‘H’ AND BSEG-HKONT 前四位不等于 ‘1002’ 时

  • BSEG-SHKZG = ‘S’ 的 RSTGR = ‘311’
    CLEAR lv_stat.
    CLEAR lw_hkont_s.
    CLEAR lw_hkont_h.
    LOOP AT bool_data-bseg INTO lw_bseg.
    CASE lw_bseg-shkzg.
    WHEN ‘S’.
    lw_hkont_s = lw_bseg-hkont.
    WHEN ‘H’.
    lw_hkont_h = lw_bseg-hkont.
    WHEN OTHERS.
    ENDCASE.
    ENDLOOP.

    IF lw_hkont_s = ‘1012100001’.
    lv_stat = ‘02’.
    ELSEIF lw_hkont_s(4) = ‘1002’ AND lw_hkont_h(4) = ‘1002’ .
    lv_stat = ‘01’.
    ELSEIF lw_hkont_s(4) NE ‘1002’.
    lv_stat = ‘03’.
    ELSEIF lw_hkont_h(4) NE ‘1002’.
    lv_stat = ‘04’.
    ENDIF.

    LOOP AT bool_data-bseg INTO lw_bseg…
    CASE lv_stat.
    WHEN ‘01’.

       CASE lw_bseg-shkzg.
         WHEN 'S'.
           lw_bseg-rstgr = '401'.
         WHEN 'H'.
           lw_bseg-rstgr = '402'.
       ENDCASE.
       lw_bseg-sgtxt = '公司内转账'.
     WHEN '02'.
    
       CASE lw_bseg-shkzg.
         WHEN 'S'.
           "lw_bseg-RSTGR = '401'.
         WHEN 'H'.
           lw_bseg-rstgr = '111'.
       ENDCASE.
       lw_bseg-sgtxt = '退款/公司间转账/对分公司或结汇待支付账户转账'.
     WHEN '03'.
       CASE lw_bseg-shkzg.
         WHEN 'S'.
           "lw_bseg-RSTGR = '401'.
         WHEN 'H'.
           lw_bseg-rstgr = '222'.
       ENDCASE.
       lw_bseg-sgtxt = '公司间转账'.
     WHEN '04'.
       CASE lw_bseg-shkzg.
         WHEN 'S'.
           lw_bseg-rstgr = '311'.
         WHEN 'H'.
           "lw_bseg-RSTGR = '222'.
       ENDCASE.
       lw_bseg-sgtxt = '公司间转账'.
     WHEN OTHERS.
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    ENDCASE.

  • 退款时,根据付款请求凭证号的分配,文本,替换新的凭证
    IF <fs_l_regup>-keyno IS NOT INITIAL .
      SELECT SINGLE * INTO ls_bseg
             FROM bseg
             WHERE belnr = <fs_l_regup>-belnr
             AND   bukrs = <fs_l_regup>-bukrs
             AND   gjahr = <fs_l_regup>-gjahr
             AND   buzei = <fs_l_regup>-buzei .
      IF sy-subrc = 0 .
        lw_bseg-zuonr = ls_bseg-zuonr .
        lw_bseg-sgtxt = ls_bseg-sgtxt .
      ENDIF.
    ENDIF.
    
    
    MODIFY bool_data-bseg FROM lw_bseg.
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    ENDLOOP.
    ENDIF.

ENDFORM.

8、报文查看增强
部分银行在发送前对报文进行修改后,可能在查看通信日志里看不到对应的报文,实际报文是存储为http_message,在显示时仅显示xml_message;因此通过增强显示对应报文:

NCEMENT 2 ZEPIC_GET_XML_MESSAGE_PAB. "active version
IF ls_xml_message-xml_message IS INITIAL AND ls_bcd-hbkid+0(3) = ‘PAB’ or ls_bcd-hbkid+0(3) = ‘SHB’.
DATA:L_XML TYPE STRING,
L_CONV TYPE REF TO CL_ABAP_CONV_IN_CE.
DATA:LV_STRING1 TYPE STRING,
LV_STRING2 TYPE STRING.

CALL METHOD CL_ABAP_CONV_IN_CE=>CREATE
EXPORTING
ENCODING = ‘8450’
INPUT = ls_xml_message-http_message
RECEIVING
CONV = L_CONV.

CALL METHOD L_CONV->READ
IMPORTING
DATA = L_XML.
SPLIT L_XML AT ‘<’ INTO LV_STRING1 LV_STRING2.
CONCATENATE ‘<’ LV_STRING2 INTO LV_STRING2.
call function ‘SCMS_STRING_TO_XSTRING’
exporting
text = LV_STRING2

  •                       MIMETYPE       = ' '
      ENCODING = '8404'
        importing
         buffer         = ls_xml_message-xml_message
                  exceptions
          failed         = 1
          others         = 2.
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    endif.
    ENDENHANCEMENT.

四、特殊报文交互方式
通常,SAP与银行交互方式为HTTP POST方式的xml报文交互,也有部分银行会采用JSON数据格式或其他数据格式,请求方式也有HTTPS方式或者Socket方式。HTTP方式较为普遍,基本按照上面配置步骤,生成报文即可,关于其他HTTPS和Socket需要注意下:

1、HTTPS请求方式
HTTPS请求方式需要在SAP中导入相关SSL证书,具体操作为:

事务代码:STRUST;操作如下

在SM59中设置为HTTPS方式:选择登录&安全性à将安全协议:SSL设置为活动,并选择对应的SSL证书:

2、Socket方式
很大一部分银行在签名时,会采用Socket方式进行报文交互,通过在EPIC默认代码发出方式为http,遇到Socket方式的一般会失败,而且在接口中进行请求方式转换也无法解决,因此可以通过中转服务器,在http请求从SAP发出之后,通过中转将http转换为Socket再发送至前置机;在KMS系统中也有很多中转服务器的文档;基本步骤为:

安装python
2)设置环境变量:

3)打开cmd;输入python,出现python版本即为安装成功;
4)在CMD下输入pip install django;安装django包;完成后输入pip install requests安装requests包;
5)在cmd下输入python;再输入import django;导入成功后继续导入requests包:impoet requests。
6)安装包中的django拷贝至C盘根目录;
7)配置django/mysite/mysite目录下views.py文件和settings文件
中转服务器中建议添加日志记录,具体可参考下面文档:
Unsupported image type.
3、FTP或SFTP
有部分银行在明细接口,可能会返回文件到前置机(农行、南京银行);我们需要主动获取文件后进行解析。

一般SAP系统会与前置机直连,在通信过程为安全(SAP与前置机为明文http形式通讯;一般SAP服务器与前置机在内网同一网络即可)的情况下,可在前置机搭建FTP服务器,当银行返回为文件时,通过FTP服务器从前置机获取文件再解析;

若用户网络环境比较特殊,考虑接口报文中的敏感信息,或用户网络安全较高;可采用SFTP的方式;因为客户网络原因,有了解过SAP通过SFTP获取文件的方法,参照其他同事总结的文档了解了大概思路,具体为:

1.在Windows环境可以通过WinSCP软件作为SFTP的客户端;并编写响应的脚本命令;

2.在SM69通过执行外部命令,执行脚本

3.通过ABAP代码,执行SM69中的外部命令,获取到文件并解析。

五、一般问题
SM59为SAP系统与银行前置机的连接,在安装好前置机之后;SM59配置对应的前置机IP地址及端口,之后进行连接测试,若不通;尝试Ping前置机IP,以及telnet前置机端口,或是检查是否需要路径前缀(中国银行、民生银行、厦门国际)。
部分客户有多个内网,确保前置机网络和SAP在一个网络。
绝大部分银行前置机可以限制源IP、即将SAP服务器地址添加值前置机白名单且仅处理来自该IP的请求;该设置一般为非必要操作;当然也有银行前置机必须要配置SAP服务器地址(兴业银行)。
部分银行SM59连接测试时会超时,ping操作以及telnet均可连通;可以尝试直接发送报文(建设银行),能收到响应报文即可。
确保TRANSFORMATION转换结构与银行接口文档的XML报文示例,以及Abap处理结构相对应。部分不需要做处理的字段可以不解析。
报文解析出错一般先检查通信日志,查看发送报文与响应报文。如报文中是正确的,则检查TRANSFORMATION中是否转换正确。
DEBUG查看时,一般接口打断点调试即可,若回单接口断点进不去,可打外部断点进入调试。
回单接口报错’缺少外部交易类型的定制’是在处理回单时,写入输出结构中根据借贷方向选择回单如应收应付。
余额或历史余额查询不返回币种,取T012K表对应账号的币种。
付款结果查询时,根据付款条目所对应的公司代码+凭证号+财年拼接的字段查询付款结果。从FPRL_ITEM表中取数据,拼接zbukr、vblnr_pay、zaldt+0(4)三个字段。
付款时部分银行可能有字段长度限制,可截取财年的后两位。且在回单认领时,需要对该银行进行处理。
遇错误一般思路是先查看通信日志,查看发送和返回报文有没有错误。根据发送或响应报文的情况,判断错误出自哪里,再进行代码修改或是联系银行解决。
在EPIC_PROC付款时,可以进行批量付款,但是建议选中的条目数不要太多,由于系统限制,一次选中不能超过1000条,这是系统标准程序的限制。可以选中一少部分进行多次付款。
使用UKEY后进行批量付款,会出现每次付款都需要输入UKEY密码;目前这个问题SAP没有解决方案,目前项目只能根据时间限制,在输入密码后,根据时间来限制使用者下次需要输入密码的时间。
遇中文生僻字转换乱码问题,在TRANSFORMATION转换报文时,根据情况转换为string或xstring类型。
关于EPIC_PROC的增强激活,在EPIC_PROC事物代码下:环境->更改定制->电子支付集成->业务加载项

其他说明:
检查通信为查看每次业务的通信日志,包括付款、查询(余额查询、历史余额查询、交易明细查询、付款结果查询)、回单业务。

更改审批人为付款时提交审批的审批流设置

维护安全用户是部分银行会有安全用户设置,该操作仅对当前客户端有效,切换客户端时,可重新配置。

部分银行通讯时,可能对HTTP头信息有特定要求,比如content-type、User-Agent等信息。
一些进行签名后的报文,可能会需要URL Encoding,发送到银行服务器时才能被解析。

六、其他
1、自动查询付款结果
用户每天有大量付款数据,且付款后,付款结果查询时,并不能确定已付款数据的结果为最终结果;在银行间转账的过程中,结果处理会有延时,或者退款的情况;因此需要在一段时间后再次查询付款结果;但在大量的付款数据中,查找上一次付款数据,非常麻烦;因此考虑能否自动查询付款结果。

付款结果查询在标准代码中处理方式如下:仅通过付款条目的GUID找到DOC1R即付款公司代码+收付凭证号+财年;

cl_epic_pi_uil=>_action_execute_query(
EXPORTING
iv_selected_keys = ls_keys
IMPORTING
ef_found = lf_found ).
那么我们可以通过程序,选择某个时间点付款的数据,在一段时间后由JOB形式自动查询这批付款数据的结果。

在cl_epic_pi_uil=>_action_execute_query中会获取EPIC前台界面选中的数据,因此拷贝出标准的cl_epic_pi_uil,修改其_action_execute_query方法后,在job程序调用修改后的_action_execute_query进行结果查询。

2、自动获取回单
在EPIC里获取回单,系统会保留上一次获取回单的结束日期,作为下一次的开始日期,;因此通过调用系统中回单查询的类;在job程序中选择账户后,也可以进行回单查询。同样也需要拷贝系统中的cl_epic_ebr_req_uil,将pai_query_result中获取回单界面选中账号的部分代码注释后,将查询账户改为我们需要查询的账户。

--------------------------------------------------------------------
*获取回单界面所有账户
--------------------------------------------------------------------
CLEAR et_account.
IF mo_epic_ebr_fi_service IS NOT BOUND.
mo_epic_ebr_fi_service = cl_epic_ebr_fi_service=>get_instance( ).
ENDIF.
mo_epic_ebr_fi_service->get_house_bank_accounts(
EXPORTING
it_usage_range = lt_usage_cat
it_bukrs_range = it_bukrs_range
it_hbkid_range = it_hbkid_range
it_hktid_range = it_hktid_range
IMPORTING
et_account = et_account
).

mo_epic_ebr_fi_service->add_communication_type_text(
  CHANGING
    ct_account = et_account
).

LOOP AT et_account ASSIGNING <ls_account>.
  mo_epic_ebr_fi_service->read_bank_account(
    EXPORTING
      iv_bukrs          = <ls_account>-zbukr
      iv_hbkid          = <ls_account>-hbkid
      iv_hktid          = <ls_account>-hktid
    IMPORTING
      ev_bank_acct_no   = <ls_account>-bnkn2
      ev_bank_acct_name = <ls_account>-text1
      ev_bank_name      = <ls_account>-banka
  ).
ENDLOOP.
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

"查询账户回单
LOOP AT et_account INTO es_account WHERE select = ‘X’ ."OR hbkid+0(3) = ‘SHB’.
IF es_account-start_date IS INITIAL AND es_account-end_date IS INITIAL."日期为空
es_account-start_date = s_date-low.
es_account-end_date = s_date-high.
IF s_date-high IS INITIAL.
es_account-end_date = s_date-low + 1.
ENDIF.
ENDIF.
CLEAR:lt_req_parameters.
APPEND es_account TO lt_req_parameters.
CALL METHOD zcl_epic_ebr_req_uil=>pai_query_result(
EXPORTING
et_req_parameters = lt_req_parameters ).
ASSIGN fs_data->* TO <lt_grid_data>.
ENDLOOP.

3、自动查询历史余额/明细
查询账户历史余额或者明细,也可以通过JOB的形式。也是拷贝出系统cl_epic_qc_uil之后,注释掉send_query_to_bank中的一部分代码。如下:

CALL METHOD zcl_epic_qc_uil=>send_query_to_bank
EXPORTING
iv_background = ‘’
iv_startdate = gv_startdate
iv_enddate = gv_enddate
IMPORTING
ot_grid_data = fs_data
CHANGING
cs_query_select = cs_query_select.
ASSIGN fs_data->* TO <lt_grid_data>.

gv_startdate、gv_enddate分别为查询的开始日期、结束日期

fs_data为查询接口返回的数据,可根据需要做展示或者保存。

cs_query_select.为账户信息

附:
修改后的send_query_to_bank:
Unsupported image type.

自动查询等操作会在EPIC_PROC可产生日志,但是对于调用接口的结果,可在接口中对报文响应结果进行判断,从而产生接口处理结果的记录,方便用户查看。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小小林熬夜学编程/article/detail/323743
推荐阅读
相关标签
  

闽ICP备14008679号