# 微信支付

引入nutzwx
```
 <dependency>
    <groupId>org.nutz</groupId>
    <artifactId>nutzwx</artifactId>
    <version>1.r.62-SNAPSHOT</version>
  </dependency>
```
## PC端扫码支付

示例代码：cn.wizzer.app.web.modules.controllers.platform.wx.WxPayTestController

```
 @At
    @Ok("json")
    @RequiresAuthentication
    public Object payWxpay(@Param("money") int money, HttpServletRequest req) {
        try {
            Wx_config config = wxConfigService.fetch(Cnd.NEW().limit(1, 1));
            NutMap payinfo = Json.fromJson(NutMap.class, config.getPayInfo());
            WxApi2 wxApi2 = wxConfigService.getWxApi2(config.getId());
            WxPayUnifiedOrder order = new WxPayUnifiedOrder();
            order.setAppid(config.getAppid());
            order.setMch_id(payinfo.getString("wxpay_mchid"));
            order.setNonce_str(R.UU32());
            order.setBody("Test");//运行环境 -Dfile.encoding=UTF-8
            order.setOut_trade_no(DateUtil.format(new Date(), "yyyyMMddHHmmss"));
            order.setTotal_fee(money);
            order.setSpbill_create_ip(Lang.getIP(req));
            order.setNotify_url("http://" + Globals.AppDomain + "/open/pay/wx/back/sendNotify");//支付结果回调通知地址
            order.setTrade_type("NATIVE");
            order.setProduct_id("Test");//NATIVE时填写
            NutMap resp = wxApi2.pay_unifiedorder(payinfo.getString("wxpay_key"), order);
            String return_code = resp.getString("return_code", "");//SUCCESS
            String code_url = resp.getString("code_url", "");
            log.debug("resp:::" + Json.toJson(resp));
            return Result.success("system.success", code_url);
        } catch (Exception e) {
            e.printStackTrace();
            return Result.error("system.error");
        }
    }
```
* 个人扫码付款、企业向个人付款（需证书）、企业发送普通红包（需证书）、企业发裂变红包（需证书）示例都有


## 微信公众号JSAPI支付(V3)

后台代码：

```
    @At("/pay/?")
    @Ok("beetl:/public/wx/test/pay.html")
    public void pay(String id, @Param("money") int money, HttpServletRequest req, HttpSession session) {
        String openid = Strings.sNull(session.getAttribute("openid"));
        String wxid = Strings.sNull(session.getAttribute("wxid"));
        log.debug("pay money:::" + money);
        log.debug("pay wxid:::" + wxid);
        log.debug("pay openid:::" + openid);
        Wx_config config = wxConfigService.fetch(wxid);
        NutMap payinfo = Json.fromJson(NutMap.class, config.getPayInfo());
        WxApi2 wxApi2 = wxConfigService.getWxApi2(wxid);
        if (Lang.isEmpty(Globals.memoryJsapiTicketStore.get(wxid))) {
            Globals.memoryJsapiTicketStore.put(wxid, new MemoryJsapiTicketStore());
        }
        MemoryJsapiTicketStore memoryJsapiTicketStore = Globals.memoryJsapiTicketStore.get(wxid);
        wxApi2.setJsapiTicketStore(memoryJsapiTicketStore);
        String url = "http://" + Globals.AppDomain + Globals.AppBase + "/test/pay/" + Strings.sNull(id);
        NutMap jsConfig = wxApi2.genJsSDKConfig(url, "chooseWXPay");
        String nonce_str=R.UU32();
        WxPayUnifiedOrder order = new WxPayUnifiedOrder();
        order.setAppid(config.getAppid());
        order.setMch_id(payinfo.getString("wxpay_mchid"));
        order.setNonce_str(nonce_str);
        order.setBody("Test");//运行环境 -Dfile.encoding=UTF-8
        order.setOut_trade_no(DateUtil.format(new Date(), "yyyyMMddHHmmss"));
        order.setTotal_fee(money);
        order.setSpbill_create_ip(Globals.AppIp);
        order.setNotify_url("http://" + Globals.AppDomain + Globals.AppBase + "/test/payback");//支付结果通知回调地址
        order.setTrade_type("JSAPI");
        order.setOpenid(openid);//JSAPI时openid必填
        order.setProduct_id("Test");
        order.setAttach("购买套餐");
        log.debug("order:::" + Json.toJson(order));
        NutMap resp = wxApi2.pay_jsapi(payinfo.getString("wxpay_key"), order);
        String return_code = resp.getString("return_code", "");//SUCCESS
        log.debug("return_code:::" + return_code);
        log.debug("resp:::" + Json.toJson(resp));
        req.setAttribute("jsConfig", Json.toJson(jsConfig));
        req.setAttribute("money", money);
        req.setAttribute("moneys", MoneyUtil.fenToYuan(money));
        req.setAttribute("resp", resp);
        req.setAttribute("id", id);
    }
    
    //支付成功回调处理
    @At("/payback")
    @Ok("raw")
    @AdaptBy(type = VoidAdaptor.class)
    public String payback(Reader reader) throws IOException {
        NutMap res = Xmls.xmlToMap(Streams.readAndClose(reader));
        log.debug("res::" + Json.toJson(res));
        Map<String, Object> map = new HashMap<>();
        //业务处理代码
        map.put("return_code", "SUCCESS");
        return Xmls.mapToXml(map);
    }
```

前台代码：

```
<script src="https://res.wx.qq.com/open/js/jweixin-1.0.0.js"></script>

<script language="JavaScript">
    wx.config(${jsConfig});
    function wxPay() {
        WeixinJSBridge.invoke('getBrandWCPayRequest', {
            appId:'${resp.appId!}',
            timeStamp: '${resp.timeStamp!}',
            nonceStr: '${resp.nonceStr!}',
            package: '${resp.package!}',
            signType: '${resp.signType!}',
            paySign: '${resp.paySign!}'
        },function (res) {
            if (res.err_msg == "get_brand_wcpay_request:ok") {
                //微信团队郑重提示：res.err_msg 将在用户支付成功后返回 ok，但并不保证它绝对可靠。
                window.location.href="${base!}/test/success/${id}";
            }
            if (res.err_msg == "get_brand_wcpay_request:fail") {
                window.location.href="${base!}/test/fail/${id}";
            }
        });
    }
    wx.ready(function(){
        wxPay();
    });
</script>
```

* 微信公众号后台，需设置支付授权目录
* 微信公众号后台，需添加access_token IP白名单（业务需要，通过code获取openid等）
* 注意金额单位是分
* JS返回的成功，不确定一定是成功的，所以业务需要在回调里再次处理