精华内容
下载资源
问答
  • 本文中的设计原型简单介绍:在金蝶云星空K3 Cloud中发起付款单,对接到企业微信中进行审批流程,并将审批结果对接回金蝶云星空。 在金蝶云星空发起付款单审批 提交人填写付款单单据内容后,点击“提交”,单据进入...

    与财务单据对接、业务单据对接不同,易对接的审批流对接产品是指:业务单据在业务系统中生成,推送企业微信进行审批流程处理,然后返回审批结果到业务系统。
    本文中的设计原型简单介绍:在金蝶云星空K3 Cloud中发起付款单,对接到企业微信中进行审批流程,并将审批结果对接回金蝶云星空
    在这里插入图片描述

    在金蝶云星空发起付款单审批

    提交人填写付款单单据内容后,点击“提交”,单据进入审批流程。
    在这里插入图片描述

    在企业微信中完成单据审批

    审批人将在企业微信中收到付款单审批申请。单据按照设置的审批流程,完成所有环节的审批。
    在这里插入图片描述

    同步审批结果回到金蝶云星空

    审批流程结束后,易对接会把审批结果对接回金蝶云星空,付款单状态变更为审批通过。
    在这里插入图片描述
    ——————————————————
    易对接“企业微信对接”方案,利用企业微信的审批引擎创建业务单据,经过设置的审批流程后,将业务单据和审批结果对接到业务系统;帮助企业用户能更好地使用企业微信来实现审批流程移动化,赋能企业提升经营效率,助力企业更低成本实现数字化转型。

    展开全文
  • --付款条件 l_vendor_site_rec.purchasing_site_flag :='Y'; l_vendor_site_rec.pay_site_flag :='Y'; l_vendor_site_rec.rfq_only_site_flag :='N'; l_vendor_site_rec.vat_code := org1.vat_code; l_vendor_...

    用户需求:由于公司没有OA系统,但是又想对新建的供应商有一个审批的功能,以致可以很好的

    对新供应商进行有效管理,收集供应商数据,审厂审批,部门经理审批等流程。

    做法:客制Form界面,用户界面中录入供应商相关资料,然后workflow送审到相关人员,

    最后部门主管审批时,系统调用api导入供应商

    供应商导入api code如下:

    procedure new_vendor_api(p_vendor_id number,p_flag out varchar2) is--供应商导入api
        --新建供应商部分 
        p_api_version          number;
        p_init_msg_list        varchar2(200);
        p_commit               varchar2(200);
        p_validation_level     number;
        x_return_status        varchar2(200);
        x_msg_count            number;
        x_msg_data             varchar2(200);
        l_msg                  varchar2(200);
        lr_vend                apps.ap_vendor_pub_pkg.r_vendor_rec_type;
        lr_ex_vend             ap_suppliers%rowtype;
        x_vendor_id            number;
        x_party_id             number;
        pin_copy_vendor_id     number;
        
        --新建供应商地点部分
        l_vendor_site_rec      ap_vendor_pub_pkg.r_vendor_site_rec_type;
        lc_return_status         VARCHAR2(10);
        ln_msg_count            NUMBER;
        lc_msg_data               VARCHAR2(1000);
        ln_vendor_site_id     NUMBER;
        ln_party_site_id         NUMBER;
        ln_location_id            NUMBER;
        
        --新建联系人部分
        l_vendor_contact_rec ap_vendor_pub_pkg.r_vendor_contact_rec_type;
        l_return_status VARCHAR2(10);
        l_msg_count NUMBER;
        l_msg_data VARCHAR2(1000);
        l_vendor_contact_id NUMBER;
        l_per_party_id NUMBER;
        l_rel_party_id NUMBER;
        l_rel_id NUMBER;
        l_org_contact_id NUMBER;
        l_party_site_id NUMBER;
        
        l_vendor jw_vendor_t%rowtype;
        
        cursor ou1 is
          select o.ou_id,o.vat_code
            from jw_vendor_org_t  o 
           where o.jw_vendor_id = p_vendor_id
             and o.flag = 'Y';
      begin
        select * into l_vendor from  jw_vendor_t t where t.jw_vendor_id = p_vendor_id;
        fnd_global.apps_initialize(l_vendor.created_by,
                                 50643,
                                 201);
        mo_global.init('SQLAP'); 
        p_api_version      := 1.0;
        p_init_msg_list    := fnd_api.g_true;
        p_commit           := fnd_api.g_true;
        p_validation_level := fnd_api.g_valid_level_full;
        lr_vend.hold_flag              := null;
        lr_vend.purchasing_hold_reason := null;
        lr_vend.hold_by                := null;
        lr_vend.hold_date              := null; 
        begin
        if l_vendor.attribute9 is not null then
          lr_vend.END_DATE_ACTIVE := sysdate + l_vendor.attribute9;--增加临时厂商的有效期天数
        end if;
        exception
          when others then
             null;
        end;
        lr_vend.vendor_id         := null;
        lr_vend.vendor_name       := l_vendor.vendor_name;   --供应商名字
        lr_vend.start_date_active := sysdate;
        ap_vendor_pub_pkg.create_vendor(p_api_version      => p_api_version,
                                      p_init_msg_list    => p_init_msg_list,
                                      p_commit           => p_commit,
                                      p_validation_level => p_validation_level,
                                      x_return_status    => x_return_status,
                                      x_msg_count        => x_msg_count,
                                      x_msg_data         => x_msg_data,
                                      p_vendor_rec       => lr_vend,
                                      x_vendor_id        => x_vendor_id,
                                      x_party_id         => x_party_id);
        commit;                              
        IF (x_return_status <> FND_API.G_RET_STS_SUCCESS) THEN --失败 
           p_flag := 'E';
        else--成功后新建供应商地点
           p_flag := 'Y';
           for org1 in ou1 loop
             
             l_vendor_site_rec.vendor_id               := x_vendor_id;--vendor_id
             l_vendor_site_rec.vendor_site_code  := l_vendor.vendor_site_code;
             l_vendor_site_rec.address_line1         := l_vendor.vendor_site_address;
              --l_vendor_site_rec.city                           := 'New York';
             l_vendor_site_rec.country                    := 'CN';
             l_vendor_site_rec.org_id                      := org1.ou_id;
             l_vendor_site_rec.terms_id := l_vendor.attribute1;--付款条件
             l_vendor_site_rec.purchasing_site_flag  :='Y';
             l_vendor_site_rec.pay_site_flag                :='Y'; 
             l_vendor_site_rec.rfq_only_site_flag       :='N';
             l_vendor_site_rec.vat_code := org1.vat_code;
             l_vendor_site_rec.payment_currenCY_code := l_vendor.attribute4;
             l_vendor_site_rec.INVOICE_currenCY_code := l_vendor.attribute4;
             pos_vendor_pub_pkg.create_vendor_site
            ( 
                  -- ------------------------------
                  -- Input data elements
                  -- ------------------------------
                  p_vendor_site_rec    => l_vendor_site_rec,
                  -- ---------------------------------
                  -- Output data elements
                  -- ---------------------------------
                  x_return_status         => lc_return_status,
                  x_msg_count             => ln_msg_count,
                  x_msg_data                => lc_msg_data,
                  x_vendor_site_id      => ln_vendor_site_id,
                  x_party_site_id         => ln_party_site_id,
                  x_location_id            => ln_location_id
            );
            commit;
            IF (lc_return_status <> FND_API.G_RET_STS_SUCCESS) THEN  --失败
              p_flag :='E';
            else
              p_flag := 'Y';
              
            end if;
           end loop;
           if p_flag  = 'Y' then
             if l_vendor.vendor_contact is not null then--有联系人时才调用此api
                   l_vendor_contact_rec.vendor_id := x_vendor_id;
                --   l_vendor_contact_rec.org_id := org1.ou_id; 
                   l_vendor_contact_rec.person_last_name := l_vendor.vendor_contact; 
                   l_vendor_contact_rec.phone := l_vendor.vendor_contact_tel;
                   l_vendor_contact_rec.org_party_site_id := ln_party_site_id;
                   pos_vendor_pub_pkg.create_vendor_contact(
                      p_vendor_contact_rec => l_vendor_contact_rec,
                      x_return_status => l_return_status,
                      x_msg_count => l_msg_count,
                      x_msg_data => l_msg_data,
                      x_vendor_contact_id => l_vendor_contact_id,
                      x_per_party_id => l_per_party_id,
                      x_rel_party_id => l_rel_party_id,
                      x_rel_id => l_rel_id,
                      x_org_contact_id => l_org_contact_id,
                      x_party_site_id => l_party_site_id);
    
                   COMMIT;
                   IF (l_return_status <> FND_API.G_RET_STS_SUCCESS) THEN
                     p_flag :='E';
                   else
                     p_flag := 'Y';
                   end if;
                end if;
           end if;
        end if;                                                
        null;
      end;

    ps:以上api包括导入供应商名字,地点,联系人,没有银行等数据,系统版本R12.1.3
    展开全文
  • 提供了很丰富的企业应用,其中包括了业务审批处理,审批业务包括请假、报销、费用、出差等很多个审批场景,在Winform开发框架中工作流模块这些模块也是可以很好的实现,本篇随笔介绍如何参照企业微信审批业务,结合...

    目前微信的企业号已经切换到企业微信里面,这个是一个APP程序,提供了很丰富的企业应用,其中包括了业务审批处理,审批业务包括请假、报销、费用、出差等很多个审批场景,在Winform开发框架中工作流模块这些模块也是可以很好的实现,本篇随笔介绍如何参照企业微信审批业务,结合框架中的工作流模块,实现多种表单的审批处理。

    1、企业微信审批

    在开始介绍框架中工作流模块之前,我们先来了解下企业微信中的审批业务,如下界面所示,这些审批表单包括有:请假、报销、费用、出差、采购、加班、外出、用车、用章、合同审批、物品领用、付款、物品维修、会议室预定等这些常见的流程业务。

    我们打开其中一个业务,看看其中的业务表单信息。

    其中包括一些请假业务的相关信息,包括内容输入、附件管理等,这样就可以提交及抄送给对应给的人员了。

    提交后,对业务表单的数据就可以查看及进行流程处理了,如下是业务表单的查看界面。

     

    2、开发框架中工作流模块的业务审批

    首先我们需要根据业务表单的数据,填写相关的信息,从而可以在业务的动态展示列表中展现可以新建的表单,如下界面所示。

    至于每个业务表单的相关开发,我在随笔《Winform开发框架中工作流模块的业务表单开发》中介绍比较详细,每个流程业务表单主要涉及到几个窗体的处理,一个是新增编辑业务申请单、一个是查看业务申请和展示申请单的用户控件,以及一个常规的业务查询需要的界面,其中一些窗体我们已经进行了基类封装,简化了子类窗体的代码,如下界面所示。

    例如对于请假业务申请单,我们的界面效果如下所示。

    它主要是继承FrmAddApply ,并实现业务申请单数据校验、表单流程发送及数据显示(重新编辑的时候显示)等处理即可。界面代码相对比较简单了。

    对于查看具体业务表单的显示界面,继承查看申请单的基类FrmViewApply类基类,那么这个子类只需要负责数据的展示就是了。

    数据展示部分分为固定通用的申请单信息,以及业务表单信息两部分组成,其中附件处理则采用通用附件管理模块按钮即可,如下所示。

    这些是在用户控件上进行展示的,设计状态下的用户控件效果如下所示。

    上面的介绍的请假申请单是单表的情况,有时候,我们申请单是主从表的情况,如报销申请单,需要汇总总的报销信息、包括总金额,然后把各种明细记录提交,这种表单界面效果如下所示。

    这种明细表单可以直接在表格控件Griview上进行新增、编辑处理。

    查看详细的表单界面效果如下所示。

    这种业务申请单比较单表而已,相对复杂一些,需要处理GridView的数据录入和保存处理,以及数据的显示处理,不过也是比较标准的处理,我们也是同样继承相同的基类,在子类实现不同的业务处理代码即可。

    后面我们为了减轻开发工作流,把这些业务表单的界面使用代码生成工具一键生成,直接可用,这样就省事多了。

     

    3、工作流业务界面的代码生成

    从上面我们可以看到,其中对于工作流业务表单的窗体界面都可以实现标准的处理了,继承自某个基类,然后整合相关的数据处理规则即可。

    那么我们提炼业务信息后,可以使用代码生成工具快速生成,这样可以极大提高我们的开发效率。

    针对上面的构想,我们花费了好几天的时间,创建了工作流界面的自动生成规则和反复校验,最终整合到代码生成工具中方便开发。

    对于主从表表的界面,我们依旧也可以使用代码生成工具进行快速的工作流界面生成。

     

    至于如何使用这个功能,后面在开一篇随笔详细进行介绍过程。

    WInform开发框架之工作流系列文章:

    Winform开发框架之简易工作流设计

    Winform开发框架中工作流模块的表设计分析

    Winform开发框架中工作流模块的业务表单开发

    Winform开发框架中工作流模块之审批会签操作

    Winform开发框架中工作流模块之审批会签操作(2)

    参照企业微信审批业务,在Winform开发框架中工作流模块的实现业务审批

    展开全文
  • 审批接口调用总是伴随着状态回调的通知,设置接收消息,可以让自建应用和企业微信之间进行双向通信。 当然在此之前,我们需要确定,企业微信后台是否开启了审批状态通知。 一. 企业微信回调验证 二. 企业...

    审批接口调用总是伴随着状态回调的通知,设置接收消息,可以让自建应用和企业微信之间进行双向通信。

    当然在此之前,我们需要确定,企业微信后台是否开启了审批状态通知。

     一. 企业微信回调验证

     二. 企业微信消息交互(重要)

     三. 审批状态回调

     四. 查询审批状态

     

    注意: 想要成功接收到企业微信回调的信息 ,解密Encrypt,得到明文的消息结构体尤为重要,当然解密后得到的是xml格式文件,我们还需要解析xml文件,才能得到我们想要拿到的字段。

     

    一. 企业微信回调验证

    点击保存即会开始验证url的有效性。官方文档关于验证url有效性也是介绍的很仔细。(回想当时,一步一个坑!!!)

    验证URL有效性

    当点击“保存”提交以上信息时,企业微信会发送一条验证消息到填写的URL,发送方法为GET
    企业的接收消息服务器接收到验证请求后,需要作出正确的响应才能通过URL验证。

    企业在获取请求时需要做Urldecode处理,否则可能会验证不成功
    你可以访问接口调试工具进行调试,依次选择 建立连接 > 接收消息。

    假设接收消息地址设置为:http://api.3dept.com/,企业微信将向该地址发送如下验证请求:

    请求方式:GET
    请求地址:http://api.3dept.com/?msg_signature=ASDFQWEXZCVAQFASDFASDFSS&timestamp=13500001234&nonce=123412323&echostr=ENCRYPT_STR
    参数说明

    参数 必须 说明
    msg_signature 企业微信加密签名,msg_signature结合了企业填写的token、请求中的timestamp、nonce参数、加密的消息体
    timestamp 时间戳
    nonce 随机数
    echostr 加密的字符串。需要解密得到消息内容明文,解密后有random、msg_len、msg、receiveid四个字段,其中msg即为消息内容明文

    企业后台收到请求后,需要做如下操作:

    1. 对收到的请求做Urldecode处理
    2. 通过参数msg_signature对请求进行校验,确认调用者的合法性。
    3. 解密echostr参数得到消息内容(即msg字段)
    4. 1秒内响应GET请求,响应内容为上一步得到的明文消息内容(不能加引号,不能带bom头,不能带换行符)

    以上2~3步骤可以直接使用验证URL函数一步到位。
    之后接入验证生效,接收消息开启成功。

    (以上来自企业微信官方文档)

    在后台编码中,我们需要先下载官方demo,demo里面封装了加密、解密算法,还用验证过程中需要用到对象类。(下载官方demohttps://work.weixin.qq.com/api/doc#90000/90138/90307

        //企业微信回调验证
        @RequestMapping(value = "callback",method = RequestMethod.GET)
        public void connect(HttpServletRequest request, HttpServletResponse response){
    
            //当你提交以上信息时,企业号将发送GET请求到填写的URL上,GET请求携带四个参数,企业在获取时需要做urldecode处理,否则会验证不成功
    
            // 微信加密签名
            String msg_signature = request.getParameter("msg_signature");
            // 时间戳
            String timestamp = request.getParameter("timestamp");
            // 随机数
            String nonce = request.getParameter("nonce");
            // 随机字符串
            String echoStr = request.getParameter("echostr");
    
            //回调key值
            String sEchoStr = null;
    
            String contacts_token = PropertiesUtil.getProperty("contacts_token");
            String contacts_encodingaeskey = PropertiesUtil.getProperty("contacts_encodingaeskey");
            String corpId = PropertiesUtil.getProperty("corpid");
    
            try {
    
                PrintWriter out = response.getWriter();
    
                WXBizMsgCrypt wxcpt = new WXBizMsgCrypt(contacts_token,contacts_encodingaeskey,corpId);
                sEchoStr = wxcpt.VerifyURL(msg_signature,timestamp,nonce,echoStr);
    
                if(StringUtils.isBlank(sEchoStr)){
                    logger.error("URL验证失败");
                }
                out.write(sEchoStr);
                out.flush();
    
            }catch (Exception e){
                logger.error("企业微信回调url验证错误",e);
            }
        }

    验证url有效性,按照步骤走,一般没什么大问题。

    二. 企业微信消息交互

    使用接收消息

    开启接收消息模式后,企业微信会将消息发送给企业填写的URL,企业后台需要做正确的响应。

    接收消息协议的说明

    • 企业微信服务器在五秒内收不到响应会断掉连接,并且重新发起请求,总共重试三次。如果企业在调试中,发现成员无法收到被动回复的消息,可以检查是否消息处理超时。
    • 当接收成功后,http头部返回200表示接收ok,其他错误码企业微信后台会一律当做失败并发起重试。
    • 关于重试的消息排重,有msgid的消息推荐使用msgid排重。事件类型消息推荐使用FromUserName + CreateTime排重。
    • 假如企业无法保证在五秒内处理并回复,或者不想回复任何内容,可以直接返回200(即以空串为返回包)。企业后续可以使用主动发消息接口进行异步回复。

    接收消息请求的说明

    假设企业的接收消息的URL设置为http://api.3dept.com。
    请求方式:POST
    请求地址 :http://api.3dept.com/?msg_signature=ASDFQWEXZCVAQFASDFASDFSS&timestamp=13500001234&nonce=123412323

    接收数据格式 :

    
     
    1. <xml>
    2. <ToUserName><![CDATA[toUser]]></ToUserName>
    3. <AgentID><![CDATA[toAgentID]]></AgentID>
    4. <Encrypt><![CDATA[msg_encrypt]]></Encrypt>
    5. </xml>

    参数说明

    参数 说明
    ToUserName 企业微信的CorpID,当为第三方套件回调事件时,CorpID的内容为suiteid
    AgentID 接收的应用id,可在应用的设置页面获取
    Encrypt 消息结构体加密后的字符串

    企业收到消息后,需要作如下处理:

    1. 对msg_signature进行校验
    2. 解密Encrypt,得到明文的消息结构体(消息结构体后面章节会详说)
    3. 如果需要被动回复消息,构造被动响应包
    4. 正确响应本次请求

    以上1~2步骤可以直接使用解密函数一步到位。
    3步骤其实包含加密被动回复消息、生成新签名、构造被动响应包三个步骤,可以直接使用加密函数一步到位。

    (以上来自企业微信官方文档)

     

     //企业微信消息交互
        @RequestMapping(value = "callback",method = RequestMethod.POST)
        public void acceptMessage(HttpServletRequest request, RedirectAttributes attributes, HttpSession session){
    
            logger.debug("企业微信信息交互");
    
            // 微信加密签名
            String sMsgSignature = request.getParameter("msg_signature");
            // 时间戳
            String sTimestamp = request.getParameter("timestamp");
            // 随机数
            String sNonce = request.getParameter("nonce");
    
            String sMsg = "";
    
    
            String contacts_token = PropertiesUtil.getProperty("contacts_token");
            String contacts_encodingaeskey = PropertiesUtil.getProperty("contacts_encodingaeskey");
            String corpId = PropertiesUtil.getProperty("corpid");
    
            try{
                InputStream inputStream = request.getInputStream();
                String sPostData = IOUtils.toString(inputStream,"UTF-8");
    
                WXBizMsgCrypt wxcpt = new WXBizMsgCrypt(contacts_token,contacts_encodingaeskey,corpId);
                sMsg = wxcpt.DecryptMsg(sMsgSignature,sTimestamp,sNonce,sPostData);
    
                //将post数据转换为map
                Map<String,String> dataMap = MessageUtil.parseXml(sMsg);
    
                //成员userId
                String fromUserName = dataMap.get("FromUserName");
                ServerResponse<EmpVo> response = iEmployeeService.updateOrInsertByUserId(fromUserName);
                if(response.isSuccess()){
                    session.setAttribute(Common.CURRENT_USER,response.getData());
                }
    
                String msgType = dataMap.get("MsgType");
    
                if(msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_EVENT)){
                    String eventType = dataMap.get("Event");
    
                    //审批状态回调通知
                    if(eventType.equals(MessageUtil.EVENT_TYPE_OPEN_APPROVAL_CHANGE)){
                        ServerResponse approvalCallbackResponse = iApprovalService.approvalChangeCallback(dataMap);
                        if(!approvalCallbackResponse.isSuccess()){
                            logger.error("审批回调通知,审批单号为:"+dataMap.get("ThirdNo")+",异常信息为:"+response.getMsg());
                        }
                    }
                }
            }catch (Exception e){
                logger.error("企业微信消息交互错误",e);
            }
        }

     

    请求方式为post,企业微信消息交互时用的是post请求,自身验证时用的是get方式。post请求一般用于接收企业微信端发送的消息,各类事件通知。

    关于消息体Encrypt,消息结构体加密后的字符串,企业微信文档的介绍大概可以用一句话描述,我一笔带过,你采坑无数。

    这里开始时真的有点摸不着头脑,文档关于加密,解密介绍的很高大上,原理,算法,就是不告诉你该用何种方法进行接收。 

     所以贴一个,用于信息交互,解析xml消息体的工具类:

    public class MessageUtil {
    
        /**
         * 返回消息类型:文本
         */
        public static final String RESP_MESSAGE_TYPE_TEXT = "text";
    
        /**
         * 返回消息类型:音乐
         */
        public static final String RESP_MESSAGE_TYPE_MUSIC = "music";
    
        /**
         * 返回消息类型:图文
         */
        public static final String RESP_MESSAGE_TYPE_NEWS = "news";
    
        /**
         * 请求消息类型:文本
         */
        public static final String REQ_MESSAGE_TYPE_TEXT = "text";
    
        /**
         * 请求消息类型:图片
         */
        public static final String REQ_MESSAGE_TYPE_IMAGE = "image";
    
        /**
         * 请求消息类型:链接
         */
        public static final String REQ_MESSAGE_TYPE_LINK = "link";
    
        /**
         * 请求消息类型:地理位置
         */
        public static final String REQ_MESSAGE_TYPE_LOCATION = "location";
    
        /**
         * 请求消息类型:音频
         */
        public static final String REQ_MESSAGE_TYPE_VOICE = "voice";
    
        /**
         * 请求消息类型:推送
         */
        public static final String REQ_MESSAGE_TYPE_EVENT = "event";
    
        /**
         * 事件类型:subscribe(订阅)
         */
        public static final String EVENT_TYPE_SUBSCRIBE = "subscribe";
    
        /**
         * 事件类型:unsubscribe(取消订阅)
         */
        public static final String EVENT_TYPE_UNSUBSCRIBE = "unsubscribe";
    
        /**
         * 事件类型:CLICK(自定义菜单点击事件)
         */
        public static final String EVENT_TYPE_CLICK = "CLICK";
    
        /**
         * 事件类型:taskcard_click(点击任务卡片按钮)
         */
        public static final String EVENT_TYPE_TASKCARD_CLICK = "taskcard_click";
    
    
        /**
         * 事件类型:open_approval_change(审批状态通知事件)
         */
        public static final String EVENT_TYPE_OPEN_APPROVAL_CHANGE = "open_approval_change";
    
        public static final String EVENT_TYPE_ENTER_AGENT = "enter_agent";
    
        /**
         * 解析微信发来的请求(XML)
         *
         * @return
         * @throws Exception
         */
        @SuppressWarnings("unchecked")
        public static Map<String, String> parseXml(String msg) throws Exception {
            // 将解析结果存储在HashMap中
            Map<String, String> map = new HashMap<String, String>();
    
            // 从request中取得输入流
            InputStream inputStream = new ByteArrayInputStream(msg.getBytes("UTF-8"));
    
            // 读取输入流
            SAXReader reader = new SAXReader();
            Document document = reader.read(inputStream);
            // 得到xml根元素
            Element root = document.getRootElement();
            // 得到根元素的所有子节点
            List<Element> elementList = root.elements();
    
            // 遍历所有子节点
            for (Element e : elementList)
                map.put(e.getName(), e.getText());
    
            // 释放资源
            inputStream.close();
            inputStream = null;
    
            return map;
        }

     解析xml文件,用的是SAX方式解析,得到根节点,在遍历子节点。

    三. 审批状态回调

    审批状态回调事件:open_approval_change

    消息体解密后为xml格式,需要对xml文件进行解析,得到消息体内容

        <xml>
         <ToUserName>wwd08c8e7c775ab44d</ToUserName>  
          <FromUserName>sys</FromUserName>  
          <CreateTime>1527838022</CreateTime>  
          <MsgType>event</MsgType>  
          <Event>open_approval_change</Event>
          <AgentID>1</AgentID>
          <ApprovalInfo> 
            <ThirdNo>201806010001</ThirdNo>  
            <OpenSpName>付款</OpenSpName>  
            <OpenTemplateId>1234567890</OpenTemplateId> 
            <OpenSpStatus>1</OpenSpStatus>  
            <ApplyTime>1527837645</ApplyTime>  
            <ApplyUserName>jackiejjwu</ApplyUserName>  
            <ApplyUserId>WuJunJie</ApplyUserId>  
            <ApplyUserParty>产品部</ApplyUserParty>  
            <ApplyUserImage>http://www.qq.com/xxx.png</ApplyUserImage>  
            <ApprovalNodes> 
              <ApprovalNode> 
                <NodeStatus>1</NodeStatus>  
                <NodeAttr>1</NodeAttr> 
                <NodeType>1</NodeType>  
                <Items> 
                  <Item> 
                    <ItemName>chauvetxiao</ItemName>  
                    <ItemUserid>XiaoWen</ItemUserid> 
                    <ItemParty>产品部</ItemParty>  
                    <ItemImage>http://www.qq.com/xxx.png</ItemImage>  
                    <ItemStatus>1</ItemStatus>  
                    <ItemSpeech></ItemSpeech>  
                    <ItemOpTime>0</ItemOpTime> 
                  </Item> 
                </Items> 
              </ApprovalNode> 
            </ApprovalNodes>  
            <NotifyNodes> 
              <NotifyNode> 
                <ItemName>jinhuiguo</ItemName>  
                <ItemUserid>GuoJinHui</ItemUserid> 
                <ItemParty>行政部</ItemParty>  
                <ItemImage>http://www.qq.com/xxx.png</ItemImage>  
              </NotifyNode> 
            </NotifyNodes> 
            <approverstep>0</approverstep>  
          </ApprovalInfo> 
        </xml>

    成功解析回调事件发送的xml消息体后,我们会得到xml消息的内容,可以自行封装approvalInfo,拿到自己需要的字段。

    OpenSpStatus这个字段很重要:申请单当前审批状态:1-审批中;2-已通过;3-已驳回;4-已取消

     

    四. 查询审批状态

    主动查询审批单的当前审批状态。

    请求方式: POST(HTTPS
    请求地址: https://qyapi.weixin.qq.com/cgi-bin/corp/getopenapprovaldata?access_token=ACCESS_TOKEN

    请求示例:

             入参:(审批单号)json格式

       {"thirdNo": "201806010001"}

    参数说明:

    参数 必须 说明
    access_token 调用接口凭证
    thirdNo 开发者发起申请时定义的审批单号

    返回结果:(json格式)

        {
            "errcode": 0,
            "errmsg": "ok",
            "data": {
                "ThirdNo": "201806010001",
                "OpenTemplateId": "1234567890",
                "OpenSpName": "付款",
                "OpenSpstatus": 1,
                "ApplyTime": 1527837645,
                "ApplyUsername": "jackiejjwu",
                "ApplyUserParty": "产品部",
                "ApplyUserImage": "http://www.qq.com/xxx.png",
                "ApplyUserId": "WuJunJie",
                "ApprovalNodes": {
                    "ApprovalNode": [
                        {
                            "NodeStatus": 1,
                            "NodeAttr": 1,
                            "NodeType": 1,
                            "Items": {
                                "Item": [
                                    {
                                        "ItemName": "chauvetxiao",
                                        "ItemParty": "产品部",
                                        "ItemImage": "http://www.qq.com/xxx.png",
                                        "ItemUserId": "XiaoWen",
                                        "ItemStatus": 1,
                                        "ItemSpeech": "",
                                        "ItemOpTime": 0
                                    }
                                ]
                            }
                        }
                    ]
                },
                "NotifyNodes": {
                    "NotifyNode": [
                        {
                            "ItemName": "jinhuiguo",
                            "ItemParty": "行政部",
                            "ItemImage": "http://www.qq.com/xxx.png",
                            "ItemUserId": "GuoJinHui"
                        }
                    ]
                },
                "approverstep": 0
            }
        }
        public String CHECK_APPROVAL_STATUS = "https://qyapi.weixin.qq.com/cgi-bin/corp/getopenapprovaldata?access_token=ACCESS_TOKEN";        
        //查询审批
        public ServerResponse checkApprovalStatus(Integer thirdNo){
    
            JSONObject jsonObject = new JSONObject();
            String accessToken = WeiXinUtil.getAppAccessToken();
            String url = CHECK_APPROVAL_STATUS.replace("ACCESS_TOKEN",accessToken);
            jsonObject.put("thirdNo",String.valueOf(thirdNo));
            JSONObject resultApproval = WeiXinUtil.httpRequest(url,"POST",jsonObject.toString());
            if("ok".equals(resultApproval.get("errmsg"))){
                JSONObject approvalInfoJson = resultApproval.getJSONObject("data");
                 //do something 
                return ServerResponse.createBySuccessMessage("审批状态变化");
            }
            return ServerResponse.createByErrorMessage("该任务未发起审批或者审批接口调用发生错误");
        }

    下面是两个工具类:

                发起get、post请求

                获取access_token

      /**
         * 1.发起https请求并获取结果
         *
         * @param requestUrl 请求地址
         * @param requestMethod 请求方式(GET、POST)
         * @param outputStr 提交的数据
         * @return JSONObject(通过JSONObject.get(key)的方式获取json对象的属性值)
         */
        public static JSONObject httpRequest(String requestUrl, String requestMethod, String outputStr) {
            JSONObject jsonObject = null;
            StringBuffer buffer = new StringBuffer();
            try {
                // 创建SSLContext对象,并使用我们指定的信任管理器初始化
                TrustManager[] tm = { new MyX509TrustManager() };
                SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
                sslContext.init(null, tm, new java.security.SecureRandom());
                // 从上述SSLContext对象中得到SSLSocketFactory对象
                SSLSocketFactory ssf = sslContext.getSocketFactory();
    
                URL url = new URL(requestUrl);
                HttpsURLConnection httpUrlConn = (HttpsURLConnection) url.openConnection();
                httpUrlConn.setSSLSocketFactory(ssf);
    
                httpUrlConn.setDoOutput(true);
                httpUrlConn.setDoInput(true);
                httpUrlConn.setUseCaches(false);
                // 设置请求方式(GET/POST)
                httpUrlConn.setRequestMethod(requestMethod);
    
                if ("GET".equalsIgnoreCase(requestMethod))
                    httpUrlConn.connect();
    
                // 当有数据需要提交时
                if (null != outputStr) {
                    OutputStream outputStream = httpUrlConn.getOutputStream();
                    // 注意编码格式,防止中文乱码
                    outputStream.write(outputStr.getBytes("UTF-8"));
                    outputStream.close();
                }
    
                // 将返回的输入流转换成字符串
                InputStream inputStream = httpUrlConn.getInputStream();
                InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
                BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
    
                String str = null;
                while ((str = bufferedReader.readLine()) != null) {
                    buffer.append(str);
                }
                bufferedReader.close();
                inputStreamReader.close();
                // 释放资源
                inputStream.close();
                inputStream = null;
                httpUrlConn.disconnect();
                jsonObject = JSONObject.fromObject(buffer.toString());
            } catch (ConnectException ce) {
                log.error("Weixin server connection timed out.");
            } catch (Exception e) {
                log.error("https request error:{}", e);
            }
            return jsonObject;
        }

     

     /**
         * 获取应用的access_token
         * @param appid 凭证
         * @param appsecret 密钥
         * @return
         */
        public static AccessToken getAccessToken(String appid, String appsecret) {
            AccessToken accessToken = null;
    
            String requestUrl = access_token_url.replace("{corpId}", appid).replace("{corpsecret}", appsecret);
            JSONObject jsonObject = httpRequest(requestUrl, "GET", null);
            // 如果请求成功
            if (null != jsonObject) {
                try {
                    accessToken = new AccessToken();
                    accessToken.setAccess_token(jsonObject.getString("access_token"));
                    accessToken.setExpires_in(jsonObject.getInt("expires_in"));
                } catch (JSONException e) {
                    accessToken = null;
                    // 获取token失败
                    log.error("获取token失败 errcode:{} errmsg:{}", jsonObject.getInt("errcode"), jsonObject.getString("errmsg"));
                }
            }
            return accessToken;
        }

     

     

     

     

     

     

    展开全文
  • 合同审批通过后正式生效,同时合同进入收付款计划的履行状态。当企业与合同中指定的客户或供应商发 生应收或应付业务时,财务部参照合同进行应收或应付账款的确认,合同执行人可根据相应收付款计划进 行收款或付款...
  • 条码支付收业务,是指收机构与特约商户签订受理协议,在特约商户按约定受理基于条码技术的支付方式并与付款人达成交易后,为特约商户提供交易资金结算服务的行为。银行和支付机构在为特约商户提供条码支付收...
  • DF系统 CRM•工•进销存•资金综合管理-v1.0 系统简介 开发技术:采用SSM框架+... 本系统包含进销存及资金管理、收付款功能,销售可直接生成工(工需使用者提供模板和流程)处理,流程衔接且设计严谨。 本...
  • 付款申请表.doc

    2019-08-15 10:07:50
    说明:1、本表一式三份,业主单位、承建单位、监理单位...2、收到此申请表后,总监理工程师应组织按照合同的付款条件核对项目实施是否满足付款条件,符合条件时,签发工程款支付意见表,交业主单位按合同条款进行付款
  • 付款合同管理介绍 合同管理全过程,就是从合同洽谈、草拟、签订、生效开始,直到合同的失效为止。在这个过程中,不仅要重视签订前的管理,更要重视签订后的管理。将涉及合同条款内容的各个部门都要一起来进行管理...
  • 企业业务流程数字化

    2021-02-23 23:43:22
    传统业务流程都是需要手工工或者人工纸质审批,所有的环节都缺少数据记录,没有电子化就没有办法用数据分析,流程效率非常缓慢,一个高层管理者出差,所有需要审批的文件都需要他回来之后才能审批。老板出差两个...
  • odoo企业版与社区开源版主要区别见下表:其中odoo企业版具备全部功能,而打 × 的是社区版不具备的功能。 企业版 社区 通用 无限功能支持 × 版本升级 × 托管 × 用户...
  • “三单匹配”与采购付款流程

    千次阅读 2019-05-02 16:47:00
    三单匹配是指采购订单、收货,发票的三单匹配。...随后采购员将收货,采购订单,采购申请和发票进行匹配,如果一致,则将单据送给财务部要求付款。而财务部检查三单是否匹配,以及三单和采购申请...
  • 施工企业财务软件

    2018-05-04 16:17:48
    15 付款审批管理 借款审批 按权限流行对下级的借款申请进行审批,对历史借款总额,借款总额,当前工资总额进行自动汇总,减少因为人员流动造成 的损失。 16 报销审批 严格按流程管理内部报销制度,对于报销进项发票...
  • 预算资金也不是一立项后就全部审批下来,也不是项目完结后才发放预算,而是根据立项时定义的项目关键时间节点关键事物,到节点才申请到节点才批复到节点才能付款。 这只有战略管理系统、项目管理系统、预算管理系统...
  • 对接总账,包括报销、收款付款单、借款、费用申请等常用财务单据,及科目、人员、部门、项目、供应商、客户等基础数据。 业务单据对接:利用企业微信的审批引擎创建业务单据,经过设置的审批流程后,将...
  • “采购到付款”(P2P)这个词可能会让你联想到复杂的金融交易和流程。从某种意义上说,你是对的。 但是仔细想想,实际的应付账款概念其实相当简单。 用最通俗的话讲,采购到付款周期只不过是公司针对原材料和服务...
  • 审批工作流系统预览

    2013-04-25 12:18:00
    2019独角兽企业重金招聘Python工程师标准>>> ...
  • 对接总账,包括报销、收款付款单、借款、费用申请等常用财务单据,及科目、人员、部门、项目、供应商、客户等基础数据。业务单据对接:利用企业微信的审批引擎创建业务单据,经过设置的审批流程后,将业务...
  • 对接总账,包括报销、收款付款单、借款、费用申请等常用财务单据,及科目、人员、部门、项目、供应商、客户等基础数据。业务单据对接:利用企业微信的审批引擎创建业务单据,经过设置的审批流程后,将业务...
  • 在发展初期,大多数中小企业在采购时通常都不使用采购订单,而倾向于口头约定的非正式流程,依赖于与供应商之间的不成文规定。采购订单管理成为中小企业采购管理中容易忽视的关键环节,但是,采购订单管理远比你想象...
  • 钉钉流程报销付款的一种解决方案

    千次阅读 2019-04-08 13:56:06
    需求 小微公司需要搭建一套完整的OA系统,且需求比较急。钉钉的OA解决方案是业内比较认可的,且接入的公司比较多, 配置后即可使用,降低开发...把审批流的数据通过审批回调接口落地,数据校验成功后调用付款接口进...
  • 满足印刷企业从接、下生产、生产审批、物料消耗采购、材料领用、生产过程跟踪、生产完成入库、送货以及所产生的应收应付业务和所有管理报表,进行全过程的规范化管理。帮助印刷企业走上发展的快车道。 软件主要...
  • 同时,对于报销打印、日常工作审批、报销关联项目审批、报销关联借款、部门费用统计报表及申请单据查询等都有相关细节功能新增与优化。目前,喜报WEB端和APP端已同步更新至最新版本,欢迎至喜报官网...
  • 基于SOA的OA与ERP的整合应用10 引言办公自动化(Office automation,OA)系统是实现办公自动化的信息系统。企业资源计划系统( Enterp rise ResourcePlanning, ERP)是对企业中的
  • 我询问了很多CIO,一提起企业移动应用,大家说的最多的就是移动OA,而移动OA中说的最多的就是审批。我想了想审批,不外乎应该是以下这些: 1、事务:计划/变更、验收 2、财务:采购、合同、价格、付款/资金发放 3、...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 2,164
精华内容 865
关键字:

企业付款审批单