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