工行银企互联 - CSDN
精华内容
参与话题
  • JAVA版 工行银企互联demo(NC)

    热门讨论 2020-07-28 23:32:49
    鉴于很多人都需要Java版本的 不必加本人QQ了 现提供demo版下载。
  • 2019年10月版本,通过工行银企互联(前置机NC模式+推广版)下载电子回单数据,并使用商业控件制作PDF电子回单。支持合并回单(一天的回单放在一个pdf文件中)。方法与官方网站open.icbc介绍的一致。需要安装.NET4...
  •  银企互联是指我行系统和企业的财务系统相联接,企业直接通过财务系统办理账户管理、转账支付等银行服务,并可根据需要自行在其财务系统中定制更多个性化功能的网上银行业务,是目前工行提供给高端客户的电子银行...
    一、业务简述


      银企互联是指我行系统和企业的财务系统相联接,企业直接通过财务系统办理账户管理、转账支付等银行服务,并可根据需要自行在其财务系统中定制更多个性化功能的网上银行业务,是目前工行提供给高端客户的电子银行产品。


      银企互联向客户提供了综合付款、综合收款、定期自动资金归集下拨、通过企业ERP提交的不定期资金归集下拨、账户余额保留、电子对账信息服务、电子工资单等多种功能,能够满足企业客户资金流入、资金内部流转、资金流出的全方位现金管理需求。


    二、适用对象


      银企互联适合于所有的企业网上银行客户,特别是希望实现资金集中管理,对企业财务信息与银行账户信息的实时一致性要求较高,注重财务工作效率,且具有ERP系统或财务软件系统的大型集团企业(部队、公共事业企业、大型集团公司、财务公司、结算中心)。


    三、特色优势


      1. 银企指令和数据联动,处理实时高效。


      使用银企互联,双方系统直接相联,客户可以通过自己的财务系统进行银行业务操作,可以实现指令实时处理和数据联动同步更新,保证了企业财务处理的高效率和财务信息的及时反馈。


      2. 全面的账户信息服务。


      银企互联提供了根据查询缴费账号、查询综合收付款指令处理状态、多账户余额查询、查询当日明细、查询综合收付款清单、查询归集(清扫)/下拨清单等多种标准信息的查询功能,同时还可以通过在银行柜面提供的及时的信息补录和对账补录,为您提供实时、准确、全面的对账服务。


      3. 个性化的定制功能。


      客户可利用工行提供的接口,根据内部管理需要灵活定制各种功能,实现各种个性化的设置,如操作的界面、权限的控制、资金运转的模式、账户的定向关系、指令处理的时间以及对账单的格式等。


      4. 强大的系统兼容性。


      银企互联的接口可以按照客户需求进行个性化定制,并支持Oracle、SAP、用友、金蝶等多种企业财务管理系统或银企互联系统。银企互联可以实现标准版企业网上银行的绝大部分功能,您可根据自身需要,通过财务软件系统对网上银行基本功能进行灵活的组合和控制,全面满足其日常财务工作需要。 [返回页首]


    四、开办条件


      在我行开立存结算账户,同时具有独立ERP系统的企业客户均可申请该业务。


    五、开通流程


      1. 签署协议


      企业与开户行协商确认需要实现的功能,并就各项收费达成一致后与银行签署《中国工商银行银企互联服务协议》。


      2. 提交开发计划


      客户获取产品接口文档和技术开发手册,了解相关接口开发说明,向开户行电子银行部门或主管部门提交《银企互联开发计划表》并组织开发。


      3. 填写申请表


      工商银行协助客户填写《中国工商银行银企互联客户注册申请表》及附表交开户行,并将《中国工商银行银企互联服务合作协议》复印件和各类申请表复印件交企业开户行电子银行部门或主管部门。


      4. 联合测试


      客户完成相关接口开发后,与开户行就测试的内容和时间要求进行协商,并提交《银企互联测试计划表》,申请进行业务测试。开户行根据客户实现功能情况,在《银企互联功能测试要点》基础上编写详细的测试要点。银行和企业按照《银企互联测试计划表》和《银企互联功能测试要点》完成测试,企业或者企业财务软件开发商应向企业开户行提交《银企互联测试总结报告》。


      5. 系统投产


      企业或者企业财务软件开发商应做好生产环境的准备工作,企业应向开户行提交《银企互联项目投产申请表》。开户行审批通过之后,向客户发放生产证书,完成投产工作。


      6. 投产验证


    开户行协助客户对查询、转账等交易进行验证。验证无误后可正式开通银企互联业务。


    六、服务渠道与时间


      企业ERP或财务系统。


    七、操作指南


      完全依照企业ERP或财务系统的操作步骤进行操作。


    八、名词解释

      综合付款功能:为客户提供对集团内、外任意本、外币账户付款,业务类型全面,付款对象范围包括工行系统内同城(同网点或跨网点)或异地账户,也包括跨行同城或异地账号。

      综合收款功能:是我行为客户提供主动收取其经过授权或签约客户(以下简称缴费客户)各类应缴费用的一项精品业务。客户可通过此服务主动扣收缴费客户的资金,实现资金快速入账。

      资金归集功能:可按照您的灵活要求将集团内下级单位账户的资金周期性的、自动的逐级上收至上级单位账户(顶点账户),同时,系统也可接受您不定时的指令完成资金归集。本功能只支持人民币。

      资金下拨功能:资金流向与资金归集的资金流向相反,可按照您的灵活要求将集团某个账户(顶点账户)的资金周期性的、自动的向下级单位的账户逐级下拨,同时,系统也可接受您不定时的指令完成资金下拨。该功能也只支持人民币。

      电子对账:我行系统每日按照集团客户要求的对账单格式,自动、定时向客户ERP系统发送内容全面、信息完整的账户对账信息。同时,客户也可通过ERP系统主动向银行查询账户对账信息文件。电子对账功能根据其查询的类别分为:查询余额、查询综合收付款指令处理状态、查询对账单、查询综合收付款清单、查询归集/下拨清单、根据协议查询缴费账号、查询当日明细等功能。

      工资单:企业客户向我行提交工资单文件,我行将工资单信息存入数据库,方便企业客户员工通过个人网上银行查询个人工资单信息,同时向企业客户提供了工资单文件的查询和删除功能。

      票据托管:票据托管实现了集团公司对分支机构所持票据的信息录入、查询,以及票据贴现、质押、转让、托收等功能。其中票据信息查询不仅可以查询到本集团录入的票据,还可以查到分支机构作录入的票据。集团公司将分支机构票据统一托管至开户行后,能够实时了解整个集团的票据情况,并通过网上银行对所持票据进行贴现、转让、委托银行到期收款等操作。

    九、风险提示

      请妥善保管企业网上银行客户证书及密码,证书及密码丢失有可能造成账户信息泄露和资金被盗的风险。
    展开全文
  • 工行银企互联接入详解(1)--流程说明

    千次阅读 2020-02-15 10:34:50
    要申请银企互联接口,得先向工行网点提交申请,具体需要什么材料可以根据银行要求提供即可,这方面的工作一般也不需要我们开发人员去办理。 申请通过后,工行会给一些东西,这里我统一称之为“凭证”,...

    兄弟们,今日头条搜索三线城市程序员老陈关注我,我将持续不断推出视频教程。

    背景

    公司需要调用银企互联接口实现财务操作的自动化,要知道银行接口是非常难以调试的,幸好从网上找到了《 Mr方de银企互联知识分享》系列文章,得以简洁快速的搞定项目,前人栽树后人乘凉,在此详细总结下。

    业务流程

    要申请银企互联接口,得先向工行网点提交申请,具体需要什么材料可以根据银行要求提供即可,这方面的工作一般也不需要我们开发人员去办理。

    申请通过后,工行会给一些东西,这里我统一称之为“凭证”,也就是说我们的程序通过凭证调用工行银企互联接口。

    貌似凭证种类挺多,我的凭证里面包括:公司名称、公司证书ID、一个U盾,参考号和授权码(用来往U盾中下载证书)、还有一个算法提示(此处是RSA1024)。上面这些信息中U盾是实物,剩下的都是银行工作人员打印出来的一张明白纸上写的。

    开发流程

    第一步,通过NC将证书下载到U盾,NC是工行银企互联的一个工具。
    该步骤我的理解是,U盾只是一个载体,具体证书还是用参考号和授权码换取后下载到U盾中的。

    第二步,需要配置并启动NC。
    NC相当于一个中间程序,我们的程序通过NC与工行核心服务器交互。

    第三步,需要部署银企互联的中间件,这样我们就可以直接调用中间件接口(WebService)来访问银企互联,而不用从头自己封装了。
    水平高的完全可以不用中间件自己封装,简单一些需求比如查询对账,也可以使用中间件来实现,再次要感谢Mr方老师的中间件,不然要自己写确实很费劲啊。
    注意中间件是.net的webservice,需要部署到IIS(相当于Java里面的Tomcat)上运行,这块如果没玩过.net的也没事,直接按照步骤操作即可。

    第四步,就是根据接口文档,实现具体的接口代码。
    参考示例代码,直接实现具体逻辑即可。

    展开全文
  • 此处参考文档即为《中国工商银行银企互联系统企业开发手册》,如果时间比较充分的话,可以按照手册描述进行开发。 当然还有一种捷径,【Mr方In苏州】老师已经封装了银企互联中间件,我们可以通过标准的Http接口访问...

    兄弟们,今日头条搜索三线城市程序员老陈关注我,我将持续不断推出视频教程。

    背景

    之前我们已经将NC启动了,所以接下来可以直接按照工行提供的开发文档,编写代码与NC交互,来实现对银企互联接口的调用。

    此处参考文档即为《中国工商银行银企互联系统企业开发手册》,如果时间比较充分的话,可以按照手册描述进行开发。

    当然还有一种捷径,【Mr方In苏州】老师已经封装了银企互联中间件,我们可以通过标准的Http接口访问中间件,然后再访问NC。

    也就是说,如果我们自己开发对接,则模式为:我们的程序--NC--工行服务

    如果我们用中间件对接开发,则模式为:我们的程序--中间件--NC--工行服务

    站在巨人的肩膀上好办事,此处我们采用NC中间件来实现对工行银企互联服务的访问。

    原理

    原理并不复杂,中间件已经实现了与NC的对接,然后中间件再屏蔽掉对接的一些细节,只把需要传递的内容报文部分作为参数让我们输入,简化了开发过程。

    需要注意中间件是用.net开发的webserivce,需要部署到iis上运行,IIS是微软的web容器。写Java的同学可能对Tomcat比较熟悉,IIS和Tomcat差不多的意思。

    声明

    该中间件是从公众号《Mr方的银企互联知识分享》下载的,版权等都归属原作者,此处只是简单介绍下具体使用流程,建议大家关注原作者公众号获取更多银企互联知识。

    另外我好像还找到了原作者CSDN博客,大家可以去看看:https://blog.csdn.net/fangrk

    部署流程

    原作者对实施流程写的比较详细了:https://mp.weixin.qq.com/s?__biz=MzUzMDk5NzM2NQ==&mid=2247483909&idx=1&sn=ba0a724a4e170790978fb49458e8059c&chksm=fa480b1fcd3f82099deddb320967e0d045c081fd78a61cda00f5453b1e8de0197fda46d22a44&scene=21#wechat_redirect

    此处按我自己的理解写下流程。

    第一步,下载并解压NC中间件

    下载地址:https://share.weiyun.com/5eoYcJL,路径如下图,我们只需要其中第一个rar文件。
    在这里插入图片描述

    第二步,修改Web.Config文件,如下图:

    在这里插入图片描述
    我们只需要修改:

    • nc_ip:改为之前配置的NC局域网ip,此处我的是192.168.20.2
    • cis:这个改为客户编号/CIS号,这个问下工行客户经理要下。
    • id:这个是工行给的证书名称,就是那个类似于FangNC3.y.1102的文本
    第三步,启用IIS功能

    打开控制面板–程序和功能–启用或关闭Windows功能–把Internet Information Services下面的勾全部打上,这样保证IIS功能都启用。
    在这里插入图片描述

    第四步,在IIS管理器中添加网站

    打开控制面板–管理工具–IIS管理器,右击网站–添加网站,如下图:
    在这里插入图片描述

    注意:

    • 网站名称随便写
    • 物理路径就是解压后的中间件所在文件夹
    • 需要点击连接为,然后选特定用户,然后输入登录用户名和密码后确定
    • IP地址填写局域网IP,因为我的中间件和NC都部署于一台服务器,所以此处依然为192.168.20.2
    • 端口写一个未占用的就行,此处使用666
    第五步,测试中间件是否部署成功

    刚刚设置了中间件的IP为192.168.20.2,端口为666,所以直接使用浏览器访问http://192.168.20.2:666/WebService.asmx,结果如下,这个问题百度下CS0016错误解决即可。

    在这里插入图片描述

    再次访问,结果如下:
    在这里插入图片描述
    说明中间件部署成功。

    第六步,测试中间件参数是否正确

    此处继续点击上图中的Check_NC方法,然后点击调用按钮,如果结果如下:
    在这里插入图片描述
    则表示一切正常。

    如果提示有问题,还需要检查web.config以及NC配置的参数是否都准确。

    总结

    中间件的作用就是简化开发,目前中间件已经运行了,NC也运行着,我们可以直接根据文档开发接口了。

    展开全文
  • 开通业务:工行银企互联推广版(NC 模式)。鉴于安全角度考虑,可以申请一个仅查询权限的银企互联(磁盘)证书。 功能简述: 1、检测NetSafeClient通讯是否正常。 2、查询余额。如果账号的备注信息中包含“保证金”...
  • 相关NC中间件的文章,已经放到个人公众号(“开发谈”栏目),扫码可以进入。... 客户使用银企互联,应遵从谨小慎微的原则,从查询业务、小金额业务着手,必要时采用银企互联提交指令、企业网银授权的模式。 本WebS...

    相关NC中间件的文章,已经放到个人公众号(“开发谈”栏目),扫码可以进入。

    1. 适用对象:自己动手开发银企互联的企业客户。
    2. 非官方产品,客户应优先根据官方开发手册自行开发。
    3. 开发者免责:开发者力求正确,也经过测试,但无法避免潜在的错误。任何软件都可能存在错误。
    4. 客户使用银企互联,应遵从谨小慎微的原则,从查询业务、小金额业务着手,必要时采用银企互联提交指令、企业网银授权的模式。
    5. 本WebService程序在Windows操作系统上部署,需要.net4.0框架。
    6. 未尽事宜,请参阅官方开发手册。

    常规开发模式中,数据交互方式如下:

     

    如果是签名类交易,业务发起流程如上图。客户开发的工作量主要是 1、3,较为繁琐。
    如果是查询类交易,则上述步骤中 1、2 不做。

    企业客户开发过程通常遇到的问题:

    1. 不太愿意看官方开发文档。实际上,我自己开始着手练习银企互联技术,就是按照官方文档来的。
    2. 不知道如何去做签名。
    3. 银行测试环境日期非标准,无法灵活应对请求信息中的日期、时间相关参数。
    4. 很少自己产生日志文件,遇到错误难以确定。向银行陈述错误没有依据。
    5. 采用过程化,很少对象化,代码复用性差,程序不健壮。
    6. 官方提供的DEMO比较少。
    7. 部分企业客户的系统不支持socket协议,需要银行或者开发商提供辅助手段。
    8. 一些高级技巧、应用无从谈起,比如大批量指令发送,制作PDF格式的电子回单。

    本方案设计的数据交互为:

    本方案图中步骤 2、5,相当于第一图中的 1、2、3、6,由 WebService 自动执行。

    特点:

    1. ERP系统只需要通过HTTP协议将参数和发送内容一次性POST到WebService指定页面,接收应答即可。开发者不需要关注签名、提交页面格式、报文头参数、压缩模式等,实现了跨平台、跨语言的简单开发。
    2. 支持压缩模式提交大批量指令:rd最外层头尾套<zip>、</zip>即可,比如:……<zip><rd>……</rd>……<rd>……</rd></zip>……。WebService会自行压缩数据。如将压缩好的数据放入zip节点(官方做法)后使用本程序提交反而会出错。
    3. XML报文中日期/时间关键参数自动配置,大部分情况下自适应银行主机时间。特别是在测试环境的时候,不需要调整本机时间。
    4. ICBC_Log文件夹可以保存日志文件,方便跟踪。
    5. 提供PDF文件的高级应用。

    部署本WebService,需要.NET4框架。

    1. 如果没有按照.net4框架,请安装。如果没有安装IIS,请安装。为减少错误,其中应用程序开发功能请全选。
    2. 添加网站,选择物理路径,自己定义一个不常用的端口,本例使用1398。
    3. 运行。浏览器打开对应地址,比如http://127.0.0.1:1398,点击WebService.asmx,可以看到提供的服务。点击CheckNC或者CheckWS,可以查看到对应返回内容,则表明部署成功。
    4. 如果需要从局域网其他电脑访问本WebService,则需要在防火墙中添加的本服务端口(入站、TCP)。

     

    WebService中Web.Config信息:

    nc_ip:NetSafeClient的IP地址。

    nc_hp、nc_sp:NetSafeClient的HTTPS服务端口以及签名端口。

    cis、id:客户企业网银对应的CIS编号和证书名称。使用ICBC_YQHL方法时与XML中信息校验。

    log、pdf_save:是否产生日志文件,是否保留pdf回单文档。方便客户调试。

    如果防火墙端口未添加,从其他电脑访问出错:

     

    添加端口后,访问正常:

    提供的方法以及需要的参数,可以自行点击WebService.asmx查看。比如QACCBAL,从图中看到就是acct一个参数:

     

    本项目的第一个测试客户,是因为sap不支持socket协议,提出“银行给出中间服务层”的需求。给了他们第一个版本(参数个数和现在有些不同),经过调试,畅通。下图是客户sap界面,他们用了get方式,已经建议修改为post。

    对于最重要的ICBC_YQHL方法做些说明:

    • 程序自动替换内容的空白节点请使用<node></node>这种格式,如果写成<node/>这种,程序无法自动填充其数值。TranDate、TranTime、SignTime等字段,程序将自动补充,为避免部分系统自动将<TranDate></TranDate>变成<TranDate/>这种格式,可以随意输入些内容,比如<TranDate>NotCare</TranDate>。
    • fSeqno节点内容如果空白或内容长度<=3,则由系统自动填写。个人建议:查询类的报文该字段可以空白或输入长度小于3的内容,交易类的请指定fseqno内容(长度>3),避免发送请求后没有接收到回执而无从判断银行究竟接收到了指令没有。

    从网上摘录一些代码,作为本项目的多语言测试。

    PHP:先查询余额;做一笔支付;再查询余额。由于是工行系统内支付,实时处理,故第二次查询的时候,余额已经变化了。

    <?php
    header('charset: GBK');
    
    function send_post($url, $post_data) {
        $postdata = http_build_query($post_data);
        $options = array(
            'http' => array(
                'method' => 'POST',
                'header' => 'Content-type:application/x-www-form-urlencoded',
                'content' => $postdata,
                'timeout' => 30 // 超时时间(单位:s)
            )
        );
        $context = stream_context_create($options);
        $result = file_get_contents($url, false, $context);
        return $result;
    }
    $xml_info='<?xml version="1.0"encoding="GBK"?><CMS><eb><pub><TransCode>PAYENT</TransCode><CIS>46694306-XAAAAA</CIS>'
    .'<BankCode>102</BankCode><ID>suzhouTest.y.1102</ID><TranDate></TranDate>NotCare<TranTime>NotCare</TranTime><fSeqno>X</fSeqno>'
    .'</pub><in><OnlBatF>1</OnlBatF><SettleMode>0</SettleMode><TotalNum>1</TotalNum><TotalAmt>1122</TotalAmt><SignTime></SignTime>'
    .'<ReqReserved1></ReqReserved1><ReqReserved2></ReqReserved2><rd><iSeqno>1</iSeqno><ReimburseNo></ReimburseNo><ReimburseNum>'
    .'</ReimburseNum><StartDate></StartDate><StartTime></StartTime><PayType>1</PayType><PayAccNo>1102020109000009078</PayAccNo>'
    .'<PayAccNameCN>剥滥火判酬</PayAccNameCN><PayAccNameEN></PayAccNameEN><RecAccNo>1102020109000203242</RecAccNo>'
    .'<RecAccNameCN>剥滥判幕耕婚舒憾</RecAccNameCN><RecAccNameEN></RecAccNameEN><SysIOFlg>1</SysIOFlg><IsSameCity></IsSameCity>'
    .'<Prop></Prop><RecICBCCode></RecICBCCode><RecCityName>工行系统内无需注明</RecCityName><RecBankNo></RecBankNo>'
    .'<RecBankName>工行系统内无需注明</RecBankName><CurrType>001</CurrType><PayAmt>1122</PayAmt><UseCode></UseCode>'
    .'<UseCN>上线测试</UseCN><EnSummary></EnSummary><PostScript></PostScript><Summary></Summary><Ref></Ref><Oref></Oref>'
    .'<ERPSqn></ERPSqn><BusCode></BusCode><ERPcheckno></ERPcheckno><CrvouhType></CrvouhType><CrvouhName></CrvouhName>'
    .'<CrvouhNo></CrvouhNo><BankType></BankType><FileNames></FileNames><Indexs></Indexs><PaySubNo></PaySubNo>'
    .'<RecSubNo></RecSubNo><MCardNo></MCardNo><MCardName></MCardName></rd></in></eb></CMS>';
    $post_data = array(
    	'ver'=>'0.0.1.0',
    	'b64_xml'=>base64_encode($xml_info)
    );
    $post_data2 = array('acct'=>'1102020109000009078');
    echo send_post('http://127.0.0.1:1398/WebService.asmx/QACCBAL', $post_data2);
    echo "\r\n";
    echo send_post('http://127.0.0.1:1398/WebService.asmx/ICBC_YQHL', $post_data);
    echo "\r\n";
    echo send_post('http://127.0.0.1:1398/WebService.asmx/QACCBAL', $post_data2);
    
    ?>

    对ReqResult信息做BASE64解码,就能得到原文了,在此不述。

    Python3.7:相同的演示。

    #!/usr/bin/python
    # -*- coding: GBK -*-
    import base64
    from urllib import request
    from urllib import parse
    from urllib.request import urlopen
    
    test_data = {'acct':'1102020109000009078'}
    test_data_urlencode = parse.urlencode(test_data).encode('GBK')
    requrl = 'http://10.0.0.5:1398/WebService.asmx/QACCBAL'
    req = request.Request(requrl,test_data_urlencode)
    res_data = urlopen(req)
    res = res_data.read()
    print (res.decode())
    
    xml_info='<?xml version="1.0"encoding="GBK"?><CMS><eb><pub><TransCode>PAYENT</TransCode><CIS>46694306-XAAAAA</CIS>'\
    '<BankCode>102</BankCode><ID>suzhouTest.y.1102</ID><TranDate></TranDate>NotCare<TranTime>NotCare</TranTime><fSeqno>X</fSeqno>'\
    '</pub><in><OnlBatF>1</OnlBatF><SettleMode>0</SettleMode><TotalNum>1</TotalNum><TotalAmt>4455</TotalAmt><SignTime></SignTime>'\
    '<ReqReserved1></ReqReserved1><ReqReserved2></ReqReserved2><rd><iSeqno>1</iSeqno><ReimburseNo></ReimburseNo><ReimburseNum>'\
    '</ReimburseNum><StartDate></StartDate><StartTime></StartTime><PayType>1</PayType><PayAccNo>1102020109000009078</PayAccNo>'\
    '<PayAccNameCN>剥滥火判酬</PayAccNameCN><PayAccNameEN></PayAccNameEN><RecAccNo>1102020109000203242</RecAccNo>'\
    '<RecAccNameCN>剥滥判幕耕婚舒憾</RecAccNameCN><RecAccNameEN></RecAccNameEN><SysIOFlg>1</SysIOFlg><IsSameCity></IsSameCity>'\
    '<Prop></Prop><RecICBCCode></RecICBCCode><RecCityName>工行系统内无需注明</RecCityName><RecBankNo></RecBankNo>'\
    '<RecBankName>工行系统内无需注明</RecBankName><CurrType>001</CurrType><PayAmt>4455</PayAmt><UseCode></UseCode>'\
    '<UseCN>上线测试</UseCN><EnSummary></EnSummary><PostScript></PostScript><Summary></Summary><Ref></Ref><Oref></Oref>'\
    '<ERPSqn></ERPSqn><BusCode></BusCode><ERPcheckno></ERPcheckno><CrvouhType></CrvouhType><CrvouhName></CrvouhName>'\
    '<CrvouhNo></CrvouhNo><BankType></BankType><FileNames></FileNames><Indexs></Indexs><PaySubNo></PaySubNo>'\
    '<RecSubNo></RecSubNo><MCardNo></MCardNo><MCardName></MCardName></rd></in></eb></CMS>'
    
    test_data = {'ver':'0.0.1.0','b64_xml':base64.b64encode(xml_info.encode('GBK'))}
    test_data_urlencode = parse.urlencode((test_data)).encode('GBK')
    requrl = 'http://10.0.0.5:1398/WebService.asmx/ICBC_YQHL'
    req = request.Request(requrl,test_data_urlencode)
    res_data = urlopen(req)
    res = res_data.read()
    print (res.decode())
    
    test_data = {'acct':'1102020109000009078'}
    test_data_urlencode = parse.urlencode(test_data).encode('GBK')
    requrl = 'http://10.0.0.5:1398/WebService.asmx/QACCBAL'
    req = request.Request(requrl,test_data_urlencode)
    res_data = urlopen(req)
    res = res_data.read()
    print (res.decode())
    

    JAVA:

    import java.util.*;
    
    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.io.PrintWriter;
    import java.net.URL;
    import java.net.URLConnection;
    import java.util.List;
    import java.util.Map;
    
    public class YQHL
    {
    public static void main(String[] args)throws Exception
    {
     //Base64.Decoder decoder = Base64.getDecoder();
     Base64.Encoder encoder = Base64.getEncoder();
     String xml_text = "<?xml version=\"1.0\"encoding=\"GBK\"?><CMS><eb><pub><TransCode>PAYENT</TransCode><CIS>46694306-XAAAAA</CIS>"+
    "<BankCode>102</BankCode><ID>suzhouTest.y.1102</ID><TranDate></TranDate>NotCare<TranTime>NotCare</TranTime><fSeqno>X</fSeqno>"+
    "</pub><in><OnlBatF>1</OnlBatF><SettleMode>0</SettleMode><TotalNum>1</TotalNum><TotalAmt>6789</TotalAmt><SignTime></SignTime>"+
    "<ReqReserved1></ReqReserved1><ReqReserved2></ReqReserved2><rd><iSeqno>1</iSeqno><ReimburseNo></ReimburseNo><ReimburseNum>"+
    "</ReimburseNum><StartDate></StartDate><StartTime></StartTime><PayType>1</PayType><PayAccNo>1102020109000009078</PayAccNo>"+
    "<PayAccNameCN>剥滥火判酬</PayAccNameCN><PayAccNameEN></PayAccNameEN><RecAccNo>1102020109000203242</RecAccNo>"+
    "<RecAccNameCN>剥滥判幕耕婚舒憾</RecAccNameCN><RecAccNameEN></RecAccNameEN><SysIOFlg>1</SysIOFlg><IsSameCity></IsSameCity>"+
    "<Prop></Prop><RecICBCCode></RecICBCCode><RecCityName>工行系统内无需注明</RecCityName><RecBankNo></RecBankNo>"+
    "<RecBankName>工行系统内无需注明</RecBankName><CurrType>001</CurrType><PayAmt>6789</PayAmt><UseCode></UseCode>"+
    "<UseCN>上线测试</UseCN><EnSummary></EnSummary><PostScript></PostScript><Summary></Summary><Ref></Ref><Oref></Oref>"+
    "<ERPSqn></ERPSqn><BusCode></BusCode><ERPcheckno></ERPcheckno><CrvouhType></CrvouhType><CrvouhName></CrvouhName>"+
    "<CrvouhNo></CrvouhNo><BankType></BankType><FileNames></FileNames><Indexs></Indexs><PaySubNo></PaySubNo>"+
    "<RecSubNo></RecSubNo><MCardNo></MCardNo><MCardName></MCardName></rd></in></eb></CMS>";
    
     byte[] textByte = xml_text.getBytes("GBK");
    
     String encodedText = encoder.encodeToString(textByte);
    //System.out.println(encodedText);
    
    //System.out.println(new String(decoder.decode(encodedText), "GBK"));
    System.out.println(sendPost("http://10.0.0.5:1398/WebService.asmx/QACCBAL","acct=1102020109000203242"));
    System.out.println(sendPost("http://10.0.0.5:1398/WebService.asmx/ICBC_YQHL","ver=0.0.1.0&b64_xml="+encodedText));
    System.out.println(sendPost("http://10.0.0.5:1398/WebService.asmx/QACCBAL","acct=1102020109000203242"));
    
    }
     public static String sendPost(String url, String param) {
            PrintWriter out = null;
            BufferedReader in = null;
            String result = "";
            try {
                URL realUrl = new URL(url);
                // 打开和URL之间的连接
                URLConnection conn = realUrl.openConnection();
                // 设置通用的请求属性
                conn.setRequestProperty("accept", "*/*");
                conn.setRequestProperty("connection", "Keep-Alive");
                conn.setRequestProperty("user-agent",
                        "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
                conn.setRequestProperty("Accept-Charset", "utf-8");
                conn.setRequestProperty("contentType", "utf-8");
                // 发送POST请求必须设置如下两行
                conn.setDoOutput(true);
                conn.setDoInput(true);
                // 获取URLConnection对象对应的输出流
                out = new PrintWriter(conn.getOutputStream());
                // 发送请求参数
                out.print(param);
                // flush输出流的缓冲
                out.flush();
                // 定义BufferedReader输入流来读取URL的响应
                in = new BufferedReader(
                        new InputStreamReader(conn.getInputStream(),"UTF-8"));
                String line;
                while ((line = in.readLine()) != null) {
                    result += line;
                }
            } catch (Exception e) {
                System.out.println("发送 POST 请求出现异常!"+e);
                e.printStackTrace();
            }
            //使用finally块来关闭输出流、输入流
            finally{
                try{
                    if(out!=null){
                        out.close();
                    }
                    if(in!=null){
                        in.close();
                    }
                }
                catch(IOException ex){
                    ex.printStackTrace();
                }
            }
            return result;
        } 
    }

    运行:

    使用.NET:介绍一下大批量支付(一次性提交1000笔指令)。使用本项目会非常简单,在最外层的rd循环节点套一个<zip>即可。

    using System;
    using System.Text;
    using System.Net;
    using System.IO;
    
    class Program
     {
      static void Main(string[] args)
      {
    	string rd_text="<rd><iSeqno>_X_</iSeqno><ReimburseNo></ReimburseNo><ReimburseNum></ReimburseNum><StartDate></StartDate><StartTime></StartTime>"+
    "<PayType>1</PayType><PayAccNo>1102020109000009078</PayAccNo><PayAccNameCN>剥滥火判酬</PayAccNameCN><PayAccNameEN></PayAccNameEN>"+
    "<RecAccNo>1102020109000203242</RecAccNo><RecAccNameCN>剥滥判幕耕婚舒憾</RecAccNameCN><RecAccNameEN></RecAccNameEN>"+
    "<SysIOFlg>1</SysIOFlg><IsSameCity></IsSameCity><Prop></Prop><RecICBCCode></RecICBCCode><RecCityName>工行系统内无需注明"+
    "</RecCityName><RecBankNo></RecBankNo><RecBankName>工行系统内无需注明</RecBankName><CurrType>001</CurrType><PayAmt>_X_</PayAmt>"+
    "<UseCode></UseCode><UseCN>上线测试</UseCN><EnSummary></EnSummary><PostScript></PostScript><Summary></Summary><Ref></Ref><Oref></Oref>"+
    "<ERPSqn></ERPSqn><BusCode></BusCode><ERPcheckno></ERPcheckno><CrvouhType></CrvouhType><CrvouhName></CrvouhName>"+
    "<CrvouhNo></CrvouhNo><BankType></BankType><FileNames></FileNames><Indexs></Indexs><PaySubNo></PaySubNo>"+
    "<RecSubNo></RecSubNo><MCardNo></MCardNo><MCardName></MCardName></rd>";
      string rd_total="";
      int money=0;
      for(int i=1;i<=1000;++i){
      	rd_total+=rd_text.Replace("_X_",i.ToString());
      	money+=i;
      }
      
        string xml_text = "<?xml version=\"1.0\"encoding=\"GBK\"?><CMS><eb><pub><TransCode>PAYENT</TransCode><CIS>46694306-XAAAAA</CIS>"+
    "<BankCode>102</BankCode><ID>suzhouTest.y.1102</ID><TranDate></TranDate>NotCare<TranTime>NotCare</TranTime><fSeqno>X</fSeqno>"+
    "</pub><in><OnlBatF>1</OnlBatF><SettleMode>0</SettleMode><TotalNum>1000</TotalNum><TotalAmt>"+money.ToString()+"</TotalAmt><SignTime></SignTime>"+
    "<ReqReserved1>大批量压缩测试</ReqReserved1><ReqReserved2></ReqReserved2><zip>"+rd_total+"</zip></in></eb></CMS>";
    
       string b64_xml=Convert.ToBase64String(Encoding.GetEncoding("GBK").GetBytes(xml_text));
       Console.WriteLine(HttpPostTest("http://127.0.0.1:1398/WebService.asmx/QACCBAL","acct=1102020109000009078"));
       Console.WriteLine();
       Console.WriteLine(HttpPostTest("http://127.0.0.1:1398/WebService.asmx/ICBC_YQHL","ver=0.0.1.0&b64_xml="+b64_xml));
       Console.WriteLine();
       Console.WriteLine(HttpPostTest("http://127.0.0.1:1398/WebService.asmx/QACCBAL","acct=1102020109000009078"));
      }
    static string HttpPostTest(string url, string content)
            {
                byte[] bytesToPost = Encoding.GetEncoding("UTF-8").GetBytes(content);
                string cookieheader = string.Empty;
                CookieContainer cookieCon = new CookieContainer();
    
                #region 创建HttpWebRequest对象
                HttpWebRequest httpRequest = (HttpWebRequest)WebRequest.Create(url);
                #endregion
    
                #region 初始化HtppWebRequest对象
    
                httpRequest.CookieContainer = cookieCon;
                httpRequest.UserAgent = "Mozilla/4.0 (compatible; MSIE 6.0;)";
                httpRequest.ContentType = "application/x-www-form-urlencoded";
                httpRequest.Method = "POST";
                httpRequest.Timeout = 15 * 1000;
    
                if (cookieheader.Equals(string.Empty))
                {
                    cookieheader = httpRequest.CookieContainer.GetCookieHeader(new Uri(url));
                }
                else
                {
                    httpRequest.CookieContainer.SetCookies(new Uri(url), cookieheader);
                }
                #endregion
    
                string stringResponse = "";
                try
                {
    
                    #region 附加Post给服务器的数据到HttpWebRequest对象
                    httpRequest.ContentLength = bytesToPost.Length;
                    System.IO.Stream requestStream = httpRequest.GetRequestStream();
                    requestStream.Write(bytesToPost, 0, bytesToPost.Length);
                    requestStream.Close();
                    #endregion
    
    
                    #region 读取服务器返回信息
    
    
                    System.IO.Stream responseStream = httpRequest.GetResponse().GetResponseStream();
    
                    using (System.IO.StreamReader responseReader = new System.IO.StreamReader(responseStream, Encoding.GetEncoding("UTF-8")))
                    {
                        stringResponse = responseReader.ReadToEnd();
                    }
                    responseStream.Close();
                    #endregion
                }
                catch (Exception)
                {
                    ;
                }
                return  stringResponse;
            }
     }

    运行截图:

    大批量支付,一般需要10分钟左右来处理,因此马上查询余额没有变化。

    对应查询指令,只要把支付时候的请求编号放到查询报文的对应字段QryfSeqno即可。

    查询指令状态代码:BASE64解码,直接输出明文:

    using System;
    using System.Text;
    using System.Net;
    using System.IO;
    
    class Program
     {
      static void Main(string[] args)
      {
    
        string xml_text = "<?xml version=\"1.0\" encoding = \"GBK\"?><CMS><eb><pub><TransCode>QPAYENT</TransCode>"+
    "<CIS>46694306-XAAAAA</CIS><BankCode>102</BankCode><ID>suzhouTest.y.1102</ID><TranDate></TranDate><TranTime></TranTime><fSeqno></fSeqno></pub>"+
    "<in><QryfSeqno>1810281121DHCV@PE</QryfSeqno><QrySerialNo></QrySerialNo></in></eb></CMS>";
    
       string b64_xml=Convert.ToBase64String(Encoding.GetEncoding("GBK").GetBytes(xml_text));   
       string result=HttpPostTest("http://127.0.0.1:1398/WebService.asmx/ICBC_YQHL","ver=0.0.1.0&b64_xml="+b64_xml);
       int p1=result.IndexOf("ReqResult=");
       int p2=result.LastIndexOf("</string>");
       string result2= Encoding.GetEncoding("GBK").GetString(Convert.FromBase64String(result.Substring(p1+10,p2-p1-10)));
       Console.WriteLine(result2);
       
      }
    static string HttpPostTest(string url, string content)
            {
                byte[] bytesToPost = Encoding.GetEncoding("UTF-8").GetBytes(content);
                string cookieheader = string.Empty;
                CookieContainer cookieCon = new CookieContainer();
    
                #region 创建HttpWebRequest对象
                HttpWebRequest httpRequest = (HttpWebRequest)WebRequest.Create(url);
                #endregion
    
                #region 初始化HtppWebRequest对象
    
                httpRequest.CookieContainer = cookieCon;
                httpRequest.UserAgent = "Mozilla/4.0 (compatible; MSIE 6.0;)";
                httpRequest.ContentType = "application/x-www-form-urlencoded";
                httpRequest.Method = "POST";
                httpRequest.Timeout = 15 * 1000;
    
                if (cookieheader.Equals(string.Empty))
                {
                    cookieheader = httpRequest.CookieContainer.GetCookieHeader(new Uri(url));
                }
                else
                {
                    httpRequest.CookieContainer.SetCookies(new Uri(url), cookieheader);
                }
                #endregion
    
                string stringResponse = "";
                try
                {
    
                    #region 附加Post给服务器的数据到HttpWebRequest对象
                    httpRequest.ContentLength = bytesToPost.Length;
                    System.IO.Stream requestStream = httpRequest.GetRequestStream();
                    requestStream.Write(bytesToPost, 0, bytesToPost.Length);
                    requestStream.Close();
                    #endregion
    
    
                    #region 读取服务器返回信息
    
    
                    System.IO.Stream responseStream = httpRequest.GetResponse().GetResponseStream();
    
                    using (System.IO.StreamReader responseReader = new System.IO.StreamReader(responseStream, Encoding.GetEncoding("UTF-8")))
                    {
                        stringResponse = responseReader.ReadToEnd();
                    }
                    responseStream.Close();
                    #endregion
                }
                catch (Exception)
                {
                    ;
                }
                return  stringResponse;
            }
     }

    运行:

    可用输出重定向的方式保存到文件查看,比如:QPAYENT > show.txt

    对于回单,经过自己的技术积累,目前提供PDF回单服务,回单格式是自己设计的,比官方的似乎要多一些内容。使用的是破解版商业控件,本人在PDF文档中做了说明,仅用于学习和研究之用。另外,PDF回单文件中文字、图片等都是可以自己修改,所以回单的意义在于存档,生产环境数据得到的回单可以去官方网站验证。如果涉及法律纠纷,需要向银行索要纸质有盖章的凭据。

    讲一下PDF回单的获取方法:

    输入参数:账号、日期(年月日yyyyMMdd格式)、时间戳,金额(整数,无小数点)。

    输出:0|错误消息;1|经过BASE64编码的二进制文件流

    输入参数,可以通过查询明细的方式获取,建议使用0.0.1.0版本的QHISD接口。

    我用.NET代码演示一下:

    using System;
    using System.Text;
    using System.Net;
    using System.IO;
    
    class Program
     {
      static void Main(string[] args)
      {
       Console.WriteLine(DateTime.Now.ToString());
       string result=HttpPostTest("http://127.0.0.1:1398/WebService.asmx/PDF_Receipt","acct=1102020109000009078&date=20181003&time=2018-10-04-15.00.23.937835&amount=582");
       int p1=result.IndexOf("|");
       int p2=result.IndexOf("</string>");
       if(p1>0 && p2>0 && result[p1-1]=='1'){
       	B64String2File(result.Substring(p1+1,p2-p1-1),"csc_code.pdf");
       	Console.WriteLine("csc_code.pdf saved!");
       }else Console.WriteLine(result);
       Console.WriteLine(DateTime.Now.ToString());
       
      }
    static void B64String2File(string B64Str,string fileName)
            {
                byte[] bb= Convert.FromBase64String(B64Str);
                FileStream fs = new FileStream(fileName, FileMode.Create);
                fs.Write(bb, 0, bb.Length);
                fs.Close();
            }
    static string HttpPostTest(string url, string content)
            {
                byte[] bytesToPost = Encoding.GetEncoding("UTF-8").GetBytes(content);
                string cookieheader = string.Empty;
                CookieContainer cookieCon = new CookieContainer();
    
                #region 创建HttpWebRequest对象
                HttpWebRequest httpRequest = (HttpWebRequest)WebRequest.Create(url);
                #endregion
    
                #region 初始化HtppWebRequest对象
    
                httpRequest.CookieContainer = cookieCon;
                httpRequest.UserAgent = "Mozilla/4.0 (compatible; MSIE 6.0;)";
                httpRequest.ContentType = "application/x-www-form-urlencoded";
                httpRequest.Method = "POST";
                httpRequest.Timeout = 30 * 1000;
    
                if (cookieheader.Equals(string.Empty))
                {
                    cookieheader = httpRequest.CookieContainer.GetCookieHeader(new Uri(url));
                }
                else
                {
                    httpRequest.CookieContainer.SetCookies(new Uri(url), cookieheader);
                }
                #endregion
    
                string stringResponse = "";
                try
                {
    
                    #region 附加Post给服务器的数据到HttpWebRequest对象
                    httpRequest.ContentLength = bytesToPost.Length;
                    System.IO.Stream requestStream = httpRequest.GetRequestStream();
                    requestStream.Write(bytesToPost, 0, bytesToPost.Length);
                    requestStream.Close();
                    #endregion
    
    
                    #region 读取服务器返回信息
    
    
                    System.IO.Stream responseStream = httpRequest.GetResponse().GetResponseStream();
    
                    using (System.IO.StreamReader responseReader = new System.IO.StreamReader(responseStream, Encoding.GetEncoding("UTF-8")))
                    {
                        stringResponse = responseReader.ReadToEnd();
                    }
                    responseStream.Close();
                    #endregion
                }
                catch (Exception)
                {
                    ;
                }
                return  stringResponse;
            }
     }

    运行截图:

    打开看看pdf文档:

    PHP代码用于获取PDF回单:

    <?php
    header('charset: GBK');
    function send_post($url, $post_data) {
        $postdata = http_build_query($post_data);
        $options = array(
            'http' => array(
                'method' => 'POST',
                'header' => 'Content-type:application/x-www-form-urlencoded',
                'content' => $postdata,
                'timeout' => 30 // 超时时间(单位:s)
            )
        );
        $context = stream_context_create($options);
        $result = file_get_contents($url, false, $context);
        return $result;
    }
    $post_data = array(
    	'acct'=>'1102020109000043166',
    	'date'=>'20181003',
    	'time'=>'2018-10-04-15.07.05.677042',
    	'amount'=>'166'
    );
    $bank_ret=send_post('http://127.0.0.1:1398/WebService.asmx/PDF_Receipt', $post_data);
    $p1= strpos($bank_ret,'|');
    $p2= strpos($bank_ret,'</string>');
    $b64ed=substr($bank_ret,$p1+1,$p2-$p1-1); 
    $content = base64_decode($b64ed); // 解码
    $saveFile = 'php_test.pdf';
    file_put_contents($saveFile, $content, true);
    
    ?>

    回单截图:

    其他编程语言用于获取PDF回单的代码,读者可自行尝试。

    后记:

    银企互联业务绝大部分客户都是使用NC模式。非NC模式需要使用官方的jar控件包来实现NetSafeClient的两个服务功能,这增加了开发工作量,也限制了开发语言,好处是能得到银行主动通知。我对非NC模式没有研究。


    在十多年的工作中,本人多次协助、指导客户开发,感觉客户自身在银企互联对接方面做的都不够完善和健壮。可能职业程序员都是赶任务,完成目标即可,根本没时间也没动力去对项目优化。本人技术水平一般,甚至可以说是落后的(毕竟工作岗位不是软件开发),但有比较充裕的时间专攻一面。本程序是我十多年银企互联技术支持的经验积累成果,功能完备,能大幅缩减企业开发周期和成本,方便跟踪、调试。


    该WebService是鉴于某个SAP客户的需求而生,因客户的SAP不支持socket协议,要求银行提供中间服务层。先是咨询了本地一个软件服务商(坐标江苏),开发这么一个中间层大约需要10天,友情报价4万元。后来又听客户说某个银行开发这么个东西花了10万。这个价格本人觉得合理的,每天4K-5K,花上十天、大半月能搞定已经很不错了。但普通的软件开发商对这项业务以及技术的了解,应该不会比我更加深入。日常接触到使用一些颇有名气的软件的客户,还会打电话问“这笔指令你们银行接收到了吗?”——财务系统居然连一个查询指令状态的接口都没做。思来想去,决定还是自己动手开发一套程序试试。之后发现该方案适用面很大,可以让更多的客户受益,也算是为工行银企互联业务的推广出一把力吧。

    Bug Report & Advise:fangrk_sz@qq.com

     

    百度网盘:

    https://pan.baidu.com/s/1lrR9qyJcDQdZTO0XtB3lyA

    展开全文
  • 工行银企互联经验点滴

    千次阅读 2009-11-05 21:10:00
    工行银企互联经验点滴 现在越来越多企业为了提高工作效率、加快资金周转速率、节约资金成本、提升企业综合竞争力,直接使用银企互联来代替原有的网银等工作,完成原有网银能胜任的所有工作及大量原有网银不能完成的...
  • 准备工作 ... 然后需要确认下NC中间件是启动的,这个上一篇已经说过了。 创建项目 ...申请银企互联通过后,工行一般会发给接口文档,给我的是每个接口一个excel文件如下: 我们打开《查询当日明细.xl...
  • 我们的程序通过NC与工行服务进行交互,所以需要配置NC的参数,并启动NC,我们的程序才能访问NC。 注意配置和启动NC前,需要确保U盾证书已下载,并且U盾已连接电脑。 打开NC 同样启动startup.bat,然后浏览器地址栏...
  • http返回码是 200 错误代码是 errorCode=RDAwOTg= 哪位大神知道这是什么问题啊
  • 用XML数据打包发送数据到NC(加密),再传输给工行工行依据指令向账户汇款!有相关的可借鉴的代码块,希望能给我参考下!
  • 工行银企互联,实现向工行发送数据包,银行向各个银行卡汇款!小弟一脸懵逼中!
  • 工行api开放平台

    千次阅读 2019-03-24 20:22:38
    工行api开发平台是基于工商银行海量用户,接入第三方合作伙伴服务,向用户提供安全、稳定、简洁的金融接入服务,构建用户、开发者、银行互利共赢的“金融生态圈” 目前在工行api门户提供了8大类服务,其中包括账号...
  • 工行接口比较坑

    千次阅读 2018-07-25 10:19:39
    说必须申请银企互联接口. 说说跟银行对接的业务问题,业务人员不会告诉你对接会遇到的各种问题。比如,服务器环境要求,我直接是网站环境php5.3 +php7.0做的工行接口。刚开始无法下单,报了个存储故障,通过和工行...
  • 工行聚合支付经验总结

    千次阅读 2018-12-29 16:23:19
    工行聚合支付经验总结 1.被动通知查询验签结果ReturnValue.verifySign()为1(0为成功),可能是用的公钥不对,非文档或者demo里用的证书公钥(xxx.cer),而是需要用一个叫需要用总行聚合支付公钥(prod_ebb2cpublic....
  • 工行银企互联

    2020-07-30 23:31:53
    工行银企互联最新版所有的接口。 功能简述: 1、检测NetSafeClient通讯是否正常。 2、查询余额。如果账号的备注信息中包含“保证金”字样,将查询保证金账户的信息。 3、查询明细,含当天明细和历史明细。明细结果...
  • asp.net(C#)工商银行银企互联 例子 使用vs2010开发,可做参考
  • C#工行 银企互联demo(NC)

    热门讨论 2020-07-30 23:32:33
    本人亲测 并且开发过程也遇到很多问题 对工行解决问题的态度也很不爽 最终弄了一个demo给大家参考参考 望有用处。
  • 中间件的介绍以及下载地址见上一文章:... ... 2018.11上旬更新: 1、PDF电子回单的下方链接信息,增加了工行主页、个人网银、企业网银的链接。 2、新增了PDF_PAYPE...
1 2 3 4 5
收藏数 94
精华内容 37
热门标签
关键字:

工行银企互联