From 1c62b5e66587a54150c068535dcbb18bd663e44e Mon Sep 17 00:00:00 2001 From: Kit Date: Tue, 17 Sep 2019 15:16:54 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8D=A1=E5=88=B8=E3=80=81=E4=BC=81=E4=B8=9A?= =?UTF-8?q?=E4=BB=98=E6=AC=BE=E5=8F=8A=E6=B5=B7=E5=85=B3API=E5=8A=A0?= =?UTF-8?q?=E5=85=A5pay=E5=AD=90=E6=A8=A1=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/foxinmy/weixin4j/pay/README.md | 47 + .../foxinmy/weixin4j/pay/WeixinPayProxy.java | 819 ++++++++++++++++++ .../com/foxinmy/weixin4j/pay/api/CashApi.java | 269 ++++++ .../foxinmy/weixin4j/pay/api/CouponApi.java | 122 +++ .../foxinmy/weixin4j/pay/api/CustomsApi.java | 84 ++ .../pay/payment/coupon/CouponDetail.java | 377 ++++++++ .../pay/payment/coupon/CouponResult.java | 119 +++ .../pay/payment/coupon/CouponStock.java | 307 +++++++ .../pay/payment/coupon/OrderCouponInfo.java | 95 ++ .../pay/payment/coupon/RefundCouponInfo.java | 76 ++ .../foxinmy/weixin4j/pay/type/TradeState.java | 46 + .../weixin4j/payment/weixin.properties | 59 ++ 12 files changed, 2420 insertions(+) create mode 100644 weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/README.md create mode 100644 weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/WeixinPayProxy.java create mode 100644 weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/api/CashApi.java create mode 100644 weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/api/CouponApi.java create mode 100644 weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/api/CustomsApi.java create mode 100644 weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/coupon/CouponDetail.java create mode 100644 weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/coupon/CouponResult.java create mode 100644 weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/coupon/CouponStock.java create mode 100644 weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/coupon/OrderCouponInfo.java create mode 100644 weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/coupon/RefundCouponInfo.java create mode 100644 weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/TradeState.java create mode 100644 weixin4j-pay/src/main/resources/com/foxinmy/weixin4j/payment/weixin.properties diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/README.md b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/README.md new file mode 100644 index 00000000..1792dfa0 --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/README.md @@ -0,0 +1,47 @@ +支付模块【JSAPI】【NATIVE】【MICROPAY】 + +微信公众平台[V2版本支付](https://mp.weixin.qq.com/paymch/readtemplate?t=mp/business/course2_tmpl&lang=zh_CN)文档 + +微信公众平台[V3版本支付](https://mp.weixin.qq.com/paymch/readtemplate?t=mp/business/course3_tmpl&lang=zh_CN)文档 + +**在`2014年10月9号`之前申请并审核通过的支付接口应该属于`V2版本`支付,而之后申请的接口则为`V3版本(商户平台)`支付** + + +[WeixinPayProxy](WeixinPayProxy.java) +------------------------- + +* createPayJsRequestJson: 创建V3版本(商户平台)的JSAPI支付串 + +* createNativePayRequestURL: 创建V3版本(商户平台)的扫码支付链接 + +* createPrePay: 调用V3版本(商户平台)的统一订单接口生成预订单数据 + +* createMicroPay: 创建刷卡支付(商户平台)请求 + +* orderQuery: 订单查询接口 + +* refundOrder: 退款申请接口 + +* reverseOrder: 冲正订单接口 + +* closeOrder: 关闭订单接口 + +* downloadBill: 下载对账单接口 + +* refundQuery: 退款查询接口 + + +[Pay2Api](https://github.com/foxinmy/weixin4j/blob/master/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/Pay2Api.java) +------------------------- + +* createPayJsRequestJson: 创建V2版本的JSAPI支付串 + +* createNativePayRequestURL: 创建V2版本的扫码支付链接 + +* orderQuery: 订单查询接口 + +* refundOrder: 退款申请接口 + +* downloadBill: 下载对账单接口 + +* refundQuery: 退款查询接口 diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/WeixinPayProxy.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/WeixinPayProxy.java new file mode 100644 index 00000000..6e68c7e3 --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/WeixinPayProxy.java @@ -0,0 +1,819 @@ +package com.foxinmy.weixin4j.pay; + +import com.alibaba.fastjson.JSON; +import com.foxinmy.weixin4j.pay.api.*; +import com.foxinmy.weixin4j.exception.WeixinException; +import com.foxinmy.weixin4j.http.weixin.XmlResult; +import com.foxinmy.weixin4j.pay.model.WeixinPayAccount; +import com.foxinmy.weixin4j.model.paging.Pageable; +import com.foxinmy.weixin4j.pay.payment.coupon.*; +import com.foxinmy.weixin4j.pay.payment.mch.*; +import com.foxinmy.weixin4j.pay.sign.WeixinSignature; +import com.foxinmy.weixin4j.pay.type.*; +import com.foxinmy.weixin4j.pay.type.mch.BillType; +import com.foxinmy.weixin4j.pay.type.mch.RefundAccountType; +import com.foxinmy.weixin4j.util.Consts; +import com.foxinmy.weixin4j.util.Weixin4jConfigUtil; + +import java.io.OutputStream; +import java.util.Date; +import java.util.List; +import java.util.concurrent.Future; + +/** + * 微信支付接口实现 + * + * @className WeixinPayProxy + * @author jinyu(foxinmy@gmail.com) + * @date 2015年1月3日 + * @since JDK 1.6 + * @see 商户平台支付API + */ +public class WeixinPayProxy { + + /** + * 微信支付API:js支付、扫码支付等接口 + */ + private final PayApi payApi; + /** + * 代金券API + */ + private final CouponApi couponApi; + /** + * 现金API + */ + private final CashApi cashApi; + /** + * 海关API + */ + private final CustomsApi customsApi; + /** + * 商户信息 + */ + private final WeixinPayAccount weixinPayAccount; + + /** + * 微信支付接口实现(使用weixin4j.properties配置的account商户信息) + */ + public WeixinPayProxy() { + this(JSON.parseObject(Weixin4jConfigUtil.getValue("account"), + WeixinPayAccount.class)); + } + + /** + * 微信支付接口实现 + * + * @param weixinPayAccount + * 微信商户信息 + */ + public WeixinPayProxy(WeixinPayAccount weixinPayAccount) { + if (weixinPayAccount == null) { + throw new IllegalArgumentException( + "weixinPayAccount must not be empty"); + } + this.weixinPayAccount = weixinPayAccount; + this.payApi = new PayApi(weixinPayAccount); + this.couponApi = new CouponApi(weixinPayAccount); + this.cashApi = new CashApi(weixinPayAccount); + this.customsApi = new CustomsApi(weixinPayAccount); + } + + /** + * 获取微信商户账号信息 + * + * @return + */ + public WeixinPayAccount getWeixinPayAccount() { + return weixinPayAccount; + } + + /** + * 获取微信签名类 + * + * @return + */ + public WeixinSignature getWeixinSignature() { + return payApi.getWeixinSignature(); + } + + /** + * 统一下单接口
+ * 除被扫支付场景以外,商户系统先调用该接口在微信支付服务后台生成预支付交易单,返回正确的预支付交易回话标识后再按扫码、JSAPI + * 、APP等不同场景生成交易串调起支付。 + * + * @param payPackage + * 包含订单信息的对象 + * @see PayApi + * @see MchPayPackage + * @see PrePay + * @see 统一下单接口 + * + * @return 预支付对象 + */ + public PrePay createPrePay(MchPayPackage payPackage) throws WeixinException { + return payApi.createPrePay(payPackage); + } + + /** + * 创建支付请求对象 + * + * @param payPackage + * 支付详情 + * @return 支付请求对象 + * @see PayApi + * @see JSAPIPayRequest JS支付 + * @see NATIVEPayRequest 扫码支付 + * @see MICROPayRequest 刷卡支付 + * @see APPPayRequest APP支付 + * @see WAPPayRequest WAP支付 + * @see MchPayRequest#toRequestString() + * @throws WeixinException + */ + public MchPayRequest createPayRequest(MchPayPackage payPackage) + throws WeixinException { + return payApi.createPayRequest(payPackage); + } + + /** + * 创建JSAPI支付请求对象 + * + * @param openId + * 用户ID + * @param body + * 订单描述 + * @param outTradeNo + * 订单号 + * @param totalFee + * 订单总额(元) + * @param notifyUrl + * 支付通知地址 + * @param createIp + * ip地址 + * @param attach + * 附加数据 非必填 + * @see PayApi + * @see JSAPIPayRequest + * @see MchPayRequest#toRequestString() + * @return JSAPI支付对象 + * @throws WeixinException + */ + public MchPayRequest createJSPayRequest(String openId, String body, + String outTradeNo, double totalFee, String notifyUrl, + String createIp, String attach) throws WeixinException { + return payApi.createJSPayRequest(openId, body, outTradeNo, totalFee, + notifyUrl, createIp, attach); + } + + /** + *

+ * 生成编辑地址请求 + *

+ * + * err_msg edit_address:ok获取编辑收货地址成功
edit_address:fail获取编辑收货地址失败
+ * userName 收货人姓名
telNumber 收货人电话
addressPostalCode 邮编
+ * proviceFirstStageName 国标收货地址第一级地址
addressCitySecondStageName + * 国标收货地址第二级地址
addressCountiesThirdStageName 国标收货地址第三级地址
+ * addressDetailInfo 详细收货地址信息
nationalCode 收货地址国家码
+ * + * @param url + * 当前访问页的URL + * @param oauthToken + * oauth授权时产生的token + * @see PayApi + * @see + * 收货地址共享 + * @return 编辑地址请求JSON串 + */ + public String createAddressRequestJSON(String url, String oauthToken) { + return payApi.createAddressRequestJSON(url, oauthToken); + } + + /** + * 创建Native支付(扫码支付)链接【模式一】 + * + * @param productId + * 与订单ID等价 + * @return 支付链接 + * @see PayApi + * @see 扫码支付 + * + * @see 模式一 + * + */ + public String createNativePayRequest(String productId) { + return payApi.createNativePayRequest(productId); + } + + /** + * 创建Native支付(扫码支付)回调对象【模式一】 + * + * @param productId + * 商品ID + * @param body + * 商品描述 + * @param outTradeNo + * 商户内部唯一订单号 + * @param totalFee + * 商品总额 单位元 + * @param notifyUrl + * 支付回调URL + * @param createIp + * 订单生成的机器 IP + * @param attach + * 附加数据 非必填 + * @return Native回调对象 + * @see PayApi + * @see NativePayResponse + * @see 扫码支付 + * + * @see 模式一 + * + * @throws WeixinException + */ + public NativePayResponse createNativePayResponse(String productId, + String body, String outTradeNo, double totalFee, String notifyUrl, + String createIp, String attach) throws WeixinException { + return payApi.createNativePayResponse(productId, body, outTradeNo, + totalFee, notifyUrl, createIp, attach); + } + + /** + * 创建Native支付(扫码支付)链接【模式二】 + * + * @param productId + * 商品ID + * @param body + * 商品描述 + * @param outTradeNo + * 商户内部唯一订单号 + * @param totalFee + * 商品总额 单位元 + * @param notifyUrl + * 支付回调URL + * @param createIp + * 订单生成的机器 IP + * @param attach + * 附加数据 非必填 + * @return Native支付对象 + * @see PayApi + * @see NATIVEPayRequest + * @see MchPayRequest#toRequestString() + * @see 扫码支付 + * + * @see 模式二 + * + * @throws WeixinException + */ + public MchPayRequest createNativePayRequest(String productId, String body, + String outTradeNo, double totalFee, String notifyUrl, + String createIp, String attach) throws WeixinException { + return payApi.createNativePayRequest(productId, body, outTradeNo, + totalFee, notifyUrl, createIp, attach); + } + + /** + * 创建APP支付请求对象 + * + * @param body + * 商品描述 + * @param outTradeNo + * 商户内部唯一订单号 + * @param totalFee + * 商品总额 单位元 + * @param notifyUrl + * 支付回调URL + * @param createIp + * 订单生成的机器 IP + * @param attach + * 附加数据 非必填 + * @param store + * 门店信息 非必填 + * @return APP支付对象 + * @see PayApi + * @see SceneInfoStore + * @see APPPayRequest + * @see MchPayRequest#toRequestString() + * @see + * APP支付 + * @throws WeixinException + */ + public MchPayRequest createAppPayRequest(String body, String outTradeNo, + double totalFee, String notifyUrl, String createIp, String attach, + SceneInfoStore store) throws WeixinException { + return payApi.createAppPayRequest(body, outTradeNo, totalFee, + notifyUrl, createIp, attach, store); + } + + /** + * 创建WAP支付请求对象 + * + * @param body + * 商品描述 + * @param outTradeNo + * 商户内部唯一订单号 + * @param totalFee + * 商品总额 单位元 + * @param notifyUrl + * 支付回调URL + * @param createIp + * 订单生成的机器 IP + * @param attach + * 附加数据 非必填 + * @param app + * 应用信息 + * @return WAP支付对象 + * @see PayApi + * @see SceneInfoApp + * @see WAPPayRequest + * @see MchPayRequest#toRequestString() + * @see WAP支付 + * + * @throws WeixinException + */ + public MchPayRequest createWapPayRequest(String body, String outTradeNo, + double totalFee, String notifyUrl, String createIp, String attach, + SceneInfoApp app) throws WeixinException { + return payApi.createWapPayRequest(body, outTradeNo, totalFee, + notifyUrl, createIp, attach, app); + } + + /** + * 提交被扫支付 + * + * @param authCode + * 扫码支付授权码 ,设备读取用户微信中的条码或者二维码信息 + * @param body + * 商品描述 + * @param outTradeNo + * 商户内部唯一订单号 + * @param totalFee + * 商品总额 单位元 + * @param createIp + * 订单生成的机器 IP + * @param attach + * 附加数据 非必填 + * @param store + * 门店信息 非必填 + * @return 支付的订单信息 + * @see PayApi + * @see Order + * @see SceneInfoStore + * @see MICROPayRequest + * @see MchPayRequest#toRequestString() + * @see + * 提交被扫支付API + * @throws WeixinException + */ + public MchPayRequest createMicroPayRequest(String authCode, String body, + String outTradeNo, double totalFee, String createIp, String attach, + SceneInfoStore store) throws WeixinException { + return payApi.createMicroPayRequest(authCode, body, outTradeNo, + totalFee, createIp, attach, store); + } + + /** + * 订单查询 + *

+ * 当商户后台、网络、服务器等出现异常,商户系统最终未接收到支付通知;
调用支付接口后,返回系统错误或未知交易状态情况;
+ * 调用被扫支付API,返回USERPAYING的状态;
调用关单或撤销接口API之前,需确认支付状态; + *

+ * + * @param idQuery + * 商户系统内部的订单号, transaction_id、out_trade_no 二 选一,如果同时存在优先级: + * transaction_id> out_trade_no + * @since V3 + * @see Order + * @see PayApi + * @see + * 订单查询API + * @return 订单详情 + * @throws WeixinException + */ + public Order queryOrder(IdQuery idQuery) throws WeixinException { + return payApi.queryOrder(idQuery); + } + + /** + * 申请退款 + * + * @see PayApi#applyRefund(IdQuery, String, double, double, CurrencyType, String, String, RefundAccountType) + */ + public RefundResult applyRefund(IdQuery idQuery, String outRefundNo, + double totalFee, double refundFee, CurrencyType refundFeeType, + String opUserId, String refundDesc, + RefundAccountType refundAccountType) throws WeixinException { + return payApi.applyRefund(idQuery, outRefundNo, totalFee, refundFee, + refundFeeType, opUserId, refundDesc, refundAccountType); + } + + /** + * 申请退款 + * + * @see PayApi#applyRefund(IdQuery, String, double) + */ + public RefundResult applyRefund(IdQuery idQuery, String outRefundNo, + double totalFee) throws WeixinException { + return payApi.applyRefund(idQuery, outRefundNo, totalFee); + } + + /** + * 退款查询 + *

+ * 提交退款申请后,通过调用该接口查询退款状态。退款有一定延时,用零钱支付的退款20分钟内到账,银行卡支付的退款3个工作日后重新查询退款状态。 + *

+ * + * @param idQuery + * 单号 refund_id、out_refund_no、 out_trade_no 、 transaction_id + * 四个参数必填一个,优先级为: + * refund_id>out_refund_no>transaction_id>out_trade_no + * @return 退款记录 + * @see PayApi + * @see RefundRecord + * @see + * 退款查询API + * @since V3 + * @throws WeixinException + */ + public RefundRecord queryRefund(IdQuery idQuery) throws WeixinException { + return payApi.queryRefund(idQuery); + } + + /** + * 下载对账单
+ * 1.微信侧未成功下单的交易不会出现在对账单中。支付成功后撤销的交易会出现在对账 单中,跟原支付单订单号一致,bill_type 为 + * REVOKED;
+ * 2.微信在次日 9 点启动生成前一天的对账单,建议商户 9 点半后再获取;
+ * 3.对账单中涉及金额的字段单位为“元”。
+ * + * @param billDate + * 下载对账单的日期 + * @param billType + * 下载对账单的类型 ALL,返回当日所有订单信息, 默认值 SUCCESS,返回当日成功支付的订单 + * REFUND,返回当日退款订单 + * @para outputStream 输出流 + * @param tarType + * 非必传参数,固定值:GZIP,返回格式为.gzip的压缩包账单。不传则默认为数据流形式。 + * @since V2 & V3 + * @see PayApi + * @see + * 下载对账单API + * @throws WeixinException + */ + public void downloadBill(Date billDate, BillType billType, + OutputStream outputStream, TarType tarType) throws WeixinException { + payApi.downloadBill(billDate, billType, outputStream, tarType); + } + + /** + * 冲正订单(需要证书)
当支付返回失败,或收银系统超时需要取消交易,可以调用该接口
接口逻辑:支 + * 付失败的关单,支付成功的撤销支付
7天以内的单可撤销,其他正常支付的单 + * 如需实现相同功能请调用退款接口
调用扣款接口后请勿立即调用撤销,需要等待5秒以上。先调用查单接口,如果没有确切的返回,再调用撤销
+ * + * @param idQuery + * 商户系统内部的订单号, transaction_id 、 out_trade_no 二选一,如果同时存在优先级: + * transaction_id> out_trade_no + * @return 撤销结果 + * @see PayApi + * @since V3 + * @throws WeixinException + */ + public MerchantResult reverseOrder(IdQuery idQuery) throws WeixinException { + return payApi.reverseOrder(idQuery); + } + + /** + * 关闭订单 + *

+ * 商户订单支付失败需要生成新单号重新发起支付,要对原订单号调用关单,避免重复支付;系统下单后,用户支付超时,系统退出不再受理,避免用户继续 + * ,请调用关单接口,如果关单失败,返回已完 成支付请按正常支付处理。如果出现银行掉单,调用关单成功后,微信后台会主动发起退款。 + *

+ * + * @param outTradeNo + * 商户系统内部的订单号 + * @return 执行结果 + * @see PayApi + * @since V3 + * @throws WeixinException + * @see + * 关闭订单API + */ + public MerchantResult closeOrder(String outTradeNo) throws WeixinException { + return payApi.closeOrder(outTradeNo); + } + + /** + * native支付URL转短链接:用于扫码原生支付模式一中的二维码链接转成短链接(weixin://wxpay/s/XXXXXX),减小二维码数据量 + * ,提升扫描速度和精确度。 + * + * @param url + * 具有native标识的支付URL + * @return 转换后的短链接 + * @see PayApi + * @see + * 转换短链接API + * @since V3 + * @throws WeixinException + */ + public String getPayShorturl(String url) throws WeixinException { + return payApi.getShorturl(url); + } + + /** + * 接口上报 + * + * @param interfaceUrl + * 上报对应的接口的完整 URL, 类似: https://api.mch.weixin.q + * q.com/pay/unifiedorder + * @param executeTime + * 接口耗时情况,单位为毫秒 + * @param outTradeNo + * 商户系统内部的订单号,商 户可以在上报时提供相关商户订单号方便微信支付更好 的提高服务质量。 + * @param ip + * 发起接口调用时的机器 IP + * @param time + * 商户调用该接口时商户自己 系统的时间 + * @param returnXml + * 调用接口返回的基本数据 + * @return 处理结果 + * @see PayApi + * @see + * 接口测试上报API + * @throws WeixinException + */ + public XmlResult reportInterface(String interfaceUrl, int executeTime, + String outTradeNo, String ip, Date time, XmlResult returnXml) + throws WeixinException { + return payApi.reportInterface(interfaceUrl, executeTime, outTradeNo, + ip, time, returnXml); + } + + /** + * 发放代金券(需要证书) + * + * @param couponStockId + * 代金券批次id + * @param partnerTradeNo + * 商户发放凭据号(格式:商户id+日期+流水号),商户侧需保持唯一性 + * @param openId + * 用户的openid + * @param opUserId + * 操作员帐号, 默认为商户号 可在商户平台配置操作员对应的api权限 可为空 + * @return 发放结果 + * @see CouponApi + * @see CouponResult + * @see + * 发放代金券接口 + * @throws WeixinException + */ + public CouponResult sendCoupon(String couponStockId, String partnerTradeNo, + String openId, String opUserId) throws WeixinException { + return couponApi.sendCoupon(couponStockId, partnerTradeNo, openId, + opUserId); + } + + /** + * 查询代金券批次 + * + * @param couponStockId + * 代金券批次ID + * @return 代金券批次信息 + * @see CouponApi + * @see CouponStock + * @see + * 查询代金券批次信息接口 + * @throws WeixinException + */ + public CouponStock queryCouponStock(String couponStockId) + throws WeixinException { + return couponApi.queryCouponStock(couponStockId); + } + + /** + * 查询代金券详细 + * + * @param openId + * 用户ID + * @param couponId + * 代金券ID + * @param stockId + * 代金劵对应的批次号 + * @return 代金券详细信息 + * @see CouponApi + * @see CouponDetail + * @see + * 查询代金券详细信息接口 + * @throws WeixinException + */ + public CouponDetail queryCouponDetail(String openId, String couponId, + String stockId) throws WeixinException { + return couponApi.queryCouponDetail(openId, couponId, stockId); + } + + /** + * 发放红包 企业向微信用户个人发现金红包 + * + * @param redpacket + * 红包信息 + * @return 发放结果 + * @see CashApi + * @see Redpacket + * @see RedpacketSendResult + * @see + * 发放现金红包接口 + * @see + * 发放裂变红包接口 + * @throws WeixinException + */ + public RedpacketSendResult sendRedpack(Redpacket redpacket) + throws WeixinException { + return cashApi.sendRedpack(redpacket); + } + + /** + * 批量发放红包 企业向微信用户个人发现金红包 + * + * @param redpackets + * 多个红包信息 + * @return 发放结果 + * @see CashApi + * @see #sendRedpacks(Redpacket...) + * @throws WeixinException + */ + public List> sendRedpacks( + Redpacket... redpackets) { + return cashApi.sendRedpacks(redpackets); + } + + /** + * 查询红包记录 + * + * @param outTradeNo + * 商户发放红包的商户订单号 + * @return 红包记录 + * @see CashApi + * @see RedpacketRecord + * @see + * 查询现金红包接口 + * @see + * 查询裂变红包接口 + * @throws WeixinException + */ + public RedpacketRecord queryRedpack(String outTradeNo) + throws WeixinException { + return cashApi.queryRedpack(outTradeNo); + } + + /** + * 企业付款 + * + * @see CashApi#sendCorpPayment(CorpPayment) + */ + public CorpPaymentResult sendCorpPayment(CorpPayment payment) + throws WeixinException { + return cashApi.sendCorpPayment(payment); + } + + /** + * 企业付款查询 用于商户的企业付款操作进行结果查询,返回付款操作详细结果 + * + * @param outTradeNo + * 商户调用企业付款API时使用的商户订单号 + * @return 付款记录 + * @see CashApi + * @see CorpPaymentRecord + * @see + * 企业付款查询接口 + * @throws WeixinException + */ + public CorpPaymentRecord queryCorpPayment(String outTradeNo) + throws WeixinException { + return cashApi.queryCorpPayment(outTradeNo); + } + + /** + * 授权码查询OPENID + * + * @param authCode + * 扫码支付授权码,设备读取用户微信中的条码或者二维码信息 + * @return 查询结果 + * @see CashApi + * @see OpenIdResult + * @see + * 授权码查询OPENID + * @throws WeixinException + */ + public OpenIdResult authCode2openId(String authCode) throws WeixinException { + return payApi.authCode2openId(authCode); + } + + /** + * 查询结算资金 + * + * @param status + * 是否结算 + * @param pageable + * 分页数据 + * @param start + * 开始日期 查询未结算记录时,该字段可不传 + * @param end + * 结束日期 查询未结算记录时,该字段可不传 + * @return 结算金额记录 + * @throws WeixinException + * @see CashApi + * @see SettlementRecord + * @see + * 查询结算资金接口 + */ + public SettlementRecord querySettlement(boolean status, Pageable pageable, + Date start, Date end) throws WeixinException { + return cashApi.querySettlement(status, pageable, start, end); + } + + /** + * 查询汇率 + * + * @param currencyType + * 外币币种 + * @param date + * 日期 不填则默认当天 + * @return 汇率对象 + * @throws WeixinException + * @see CashApi + * @see + * 查询汇率接口 + */ + public double queryExchageRate(CurrencyType currencyType, Date date) + throws WeixinException { + return cashApi.queryExchageRate(currencyType, date); + } + + /** + * 订单附加信息提交 + * + * @param customsOrder + * 附加订单信息 + * @return 报关结果 + * @see CustomsApi + * @see CustomsOrder + * @see CustomsOrderResult + * @see + * 附加订单信息提交接口 + * @throws WeixinException + */ + public CustomsOrderResult declareCustomsOrder(CustomsOrder customsOrder) + throws WeixinException { + return customsApi.declareCustomsOrder(customsOrder); + } + + /** + * 订单附加信息查询 + * + * @param idQuery + * out_trade_no,transaction_id,sub_order_no,sub_order_id四选一 + * @param customsCity + * 海关 + * @return 报关记录 + * @see CustomsOrderRecord + * @see CustomsApi + * @see + * 附加订单信息查询接口 + * @throws WeixinException + */ + public CustomsOrderRecord queryCustomsOrder(IdQuery idQuery, + CustomsCity customsCity) throws WeixinException { + return customsApi.queryCustomsOrder(idQuery, customsCity); + } + + public final static String VERSION = Consts.VERSION; +} diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/api/CashApi.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/api/CashApi.java new file mode 100644 index 00000000..c02b7b0e --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/api/CashApi.java @@ -0,0 +1,269 @@ +package com.foxinmy.weixin4j.pay.api; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.alibaba.fastjson.TypeReference; +import com.foxinmy.weixin4j.exception.WeixinException; +import com.foxinmy.weixin4j.http.weixin.WeixinResponse; +import com.foxinmy.weixin4j.pay.model.WeixinPayAccount; +import com.foxinmy.weixin4j.model.paging.Pageable; +import com.foxinmy.weixin4j.pay.payment.mch.*; +import com.foxinmy.weixin4j.pay.type.CurrencyType; +import com.foxinmy.weixin4j.util.DateUtil; +import com.foxinmy.weixin4j.util.RandomUtil; +import com.foxinmy.weixin4j.util.StringUtil; +import com.foxinmy.weixin4j.xml.XmlStream; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.concurrent.*; + +/** + * 现金API + * + * @className CashApi + * @author jinyu(foxinmy@gmail.com) + * @date 2015年3月28日 + * @since JDK 1.6 + * @see + * 现金红包 + * @see + * 企业付款 + */ +public class CashApi extends MchApi { + + public CashApi(WeixinPayAccount weixinAccount) { + super(weixinAccount); + } + + /** + * 发放红包 企业向微信用户个人发现金红包 + * + * @param redpacket + * 红包信息 + * @return 发放结果 + * @see Redpacket + * @see RedpacketSendResult + * @see + * 发放现金红包接口 + * @see + * 发放裂变红包接口 + * @throws WeixinException + */ + public RedpacketSendResult sendRedpack(Redpacket redpacket) + throws WeixinException { + String appId = redpacket.getAppId(); + super.declareMerchant(redpacket); + final JSONObject obj = (JSONObject) JSON.toJSON(redpacket); + if (StringUtil.isNotBlank(appId)) { + obj.put("appid", appId); + } + obj.put("wxappid", obj.remove("appid")); + final String redpack_uri = redpacket.getTotalNum() > 1 ? getRequestUri("groupredpack_send_uri") + : getRequestUri("redpack_send_uri"); + obj.put("sign", weixinSignature.sign(obj)); + String param = XmlStream.map2xml(obj); + WeixinResponse response = getWeixinSSLExecutor().post(redpack_uri, + param); + String text = response.getAsString() + .replaceFirst("", "") + .replaceFirst("", ""); + return XmlStream.fromXML(text, RedpacketSendResult.class); + } + + /** + * 批量发放红包 企业向微信用户个人发现金红包 + * + * 多个红包信息 + * @return 发放结果 + * @see #sendRedpacks(Redpacket...) + * @throws WeixinException + */ + public List> sendRedpacks( + Redpacket... redpackets) { + ExecutorService sendExecutor = Executors.newFixedThreadPool(Math.max(1, + redpackets.length / 10)); // 十分之一? + CompletionService completion = new ExecutorCompletionService( + sendExecutor); + List> callSendList = new ArrayList>( + redpackets.length); + for (final Redpacket redpacket : redpackets) { + Future futureSend = completion + .submit(new Callable() { + @Override + public RedpacketSendResult call() throws Exception { + return sendRedpack(redpacket); + } + }); + callSendList.add(futureSend); + } + // 关闭启动线程,不再接受新的任务 + sendExecutor.shutdown(); + return callSendList; + } + + /** + * 查询红包记录 + * + * @param outTradeNo + * 商户发放红包的商户订单号 + * @return 红包记录 + * @see RedpacketRecord + * @see + * 查询现金红包接口 + * @see + * 查询裂变红包接口 + * @throws WeixinException + */ + public RedpacketRecord queryRedpack(String outTradeNo) + throws WeixinException { + Map para = createBaseRequestMap(null); + para.put("bill_type", "MCHT"); + para.put("mch_billno", outTradeNo); + para.put("sign", weixinSignature.sign(para)); + String param = XmlStream.map2xml(para); + WeixinResponse response = getWeixinSSLExecutor().post( + getRequestUri("redpack_query_uri"), param); + return response.getAsObject(new TypeReference() { + }); + } + + /** + * 企业付款为企业提供付款至用户零钱的能力 + * + * @param payment 付款信息 + * @return 付款结果 + * @see CorpPayment + * @see CorpPaymentResult + * @see 企业付款 + * @see 场景介绍(使用条件、付款资金、付款规则等) + * @throws WeixinException + */ + public CorpPaymentResult sendCorpPayment(CorpPayment payment) + throws WeixinException { + super.declareMerchant(payment); + JSONObject obj = (JSONObject) JSON.toJSON(payment); + obj.put("mchid", obj.remove("mch_id")); + obj.put("mch_appid", obj.remove("appid")); + obj.put("sign", weixinSignature.sign(obj)); + String param = XmlStream.map2xml(obj); + WeixinResponse response = getWeixinSSLExecutor().post( + getRequestUri("corppayment_send_uri"), param); + String text = response.getAsString() + .replaceFirst("", "") + .replaceFirst("", "") + .replaceFirst("", "") + .replaceFirst("", ""); + return XmlStream.fromXML(text, CorpPaymentResult.class); + } + + /** + * 企业付款查询 用于商户的企业付款操作进行结果查询,返回付款操作详细结果 + * + * @param outTradeNo + * 商户调用企业付款API时使用的商户订单号 + * @return 付款记录 + * @see CorpPaymentRecord + * @see + * 企业付款查询接口 + * @throws WeixinException + */ + public CorpPaymentRecord queryCorpPayment(String outTradeNo) + throws WeixinException { + JSONObject obj = new JSONObject(); + obj.put("nonce_str", RandomUtil.generateString(16)); + obj.put("mch_id", weixinAccount.getMchId()); + obj.put("appid", weixinAccount.getId()); + obj.put("partner_trade_no", outTradeNo); + obj.put("sign", weixinSignature.sign(obj)); + String param = XmlStream.map2xml(obj); + WeixinResponse response = getWeixinSSLExecutor().post( + getRequestUri("corppayment_query_uri"), param); + return response.getAsObject(new TypeReference() { + }); + } + + /** + * 查询结算资金 + * + * @param status + * 是否结算 + * @param pageable + * 分页数据 + * @param start + * 开始日期 查询未结算记录时,该字段可不传 + * @param end + * 结束日期 查询未结算记录时,该字段可不传 + * @return 结算金额记录 + * @throws WeixinException + * @see SettlementRecord + * @see + * 查询结算资金接口 + */ + public SettlementRecord querySettlement(boolean status, Pageable pageable, + Date start, Date end) throws WeixinException { + JSONObject obj = new JSONObject(); + obj.put("nonce_str", RandomUtil.generateString(16)); + obj.put("mch_id", weixinAccount.getMchId()); + obj.put("appid", weixinAccount.getId()); + obj.put("usetag", status ? 1 : 2); + obj.put("offset", pageable.getOffset()); + obj.put("limit", pageable.getPageSize()); + if (start != null) { + obj.put("date_start", DateUtil.fortmat2yyyyMMdd(start)); + } + if (end != null) { + obj.put("date_end", DateUtil.fortmat2yyyyMMdd(end)); + } + obj.put("sign", weixinSignature.sign(obj)); + String param = XmlStream.map2xml(obj); + WeixinResponse response = weixinExecutor.post( + getRequestUri("settlement_query_uri"), param); + return response.getAsObject(new TypeReference() { + }); + } + + /** + * 查询汇率 + * + * @param currencyType + * 外币币种 + * @param date + * 日期 不填则默认当天 + * @return 汇率 例如美元兑换人民币的比例为6.5 + * @throws WeixinException + * @see + * 查询汇率接口 + */ + public double queryExchageRate(CurrencyType currencyType, Date date) + throws WeixinException { + if (date == null) { + date = new Date(); + } + JSONObject obj = new JSONObject(); + obj.put("mch_id", weixinAccount.getMchId()); + obj.put("appid", weixinAccount.getId()); + obj.put("sub_mch_id", weixinAccount.getSubMchId()); + obj.put("fee_type", currencyType.name()); + obj.put("date", DateUtil.fortmat2yyyyMMdd(date)); + obj.put("sign", weixinSignature.sign(obj)); + String param = XmlStream.map2xml(obj); + WeixinResponse response = weixinExecutor.post( + getRequestUri("exchagerate_query_uri"), param); + BigDecimal rate = new BigDecimal(XmlStream.xml2map( + response.getAsString()).get("rate")); + return rate.divide(new BigDecimal(100000000d)).doubleValue(); + } +} diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/api/CouponApi.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/api/CouponApi.java new file mode 100644 index 00000000..67c80c13 --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/api/CouponApi.java @@ -0,0 +1,122 @@ +package com.foxinmy.weixin4j.pay.api; + +import com.alibaba.fastjson.TypeReference; +import com.foxinmy.weixin4j.exception.WeixinException; +import com.foxinmy.weixin4j.http.weixin.WeixinResponse; +import com.foxinmy.weixin4j.pay.model.WeixinPayAccount; +import com.foxinmy.weixin4j.pay.payment.coupon.CouponDetail; +import com.foxinmy.weixin4j.pay.payment.coupon.CouponResult; +import com.foxinmy.weixin4j.pay.payment.coupon.CouponStock; +import com.foxinmy.weixin4j.util.StringUtil; +import com.foxinmy.weixin4j.xml.XmlStream; + +import java.util.Map; + +/** + * 代金券API + * + * @className CouponApi + * @author jinyu(foxinmy@gmail.com) + * @date 2015年3月25日 + * @since JDK 1.6 + * @see 代金券 + */ +public class CouponApi extends MchApi { + + public CouponApi(WeixinPayAccount weixinAccount) { + super(weixinAccount); + } + + /** + * 发放代金券(需要证书) + * + * @param couponStockId + * 代金券批次id + * @param partnerTradeNo + * 商户发放凭据号(格式:商户id+日期+流水号),商户侧需保持唯一性 + * @param openId + * 用户的openid + * @param opUserId + * 操作员帐号, 默认为商户号 可在商户平台配置操作员对应的api权限 可为空 + * @return 发放结果 + * @see CouponResult + * @see 发放代金券接口 + * @throws WeixinException + */ + public CouponResult sendCoupon(String couponStockId, String partnerTradeNo, + String openId, String opUserId) throws WeixinException { + Map map = createBaseRequestMap(null); + map.put("coupon_stock_id", couponStockId); + map.put("partner_trade_no", partnerTradeNo); + map.put("openid", openId); + // openid记录数(目前支持num=1) + map.put("openid_count", "1"); + // 操作员帐号, 默认为商户号 可在商户平台配置操作员对应的api权限 + if (StringUtil.isBlank(opUserId)) { + opUserId = weixinAccount.getMchId(); + } + map.put("op_user_id", opUserId); + map.put("version", "1.0"); + map.put("type", "XML"); + map.put("sign", weixinSignature.sign(map)); + String param = XmlStream.map2xml(map); + WeixinResponse response = getWeixinSSLExecutor().post( + getRequestUri("coupon_send_uri"), param); + return response.getAsObject(new TypeReference() { + }); + } + + /** + * 查询代金券批次 + * + * @param couponStockId + * 代金券批次ID + * @return 代金券批次信息 + * @see CouponStock + * @see 查询代金券批次信息接口 + * @throws WeixinException + */ + public CouponStock queryCouponStock(String couponStockId) + throws WeixinException { + Map map = createBaseRequestMap(null); + map.put("coupon_stock_id", couponStockId); + map.put("sign", weixinSignature.sign(map)); + String param = XmlStream.map2xml(map); + WeixinResponse response = weixinExecutor.post( + getRequestUri("couponstock_query_uri"), param); + return response.getAsObject(new TypeReference() { + }); + } + + /** + * 查询代金券详细 + * + * @param openId + * 用户ID + * @param couponId + * 代金券ID + * @param stockId + * 代金劵对应的批次号 + * @return 代金券详细信息 + * @see CouponDetail + * @see 查询代金券详细信息接口 + * @throws WeixinException + */ + public CouponDetail queryCouponDetail(String openId, String couponId, + String stockId) throws WeixinException { + Map map = createBaseRequestMap(null); + map.put("openid", openId); + map.put("coupon_id", couponId); + map.put("stock_id", stockId); + map.put("sign", weixinSignature.sign(map)); + String param = XmlStream.map2xml(map); + WeixinResponse response = weixinExecutor.post( + getRequestUri("coupondetail_query_uri"), param); + return response.getAsObject(new TypeReference() { + }); + } +} \ No newline at end of file diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/api/CustomsApi.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/api/CustomsApi.java new file mode 100644 index 00000000..258396dc --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/api/CustomsApi.java @@ -0,0 +1,84 @@ +package com.foxinmy.weixin4j.pay.api; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.alibaba.fastjson.TypeReference; +import com.foxinmy.weixin4j.exception.WeixinException; +import com.foxinmy.weixin4j.http.weixin.WeixinResponse; +import com.foxinmy.weixin4j.pay.model.WeixinPayAccount; +import com.foxinmy.weixin4j.pay.payment.mch.CustomsOrder; +import com.foxinmy.weixin4j.pay.payment.mch.CustomsOrderRecord; +import com.foxinmy.weixin4j.pay.payment.mch.CustomsOrderResult; +import com.foxinmy.weixin4j.pay.type.CustomsCity; +import com.foxinmy.weixin4j.pay.type.IdQuery; +import com.foxinmy.weixin4j.xml.ListsuffixResultDeserializer; +import com.foxinmy.weixin4j.xml.XmlStream; + +/** + * 报关接口 + * + * @className CustomsApi + * @author jinyu(foxinmy@gmail.com) + * @date 2016年3月67日 + * @since JDK 1.6 + * @see + */ +public class CustomsApi extends MchApi { + + public CustomsApi(WeixinPayAccount weixinAccount) { + super(weixinAccount); + } + + /** + * 订单附加信息提交 + * + * @param customsOrder + * 附加订单信息 + * @return 报关结果 + * @see CustomsOrder + * @see CustomsOrderResult + * @see 附加订单信息提交接口 + * @throws WeixinException + */ + public CustomsOrderResult declareCustomsOrder(CustomsOrder customsOrder) + throws WeixinException { + JSONObject para = (JSONObject) JSON.toJSON(customsOrder); + para.put("appid", weixinAccount.getId()); + para.put("mch_id", weixinAccount.getMchId()); + para.put("sign", weixinSignature.sign(para)); + String param = XmlStream.map2xml(para); + WeixinResponse response = weixinExecutor.post( + getRequestUri("customsorder_declare_uri"), param); + return response.getAsObject(new TypeReference() { + }); + } + + /** + * 订单附加信息查询 + * + * @param idQuery + * out_trade_no,transaction_id,sub_order_no,sub_order_id四选一 + * @param customsCity + * 海关 + * @return 报关记录 + * @see CustomsOrderRecord + * @see 附加订单信息查询接口 + * @throws WeixinException + */ + public CustomsOrderRecord queryCustomsOrder(IdQuery idQuery, + CustomsCity customsCity) throws WeixinException { + JSONObject para = new JSONObject(); + para.put("appid", weixinAccount.getId()); + para.put("mch_id", weixinAccount.getMchId()); + para.put(idQuery.getType().getName(), idQuery.getId()); + para.put("customs", customsCity.name()); + para.put("sign", weixinSignature.sign(para)); + String param = XmlStream.map2xml(para); + WeixinResponse response = weixinExecutor.post( + getRequestUri("customsorder_query_uri"), param); + return ListsuffixResultDeserializer.deserialize(response.getAsString(), + CustomsOrderRecord.class); + } +} diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/coupon/CouponDetail.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/coupon/CouponDetail.java new file mode 100644 index 00000000..949e02bb --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/coupon/CouponDetail.java @@ -0,0 +1,377 @@ +package com.foxinmy.weixin4j.pay.payment.coupon; + +import com.alibaba.fastjson.annotation.JSONField; +import com.foxinmy.weixin4j.pay.payment.mch.MerchantResult; +import com.foxinmy.weixin4j.pay.type.mch.CouponStatus; +import com.foxinmy.weixin4j.pay.type.mch.CouponStockType; +import com.foxinmy.weixin4j.pay.type.mch.CouponType; +import com.foxinmy.weixin4j.util.DateUtil; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; +import java.util.Date; + +/** + * 代金券详细 + * + * @className CouponDetail + * @author jinyu(foxinmy@gmail.com) + * @date 2015年3月27日 + * @since JDK 1.6 + * @see + */ +@XmlRootElement +@XmlAccessorType(XmlAccessType.FIELD) +public class CouponDetail extends MerchantResult { + + private static final long serialVersionUID = -311265355895457070L; + + /** + * 代金券批次Id + */ + @XmlElement(name = "coupon_stock_id") + @JSONField(name = "coupon_stock_id") + private String couponStockId; + + /** + * 批次类型;1-批量型,2-触发型 + */ + @XmlElement(name = "coupon_stock_type") + @JSONField(name = "coupon_stock_type") + private int couponStockType; + + /** + * 代金券id + */ + @XmlElement(name = "coupon_id") + @JSONField(name = "coupon_id") + private String couponId; + /** + * 代金券面值,单位是分 + */ + @XmlElement(name = "coupon_value") + @JSONField(name = "coupon_value") + private int couponValue; + + /** + * 代金券使用最低限额,单位是分 + */ + @XmlElement(name = "coupon_mininum") + @JSONField(name = "coupon_mininum") + private int couponMininum; + /** + * 代金券名称 + */ + @XmlElement(name = "coupon_name") + @JSONField(name = "coupon_name") + private String couponName; + /** + * 代金券状态:2-已激活,4-已锁定,8-已实扣 + */ + @XmlElement(name = "coupon_state") + @JSONField(name = "coupon_state") + private int couponStatus; + /** + * 代金券类型:1-代金券无门槛,2-代金券有门槛互斥,3-代金券有门槛叠加, + */ + @XmlElement(name = "coupon_type") + @JSONField(name = "coupon_type") + private int couponType; + /** + * 代金券描述 + */ + @XmlElement(name = "coupon_desc") + @JSONField(name = "coupon_desc") + private String couponDesc; + + /** + * 代金券实际使用金额 + */ + @XmlElement(name = "coupon_use_value") + @JSONField(name = "coupon_use_value") + private int couponUseValue; + + /** + * 代金券剩余金额:部分使用情况下,可能会存在券剩余金额 + */ + @XmlElement(name = "coupon_remain_value") + @JSONField(name = "coupon_remain_value") + private int couponRemainValue; + + /** + * 生效开始时间:格式为yyyyMMddhhmmss,如2009年12月27日9点10分10秒表示为20091227091010。 + */ + @XmlElement(name = "begin_time") + @JSONField(name = "begin_time") + private String beginTime; + + /** + * 生效结束时间:格式为yyyyMMddhhmmss,如2009年12月27日9点10分10秒表示为20091227091010。 + */ + @XmlElement(name = "end_time") + @JSONField(name = "end_time") + private String endTime; + + /** + * 发放时间:格式为yyyyMMddhhmmss,如2009年12月27日9点10分10秒表示为20091227091010。 + */ + @XmlElement(name = "send_time") + @JSONField(name = "send_time") + private String sendTime; + + /** + * 使用时间:格式为yyyyMMddhhmmss,如2009年12月27日9点10分10秒表示为20091227091010。 + */ + @XmlElement(name = "use_time") + @JSONField(name = "use_time") + private String useTime; + + /** + * 使用单号:代金券使用后,关联的大单收单单号 + */ + @XmlElement(name = "trade_no") + @JSONField(name = "trade_no") + private String tradeNo; + + /** + * 消耗方商户id:代金券使用后,消耗方商户id + */ + @XmlElement(name = "consumer_mch_id") + @JSONField(name = "consumer_mch_id") + private String consumerMchId; + + /** + * 消耗方商户名称:代金券使用后,消耗方商户名称 + */ + @XmlElement(name = "consumer_mch_name") + @JSONField(name = "consumer_mch_name") + private String consumerMchName; + + /** + * 消耗方商户appid:代金券使用后,消耗方商户appid + */ + @XmlElement(name = "consumer_mch_appid") + @JSONField(name = "consumer_mch_appid") + private String consumerMchAppid; + + /** + * 发放来源:代金券发放来源 + */ + @XmlElement(name = "send_source") + @JSONField(name = "send_source") + private String sendSource; + + /** + * 是否允许部分使用:该代金券是否允许部分使用标识:1-表示支持部分使用 + */ + @XmlElement(name = "is_partial_use") + @JSONField(name = "is_partial_use") + private int isPartialUse; + + public CouponDetail() { + + } + + public String getCouponStockId() { + return couponStockId; + } + + public int getCouponStockType() { + return couponStockType; + } + + @JSONField(serialize = false) + public CouponStockType getFormatCouponStockType() { + for (CouponStockType couponStockType : CouponStockType.values()) { + if (couponStockType.getVal() == this.couponStockType) { + return couponStockType; + } + } + return null; + } + + public String getCouponId() { + return couponId; + } + + public int getCouponValue() { + return couponValue; + } + + /** + * 调用接口获取单位为分,get方法转换为元方便使用 + * + * @return 元单位 + */ + @JSONField(serialize = false) + public double getFormatCouponValue() { + return couponValue / 100d; + } + + public int getCouponMininum() { + return couponMininum; + } + + /** + * 调用接口获取单位为分,get方法转换为元方便使用 + * + * @return 元单位 + */ + @JSONField(serialize = false) + public double getFormatCouponMininum() { + return couponMininum / 100d; + } + + public String getCouponName() { + return couponName; + } + + public int getCouponStatus() { + return couponStatus; + } + + @JSONField(serialize = false) + public CouponStatus getFormatCouponStatus() { + for (CouponStatus couponStatus : CouponStatus.values()) { + if (couponStatus.getVal() == this.couponStatus) { + return couponStatus; + } + } + return null; + } + + public int getCouponType() { + return couponType; + } + + @JSONField(deserialize = false, serialize = false) + public CouponType getFormatCouponType() { + for (CouponType couponType : CouponType.values()) { + if (couponType.getVal() == this.couponType) { + return couponType; + } + } + return null; + } + + public String getCouponDesc() { + return couponDesc; + } + + public int getCouponUseValue() { + return couponUseValue; + } + + /** + * 调用接口获取单位为分,get方法转换为元方便使用 + * + * @return 元单位 + */ + @JSONField(serialize = false) + public double getFormatCouponUseValue() { + return couponUseValue / 100d; + } + + public int getCouponRemainValue() { + return couponRemainValue; + } + + /** + * 调用接口获取单位为分,get方法转换为元方便使用 + * + * @return 元单位 + */ + @JSONField(serialize = false) + public double getFormatCouponRemainValue() { + return couponRemainValue / 100d; + } + + public String getBeginTime() { + return beginTime; + } + + @JSONField(serialize = false) + public Date getFormatBeginTime() { + return beginTime != null ? DateUtil.parse2yyyyMMddHHmmss(beginTime) + : null; + } + + public String getEndTime() { + return endTime; + } + + @JSONField(serialize = false) + public Date getFormatEndTime() { + return endTime != null ? DateUtil.parse2yyyyMMddHHmmss(endTime) : null; + } + + public String getSendTime() { + return sendTime; + } + + @JSONField(serialize = false) + public Date getFormatSendTime() { + return sendTime != null ? DateUtil.parse2yyyyMMddHHmmss(sendTime) + : null; + } + + public String getUseTime() { + return useTime; + } + + @JSONField(serialize = false) + public Date getFormatUseTime() { + return useTime != null ? DateUtil.parse2yyyyMMddHHmmss(useTime) : null; + } + + public String getTradeNo() { + return tradeNo; + } + + public String getConsumerMchId() { + return consumerMchId; + } + + public String getConsumerMchName() { + return consumerMchName; + } + + public String getConsumerMchAppid() { + return consumerMchAppid; + } + + public String getSendSource() { + return sendSource; + } + + public int getIsPartialUse() { + return isPartialUse; + } + + @JSONField(serialize = false) + public boolean getFormatIsPartialUse() { + return isPartialUse == 1; + } + + @Override + public String toString() { + return "CouponDetail [couponStockId=" + couponStockId + + ", couponStockType=" + getFormatCouponStockType() + + ", couponId=" + couponId + ", couponValue=" + + getFormatCouponValue() + ", couponMininum=" + + getFormatCouponMininum() + ", couponName=" + couponName + + ", couponStatus=" + getCouponStatus() + ", couponType=" + + getFormatCouponType() + ", couponDesc=" + couponDesc + + ", couponUseValue=" + getFormatCouponUseValue() + + ", couponRemainValue=" + getFormatCouponRemainValue() + + ", beginTime=" + getFormatBeginTime() + ", endTime=" + + getFormatEndTime() + ", sendTime=" + getFormatSendTime() + + ", useTime=" + getFormatUseTime() + ", tradeNo=" + tradeNo + + ", consumerMchId=" + consumerMchId + ", consumerMchName=" + + consumerMchName + ", consumerMchAppid=" + consumerMchAppid + + ", sendSource=" + sendSource + ", isPartialUse=" + + getFormatIsPartialUse() + ", " + super.toString() + "]"; + } +} diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/coupon/CouponResult.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/coupon/CouponResult.java new file mode 100644 index 00000000..afe82022 --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/coupon/CouponResult.java @@ -0,0 +1,119 @@ +package com.foxinmy.weixin4j.pay.payment.coupon; + +import com.alibaba.fastjson.annotation.JSONField; +import com.foxinmy.weixin4j.pay.payment.mch.MerchantResult; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +/** + * 代金券发放结果 + * + * @className CouponResult + * @author jinyu(foxinmy@gmail.com) + * @date 2015年3月25日 + * @since JDK 1.6 + * @see + */ +@XmlRootElement +@XmlAccessorType(XmlAccessType.FIELD) +public class CouponResult extends MerchantResult { + + private static final long serialVersionUID = -1996967923720149124L; + + /** + * 代金券批次id + */ + @XmlElement(name = "coupon_stock_id") + @JSONField(name = "coupon_stock_id") + private String couponStockId; + /** + * 返回记录数 + */ + @XmlElement(name = "resp_count") + @JSONField(name = "resp_count") + private int responseCount; + /** + * 成功记录数 + */ + @XmlElement(name = "success_count") + @JSONField(name = "success_count") + private int successCount; + /** + * 失败记录数 + */ + @XmlElement(name = "failed_count") + @JSONField(name = "failed_count") + private int failedCount; + /** + * 用户在商户appid下的唯一标识 + */ + @XmlElement(name = "openid") + @JSONField(name = "openid") + private String openId; + /** + * 返回码 SUCCESS或者FAILED + */ + @XmlElement(name = "ret_code") + @JSONField(name = "ret_code") + private String retCode; + /** + * 代金券id + */ + @XmlElement(name = "coupon_id") + @JSONField(name = "coupon_id") + private String couponId; + /** + * 失败描述信息,例如:“用户已达领用上限” + */ + @XmlElement(name = "ret_msg") + @JSONField(name = "ret_msg") + private String retMsg; + + public CouponResult() { + + } + + public String getCouponStockId() { + return couponStockId; + } + + public int getResponseCount() { + return responseCount; + } + + public int getSuccessCount() { + return successCount; + } + + public int getFailedCount() { + return failedCount; + } + + public String getOpenId() { + return openId; + } + + public String getRetCode() { + return retCode; + } + + public String getCouponId() { + return couponId; + } + + public String getRetMsg() { + return retMsg; + } + + @Override + public String toString() { + return "CouponResult [couponStockId=" + couponStockId + + ", responseCount=" + responseCount + ", successCount=" + + successCount + ", failedCount=" + failedCount + ", openId=" + + openId + ", retCode=" + retCode + ", couponId=" + couponId + + ", retMsg=" + retMsg + "]"; + } +} diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/coupon/CouponStock.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/coupon/CouponStock.java new file mode 100644 index 00000000..d1d2be64 --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/coupon/CouponStock.java @@ -0,0 +1,307 @@ +package com.foxinmy.weixin4j.pay.payment.coupon; + +import com.alibaba.fastjson.annotation.JSONField; +import com.foxinmy.weixin4j.pay.payment.mch.MerchantResult; +import com.foxinmy.weixin4j.pay.type.mch.CouponStockStatus; +import com.foxinmy.weixin4j.pay.type.mch.CouponType; +import com.foxinmy.weixin4j.util.DateUtil; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; +import java.util.Date; + +/** + * 代金券信息 + * + * @className CouponStock + * @author jinyu(foxinmy@gmail.com) + * @date 2015年3月27日 + * @since JDK 1.6 + * @see + */ +@XmlRootElement +@XmlAccessorType(XmlAccessType.FIELD) +public class CouponStock extends MerchantResult { + + private static final long serialVersionUID = -8627202879200080499L; + + /** + * 代金券批次ID + */ + @XmlElement(name = "coupon_stock_id") + @JSONField(name = "coupon_stock_id") + private String couponStockId; + /** + * 代金券名称 + */ + @XmlElement(name = "coupon_name") + @JSONField(name = "coupon_name") + private String couponName; + /** + * 代金券面额 + */ + @XmlElement(name = "coupon_value") + @JSONField(name = "coupon_value") + private int couponValue; + /** + * 代金券使用最低限额 + */ + @XmlElement(name = "coupon_mininumn") + @JSONField(name = "coupon_mininumn") + private Integer couponMininumn; + /** + * 代金券类型:1-代金券无门槛,2-代金券有门槛互斥,3-代金券有门槛叠加 + */ + @XmlElement(name = "coupon_type") + @JSONField(name = "coupon_type") + private int couponType; + /** + * 批次状态: 1-未激活;2-审批中;4-已激活;8-已作废;16-中止发放; + */ + @XmlElement(name = "coupon_stock_status") + @JSONField(name = "coupon_stock_status") + private int couponStockStatus; + /** + * 代金券数量 + */ + @XmlElement(name = "coupon_total") + @JSONField(name = "coupon_total") + private int couponTotal; + /** + * 代金券每个人最多能领取的数量, 如果为0,则表示没有限制 + */ + @XmlElement(name = "max_quota") + @JSONField(name = "max_quota") + private Integer maxQuota; + /** + * 代金券锁定数量 + */ + @XmlElement(name = "locked_num") + @JSONField(name = "locked_num") + private Integer lockedNum; + /** + * 代金券已使用数量 + */ + @XmlElement(name = "used_num") + @JSONField(name = "used_num") + private Integer usedNum; + /** + * 代金券已经发送的数量 + */ + @XmlElement(name = "is_send_num") + @JSONField(name = "is_send_num") + private Integer sendNum; + /** + * 生效开始时间 格式为yyyyMMddhhmmss,如2009年12月27日9点10分10秒表示为20091227091010。 + */ + @XmlElement(name = "begin_time") + @JSONField(name = "begin_time") + private String beginTime; + /** + * 生效结束时间 格式为yyyyMMddhhmmss,如2009年12月27日9点10分10秒表示为20091227091010。 + */ + @XmlElement(name = "end_time") + @JSONField(name = "end_time") + private String endTime; + /** + * 创建时间 格式为yyyyMMddhhmmss,如2009年12月27日9点10分10秒表示为20091227091010。 + */ + @XmlElement(name = "create_time") + @JSONField(name = "create_time") + private String createTime; + /** + * 代金券预算额度 + */ + @XmlElement(name = "coupon_budget") + @JSONField(name = "coupon_budget") + private Integer couponBudget; + + public CouponStock() { + + } + + public String getCouponStockId() { + return couponStockId; + } + + public String getCouponName() { + return couponName; + } + + public int getCouponValue() { + return couponValue; + } + + /** + * 调用接口获取单位为分,get方法转换为元方便使用 + * + * @return 元单位 + */ + @JSONField(serialize = false) + public double getFormatCouponValue() { + return couponValue / 100d; + } + + public Integer getCouponMininumn() { + return couponMininumn; + } + + /** + * 调用接口获取单位为分,get方法转换为元方便使用 + * + * @return 元单位 + */ + @JSONField(serialize = false) + public double getFormatCouponMininumn() { + return couponMininumn != null ? couponMininumn.intValue() / 100d : 0d; + } + + public int getCouponType() { + return couponType; + } + + @JSONField(serialize = false) + public CouponType getFormatCouponType() { + for (CouponType couponType : CouponType.values()) { + if (couponType.getVal() == this.couponType) { + return couponType; + } + } + return null; + } + + public int getCouponStockStatus() { + return couponStockStatus; + } + + @JSONField(serialize = false) + public CouponStockStatus getFormatCouponStockStatus() { + for (CouponStockStatus couponStockStatus : CouponStockStatus.values()) { + if (couponStockStatus.getVal() == this.couponStockStatus) { + return couponStockStatus; + } + } + return null; + } + + public int getCouponTotal() { + return couponTotal; + } + + public Integer getMaxQuota() { + return maxQuota; + } + + /** + * 调用接口获取单位为分,get方法转换为元方便使用 + * + * @return 元单位 + */ + @JSONField(serialize = false) + public double getFormatMaxQuota() { + return maxQuota != null ? maxQuota.intValue() / 100d : 0d; + } + + public Integer getLockedNum() { + return lockedNum; + } + + /** + * 调用接口获取单位为分,get方法转换为元方便使用 + * + * @return 元单位 + */ + @JSONField(serialize = false) + public double getFormatLockedNum() { + return lockedNum != null ? lockedNum.intValue() / 100d : 0d; + } + + public Integer getUsedNum() { + return usedNum; + } + + /** + * 调用接口获取单位为分,get方法转换为元方便使用 + * + * @return 元单位 + */ + @JSONField(serialize = false) + public double getFormatUsedNum() { + return usedNum != null ? usedNum.intValue() / 100d : 0d; + } + + public Integer getSendNum() { + return sendNum; + } + + /** + * 调用接口获取单位为分,get方法转换为元方便使用 + * + * @return 元单位 + */ + @JSONField(serialize = false) + public double getFormatSendNum() { + return sendNum != null ? sendNum.intValue() / 100d : 0d; + } + + public String getBeginTime() { + return beginTime; + } + + @JSONField(serialize = false) + public Date getFormatBeginTime() { + return beginTime != null ? DateUtil.parse2yyyyMMddHHmmss(beginTime) + : null; + } + + public String getEndTime() { + return endTime; + } + + @JSONField(serialize = false) + public Date getFormatEndTime() { + return endTime != null ? DateUtil.parse2yyyyMMddHHmmss(endTime) : null; + } + + public String getCreateTime() { + return createTime; + } + + @JSONField(serialize = false) + public Date getFormatCreateTime() { + return createTime != null ? DateUtil.parse2yyyyMMddHHmmss(createTime) + : null; + } + + public Integer getCouponBudget() { + return couponBudget; + } + + /** + * 调用接口获取单位为分,get方法转换为元方便使用 + * + * @return 元单位 + */ + @JSONField(serialize = false) + public double getFormatCouponBudget() { + return couponBudget != null ? couponBudget.intValue() / 100d : 0d; + } + + @Override + public String toString() { + return "CouponDetail [couponStockId=" + couponStockId + ", couponName=" + + couponName + ", couponValue=" + getFormatCouponValue() + + ", couponMininumn=" + getFormatCouponMininumn() + + ", couponType=" + getFormatCouponType() + + ", couponStockStatus=" + getFormatCouponStockStatus() + + ", couponTotal=" + couponTotal + ", maxQuota=" + + getFormatMaxQuota() + ", lockedNum=" + getFormatLockedNum() + + ", usedNum=" + getFormatUsedNum() + ", sendNum=" + + getFormatSendNum() + ", beginTime=" + beginTime + + ", endTime=" + endTime + ", createTime=" + createTime + + ", couponBudget=" + getFormatCouponBudget() + ", " + + super.toString() + "]"; + } +} diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/coupon/OrderCouponInfo.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/coupon/OrderCouponInfo.java new file mode 100644 index 00000000..eb53a222 --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/coupon/OrderCouponInfo.java @@ -0,0 +1,95 @@ +package com.foxinmy.weixin4j.pay.payment.coupon; + +import com.alibaba.fastjson.annotation.JSONField; +import com.foxinmy.weixin4j.pay.type.mch.CouponType; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; +import java.io.Serializable; + +/** + * 订单代金券信息 + * + * @className OrderCouponInfo + * @author jinyu(foxinmy@gmail.com) + * @date 2015年3月24日 + * @since JDK 1.6 + * @see + */ +@XmlRootElement +@XmlAccessorType(XmlAccessType.FIELD) +public class OrderCouponInfo implements Serializable { + + private static final long serialVersionUID = -8744999305258786901L; + + /** + * 代金券或立减优惠批次ID + */ + @XmlElement(name = "coupon_batch_id") + @JSONField(name = "coupon_batch_id") + private String couponBatchId; + /** + * 代金券类型 + * + * @see CouponType + */ + @XmlElement(name = "coupon_type") + @JSONField(name = "coupon_type") + private String couponType; + /** + * 代金券或立减优惠ID + */ + @XmlElement(name = "coupon_id") + @JSONField(name = "coupon_id") + private String couponId; + /** + * 单个代金券或立减优惠支付金额 + */ + @XmlElement(name = "coupon_fee") + @JSONField(name = "coupon_fee") + private Integer couponFee; + + protected OrderCouponInfo() { + // jaxb requried + } + + public String getCouponBatchId() { + return couponBatchId; + } + + public String getCouponType() { + return couponType; + } + + @JSONField(serialize = false) + public CouponType getFormatCouponType() { + return couponType != null ? CouponType + .valueOf(couponType.toUpperCase()) : null; + } + + public String getCouponId() { + return couponId; + } + + public Integer getCouponFee() { + return couponFee; + } + + /** + * 调用接口获取单位为分,get方法转换为元方便使用 + * + * @return 元单位 + */ + @JSONField(serialize = false) + public double getFormatCouponFee() { + return couponFee != null ? couponFee.doubleValue() / 100d : 0d; + } + + @Override + public String toString() { + return "couponBatchId=" + couponBatchId + ", couponType=" + couponType + + ", couponId=" + couponId + ", couponFee=" + couponFee; + } +} diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/coupon/RefundCouponInfo.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/coupon/RefundCouponInfo.java new file mode 100644 index 00000000..796bea15 --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/coupon/RefundCouponInfo.java @@ -0,0 +1,76 @@ +package com.foxinmy.weixin4j.pay.payment.coupon; + +import com.alibaba.fastjson.annotation.JSONField; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; +import java.io.Serializable; + +/** + * 退款代金券信息 + * + * @className RefundCouponInfo + * @author jinyu(foxinmy@gmail.com) + * @date 2015年3月24日 + * @since JDK 1.6 + * @see + */ +@XmlRootElement +@XmlAccessorType(XmlAccessType.FIELD) +public class RefundCouponInfo implements Serializable { + + private static final long serialVersionUID = -8744999305258786901L; + + /** + * 代金券或立减优惠批次ID + */ + @XmlElement(name = "coupon_refund_batch_id") + @JSONField(name = "coupon_refund_batch_id") + private String couponBatchId; + /** + * 退款代金券ID + */ + @XmlElement(name = "coupon_refund_id") + @JSONField(name = "coupon_refund_id") + private String couponId; + /** + * 单个代金券或立减优惠支付金额 + */ + @XmlElement(name = "coupon_refund_fee") + @JSONField(name = "coupon_refund_fee") + private Integer couponFee; + + protected RefundCouponInfo() { + // jaxb requried + } + + public String getCouponBatchId() { + return couponBatchId; + } + + public String getCouponId() { + return couponId; + } + + public Integer getCouponFee() { + return couponFee; + } + + /** + * 调用接口获取单位为分,get方法转换为元方便使用 + * + * @return 元单位 + */ + @JSONField(serialize = false) + public double getFormatCouponFee() { + return couponFee != null ? couponFee.doubleValue() / 100d : 0d; + } + + @Override + public String toString() { + return "couponBatchId=" + couponBatchId + ", couponId=" + couponId + + ", couponFee=" + couponFee; + } +} diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/TradeState.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/TradeState.java new file mode 100644 index 00000000..14a30e3c --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/TradeState.java @@ -0,0 +1,46 @@ +package com.foxinmy.weixin4j.pay.type; + +/** + * 交易状态 + * + * @className TradeState + * @author jinyu(foxinmy@gmail.com) + * @date 2014年11月2日 + * @since JDK 1.6 + * @see + * @deprecated 迁移到子模块weixin4j-pay + */ +public enum TradeState { + /** + * 支付成功 + */ + SUCCESS, + /** + * 转入退款 + */ + REFUND, + /** + * 未支付 + */ + NOTPAY, + /** + * 已关闭 + */ + CLOSED, + /** + * 已撤销 + */ + REVOKED, + /** + * 用户支付中 + */ + USERPAYING, + /** + * 未支付(输入密码或 确认支付超时) + */ + NOPAY, + /** + * 支付失败(其他 原因,如银行返回失败) + */ + PAYERROR; +} diff --git a/weixin4j-pay/src/main/resources/com/foxinmy/weixin4j/payment/weixin.properties b/weixin4j-pay/src/main/resources/com/foxinmy/weixin4j/payment/weixin.properties new file mode 100644 index 00000000..68ed23ca --- /dev/null +++ b/weixin4j-pay/src/main/resources/com/foxinmy/weixin4j/payment/weixin.properties @@ -0,0 +1,59 @@ +# \u5fae\u4fe1\u5546\u6237\u5e73\u53f0\u6587\u6863\u8bf4\u660e +# https://pay.weixin.qq.com/ +# https://pay.weixin.qq.com/wiki/doc/api/index.php +# ---------------------------------------------------------------------------- + +mch_base_url=https://api.mch.weixin.qq.com + +# \u53d1\u9001\u73b0\u91d1\u7ea2\u5305 +redpack_send_uri={mch_base_url}/mmpaymkttransfers/sendredpack +# \u53d1\u9001\u73b0\u91d1\u88c2\u53d8\u7ea2\u5305 +groupredpack_send_uri={mch_base_url}/mmpaymkttransfers/sendgroupredpack +# \u67e5\u8be2\u73b0\u91d1\u7ea2\u5305 +redpack_query_uri={mch_base_url}/mmpaymkttransfers/gethbinfo +# \u7edf\u4e00\u8ba2\u5355\u751f\u6210 +order_create_uri={mch_base_url}/pay/unifiedorder +# \u88ab\u626b\u652f\u4ed8 +micropay_uri={mch_base_url}/pay/micropay +# \u8ba2\u5355\u67e5\u8be2 +order_query_uri={mch_base_url}/pay/orderquery +# \u5173\u95ed\u8ba2\u5355 +order_close_uri={mch_base_url}/pay/closeorder +# \u5bf9\u8d26\u5355\u4e0b\u8f7d +downloadbill_uri={mch_base_url}/pay/downloadbill +# \u9000\u6b3e\u67e5\u8be2 +refund_query_uri={mch_base_url}/pay/refundquery +# \u9000\u6b3e\u7533\u8bf7 +refund_apply_uri={mch_base_url}/secapi/pay/refund +# \u51b2\u6b63\u64a4\u9500 +order_reverse_uri={mch_base_url}/secapi/pay/reverse +# \u957f\u94fe\u63a5\u8f6c\u6362 +longurl_convert_uri={mch_base_url}/tools/shorturl +# \u53d1\u653e\u4ee3\u91d1\u5238 +coupon_send_uri={mch_base_url}/mmpaymkttransfers/send_coupon +# \u67e5\u8be2\u4ee3\u91d1\u5238\u6279\u6b21\u4fe1\u606f +couponstock_query_uri={mch_base_url}/mmpaymkttransfers/query_coupon_stock +# \u67e5\u8be2\u4ee3\u91d1\u5238\u8be6\u7ec6\u4fe1\u606f +coupondetail_query_uri={mch_base_url}/mmpaymkttransfers/querycouponsinfo +# \u53d1\u9001\u73b0\u91d1\u7ea2\u5305 +redpack_send_uri={mch_base_url}/mmpaymkttransfers/sendredpack +# \u67e5\u8be2\u73b0\u91d1\u7ea2\u5305 +redpack_query_uri={mch_base_url}/mmpaymkttransfers/gethbinfo +# \u4f01\u4e1a\u5411\u4e2a\u4eba\u4ed8\u6b3e +corppayment_send_uri={mch_base_url}/mmpaymkttransfers/promotion/transfers +# \u4f01\u4e1a\u4ed8\u6b3e\u67e5\u8be2 +corppayment_query_uri={mch_base_url}/mmpaymkttransfers/gettransferinfo +# \u63a5\u53e3\u4e0a\u62a5 +interface_report_uri={mch_base_url}/payitil/report +# \u6388\u6743\u7801\u67e5\u8be2OPENID\u63a5\u53e3 +authcode_openid_uri={mch_base_url}/tools/authcodetoopenid +# native\u652f\u4ed8url(\u6a21\u5f0f1) +native_pay_uri=weixin://wxpay/bizpayurl?sign=%s&appid=%s&mch_id=%s&product_id=%s&time_stamp=%s&nonce_str=%s +# \u67e5\u8be2\u7ed3\u7b97\u8d44\u91d1 +settlement_query_uri={mch_base_url}/pay/settlementquery +# \u67e5\u8be2\u6c47\u7387 +exchagerate_query_uri={mch_base_url}/pay/queryexchagerate +# \u8ba2\u5355\u9644\u52a0\u4fe1\u606f\u63d0\u4ea4 +customsorder_declare_uri={mch_base_url}/mch/customs/customdeclareorder +# \u8ba2\u5355\u9644\u52a0\u4fe1\u606f\u67e5\u8be2 +customsorder_query_uri={mch_base_url}/mch/customs/customdeclarequery \ No newline at end of file