() {
+ });
+ }
+}
diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/model/WeixinPayAccount.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/model/WeixinPayAccount.java
new file mode 100644
index 00000000..d6dc9fc2
--- /dev/null
+++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/model/WeixinPayAccount.java
@@ -0,0 +1,190 @@
+package com.foxinmy.weixin4j.pay.model;
+
+import com.alibaba.fastjson.annotation.JSONCreator;
+import com.alibaba.fastjson.annotation.JSONField;
+import com.foxinmy.weixin4j.model.WeixinAccount;
+import com.foxinmy.weixin4j.util.StringUtil;
+
+/**
+ * 微信支付账户
+ *
+ * @className WeixinPayAccount
+ * @author jinyu(foxinmy@gmail.com)
+ * @date 2015年6月26日
+ * @since JDK 1.6
+ * @see
+ */
+public class WeixinPayAccount extends WeixinAccount {
+
+ private static final long serialVersionUID = -2791256176906048632L;
+ /**
+ * 公众号支付请求中用于加密的密钥
+ */
+ private final String paySignKey;
+ /**
+ * 微信支付分配的商户号
+ */
+ private final String mchId;
+ /**
+ * 加载支付证书文件的密码(默认为商户号)
+ */
+ private String certificateKey;
+ /**
+ * 商户证书文件(默认加载classpath:ca.p12)
+ */
+ private String certificateFile;
+ /**
+ * 微信支付分配的设备号
+ */
+ private String deviceInfo;
+ /**
+ * 财付通商户身份的标识
+ */
+ private String partnerId;
+
+ /**
+ * 微信分配的子商户公众账号ID
+ */
+ private String subId;
+ /**
+ * 微信支付分配的子商户号
+ */
+ private String subMchId;
+
+ /**
+ * 支付商户信息
+ *
+ * @param id
+ * 公众号唯一的身份ID(必填)
+ * @param paySignKey
+ * 支付密钥字符串(必填)
+ * @param mchId
+ * 微信支付分配的商户号(必填)
+ */
+ public WeixinPayAccount(String id, String paySignKey, String mchId) {
+ this(id, paySignKey, mchId, mchId, "classpath:ca.p12");
+ }
+
+ /**
+ * 支付商户信息
+ *
+ * @param id
+ * 公众号唯一的身份ID(必填)
+ * @param paySignKey
+ * 支付密钥字符串(必填)
+ * @param mchId
+ * 微信支付分配的商户号(必填)
+ * @param certificateKey
+ * 加载支付证书文件的密码(默认为商户号)
+ * @param certificateFile
+ * 商户证书文件(默认加载classpath:ca.p12)
+ */
+ public WeixinPayAccount(String id, String paySignKey, String mchId, String certificateKey, String certificateFile) {
+ this(id, null, paySignKey, mchId, certificateKey, certificateFile, null, null, null, null);
+ }
+
+ /**
+ * 支付商户信息
+ *
+ * @param id
+ * 公众号唯一的身份ID(必填)
+ * @param secret
+ * 公众号调用接口的凭证(最好填写)
+ * @param paySignKey
+ * 支付密钥字符串(必填)
+ * @param mchId
+ * 微信支付分配的商户号(必填)
+ * @param certificateKey
+ * 加载支付证书文件的密码(默认为商户号)
+ * @param certificateFile
+ * 商户证书文件(默认加载classpath:ca.p12)
+ * @param deviceInfo
+ * 微信支付分配的设备号(非必填)
+ * @param partnerId
+ * 财付通的商户号(非必填)
+ * @param subId
+ * 微信分配的子商户公众账号ID(非必填)
+ * @param subMchId
+ * 微信支付分配的子商户号(非必填)
+ */
+ @JSONCreator
+ public WeixinPayAccount(@JSONField(name = "id") String id, @JSONField(name = "secret") String secret,
+ @JSONField(name = "paySignKey") String paySignKey, @JSONField(name = "mchId") String mchId,
+ @JSONField(name = "certificateKey") String certificateKey,
+ @JSONField(name = "certificateFile") String certificateFile,
+ @JSONField(name = "deviceInfo") String deviceInfo, @JSONField(name = "partnerId") String partnerId,
+ @JSONField(name = "subId") String subId, @JSONField(name = "subMchId") String subMchId) {
+ super(id, secret);
+ this.paySignKey = paySignKey;
+ this.mchId = mchId;
+ this.certificateKey = certificateKey;
+ this.certificateFile = certificateFile;
+ this.deviceInfo = deviceInfo;
+ this.partnerId = partnerId;
+ this.subId = subId;
+ this.subMchId = subMchId;
+ }
+
+ public String getPaySignKey() {
+ return paySignKey;
+ }
+
+ public String getMchId() {
+ return mchId;
+ }
+
+ public String getDeviceInfo() {
+ return deviceInfo;
+ }
+
+ public String getCertificateKey() {
+ return StringUtil.isBlank(certificateKey) ? mchId : certificateKey;
+ }
+
+ public String getPartnerId() {
+ return partnerId;
+ }
+
+ public String getSubId() {
+ return subId;
+ }
+
+ public String getSubMchId() {
+ return subMchId;
+ }
+
+ public void setCertificateKey(String certificateKey) {
+ this.certificateKey = certificateKey;
+ }
+
+ public String getCertificateFile() {
+ return certificateFile;
+ }
+
+ public void setCertificateFile(String certificateFile) {
+ this.certificateFile = certificateFile;
+ }
+
+ public void setDeviceInfo(String deviceInfo) {
+ this.deviceInfo = deviceInfo;
+ }
+
+ public void setPartnerId(String partnerId) {
+ this.partnerId = partnerId;
+ }
+
+ public void setSubId(String subId) {
+ this.subId = subId;
+ }
+
+ public void setSubMchId(String subMchId) {
+ this.subMchId = subMchId;
+ }
+
+ @Override
+ public String toString() {
+ return "WeixinPayAccount [" + super.toString() + ", paySignKey=" + paySignKey + ", mchId=" + mchId
+ + ", certificateKey=" + certificateKey + ",certificateFile =" + certificateFile + ", deviceInfo="
+ + deviceInfo + ", partnerId=" + partnerId + ", subId=" + subId + ", subMchId=" + subMchId + "]";
+ }
+}
diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/JsPayNotify.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/JsPayNotify.java
new file mode 100644
index 00000000..14af1807
--- /dev/null
+++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/JsPayNotify.java
@@ -0,0 +1,60 @@
+package com.foxinmy.weixin4j.pay.payment;
+
+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;
+
+/**
+ * JSAPI支付回调时的POST信息
+ *
+ * @className JsPayNotify
+ * @author jinyu(foxinmy@gmail.com)
+ * @date 2014年8月19日
+ * @since JDK 1.6
+ * @see
+ */
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.FIELD)
+public class JsPayNotify extends PayBaseInfo {
+
+ private static final long serialVersionUID = -4659030958445259803L;
+
+ /**
+ * 用户的openid
+ */
+ @JSONField(name = "OpenId")
+ @XmlElement(name = "OpenId")
+ private String openId;
+ /**
+ * 是否关注公众号
+ */
+ @JSONField(name = "IsSubscribe")
+ @XmlElement(name = "IsSubscribe")
+ private int isSubscribe;
+
+ public JsPayNotify() {
+
+ }
+
+ public String getOpenId() {
+ return openId;
+ }
+
+ public int getIsSubscribe() {
+ return isSubscribe;
+ }
+
+ @JSONField(serialize = false)
+ public boolean getFormatIsSubscribe() {
+ return isSubscribe == 1;
+ }
+
+ @Override
+ public String toString() {
+ return "openId=" + openId + ", isSubscribe=" + getFormatIsSubscribe()
+ + ", " + super.toString();
+ }
+}
diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/PayBaseInfo.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/PayBaseInfo.java
new file mode 100644
index 00000000..a38eaab2
--- /dev/null
+++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/PayBaseInfo.java
@@ -0,0 +1,116 @@
+package com.foxinmy.weixin4j.pay.payment;
+
+import com.alibaba.fastjson.annotation.JSONField;
+import com.foxinmy.weixin4j.pay.type.SignType;
+
+import javax.xml.bind.annotation.*;
+import java.io.Serializable;
+
+/**
+ * 基本信息
+ *
+ * @className PayBaseInfo
+ * @author jinyu(foxinmy@gmail.com)
+ * @date 2014年11月5日
+ * @since JDK 1.6
+ * @see
+ */
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.FIELD)
+public class PayBaseInfo implements Serializable {
+
+ private static final long serialVersionUID = 1843024880782466990L;
+
+ /**
+ * 公众号ID
+ */
+ @JSONField(name = "appId")
+ @XmlElement(name = "AppId")
+ private String appId;
+ /**
+ * 时间戳
+ */
+ @JSONField(name = "timeStamp")
+ @XmlElement(name = "TimeStamp")
+ private String timeStamp;
+ /**
+ * 随机字符串
+ */
+ @JSONField(name = "nonceStr")
+ @XmlElement(name = "NonceStr")
+ private String nonceStr;
+ /**
+ * 签名结果
+ */
+ @JSONField(name = "paySign")
+ @XmlElement(name = "AppSignature")
+ private String paySign;
+ /**
+ * 签名方式
+ */
+ @JSONField(name = "signType")
+ @XmlElement(name = "SignMethod")
+ private String signType;
+
+ public String getAppId() {
+ return appId;
+ }
+
+ public void setAppId(String appId) {
+ this.appId = appId;
+ }
+
+ public String getTimeStamp() {
+ return timeStamp;
+ }
+
+ public void setTimeStamp(String timeStamp) {
+ this.timeStamp = timeStamp;
+ }
+
+ public String getNonceStr() {
+ return nonceStr;
+ }
+
+ public void setNonceStr(String nonceStr) {
+ this.nonceStr = nonceStr;
+ }
+
+ public String getPaySign() {
+ return paySign;
+ }
+
+ public void setPaySign(String paySign) {
+ this.paySign = paySign;
+ }
+
+ public String getSignType() {
+ return signType;
+ }
+
+ @XmlTransient
+ @JSONField(serialize = false)
+ public SignType getFormatSignType() {
+ return signType != null ? SignType.valueOf(signType.toUpperCase())
+ : null;
+ }
+
+ public void setSignType(SignType signType) {
+ this.signType = signType != null ? signType.name() : null;
+ }
+
+ public PayBaseInfo() {
+ }
+
+ public PayBaseInfo(String appId, String timestamp, String noncestr) {
+ this.appId = appId;
+ this.timeStamp = timestamp;
+ this.nonceStr = noncestr;
+ }
+
+ @Override
+ public String toString() {
+ return "appId=" + appId + ", timeStamp=" + timeStamp + ", nonceStr="
+ + nonceStr + ", paySign=" + paySign + ", signType=" + signType;
+ }
+}
diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/PayPackage.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/PayPackage.java
new file mode 100644
index 00000000..e652828f
--- /dev/null
+++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/PayPackage.java
@@ -0,0 +1,284 @@
+package com.foxinmy.weixin4j.pay.payment;
+
+import com.alibaba.fastjson.annotation.JSONField;
+import com.foxinmy.weixin4j.pay.payment.mch.MerchantResult;
+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 PayPackage
+ * @author jinyu(foxinmy@gmail.com)
+ * @date 2014年12月18日
+ * @since JDK 1.6
+ */
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.FIELD)
+public class PayPackage extends MerchantResult {
+
+ private static final long serialVersionUID = 3450161267802545790L;
+
+ /**
+ * 商品描述 必须
+ */
+ private String body;
+ /**
+ * 商品详情 非必须
+ */
+ private String detail;
+ /**
+ * 商户系统内部的订单号 ,32 个字符内 、可包含字母 ,确保 在商户系统唯一 必须
+ */
+ @XmlElement(name = "out_trade_no")
+ @JSONField(name = "out_trade_no")
+ private String outTradeNo;
+ /**
+ * 订单总金额,单位为分,不能带小数点 必须
+ */
+ @XmlElement(name = "total_fee")
+ @JSONField(name = "total_fee")
+ private int totalFee;
+ /**
+ * 通知地址接收微信支付成功通知 必须
+ */
+ @XmlElement(name = "notify_url")
+ @JSONField(name = "notify_url")
+ private String notifyUrl;
+ /**
+ * 订单生成的机器 IP 必须
+ */
+ @XmlElement(name = "spbill_create_ip")
+ @JSONField(name = "spbill_create_ip")
+ private String createIp;
+ /**
+ * 附加数据,原样返回 非必须
+ */
+ private String attach;
+ /**
+ * 订单生成时间,格式为 yyyyMMddHHmmss,如 2009 年 12月25日9点10分10秒表示为 20091225091010。时区 为
+ * GMT+8 beijing。该时间取 自商户服务器 非必须
+ */
+ @XmlElement(name = "time_start")
+ @JSONField(name = "time_start")
+ private String timeStart;
+ /**
+ * 订单失效时间,格为 yyyyMMddHHmmss,如 2009 年 12月27日9点10分10秒表示为 20091227091010。时区 为
+ * GMT+8 beijing。该时间取 自商户服务商品标记 非必须
+ */
+ @XmlElement(name = "time_expire")
+ @JSONField(name = "time_expire")
+ private String timeExpire;
+ /**
+ * 商品标记,该字段不能随便填,不使用请填空 非必须
+ */
+ @XmlElement(name = "goods_tag")
+ @JSONField(name = "goods_tag")
+ private String goodsTag;
+
+ protected PayPackage() {
+ // jaxb required
+ }
+
+ /**
+ * 订单对象
+ *
+ * @param body
+ * 订单描述 必填
+ * @param detail
+ * 订单详情 非必填
+ * @param outTradeNo
+ * 商户内部ID 必填
+ * @param totalFee
+ * 订单总额 必填 单位为元
+ * @param notifyUrl
+ * 回调地址 必填
+ * @param createIp
+ * 生成订单数据的机器IP 必填
+ * @param attach
+ * 附加数据 非必填
+ * @param timeStart
+ * 订单生成时间 非必填
+ * @param timeExpire
+ * 订单失效时间 非必填
+ * @param goodsTag
+ * 订单标记 非必填
+ */
+ public PayPackage(String body, String detail, String outTradeNo,
+ double totalFee, String notifyUrl, String createIp, String attach,
+ Date timeStart, Date timeExpire, String goodsTag) {
+ this.body = body;
+ this.detail = detail;
+ this.outTradeNo = outTradeNo;
+ this.totalFee = DateUtil.formatYuan2Fen(totalFee);
+ this.notifyUrl = notifyUrl;
+ this.createIp = createIp;
+ this.attach = attach;
+ this.timeStart = timeStart != null ? DateUtil
+ .fortmat2yyyyMMddHHmmss(timeStart) : null;
+ this.timeExpire = timeExpire != null ? DateUtil
+ .fortmat2yyyyMMddHHmmss(timeExpire) : null;
+ this.goodsTag = goodsTag;
+ }
+
+ /**
+ * 订单对象
+ *
+ * @param body
+ * 订单描述 必填
+ * @param detail
+ * 订单详情 非必填
+ * @param outTradeNo
+ * 商户内部ID 必填
+ * @param totalFee
+ * 订单总额 必填 单位为分
+ * @param notifyUrl
+ * 回调地址 必填
+ * @param createIp
+ * 生成订单数据的机器IP 必填
+ * @param attach
+ * 附加数据 非必填
+ * @param timeStart
+ * 订单生成时间 非必填
+ * @param timeExpire
+ * 订单失效时间 非必填
+ * @param goodsTag
+ * 订单标记 非必填
+ */
+ public PayPackage(String body, String detail, String outTradeNo,
+ long totalFee, String notifyUrl, String createIp, String attach,
+ Date timeStart, Date timeExpire, String goodsTag) {
+ this.body = body;
+ this.detail = detail;
+ this.outTradeNo = outTradeNo;
+ this.totalFee = Long.valueOf(totalFee).intValue();
+ this.notifyUrl = notifyUrl;
+ this.createIp = createIp;
+ this.attach = attach;
+ this.timeStart = timeStart != null ? DateUtil
+ .fortmat2yyyyMMddHHmmss(timeStart) : null;
+ this.timeExpire = timeExpire != null ? DateUtil
+ .fortmat2yyyyMMddHHmmss(timeExpire) : null;
+ this.goodsTag = goodsTag;
+ }
+
+ public String getBody() {
+ return body;
+ }
+
+ public void setBody(String body) {
+ this.body = body;
+ }
+
+ public String getDetail() {
+ return detail;
+ }
+
+ public void setDetail(String detail) {
+ this.detail = detail;
+ }
+
+ public String getOutTradeNo() {
+ return outTradeNo;
+ }
+
+ public void setOutTradeNo(String outTradeNo) {
+ this.outTradeNo = outTradeNo;
+ }
+
+ public int getTotalFee() {
+ return totalFee;
+ }
+
+ /**
+ * 调用接口获取单位为分,get方法转换为元方便使用
+ *
+ * @return 元单位
+ */
+ @JSONField(serialize = false)
+ public double getFormatTotalFee() {
+ return totalFee / 100d;
+ }
+
+ /**
+ * 单位为元,自动格式化为分
+ *
+ * @param totalFee
+ * 订单总额 单位为元
+ */
+ public void setTotalFee(double totalFee) {
+ this.totalFee = DateUtil.formatYuan2Fen(totalFee);
+ }
+
+ public String getNotifyUrl() {
+ return notifyUrl;
+ }
+
+ public void setNotifyUrl(String notifyUrl) {
+ this.notifyUrl = notifyUrl;
+ }
+
+ public String getCreateIp() {
+ return createIp;
+ }
+
+ public void setCreateIp(String createIp) {
+ this.createIp = createIp;
+ }
+
+ public String getAttach() {
+ return attach;
+ }
+
+ public void setAttach(String attach) {
+ this.attach = attach;
+ }
+
+ public String getTimeStart() {
+ return timeStart;
+ }
+
+ public void setTimeStart(String timeStart) {
+ this.timeStart = timeStart;
+ }
+
+ public void setTimeExpire(String timeExpire) {
+ this.timeExpire = timeExpire;
+ }
+
+ public void setTimeStart(Date timeStart) {
+ this.timeStart = timeStart != null ? DateUtil
+ .fortmat2yyyyMMddHHmmss(timeStart) : null;
+ }
+
+ public String getTimeExpire() {
+ return timeExpire;
+ }
+
+ public void setTimeExpire(Date timeExpire) {
+ this.timeExpire = timeExpire != null ? DateUtil
+ .fortmat2yyyyMMddHHmmss(timeExpire) : null;
+ }
+
+ public String getGoodsTag() {
+ return goodsTag;
+ }
+
+ public void setGoodsTag(String goodsTag) {
+ this.goodsTag = goodsTag;
+ }
+
+ @Override
+ public String toString() {
+ return "body=" + body + ", detail=" + detail + ", outTradeNo="
+ + outTradeNo + ", totalFee=" + totalFee + ", notifyUrl="
+ + notifyUrl + ", createIp=" + createIp + ", attach=" + attach
+ + ", timeStart=" + timeStart + ", timeExpire=" + timeExpire
+ + ", goodsTag=" + goodsTag;
+ }
+}
\ No newline at end of file
diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/PayRequest.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/PayRequest.java
new file mode 100644
index 00000000..365bf49c
--- /dev/null
+++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/PayRequest.java
@@ -0,0 +1,75 @@
+package com.foxinmy.weixin4j.pay.payment;
+
+import com.alibaba.fastjson.annotation.JSONField;
+import com.foxinmy.weixin4j.util.DateUtil;
+import com.foxinmy.weixin4j.util.RandomUtil;
+
+import javax.xml.bind.annotation.*;
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.FIELD)
+public class PayRequest extends PayBaseInfo {
+
+ private static final long serialVersionUID = -453746488398523883L;
+
+ /**
+ * 订单详情扩展 订单信息组成该字符串
+ */
+ @XmlElement(name = "Package")
+ @JSONField(name = "package")
+ private String packageInfo;
+
+ /**
+ * 冗余字段
+ */
+ @XmlTransient
+ @JSONField(serialize = false)
+ private String prepayId;
+ /**
+ * 冗余字段
+ */
+ @XmlTransient
+ @JSONField(serialize = false)
+ private String partnerId;
+
+
+ protected PayRequest() {
+ // jaxb required
+ }
+
+ public PayRequest(String appId, String packageInfo) {
+ super(appId, DateUtil.timestamp2string(), RandomUtil.generateString(16));
+ this.packageInfo = packageInfo;
+ }
+
+ public String getPackageInfo() {
+ return packageInfo;
+ }
+
+ public void setPackageInfo(String packageInfo) {
+ this.packageInfo = packageInfo;
+ }
+
+ public String getPrepayId() {
+ return prepayId;
+ }
+
+ public void setPrepayId(String prepayId) {
+ this.prepayId = prepayId;
+ }
+
+ public String getPartnerId() {
+ return partnerId;
+ }
+
+ public void setPartnerId(String partnerId) {
+ this.partnerId = partnerId;
+ }
+
+
+ @Override
+ public String toString() {
+ return "package" + packageInfo + ", prepayId=" + prepayId
+ + super.toString();
+ }
+}
diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/README.md b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/README.md
new file mode 100644
index 00000000..1792dfa0
--- /dev/null
+++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/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/payment/WeixinPayProxy.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/WeixinPayProxy.java
new file mode 100644
index 00000000..7aa1955a
--- /dev/null
+++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/WeixinPayProxy.java
@@ -0,0 +1,827 @@
+package com.foxinmy.weixin4j.pay.payment;
+
+import com.alibaba.fastjson.JSON;
+import com.foxinmy.weixin4j.api.CashApi;
+import com.foxinmy.weixin4j.api.CouponApi;
+import com.foxinmy.weixin4j.api.CustomsApi;
+import com.foxinmy.weixin4j.api.PayApi;
+import com.foxinmy.weixin4j.exception.WeixinException;
+import com.foxinmy.weixin4j.http.weixin.XmlResult;
+import com.foxinmy.weixin4j.model.WeixinPayAccount;
+import com.foxinmy.weixin4j.model.paging.Pageable;
+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.pay.payment.mch.*;
+import com.foxinmy.weixin4j.sign.WeixinSignature;
+import com.foxinmy.weixin4j.type.CurrencyType;
+import com.foxinmy.weixin4j.type.CustomsCity;
+import com.foxinmy.weixin4j.type.IdQuery;
+import com.foxinmy.weixin4j.type.TarType;
+import com.foxinmy.weixin4j.type.mch.BillType;
+import com.foxinmy.weixin4j.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 redpacket
+ * 多个红包信息
+ * @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/payment/mch/APPPayRequest.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/APPPayRequest.java
new file mode 100644
index 00000000..c531ec78
--- /dev/null
+++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/APPPayRequest.java
@@ -0,0 +1,74 @@
+package com.foxinmy.weixin4j.pay.payment.mch;
+
+import com.foxinmy.weixin4j.pay.model.WeixinPayAccount;
+import com.foxinmy.weixin4j.pay.payment.PayRequest;
+import com.foxinmy.weixin4j.pay.type.SignType;
+import com.foxinmy.weixin4j.pay.type.TradeType;
+import com.foxinmy.weixin4j.util.DigestUtil;
+import com.foxinmy.weixin4j.util.MapUtil;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * APP支付
+ *
+ * @className APPPayRequest
+ * @author jinyu(foxinmy@gmail.com)
+ * @date 2015年12月25日
+ * @since JDK 1.6
+ * @see PrePay
+ * @see PayRequest
+ * @see APP支付
+ */
+public class APPPayRequest extends AbstractPayRequest {
+ public APPPayRequest(String prePayId, WeixinPayAccount payAccount) {
+ super(prePayId, payAccount);
+ }
+
+ @Override
+ public TradeType getPaymentType() {
+ return TradeType.APP;
+ }
+
+ /**
+ * 只做查看之用,请不要尝试作为支付请求
+ */
+ @Override
+ public PayRequest toRequestObject() {
+ PayRequest payRequest = new PayRequest(getPaymentAccount().getId(), "Sign=WXPay");
+ payRequest.setPartnerId(getPaymentAccount().getMchId());
+ payRequest.setPrepayId(getPrePayId());
+ Map map = new HashMap();
+ map.put("appid", payRequest.getAppId());
+ // 因为partnerid和prepayid在PayRequest类中是不进行序列化的
+ map.put("partnerid", payRequest.getPartnerId());
+ map.put("prepayid", payRequest.getPrepayId());
+ map.put("package", payRequest.getPackageInfo());
+ map.put("timestamp", payRequest.getTimeStamp());
+ map.put("noncestr", payRequest.getNonceStr());
+ String sign = DigestUtil.MD5(
+ String.format("%s&key=%s", MapUtil.toJoinString(map, false, true), getPaymentAccount().getPaySignKey()))
+ .toUpperCase();
+ payRequest.setPaySign(sign);
+ payRequest.setSignType(SignType.MD5);
+ return payRequest;
+ }
+
+ @Override
+ public String toRequestString() {
+ PayRequest payRequest = toRequestObject();
+ StringBuilder content = new StringBuilder();
+ content.append("");
+ content.append(String.format("", payRequest.getAppId()));
+ content.append(String.format("", payRequest.getPartnerId()));
+ content.append(String.format("", payRequest.getPrepayId()));
+ content.append(String.format("", payRequest.getPackageInfo()));
+ content.append(String.format("", payRequest.getNonceStr()));
+ content.append(String.format("", payRequest.getTimeStamp()));
+ content.append(String.format("", payRequest.getPaySign()));
+ content.append("");
+ return content.toString();
+ }
+}
diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/AbstractPayRequest.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/AbstractPayRequest.java
new file mode 100644
index 00000000..77af4ee7
--- /dev/null
+++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/AbstractPayRequest.java
@@ -0,0 +1,28 @@
+package com.foxinmy.weixin4j.pay.payment.mch;
+
+import com.foxinmy.weixin4j.pay.model.WeixinPayAccount;
+import com.foxinmy.weixin4j.pay.sign.WeixinPaymentSignature;
+import com.foxinmy.weixin4j.pay.sign.WeixinSignature;
+
+public abstract class AbstractPayRequest implements MchPayRequest {
+
+ private final String prePayId;
+ private final WeixinPayAccount paymentAccount;
+ protected final WeixinSignature weixinSignature;
+
+ public AbstractPayRequest(String prePayId, WeixinPayAccount paymentAccount) {
+ this.prePayId = prePayId;
+ this.paymentAccount = paymentAccount;
+ this.weixinSignature = new WeixinPaymentSignature(paymentAccount.getPaySignKey());
+ }
+
+ @Override
+ public String getPrePayId() {
+ return this.prePayId;
+ }
+
+ @Override
+ public WeixinPayAccount getPaymentAccount() {
+ return this.paymentAccount;
+ }
+}
\ No newline at end of file
diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/CorpPayment.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/CorpPayment.java
new file mode 100644
index 00000000..b5f5816f
--- /dev/null
+++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/CorpPayment.java
@@ -0,0 +1,147 @@
+package com.foxinmy.weixin4j.pay.payment.mch;
+
+import com.alibaba.fastjson.annotation.JSONField;
+import com.foxinmy.weixin4j.type.mch.CorpPaymentCheckNameType;
+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;
+
+/**
+ * 企业付款
+ *
+ * @className CorpPayment
+ * @author jinyu(foxinmy@gmail.com)
+ * @date 2015年4月1日
+ * @since JDK 1.6
+ * @see
+ */
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.FIELD)
+public class CorpPayment extends MerchantResult {
+
+ private static final long serialVersionUID = 3734639674346425312L;
+ /**
+ * 商户订单号
+ */
+ @XmlElement(name = "partner_trade_no")
+ @JSONField(name = "partner_trade_no")
+ private String outTradeNo;
+ /**
+ * 接收红包的用户的openid
+ */
+ @JSONField(name = "openid")
+ @XmlElement(name = "openid")
+ private String openId;
+ /**
+ * 校验用户姓名选项
+ *
+ * @see CorpPaymentCheckNameType.type.MPPaymentCheckNameType
+ */
+ @XmlElement(name = "check_name")
+ @JSONField(name = "check_name")
+ private CorpPaymentCheckNameType checkNameType;
+ /**
+ * 收款用户真实姓名。 如果check_name设置为FORCE_CHECK或OPTION_CHECK,则必填用户真实姓名 可选
+ */
+ @XmlElement(name = "re_user_name")
+ @JSONField(name = "re_user_name")
+ private String userName;
+ /**
+ * 企业付款描述信息
+ */
+ private String desc;
+ /**
+ * 付款金额 单位分
+ */
+ private int amount;
+ /**
+ * 调用接口的机器Ip地址
+ */
+ @XmlElement(name = "spbill_create_ip")
+ @JSONField(name = "spbill_create_ip")
+ private String clientIp;
+
+ protected CorpPayment() {
+ // jaxb required
+ }
+
+ /**
+ * 企业付款
+ *
+ * @param outTradeNo
+ * 商户的订单号
+ * @param openId
+ * 用户的openid
+ * @param checkNameType
+ * 校验用户姓名选项
+ * @param desc
+ * 描述
+ * @param amount
+ * 金额 单位元
+ * @param clientIp
+ * 调用接口IP
+ */
+ public CorpPayment(String outTradeNo, String openId,
+ CorpPaymentCheckNameType checkNameType, String desc, double amount,
+ String clientIp) {
+ this.outTradeNo = outTradeNo;
+ this.openId = openId;
+ this.checkNameType = checkNameType;
+ this.desc = desc;
+ this.amount = DateUtil.formatYuan2Fen(amount);
+ this.clientIp = clientIp;
+ }
+
+ public String getOutTradeNo() {
+ return outTradeNo;
+ }
+
+ public String getOpenId() {
+ return openId;
+ }
+
+ public CorpPaymentCheckNameType getCheckNameType() {
+ return checkNameType;
+ }
+
+ public String getUserName() {
+ return userName;
+ }
+
+ public String getDesc() {
+ return desc;
+ }
+
+ public int getAmount() {
+ return amount;
+ }
+
+ /**
+ * 调用接口获取单位为分,get方法转换为元方便使用
+ *
+ * @return 元单位
+ */
+ @JSONField(serialize = false)
+ public double getFormatAmount() {
+ return amount / 100d;
+ }
+
+ public String getClientIp() {
+ return clientIp;
+ }
+
+ public void setUserName(String userName) {
+ this.userName = userName;
+ }
+
+ @Override
+ public String toString() {
+ return "CorpPayment [outTradeNo=" + outTradeNo + ", openId=" + openId
+ + ", checkNameType=" + checkNameType + ", userName=" + userName
+ + ", desc=" + desc + ", amount=" + amount + ", clientIp="
+ + clientIp + ", " + super.toString() + "]";
+ }
+}
\ No newline at end of file
diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/CorpPaymentRecord.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/CorpPaymentRecord.java
new file mode 100644
index 00000000..5d93cc0a
--- /dev/null
+++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/CorpPaymentRecord.java
@@ -0,0 +1,202 @@
+package com.foxinmy.weixin4j.pay.payment.mch;
+
+import com.alibaba.fastjson.annotation.JSONField;
+import com.foxinmy.weixin4j.type.mch.CorpPaymentCheckNameType;
+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 CorpPaymentRecord
+ * @author jinyu(foxinmy@gmail.com)
+ * @date 2015年6月23日
+ * @since JDK 1.6
+ * @see
+ */
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.FIELD)
+public class CorpPaymentRecord extends MerchantResult {
+
+ private static final long serialVersionUID = -1926873539419750498L;
+
+ /**
+ * 微信订单订单号
+ */
+ @JSONField(name = "detail_id")
+ @XmlElement(name = "detail_id")
+ private String transactionId;
+ /**
+ * 商户订单号
+ */
+ @JSONField(name = "partner_trade_no")
+ @XmlElement(name = "partner_trade_no")
+ private String outTradeNo;
+ /**
+ * 交易状态 SUCCESS:转账成功 FAILED:转账失败
+ */
+ @JSONField(name = "status")
+ @XmlElement(name = "status")
+ private String transactionStatus;
+ /**
+ * 如果失败则应该有原因
+ */
+ @JSONField(name = "reason")
+ @XmlElement(name = "reason")
+ private String failureReason;
+ /**
+ * 收款用户openid
+ */
+ @JSONField(name = "openid")
+ @XmlElement(name = "openid")
+ private String openId;
+ /**
+ * 收款用户姓名
+ */
+ @JSONField(name = "transfer_name")
+ @XmlElement(name = "transfer_name")
+ private String transferName;
+ /**
+ * 付款金额(单位为分)
+ */
+ @JSONField(name = "payment_amount")
+ @XmlElement(name = "payment_amount")
+ private int paymentAmount;
+ /**
+ * 转账时间
+ */
+ @JSONField(name = "transfer_time")
+ @XmlElement(name = "transfer_time")
+ private String transferTime;
+ /**
+ * 校验用户姓名选项
+ *
+ * @see CorpPaymentCheckNameType.type.MPPaymentCheckNameType
+ */
+ @XmlElement(name = "check_name")
+ @JSONField(name = "check_name")
+ private String checkNameType;
+ /**
+ * 企业付款描述信息
+ */
+ @XmlElement(name = "desc")
+ private String desc;
+ /**
+ * 实名验证结果 PASS:通过 FAILED:不通过
+ */
+ @JSONField(name = "check_name_result")
+ @XmlElement(name = "check_name_result")
+ private String checkNameResult;
+
+ protected CorpPaymentRecord() {
+ // jaxb required
+ }
+
+ public String getTransactionId() {
+ return transactionId;
+ }
+
+ public String getOutTradeNo() {
+ return outTradeNo;
+ }
+
+ public String getTransactionStatus() {
+ return transactionStatus;
+ }
+
+ /**
+ * 格式化交易状态
+ *
+ * @return
+ */
+ @JSONField(serialize = false)
+ public boolean getFormatTransactionStatus() {
+ return "success".equalsIgnoreCase(transactionStatus);
+ }
+
+ public String getFailureReason() {
+ return failureReason;
+ }
+
+ public String getOpenId() {
+ return openId;
+ }
+
+ public String getTransferName() {
+ return transferName;
+ }
+
+ public int getPaymentAmount() {
+ return paymentAmount;
+ }
+
+ /**
+ * 调用接口获取单位为分,get方法转换为元方便使用
+ *
+ * @return 元单位
+ */
+ @JSONField(serialize = false)
+ public double getFormatPaymentAmount() {
+ return paymentAmount / 100d;
+ }
+
+ public String getTransferTime() {
+ return transferTime;
+ }
+
+ /**
+ * 格式化转账时间
+ *
+ * @return
+ */
+ @JSONField(serialize = false)
+ public Date getFormatTransferTime() {
+ return transferTime != null ? DateUtil
+ .parse2yyyyMMddHHmmss(transferTime) : null;
+ }
+
+ public String getCheckNameType() {
+ return checkNameType;
+ }
+
+ @JSONField(serialize = false)
+ public CorpPaymentCheckNameType getFormatCheckNameType() {
+ return checkNameType != null ? CorpPaymentCheckNameType
+ .valueOf(checkNameType) : null;
+ }
+
+ public String getDesc() {
+ return desc;
+ }
+
+ public String getCheckNameResult() {
+ return checkNameResult;
+ }
+
+ /**
+ * 格式化交易状态
+ *
+ * @return
+ */
+ @JSONField(serialize = false)
+ public boolean getFormatCheckNameResult() {
+ return "pass".equalsIgnoreCase(checkNameResult);
+ }
+
+ @Override
+ public String toString() {
+ return "CorpPaymentRecord [transactionId=" + transactionId
+ + ", outTradeNo=" + outTradeNo + ", transactionStatus="
+ + getFormatTransactionStatus() + ", failureReason="
+ + failureReason + ", openId=" + openId + ", transferName="
+ + transferName + ", paymentAmount=" + getFormatPaymentAmount()
+ + ", transferTime=" + transferTime + ", checkNameType="
+ + checkNameType + ", desc=" + desc + ", checkNameResult="
+ + getFormatCheckNameResult() + ", " + super.toString() + "]";
+ }
+}
diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/CorpPaymentResult.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/CorpPaymentResult.java
new file mode 100644
index 00000000..dc4b67b7
--- /dev/null
+++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/CorpPaymentResult.java
@@ -0,0 +1,74 @@
+package com.foxinmy.weixin4j.pay.payment.mch;
+
+import com.alibaba.fastjson.annotation.JSONField;
+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 CorpPaymentResult
+ * @author jinyu(foxinmy@gmail.com)
+ * @date 2015年4月1日
+ * @since JDK 1.6
+ * @see
+ */
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.FIELD)
+public class CorpPaymentResult extends MerchantResult {
+
+ private static final long serialVersionUID = 1110472826089211646L;
+
+ /**
+ * 微信订单订单号
+ */
+ @JSONField(name = "payment_no")
+ @XmlElement(name = "payment_no")
+ private String transactionId;
+ /**
+ * 商户订单号
+ */
+ @JSONField(name = "partner_trade_no")
+ @XmlElement(name = "partner_trade_no")
+ private String outTradeNo;
+ /**
+ * 支付时间
+ */
+ @JSONField(name = "payment_time")
+ @XmlElement(name = "payment_time")
+ private String paymentTime;
+
+ protected CorpPaymentResult() {
+ // jaxb required
+ }
+
+ public String getTransactionId() {
+ return transactionId;
+ }
+
+ public String getOutTradeNo() {
+ return outTradeNo;
+ }
+
+ public String getPaymentTime() {
+ return paymentTime;
+ }
+
+ @JSONField(serialize = false)
+ public Date getFormatPaymentTime() {
+ return paymentTime != null ? DateUtil.parseDate(paymentTime,
+ "yyyy-MM-dd HH:mm:ss") : null;
+ }
+
+ @Override
+ public String toString() {
+ return "CorpPaymentResult [transactionId=" + transactionId
+ + ", outTradeNo=" + outTradeNo + ", paymentTime=" + paymentTime
+ + ", " + super.toString() + "]";
+ }
+}
diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/CustomsOrder.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/CustomsOrder.java
new file mode 100644
index 00000000..e21da276
--- /dev/null
+++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/CustomsOrder.java
@@ -0,0 +1,217 @@
+package com.foxinmy.weixin4j.pay.payment.mch;
+
+import com.alibaba.fastjson.annotation.JSONField;
+import com.foxinmy.weixin4j.type.CredentialType;
+import com.foxinmy.weixin4j.type.CurrencyType;
+import com.foxinmy.weixin4j.type.CustomsCity;
+
+import javax.xml.bind.annotation.XmlElement;
+
+/**
+ * 报关对象
+ *
+ * @className CustomsOrder
+ * @author jinyu(foxinmy@gmail.com)
+ * @date 2016年3月27日
+ * @since JDK 1.6
+ * @see
+ */
+public class CustomsOrder extends MerchantResult {
+
+ private static final long serialVersionUID = 799510373861612386L;
+ /**
+ * 微信支付订单号
+ */
+ @XmlElement(name = "transaction_id")
+ @JSONField(name = "transaction_id")
+ private String transactionId;
+ /**
+ * 商户订单号
+ */
+ @XmlElement(name = "out_trade_no")
+ @JSONField(name = "out_trade_no")
+ private String outTradeNo;
+ /**
+ * 商户子订单号,如有拆单则必传
+ */
+ @XmlElement(name = "sub_order_no")
+ @JSONField(name = "sub_order_no")
+ private String subOrderNo;
+ /**
+ * 货币类型,符合 ISO 4217 标准的三位字母代码,默认人民币:CNY
+ *
+ * @see com.foxinmy.weixin4j.mp.type.CurrencyType
+ */
+ @XmlElement(name = "fee_type")
+ @JSONField(name = "fee_type")
+ private CurrencyType feeType;
+ /**
+ * 子订单金额,以分为单位,不能超过原订单金额,order_fee=transport_fee+product_fee(应付金额=物流费+商品价格),
+ * 如有拆单则必传。
+ */
+ @XmlElement(name = "order_fee")
+ @JSONField(name = "order_fee")
+ private String orderFee;
+ /**
+ * 物流费用,以分为单位,如有拆单则必传。
+ */
+ @XmlElement(name = "transport_fee")
+ @JSONField(name = "transport_fee")
+ private String transportFee;
+ /**
+ * 商品费用,以分为单位,如有拆单则必传。
+ */
+ @XmlElement(name = "product_fee")
+ @JSONField(name = "product_fee")
+ private String productFee;
+ /**
+ * 关税,以分为单位
+ */
+ @XmlElement(name = "duty")
+ @JSONField(name = "duty")
+ private String dutyFee;
+ /**
+ * 海关
+ */
+ @XmlElement(name = "customs")
+ @JSONField(name = "customs")
+ private CustomsCity customsCity;
+ /**
+ * 商户在海关登记的备案号,customsCity非NO,此参数必填
+ */
+ @XmlElement(name = "mch_customs_no")
+ @JSONField(name = "mch_customs_no")
+ private String customsNo;
+ /**
+ * 证件类型:暂只支持身份证,该参数是指用户信息,商户若有用户信息,可上送,系统将以商户上传的数据为准,进行海关通关报备
+ */
+ @XmlElement(name = "cert_type")
+ @JSONField(name = "cert_type")
+ private CredentialType credentialType;
+ /**
+ * 证件号码:身份证号,该参数是指用户信息,商户若有用户信息,可上送,系统将以商户上传的数据为准,进行海关通关报备;
+ */
+ @XmlElement(name = "cert_id")
+ @JSONField(name = "cert_id")
+ private String credentialId;
+ /**
+ * 用户姓名,该参数是指用户信息,商户若有用户信息,可上送,系统将以商户上传的数据为准,进行海关通关报备;
+ */
+ @XmlElement(name = "name")
+ @JSONField(name = "name")
+ private String uname;
+
+ public CustomsOrder(String transactionId, String outTradeNo) {
+ this.transactionId = transactionId;
+ this.outTradeNo = outTradeNo;
+ this.customsCity = CustomsCity.NO;
+ }
+
+ public String getSubOrderNo() {
+ return subOrderNo;
+ }
+
+ public void setSubOrderNo(String subOrderNo) {
+ this.subOrderNo = subOrderNo;
+ }
+
+ public CurrencyType getFeeType() {
+ return feeType;
+ }
+
+ public void setFeeType(CurrencyType feeType) {
+ this.feeType = feeType;
+ }
+
+ public String getOrderFee() {
+ return orderFee;
+ }
+
+ public void setOrderFee(String orderFee) {
+ this.orderFee = orderFee;
+ }
+
+ public String getTransportFee() {
+ return transportFee;
+ }
+
+ public void setTransportFee(String transportFee) {
+ this.transportFee = transportFee;
+ }
+
+ public String getProductFee() {
+ return productFee;
+ }
+
+ public void setProductFee(String productFee) {
+ this.productFee = productFee;
+ }
+
+ public String getDutyFee() {
+ return dutyFee;
+ }
+
+ public void setDutyFee(String dutyFee) {
+ this.dutyFee = dutyFee;
+ }
+
+ public CustomsCity getCustomsCity() {
+ return customsCity;
+ }
+
+ public void setCustomsCity(CustomsCity customsCity) {
+ this.customsCity = customsCity;
+ }
+
+ public String getCustomsNo() {
+ return customsNo;
+ }
+
+ public void setCustomsNo(String customsNo) {
+ this.customsNo = customsNo;
+ }
+
+ public CredentialType getCredentialType() {
+ return credentialType;
+ }
+
+ public void setCredentialType(CredentialType credentialType) {
+ this.credentialType = credentialType;
+ }
+
+ public String getCredentialId() {
+ return credentialId;
+ }
+
+ public void setCredentialId(String credentialId) {
+ this.credentialId = credentialId;
+ }
+
+ public String getUname() {
+ return uname;
+ }
+
+ public void setUname(String uname) {
+ this.uname = uname;
+ }
+
+ public String getTransactionId() {
+ return transactionId;
+ }
+
+ public String getOutTradeNo() {
+ return outTradeNo;
+ }
+
+ @Override
+ public String toString() {
+ return "CustomsOrder [transactionId=" + transactionId + ", outTradeNo="
+ + outTradeNo + ", subOrderNo=" + subOrderNo + ", feeType="
+ + feeType + ", orderFee=" + orderFee + ", transportFee="
+ + transportFee + ", productFee=" + productFee + ", dutyFee="
+ + dutyFee + ", customsCity=" + customsCity + ", customsNo="
+ + customsNo + ", credentialType=" + credentialType
+ + ", credentialId=" + credentialId + ", uname=" + uname + ", "
+ + super.toString() + "]";
+ }
+}
diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/CustomsOrderRecord.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/CustomsOrderRecord.java
new file mode 100644
index 00000000..7daf88a9
--- /dev/null
+++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/CustomsOrderRecord.java
@@ -0,0 +1,72 @@
+package com.foxinmy.weixin4j.pay.payment.mch;
+
+import com.alibaba.fastjson.annotation.JSONField;
+import com.foxinmy.weixin4j.xml.ListsuffixResult;
+
+import javax.xml.bind.annotation.XmlElement;
+import java.util.List;
+
+/**
+ * 报关记录
+ *
+ * @className CustomsOrderRecord
+ * @author jinyu(foxinmy@gmail.com)
+ * @date 2016年3月27日
+ * @since JDK 1.6
+ * @see
+ */
+public class CustomsOrderRecord extends MerchantResult {
+
+ private static final long serialVersionUID = -1675090110657154049L;
+ /**
+ * 微信支付订单号
+ */
+ @XmlElement(name = "transaction_id")
+ @JSONField(name = "transaction_id")
+ private String transactionId;
+ /**
+ * 笔数
+ */
+ @XmlElement(name = "count")
+ @JSONField(name = "count")
+ private int orderCount;
+
+ /**
+ * 报关详情
+ *
+ * @see CustomsOrderResult
+ */
+ @ListsuffixResult
+ private List customsOrderList;
+
+ public String getTransactionId() {
+ return transactionId;
+ }
+
+ public void setTransactionId(String transactionId) {
+ this.transactionId = transactionId;
+ }
+
+ public int getOrderCount() {
+ return orderCount;
+ }
+
+ public void setOrderCount(int orderCount) {
+ this.orderCount = orderCount;
+ }
+
+ public List getCustomsOrderList() {
+ return customsOrderList;
+ }
+
+ public void setCustomsOrderList(List customsOrderList) {
+ this.customsOrderList = customsOrderList;
+ }
+
+ @Override
+ public String toString() {
+ return "CustomsOrderRecord [transactionId=" + transactionId
+ + ", orderCount=" + orderCount + ", customsOrderList="
+ + customsOrderList + "]";
+ }
+}
diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/CustomsOrderResult.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/CustomsOrderResult.java
new file mode 100644
index 00000000..ba58c2cf
--- /dev/null
+++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/CustomsOrderResult.java
@@ -0,0 +1,123 @@
+package com.foxinmy.weixin4j.pay.payment.mch;
+
+import com.alibaba.fastjson.annotation.JSONField;
+import com.foxinmy.weixin4j.type.CustomsSatus;
+import com.foxinmy.weixin4j.util.DateUtil;
+
+import javax.xml.bind.annotation.XmlElement;
+import java.util.Date;
+
+/**
+ * 报关结果
+ *
+ * @className CustomsOrderResult
+ * @author jinyu(foxinmy@gmail.com)
+ * @date 2016年3月27日
+ * @since JDK 1.6
+ * @see
+ */
+public class CustomsOrderResult extends MerchantResult {
+
+ private static final long serialVersionUID = 799510373861612386L;
+ /**
+ * 状态码
+ */
+ private String state;
+ /**
+ * 微信支付订单号
+ */
+ @XmlElement(name = "transaction_id")
+ @JSONField(name = "transaction_id")
+ private String transactionId;
+ /**
+ * 商户订单号
+ */
+ @XmlElement(name = "out_trade_no")
+ @JSONField(name = "out_trade_no")
+ private String outTradeNo;
+ /**
+ * 商户子订单号
+ */
+ @XmlElement(name = "sub_order_no")
+ @JSONField(name = "sub_order_no")
+ private String subOrderNo;
+ /**
+ * 微信子订单号
+ *
+ */
+ @XmlElement(name = "sub_order_id")
+ @JSONField(name = "sub_order_id")
+ private String subOrderId;
+ /**
+ * 最后更新时间
+ */
+ @XmlElement(name = "modify_time")
+ @JSONField(name = "modify_time")
+ private String modifyTime;
+
+ public String getState() {
+ return state;
+ }
+
+ @JSONField(serialize = false)
+ public CustomsSatus getFormatState() {
+ return CustomsSatus.valueOf(state.toUpperCase());
+ }
+
+ public void setState(String state) {
+ this.state = state;
+ }
+
+ public String getTransactionId() {
+ return transactionId;
+ }
+
+ public void setTransactionId(String transactionId) {
+ this.transactionId = transactionId;
+ }
+
+ public String getOutTradeNo() {
+ return outTradeNo;
+ }
+
+ public void setOutTradeNo(String outTradeNo) {
+ this.outTradeNo = outTradeNo;
+ }
+
+ public String getSubOrderNo() {
+ return subOrderNo;
+ }
+
+ public void setSubOrderNo(String subOrderNo) {
+ this.subOrderNo = subOrderNo;
+ }
+
+ public String getSubOrderId() {
+ return subOrderId;
+ }
+
+ public void setSubOrderId(String subOrderId) {
+ this.subOrderId = subOrderId;
+ }
+
+ public String getModifyTime() {
+ return modifyTime;
+ }
+
+ @JSONField(serialize = false)
+ public Date getFormatModifyTime() {
+ return DateUtil.parse2yyyyMMddHHmmss(modifyTime);
+ }
+
+ public void setModifyTime(String modifyTime) {
+ this.modifyTime = modifyTime;
+ }
+
+ @Override
+ public String toString() {
+ return "CustomsOrderResult [state=" + state + ", transactionId="
+ + transactionId + ", outTradeNo=" + outTradeNo
+ + ", subOrderNo=" + subOrderNo + ", subOrderId=" + subOrderId
+ + ", modifyTime=" + modifyTime + "]";
+ }
+}
diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/JSAPIPayRequest.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/JSAPIPayRequest.java
new file mode 100644
index 00000000..804ba769
--- /dev/null
+++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/JSAPIPayRequest.java
@@ -0,0 +1,50 @@
+package com.foxinmy.weixin4j.pay.payment.mch;
+
+import com.alibaba.fastjson.JSON;
+import com.foxinmy.weixin4j.pay.model.WeixinPayAccount;
+import com.foxinmy.weixin4j.pay.payment.PayRequest;
+import com.foxinmy.weixin4j.pay.type.SignType;
+import com.foxinmy.weixin4j.pay.type.TradeType;
+
+/**
+ * 公众号JS支付:get_brand_wcpay_request
+ *
+ * get_brand_wcpay_request:ok 支付成功
+ * get_brand_wcpay_request:cancel 支付过程中用户取消
+ * get_brand_wcpay_request:fail 支付失败
+ *
+ *
+ * @className JSAPIPayRequest
+ * @author jinyu(foxinmy@gmail.com)
+ * @date 2015年12月25日
+ * @since JDK 1.6
+ * @see PrePay
+ * @see PayRequest
+ * @see 网页端调起支付API
+ */
+public class JSAPIPayRequest extends AbstractPayRequest {
+
+ public JSAPIPayRequest(String prePayId, WeixinPayAccount payAccount) {
+ super(prePayId, payAccount);
+ }
+
+ @Override
+ public TradeType getPaymentType() {
+ return TradeType.JSAPI;
+ }
+
+ @Override
+ public PayRequest toRequestObject() {
+ PayRequest payRequest = new PayRequest(getPaymentAccount().getId(),
+ "prepay_id=" + getPrePayId());
+ payRequest.setSignType(SignType.MD5);
+ payRequest.setPaySign(weixinSignature.sign(payRequest));
+ return payRequest;
+ }
+
+ @Override
+ public String toRequestString() {
+ return JSON.toJSONString(toRequestObject());
+ }
+}
diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/MICROPayRequest.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/MICROPayRequest.java
new file mode 100644
index 00000000..04521a9a
--- /dev/null
+++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/MICROPayRequest.java
@@ -0,0 +1,75 @@
+package com.foxinmy.weixin4j.pay.payment.mch;
+
+import com.alibaba.fastjson.annotation.JSONField;
+import com.foxinmy.weixin4j.pay.model.WeixinPayAccount;
+import com.foxinmy.weixin4j.pay.payment.PayRequest;
+import com.foxinmy.weixin4j.type.TradeType;
+
+import javax.xml.bind.annotation.XmlTransient;
+
+/**
+ * MICROPAY刷卡支付
+ *
+ * @className MICROPayRequest
+ * @author jinyu(foxinmy@gmail.com)
+ * @date 2015年12月25日
+ * @since JDK 1.6
+ * @see PrePay
+ * @see PayRequest
+ * @see 刷卡支付
+ */
+public class MICROPayRequest extends Order implements MchPayRequest {
+
+ private static final long serialVersionUID = 6147576305404111278L;
+
+ @XmlTransient
+ @JSONField(serialize = false)
+ private WeixinPayAccount paymentAccount;
+
+ protected MICROPayRequest() {
+ // jaxb required
+ }
+
+ @Override
+ @JSONField(serialize = false)
+ public TradeType getPaymentType() {
+ return TradeType.MICROPAY;
+ }
+
+ /**
+ * 返回null,请不要尝试作为支付请求
+ */
+ @Override
+ @JSONField(serialize = false)
+ public String toRequestString() {
+ return null;
+ }
+
+ /**
+ * 返回null,请不要尝试作为支付请求
+ */
+ @JSONField(serialize = false)
+ @Override
+ public PayRequest toRequestObject() {
+ return null;
+ }
+
+ /**
+ * 返回null,请不要尝试作为支付请求
+ */
+ @JSONField(serialize = false)
+ @Override
+ public String getPrePayId() {
+ return null;
+ }
+
+ public void setPaymentAccount(WeixinPayAccount paymentAccount) {
+ this.paymentAccount = paymentAccount;
+ }
+
+ @Override
+ public WeixinPayAccount getPaymentAccount() {
+ return this.paymentAccount;
+ }
+}
diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/MchPayPackage.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/MchPayPackage.java
new file mode 100644
index 00000000..e890dbbb
--- /dev/null
+++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/MchPayPackage.java
@@ -0,0 +1,224 @@
+package com.foxinmy.weixin4j.pay.payment.mch;
+
+import com.alibaba.fastjson.annotation.JSONField;
+import com.foxinmy.weixin4j.pay.payment.PayPackage;
+import com.foxinmy.weixin4j.pay.type.CurrencyType;
+import com.foxinmy.weixin4j.pay.type.TradeType;
+
+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 MchPayPackage
+ * @author jinyu(foxinmy@gmail.com)
+ * @date 2014年10月21日
+ * @since JDK 1.6
+ * @see
+ */
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.FIELD)
+public class MchPayPackage extends PayPackage {
+
+ private static final long serialVersionUID = 8944928173669656177L;
+
+ /**
+ * 交易类型JSAPI、NATIVE、APP 必须
+ */
+ @XmlElement(name = "trade_type")
+ @JSONField(name = "trade_type")
+ private String tradeType;
+ /**
+ * 符合ISO 4217标准的三位字母代码,默认人民币:CNY 非必须
+ */
+ @XmlElement(name = "fee_type")
+ @JSONField(name = "fee_type")
+ private String feeType;
+ /**
+ * 用户在商户 appid 下的唯一 标识, trade_type 为 JSAPI 时,此参数必传
+ */
+ @XmlElement(name = "openid")
+ @JSONField(name = "openid")
+ private String openId;
+
+ /**
+ * 只在 trade_type 为 NATIVE 且【模式一】 时需要填写 非必须
+ */
+ @XmlElement(name = "product_id")
+ @JSONField(name = "product_id")
+ private String productId;
+
+ /**
+ * 扫码支付授权码 ,设备读取用户微信中的条码或者二维码信息
+ */
+ @XmlElement(name = "auth_code")
+ @JSONField(name = "auth_code")
+ private String authCode;
+ /**
+ * 指定支付方式:no_credit--指定不能使用信用卡支付
+ */
+ @XmlElement(name = "limit_pay")
+ @JSONField(name = "limit_pay")
+ private String limitPay;
+ /**
+ * 服务商下的用户子标识 非必须
+ */
+ @XmlElement(name = "sub_openid")
+ @JSONField(name = "sub_openid")
+ private String subOpenId;
+ /**
+ * 场景信息
+ */
+ @XmlElement(name = "scene_info")
+ @JSONField(name = "scene_info")
+ private String sceneInfo;
+
+ protected MchPayPackage() {
+ // jaxb required
+ }
+
+ /**
+ * 微信支付
+ *
+ * @param body
+ * 支付详情 必填
+ * @param outTradeNo
+ * 商户侧订单号 必填
+ * @param totalFee
+ * 支付金额(单位元) 必填
+ * @param notifyUrl
+ * 支付回调URL 必填
+ * @param createIp
+ * 发起支付的IP地址 必填
+ * @param tradeType
+ * 支付类型 必填
+ * @param openId
+ * 用户唯一标识 公众号JSAPI支付必填
+ * @param authCode
+ * 支付授权码 刷卡MICROPAY支付必填
+ * @param productId
+ * 商品ID 扫码NATIVE支付必填
+ * @param attach
+ * 支付时附加信息 非必填
+ */
+ public MchPayPackage(String body, String outTradeNo, double totalFee,
+ String notifyUrl, String createIp, TradeType tradeType,
+ String openId, String authCode, String productId, String attach) {
+ this(body, null, outTradeNo, totalFee, CurrencyType.CNY, notifyUrl,
+ createIp, tradeType, openId, authCode, productId, attach, null,
+ null, null, null, null);
+ }
+
+ /**
+ * 完整参数
+ *
+ * @param body
+ * 商品描述 必填项
+ * @param detial
+ * 商品名称明细列表 非必填项
+ * @param outTradeNo
+ * 商户内部唯一订单号 必填项
+ * @param totalFee
+ * 商品总额 单位元 必填项
+ * @param notifyUrl
+ * 支付回调URL 必填项
+ * @param createIp
+ * 订单生成的机器IP 必填项
+ * @param tradeType
+ * 交易类型 必填项
+ * @param feeType
+ * 货币类型 非必填项
+ * @param openId
+ * 用户ID tradeType=JSAPI时必填
+ * @param authCode
+ * 刷卡支付授权码 tradeType=MICROPAY时必填
+ * @param productId
+ * 产品ID tradeType=NATIVE时必填
+ * @param attach
+ * 附加数据,在查询API和支付通知中原样返回,该字段主要用于商户携带订单的自定义数据 非必填项
+ * @param timeStart
+ * 订单生成时间,格式为yyyyMMddHHmmss 非必填项
+ * @param timeExpire
+ * 订单失效时间,格式为yyyyMMddHHmmss;注意:最短失效时间间隔必须大于5分钟 非必填项
+ * @param goodsTag
+ * 商品标记,代金券或立减优惠功能的参数 非必填项
+ * @param limitPay
+ * 指定支付方式:no_credit--指定不能使用信用卡支付 非必填项
+ * @param subOpenId
+ * 用户在子商户appid下的唯一标识 非必填
+ * openid和sub_openid可以选传其中之一,如果选择传sub_openid ,则必须传sub_appid
+ */
+ public MchPayPackage(String body, String detial, String outTradeNo,
+ double totalFee, CurrencyType feeType, String notifyUrl,
+ String createIp, TradeType tradeType, String openId,
+ String authCode, String productId, String attach, Date timeStart,
+ Date timeExpire, String goodsTag, String limitPay, String subOpenId) {
+ super(body, detial, outTradeNo, totalFee, notifyUrl, createIp, attach,
+ timeStart, timeExpire, goodsTag);
+ this.tradeType = tradeType != null ? tradeType.name() : null;
+ this.feeType = feeType == null ? CurrencyType.CNY.name() : feeType
+ .name();
+ this.openId = openId;
+ this.authCode = authCode;
+ this.productId = productId;
+ this.limitPay = limitPay;
+ this.subOpenId = subOpenId;
+ }
+
+ public String getTradeType() {
+ return tradeType;
+ }
+
+ public String getFeeType() {
+ return feeType;
+ }
+
+ public String getOpenId() {
+ return openId;
+ }
+
+ public String getAuthCode() {
+ return authCode;
+ }
+
+ public String getProductId() {
+ return productId;
+ }
+
+ public String getLimitPay() {
+ return limitPay;
+ }
+
+ public void setLimitPay(String limitPay) {
+ this.limitPay = limitPay;
+ }
+
+ public String getSubOpenId() {
+ return subOpenId;
+ }
+
+ public void setSubOpenId(String subOpenId) {
+ this.subOpenId = subOpenId;
+ }
+
+ public String getSceneInfo() {
+ return sceneInfo;
+ }
+
+ public void setSceneInfo(String sceneInfo) {
+ this.sceneInfo = sceneInfo;
+ }
+
+ @Override
+ public String toString() {
+ return "MchPayPackage [tradeType=" + tradeType + ",feeType=" + feeType
+ + ", openId=" + openId + ", productId=" + productId
+ + ", authCode=" + authCode + ", limitPay=" + limitPay
+ + ", subOpenId=" + subOpenId + ", sceneInfo=" + sceneInfo
+ + ", " + super.toString() + "]";
+ }
+}
diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/MchPayRequest.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/MchPayRequest.java
new file mode 100644
index 00000000..9bfce2a8
--- /dev/null
+++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/MchPayRequest.java
@@ -0,0 +1,55 @@
+package com.foxinmy.weixin4j.pay.payment.mch;
+
+import com.foxinmy.weixin4j.pay.model.WeixinPayAccount;
+import com.foxinmy.weixin4j.pay.payment.PayRequest;
+import com.foxinmy.weixin4j.pay.type.TradeType;
+
+/**
+ * 支付请求接口
+ *
+ * @className MchPayRequest
+ * @author jinyu(foxinmy@gmail.com)
+ * @date 2015年12月25日
+ * @since JDK 1.6
+ * @see JSAPIPayRequest JS支付
+ * @see NATIVEPayRequest 扫码支付
+ * @see MICROPayRequest 刷卡支付
+ * @see APPPayRequest APP支付
+ * @see WAPPayRequest WAP支付
+ */
+public interface MchPayRequest {
+ /**
+ * 预支付交易ID
+ *
+ * @return
+ */
+ public String getPrePayId();
+
+ /**
+ * 支付账号
+ *
+ * @return
+ */
+ public WeixinPayAccount getPaymentAccount();
+
+ /**
+ * 支付类型
+ *
+ * @return
+ */
+ public TradeType getPaymentType();
+
+ /**
+ * 支付请求字符串
+ *
+ * @return
+ */
+ public String toRequestString();
+
+ /**
+ * 支付请求对象
+ *
+ * @return
+ */
+ public PayRequest toRequestObject();
+}
diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/MerchantResult.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/MerchantResult.java
new file mode 100644
index 00000000..a2a940b4
--- /dev/null
+++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/MerchantResult.java
@@ -0,0 +1,176 @@
+package com.foxinmy.weixin4j.pay.payment.mch;
+
+import com.alibaba.fastjson.annotation.JSONField;
+import com.foxinmy.weixin4j.http.weixin.XmlResult;
+import com.foxinmy.weixin4j.type.SignType;
+
+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 MerchantResult
+ * @author jinyu(foxinmy@gmail.com)
+ * @date 2014年10月21日
+ * @since JDK 1.6
+ * @see
+ */
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.FIELD)
+public class MerchantResult extends XmlResult {
+
+ private static final long serialVersionUID = -8430005768959715444L;
+
+ /**
+ * 微信分配的公众账号 ID商户号 非空
+ */
+ @XmlElement(name = "appid")
+ @JSONField(name = "appid")
+ private String appId;
+ /**
+ * 微信支付分配的商户号 非空
+ */
+ @XmlElement(name = "mch_id")
+ @JSONField(name = "mch_id")
+ private String mchId;
+ /**
+ * 微信分配的子商户公众账号ID 非必须
+ */
+ @XmlElement(name = "sub_appid")
+ @JSONField(name = "sub_appid")
+ private String subAppId;
+ /**
+ * 微信支付分配的子商户号 非必须
+ */
+ @XmlElement(name = "sub_mch_id")
+ @JSONField(name = "sub_mch_id")
+ private String subMchId;
+ /**
+ * 随机字符串 非空
+ */
+ @XmlElement(name = "nonce_str")
+ @JSONField(name = "nonce_str")
+ private String nonceStr;
+ /**
+ * 签名 调用者无需关心
+ */
+ private String sign;
+ /**
+ * 签名类型 默认MD5
+ */
+ @XmlElement(name = "sign_type")
+ @JSONField(name = "sign_type")
+ private String signType;
+ /**
+ * 微信支付分配的终端设备号 可能为空
+ */
+ @XmlElement(name = "device_info")
+ @JSONField(name = "device_info")
+ private String deviceInfo;
+ /**
+ * 是否需要继续调用接口 Y- 需要,N-不需要
+ */
+ private String recall;
+
+ protected MerchantResult() {
+ // jaxb required
+ }
+
+ public MerchantResult(String returnCode, String returnMsg) {
+ super(returnCode, returnMsg);
+ }
+
+ public String getAppId() {
+ return appId;
+ }
+
+ public void setAppId(String appId) {
+ this.appId = appId;
+ }
+
+ public String getMchId() {
+ return mchId;
+ }
+
+ public void setMchId(String mchId) {
+ this.mchId = mchId;
+ }
+
+ public String getSubAppId() {
+ return subAppId;
+ }
+
+ public void setSubAppId(String subAppId) {
+ this.subAppId = subAppId;
+ }
+
+ public String getSubMchId() {
+ return subMchId;
+ }
+
+ public void setSubMchId(String subMchId) {
+ this.subMchId = subMchId;
+ }
+
+ public String getNonceStr() {
+ return nonceStr;
+ }
+
+ public void setNonceStr(String nonceStr) {
+ this.nonceStr = nonceStr;
+ }
+
+ public String getSign() {
+ return sign;
+ }
+
+ public void setSign(String sign) {
+ this.sign = sign;
+ }
+
+ public String getSignType() {
+ return signType;
+ }
+
+ @JSONField(serialize = false)
+ public SignType getFormatSignType() {
+ return signType != null ? SignType.valueOf(signType.toUpperCase())
+ : null;
+ }
+
+ public void setSignType(String signType) {
+ this.signType = signType;
+ }
+
+ public String getDeviceInfo() {
+ return deviceInfo;
+ }
+
+ public void setDeviceInfo(String deviceInfo) {
+ this.deviceInfo = deviceInfo;
+ }
+
+ public String getRecall() {
+ return recall;
+ }
+
+ public void setRecall(String recall) {
+ this.recall = recall;
+ }
+
+ @JSONField(serialize = false)
+ public boolean getFormatRecall() {
+ return recall != null && recall.equalsIgnoreCase("y");
+ }
+
+ @Override
+ public String toString() {
+ return "appId=" + appId + ", mchId=" + mchId + ", subAppId=" + subAppId
+ + ", subMchId=" + subMchId + ", nonceStr=" + nonceStr
+ + ", sign=" + sign + ", deviceInfo=" + deviceInfo + ", recall="
+ + getFormatRecall() + ", " + super.toString();
+ }
+}
diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/MerchantTradeResult.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/MerchantTradeResult.java
new file mode 100644
index 00000000..3f297f3f
--- /dev/null
+++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/MerchantTradeResult.java
@@ -0,0 +1,126 @@
+package com.foxinmy.weixin4j.pay.payment.mch;
+
+import com.alibaba.fastjson.annotation.JSONField;
+import com.foxinmy.weixin4j.type.CurrencyType;
+
+import javax.xml.bind.annotation.XmlElement;
+
+/**
+ * 商户平台交易结果
+ *
+ * @className MerchantTradeResult
+ * @author jinyu(foxinmy@gmail.com)
+ * @date 2016年7月21日
+ * @since JDK 1.7
+ * @see
+ */
+public class MerchantTradeResult extends MerchantResult {
+
+ private static final long serialVersionUID = 4205906286092873877L;
+ /**
+ * 微信支付订单号
+ */
+ @XmlElement(name = "transaction_id")
+ @JSONField(name = "transaction_id")
+ private String transactionId;
+ /**
+ * 商户订单号
+ */
+ @XmlElement(name = "out_trade_no")
+ @JSONField(name = "out_trade_no")
+ private String outTradeNo;
+ /**
+ * 订单总金额,单位为分
+ */
+ @XmlElement(name = "total_fee")
+ @JSONField(name = "total_fee")
+ private Integer totalFee;
+ /**
+ * 应结订单金额,单位为分:应结订单金额=订单金额-非充值代金券金额,应结订单金额<=订单金额。
+ */
+ @XmlElement(name = "settlement_total_fee")
+ @JSONField(name = "settlement_total_fee")
+ private Integer settlementTotalFee;
+ /**
+ * 货币类型,符合 ISO 4217 标准的三位字母代码,默认人民币:CNY
+ *
+ * @see com.foxinmy.weixin4j.mp.type.CurrencyType
+ */
+ @XmlElement(name = "fee_type")
+ @JSONField(name = "fee_type")
+ private String feeType;
+ /**
+ * 现金支付金额
+ */
+ @XmlElement(name = "cash_fee")
+ @JSONField(name = "cash_fee")
+ private Integer cashFee;
+
+ public Integer getCashFee() {
+ return cashFee;
+ }
+
+ /**
+ * 调用接口获取单位为分,get方法转换为元方便使用
+ *
+ * @return 元单位
+ */
+ @JSONField(serialize = false)
+ public double getFormatCashFee() {
+ return cashFee != null ? cashFee / 100d : 0d;
+ }
+
+ public Integer getTotalFee() {
+ return totalFee;
+ }
+
+ /**
+ * 调用接口获取单位为分,get方法转换为元方便使用
+ *
+ * @return 元单位
+ */
+ @JSONField(serialize = false)
+ public double getFormatTotalFee() {
+ return totalFee != null ? totalFee / 100d : 0d;
+ }
+
+ @JSONField(serialize = false)
+ public CurrencyType getFormatFeeType() {
+ return feeType != null ? CurrencyType.valueOf(feeType.toUpperCase())
+ : null;
+ }
+
+ public String getFeeType() {
+ return feeType;
+ }
+
+ public String getTransactionId() {
+ return transactionId;
+ }
+
+ public String getOutTradeNo() {
+ return outTradeNo;
+ }
+
+ public Integer getSettlementTotalFee() {
+ return settlementTotalFee;
+ }
+
+ /**
+ * 调用接口获取单位为分,get方法转换为元方便使用
+ *
+ * @return 元单位
+ */
+ @JSONField(serialize = false)
+ public double getFormatSettlementTotalFee() {
+ return settlementTotalFee != null ? settlementTotalFee / 100d : 0d;
+ }
+
+ @Override
+ public String toString() {
+ return "transactionId=" + transactionId + ", outTradeNo=" + outTradeNo
+ + ", totalFee=" + totalFee + ", cashFee=" + cashFee
+ + ", feeType=" + feeType + ", settlementTotalFee="
+ + settlementTotalFee + ", " + super.toString();
+ }
+}
diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/NATIVEPayRequest.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/NATIVEPayRequest.java
new file mode 100644
index 00000000..787dfacb
--- /dev/null
+++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/NATIVEPayRequest.java
@@ -0,0 +1,46 @@
+package com.foxinmy.weixin4j.pay.payment.mch;
+
+import com.foxinmy.weixin4j.pay.model.WeixinPayAccount;
+import com.foxinmy.weixin4j.pay.payment.PayRequest;
+import com.foxinmy.weixin4j.pay.type.TradeType;
+
+/**
+ * NATIVE扫码支付(模式二)
+ *
+ * @className NATIVEPayRequest
+ * @author jinyu(foxinmy@gmail.com)
+ * @date 2015年12月25日
+ * @since JDK 1.6
+ * @see PrePay
+ * @see PayRequest
+ * @see NATIVE扫码支付(模式二)
+ */
+public class NATIVEPayRequest extends AbstractPayRequest {
+
+ private final String codeUrl;
+
+ public NATIVEPayRequest(String prePayId, String codeUrl,
+ WeixinPayAccount payAccount) {
+ super(prePayId, payAccount);
+ this.codeUrl = codeUrl;
+ }
+
+ @Override
+ public TradeType getPaymentType() {
+ return TradeType.NATIVE;
+ }
+
+ /**
+ * 只做查看之用,请不要尝试作为支付请求
+ */
+ @Override
+ public PayRequest toRequestObject() {
+ return new PayRequest(getPaymentAccount().getId(), "code_url=" + codeUrl);
+ }
+
+ @Override
+ public String toRequestString() {
+ return this.codeUrl;
+ }
+}
diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/NativePayNotify.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/NativePayNotify.java
new file mode 100644
index 00000000..57c9b697
--- /dev/null
+++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/NativePayNotify.java
@@ -0,0 +1,54 @@
+package com.foxinmy.weixin4j.pay.payment.mch;
+
+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;
+
+/**
+ * Native支付回调时POST的信息
+ *
+ * @className PayNativeNotify
+ * @author jinyu(foxinmy@gmail.com)
+ * @date 2014年10月30日
+ * @since JDK 1.6
+ * @see
+ */
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.FIELD)
+public class NativePayNotify extends OpenIdResult {
+
+ private static final long serialVersionUID = 4515471400239795492L;
+ /**
+ * 用户是否关注公众账号,Y- 关注,N-未关注,仅在公众 账号类型支付有效
+ */
+ @XmlElement(name = "is_subscribe")
+ @JSONField(name = "is_subscribe")
+ private String isSubscribe;
+ /**
+ * 产品ID 可视为订单ID
+ */
+ @XmlElement(name = "product_id")
+ @JSONField(name = "product_id")
+ private String productId;
+
+ protected NativePayNotify() {
+ // jaxb required
+ }
+
+ public String getProductId() {
+ return productId;
+ }
+
+ public String getIsSubscribe() {
+ return isSubscribe;
+ }
+
+ @Override
+ public String toString() {
+ return "NativePayNotify [productId=" + productId + ", isSubscribe="
+ + isSubscribe + ", " + super.toString() + "]";
+ }
+}
diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/NativePayResponse.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/NativePayResponse.java
new file mode 100644
index 00000000..04b2f253
--- /dev/null
+++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/NativePayResponse.java
@@ -0,0 +1,79 @@
+package com.foxinmy.weixin4j.pay.payment.mch;
+
+import com.alibaba.fastjson.annotation.JSONField;
+import com.foxinmy.weixin4j.pay.model.WeixinPayAccount;
+import com.foxinmy.weixin4j.pay.sign.WeixinPaymentSignature;
+import com.foxinmy.weixin4j.util.Consts;
+import com.foxinmy.weixin4j.util.RandomUtil;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+/**
+ * Native支付时的回调响应
+ *
+ * @className NativePayResponse
+ * @author jinyu(foxinmy@gmail.com)
+ * @date 2014年10月28日
+ * @since JDK 1.6
+ * @see
+ */
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.FIELD)
+public class NativePayResponse extends MerchantResult {
+
+ private static final long serialVersionUID = 6119895998783333012L;
+
+ @XmlElement(name = "prepay_id")
+ @JSONField(name = "prepay_id")
+ private String prepayId;
+
+ protected NativePayResponse() {
+ // jaxb required
+ }
+
+ /**
+ * 作为return_code 为 FAIL 的时候返回
+ *
+ * @param returnMsg
+ * 失败消息
+ * @param resultMsg
+ * 结果消息
+ */
+ public NativePayResponse(String returnMsg, String resultMsg) {
+ super(Consts.FAIL, returnMsg);
+ super.setErrCodeDes(resultMsg);
+ super.setResultCode(Consts.FAIL);
+ }
+
+ /**
+ * 作为return_code 为 SUCCESS 的时候返回
+ *
+ * @param weixinAccount
+ * 商户信息
+ * @param prepayId
+ * 调用统一下单接口生成的预支付ID
+ */
+ public NativePayResponse(WeixinPayAccount weixinAccount, String prepayId) {
+ super(Consts.SUCCESS, "OK");
+ this.setResultCode(Consts.SUCCESS);
+ this.setMchId(weixinAccount.getMchId());
+ this.setAppId(weixinAccount.getId());
+ this.setNonceStr(RandomUtil.generateString(16));
+ this.prepayId = prepayId;
+ this.setSign(new WeixinPaymentSignature(weixinAccount.getPaySignKey())
+ .sign(this));
+ }
+
+ public String getPrepayId() {
+ return prepayId;
+ }
+
+ @Override
+ public String toString() {
+ return "NativePayResponse [prepayId=" + prepayId + ", "
+ + super.toString() + "]";
+ }
+}
diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/OpenIdResult.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/OpenIdResult.java
new file mode 100644
index 00000000..3c4cfd95
--- /dev/null
+++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/OpenIdResult.java
@@ -0,0 +1,52 @@
+package com.foxinmy.weixin4j.pay.payment.mch;
+
+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;
+
+/**
+ * authcode2openid
+ *
+ * @className OpenIdResult
+ * @author jinyu(foxinmy@gmail.com)
+ * @date 2015年7月23日
+ * @since JDK 1.6
+ * @see
+ */
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.FIELD)
+public class OpenIdResult extends MerchantResult {
+
+ private static final long serialVersionUID = 902743989722741814L;
+
+ /**
+ * 用户在商户appid下的唯一标识
+ */
+ @XmlElement(name = "openid")
+ @JSONField(name = "openid")
+ private String openId;
+
+ /**
+ * 用户在商户appid下的唯一标识
+ */
+ @XmlElement(name = "sub_openid")
+ @JSONField(name = "sub_openid")
+ private String subOpenId;
+
+ public String getOpenId() {
+ return openId;
+ }
+
+ public String getSubOpenId() {
+ return subOpenId;
+ }
+
+ @Override
+ public String toString() {
+ return "OpenIdResult [openId=" + openId + ", subOpenId=" + subOpenId
+ + ", " + super.toString() + "]";
+ }
+}
diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/Order.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/Order.java
new file mode 100644
index 00000000..f1e7be19
--- /dev/null
+++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/Order.java
@@ -0,0 +1,247 @@
+package com.foxinmy.weixin4j.pay.payment.mch;
+
+import com.alibaba.fastjson.annotation.JSONField;
+import com.foxinmy.weixin4j.pay.payment.coupon.OrderCouponInfo;
+import com.foxinmy.weixin4j.type.BankType;
+import com.foxinmy.weixin4j.type.CurrencyType;
+import com.foxinmy.weixin4j.type.TradeState;
+import com.foxinmy.weixin4j.type.TradeType;
+import com.foxinmy.weixin4j.util.DateUtil;
+import com.foxinmy.weixin4j.xml.ListsuffixResult;
+
+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;
+import java.util.List;
+
+/**
+ * 订单信息
+ *
+ * @className Order
+ * @author jinyu(foxinmy@gmail.com)
+ * @date 2014年11月2日
+ * @since JDK 1.6
+ * @see
+ */
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.FIELD)
+public class Order extends MerchantTradeResult {
+
+ private static final long serialVersionUID = 5636828325595317079L;
+ /**
+ * 交易状态
+ *
+ * @see TradeState
+ */
+ @XmlElement(name = "trade_state")
+ @JSONField(name = "trade_state")
+ private String tradeState;
+ /**
+ * 用户的openid
+ */
+ @XmlElement(name = "openid")
+ @JSONField(name = "openid")
+ private String openId;
+ /**
+ * 用户是否关注公众账号,Y- 关注,N-未关注,仅在公众 账号类型支付有效
+ */
+ @XmlElement(name = "is_subscribe")
+ @JSONField(name = "is_subscribe")
+ private String isSubscribe;
+ /**
+ * 交易类型
+ *
+ * @see TradeType
+ */
+ @XmlElement(name = "trade_type")
+ @JSONField(name = "trade_type")
+ private String tradeType;
+ /**
+ * 银行类型
+ */
+ @XmlElement(name = "bank_type")
+ @JSONField(name = "bank_type")
+ private String bankType;
+
+ /**
+ * 现金支付货币类型,符合 ISO 4217 标准的三位字母代码,默认人民币:CNY
+ *
+ * @see com.foxinmy.weixin4j.mp.type.CurrencyType
+ */
+ @XmlElement(name = "cash_fee_type")
+ @JSONField(name = "cash_fee_type")
+ private String cashFeeType;
+ /**
+ * 代金券金额:“代金券”金额<=订单金额,订单金额-“代金券”金额=现金支付金额
+ */
+ @XmlElement(name = "coupon_fee")
+ @JSONField(name = "coupon_fee")
+ private Integer couponFee;
+ /**
+ * 代金券或立减优惠使用数量
+ */
+ @XmlElement(name = "coupon_count")
+ @JSONField(name = "coupon_count")
+ private Integer couponCount;
+ /**
+ * 代金券信息 验证签名有点麻烦
+ */
+ @ListsuffixResult
+ private List couponList;
+ /**
+ * 商家数据包
+ */
+ private String attach;
+ /**
+ * 支付完成时间,格式为 yyyyMMddhhmmss
+ */
+ @XmlElement(name = "time_end")
+ @JSONField(name = "time_end")
+ private String timeEnd;
+ /**
+ * 交易状态描述
+ */
+ @XmlElement(name = "trade_state_desc")
+ @JSONField(name = "trade_state_desc")
+ private String tradeStateDesc;
+
+ /**
+ * 用户在子商户下的openid
+ */
+ @XmlElement(name = "sub_openid")
+ @JSONField(name = "sub_openid")
+ private String subOpenId;
+ /**
+ * 是否关注子公众账号,Y- 关注,N-未关注,仅在公众 账号类型支付有效
+ */
+ @XmlElement(name = "sub_is_subscribe")
+ @JSONField(name = "sub_is_subscribe")
+ private String subIsSubscribe;
+
+ protected Order() {
+ // jaxb required
+ }
+
+ @JSONField(serialize = false)
+ public TradeState getFormatTradeState() {
+ return tradeState != null ? TradeState
+ .valueOf(tradeState.toUpperCase()) : null;
+ }
+
+ public String getOpenId() {
+ return openId;
+ }
+
+ public String getIsSubscribe() {
+ return isSubscribe;
+ }
+
+ @JSONField(serialize = false)
+ public boolean getFormatIsSubscribe() {
+ return isSubscribe != null && isSubscribe.equalsIgnoreCase("y");
+ }
+
+ @JSONField(serialize = false)
+ public TradeType getFormatTradeType() {
+ return tradeType != null ? TradeType.valueOf(tradeType.toUpperCase())
+ : null;
+ }
+
+ public String getBankType() {
+ return bankType;
+ }
+
+ @JSONField(serialize = false)
+ public BankType getFormatBankType() {
+ return bankType != null ? BankType.valueOf(bankType.toUpperCase())
+ : null;
+ }
+
+ public Integer getCouponFee() {
+ return couponFee;
+ }
+
+ /**
+ * 调用接口获取单位为分,get方法转换为元方便使用
+ *
+ * @return 元单位
+ */
+ @JSONField(serialize = false)
+ public double getFormatCouponFee() {
+ return couponFee != null ? couponFee / 100d : 0d;
+ }
+
+ public Integer getCouponCount() {
+ return couponCount;
+ }
+
+ public String getTradeState() {
+ return tradeState;
+ }
+
+ public String getTradeType() {
+ return tradeType;
+ }
+
+ public String getAttach() {
+ return attach;
+ }
+
+ public String getTimeEnd() {
+ return timeEnd;
+ }
+
+ @JSONField(serialize = false)
+ public Date getFormatTimeEnd() {
+ return timeEnd != null ? DateUtil.parse2yyyyMMddHHmmss(timeEnd) : null;
+ }
+
+ public String getTradeStateDesc() {
+ return tradeStateDesc;
+ }
+
+ public List getCouponList() {
+ return couponList;
+ }
+
+ public void setCouponList(List couponList) {
+ this.couponList = couponList;
+ }
+
+ public String getSubOpenId() {
+ return subOpenId;
+ }
+
+ public String getSubIsSubscribe() {
+ return subIsSubscribe;
+ }
+
+ @JSONField(serialize = false)
+ public boolean getFormatSubIsSubscribe() {
+ return subIsSubscribe != null && subIsSubscribe.equalsIgnoreCase("y");
+ }
+
+ public String getCashFeeType() {
+ return cashFeeType;
+ }
+
+ @JSONField(serialize = false)
+ public CurrencyType getFormatCashFeeType() {
+ return cashFeeType != null ? CurrencyType.valueOf(cashFeeType
+ .toUpperCase()) : null;
+ }
+
+ @Override
+ public String toString() {
+ return "Order [tradeState=" + tradeState + ", openId=" + openId
+ + ", isSubscribe=" + isSubscribe + ", tradeType=" + tradeType
+ + ", bankType=" + bankType + ", cashFeeType=" + cashFeeType
+ + ", couponFee=" + couponFee + ", couponCount=" + couponCount
+ + ", couponList=" + couponList + ", attach=" + attach
+ + ", timeEnd=" + timeEnd + ", tradeStateDesc=" + tradeStateDesc
+ + ", subOpenId=" + subOpenId + ", subIsSubscribe="
+ + subIsSubscribe + ", " + super.toString() + "]";
+ }
+}
diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/PrePay.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/PrePay.java
new file mode 100644
index 00000000..a8059fbe
--- /dev/null
+++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/PrePay.java
@@ -0,0 +1,79 @@
+package com.foxinmy.weixin4j.pay.payment.mch;
+
+import com.foxinmy.weixin4j.type.TradeType;
+
+import javax.xml.bind.annotation.*;
+
+/**
+ * V3预订单信息
+ *
+ * @className PrePay
+ * @author jinyu(foxinmy@gmail.com)
+ * @date 2014年10月21日
+ * @since JDK 1.6
+ * @see
+ */
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.FIELD)
+public class PrePay extends MerchantResult {
+
+ private static final long serialVersionUID = -8430005768959715444L;
+
+ /**
+ * 调用接口提交的交易类型,取值如下:JSAPI,NATIVE,APP,
+ *
+ * @see com.foxinmy.weixin4j.mp.type.TradeType
+ */
+ @XmlElement(name = "trade_type")
+ private TradeType tradeType;
+ /**
+ * 微信生成的预支付回话标识,用于后续接口调用中使用,该值有效期为2小时
+ */
+ @XmlElement(name = "prepay_id")
+ private String prepayId;
+ /**
+ * 对于trade_type 为 NATIVE 或者 MWEB 是有 返回 NATVIE支付:可直接生成二维码展示出来进行扫码支付可能为空
+ * MWEB支付:可直接作为跳转支付的URL
+ */
+ @XmlElements({ @XmlElement(name = "code_url"),
+ @XmlElement(name = "mweb_url") })
+ private String payUrl;
+
+ protected PrePay() {
+ // jaxb required
+ }
+
+ public PrePay(String returnCode, String returnMsg) {
+ super(returnCode, returnMsg);
+ }
+
+ public TradeType getTradeType() {
+ return tradeType;
+ }
+
+ public void setTradeType(TradeType tradeType) {
+ this.tradeType = tradeType;
+ }
+
+ public String getPrepayId() {
+ return prepayId;
+ }
+
+ public void setPrepayId(String prepayId) {
+ this.prepayId = prepayId;
+ }
+
+ public String getPayUrl() {
+ return payUrl;
+ }
+
+ public void setPayUrl(String payUrl) {
+ this.payUrl = payUrl;
+ }
+
+ @Override
+ public String toString() {
+ return "PrePay [tradeType=" + tradeType + ", prepayId=" + prepayId
+ + ", payUrl=" + payUrl + ", " + super.toString() + "]";
+ }
+}
diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/Redpacket.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/Redpacket.java
new file mode 100644
index 00000000..6888862e
--- /dev/null
+++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/Redpacket.java
@@ -0,0 +1,269 @@
+package com.foxinmy.weixin4j.pay.payment.mch;
+
+import com.alibaba.fastjson.annotation.JSONField;
+import com.foxinmy.weixin4j.type.mch.RedpacketSceneType;
+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;
+
+/**
+ * 红包
+ *
+ * @className Redpacket
+ * @author jinyu(foxinmy@gmail.com)
+ * @date 2015年3月28日
+ * @since JDK 1.6
+ * @see 普通红包
+ * @see 裂变红包
+ */
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.FIELD)
+public class Redpacket extends MerchantResult {
+
+ private static final long serialVersionUID = -7021352305575714281L;
+
+ /**
+ * 商户订单号(每个订单号必须唯一) 组成: mch_id+yyyymmdd+10位一天内不能重复的数字。
+ */
+ @XmlElement(name = "mch_billno")
+ @JSONField(name = "mch_billno")
+ private String outTradeNo;
+ /**
+ * 接受收红包的用户的openid 必填
+ */
+ @XmlElement(name = "re_openid")
+ @JSONField(name = "re_openid")
+ private String openId;
+ /**
+ * 红包发送者名称 必填
+ */
+ @XmlElement(name = "send_name")
+ @JSONField(name = "send_name")
+ private String sendName;
+ /**
+ * 付款金额,单位分
+ */
+ @XmlElement(name = "total_amount")
+ @JSONField(name = "total_amount")
+ private int totalAmount;
+ /**
+ * 红包发放总人数
+ */
+ @XmlElement(name = "total_num")
+ @JSONField(name = "total_num")
+ private int totalNum;
+ /**
+ * 红包金额设置方式(裂变红包) ALL_RAND—全部随机,商户指定总金额和红包发放总人数,由微信支付随机计算出各红包金额
+ */
+ @XmlElement(name = "amt_type")
+ @JSONField(name = "amt_type")
+ private String amtType;
+ /**
+ * 红包祝福语
+ */
+ private String wishing;
+ /**
+ * ip地址
+ */
+ @XmlElement(name = "client_ip")
+ @JSONField(name = "client_ip")
+ private String clientIp;
+ /**
+ * 活动名称
+ */
+ @XmlElement(name = "act_name")
+ @JSONField(name = "act_name")
+ private String actName;
+ /**
+ * 备注
+ */
+ private String remark;
+
+ /**
+ * 服务商模式下触达用户时的appid(可填服务商自己的appid或子商户的appid),服务商模式下必填,
+ * 服务商模式下填入的子商户appid必须在微信支付商户平台中先录入,否则会校验不过。 非必须
+ */
+ @XmlElement(name = "msgappid")
+ @JSONField(name = "msgappid")
+ private String msgAppId;
+ /**
+ * 扣钱方mchid,常规模式下无效,服务商模式下选填,服务商模式下不填默认扣子商户的钱.非必须
+ */
+ @XmlElement(name = "consume_mch_id")
+ @JSONField(name = "consume_mch_id")
+ private String consumeMchId;
+ /**
+ * 发放红包使用场景,红包金额大于200时必传
+ */
+ @XmlElement(name = "scene_id")
+ @JSONField(name = "scene_id")
+ private RedpacketSceneType sceneType;
+ /**
+ * 活动信息
+ */
+ @XmlElement(name = "risk_info")
+ @JSONField(name = "risk_info")
+ private String risk;
+
+ protected Redpacket() {
+ // jaxb required
+ }
+
+ /**
+ * 红包
+ *
+ * @param outTradeNo
+ * 商户侧一天内不可重复的订单号 接口根据商户订单号支持重入 如出现超时可再调用 必填
+ * @param openId
+ * 接受收红包的用户的openid 必填
+ * @param sendName
+ * 红包发送者名称 必填
+ * @param totalAmount
+ * 付款金额 单位为元,自动格式化为分 必填
+ * @param totalNum
+ * 红包发放总人数 大于1视为裂变红包 必填
+ * @param wishing
+ * 红包祝福语 必填
+ * @param clientIp
+ * Ip地址 必填
+ * @param actName
+ * 活动名称 必填
+ * @param remark
+ * 备注 必填
+ */
+ public Redpacket(String outTradeNo, String openId, String sendName,
+ double totalAmount, int totalNum, String wishing, String clientIp,
+ String actName, String remark) {
+ this.outTradeNo = outTradeNo;
+ this.openId = openId;
+ this.sendName = sendName;
+ this.totalAmount = DateUtil.formatYuan2Fen(totalAmount);
+ this.totalNum = totalNum;
+ this.wishing = wishing;
+ this.clientIp = clientIp;
+ this.actName = actName;
+ this.remark = remark;
+ this.amtType = totalNum > 1 ? "ALL_RAND" : null;
+ }
+
+ /**
+ * 批量发送时可能需要
+ *
+ * @param outTradeNo
+ * 订单号
+ * @param openId
+ * 用户ID
+ * @return 红包实体
+ */
+ public Redpacket copy(String outTradeNo, String openId) {
+ Redpacket readpacket = new Redpacket(outTradeNo, openId, sendName,
+ totalAmount, totalNum, wishing, clientIp, actName, remark);
+ readpacket.setMsgAppId(msgAppId);
+ readpacket.setConsumeMchId(consumeMchId);
+ readpacket.setSceneType(sceneType);
+ readpacket.setRisk(risk);
+ return readpacket;
+ }
+
+ public String getOutTradeNo() {
+ return outTradeNo;
+ }
+
+ public String getOpenId() {
+ return openId;
+ }
+
+ public String getSendName() {
+ return sendName;
+ }
+
+ public int getTotalAmount() {
+ return totalAmount;
+ }
+
+ /**
+ * 调用接口获取单位为分,get方法转换为元方便使用
+ *
+ * @return 元单位
+ */
+ @JSONField(serialize = false)
+ public double getFormatTotalAmount() {
+ return totalAmount / 100d;
+ }
+
+ public int getTotalNum() {
+ return totalNum;
+ }
+
+ public String getWishing() {
+ return wishing;
+ }
+
+ public String getAmtType() {
+ return amtType;
+ }
+
+ public String getClientIp() {
+ return clientIp;
+ }
+
+ public String getActName() {
+ return actName;
+ }
+
+ public String getRemark() {
+ return remark;
+ }
+
+ public String getMsgAppId() {
+ return msgAppId;
+ }
+
+ public void setMsgAppId(String msgAppId) {
+ this.msgAppId = msgAppId;
+ }
+
+ public String getConsumeMchId() {
+ return consumeMchId;
+ }
+
+ public void setConsumeMchId(String consumeMchId) {
+ this.consumeMchId = consumeMchId;
+ }
+
+ public RedpacketSceneType getSceneType() {
+ return sceneType;
+ }
+
+ public void setSceneType(RedpacketSceneType sceneType) {
+ this.sceneType = sceneType;
+ }
+
+ public String getRisk() {
+ return risk;
+ }
+
+ public void setRisk(String risk) {
+ this.risk = risk;
+ }
+
+ public void setRisk(RedpacketRisk risk) {
+ this.risk = risk.toContent();
+ }
+
+ @Override
+ public String toString() {
+ return "Redpacket [outTradeNo=" + outTradeNo + ", openId=" + openId
+ + ", sendName=" + sendName + ", totalAmount=" + totalAmount
+ + ", totalNum=" + totalNum + ", amtType=" + amtType
+ + ", wishing=" + wishing + ", clientIp=" + clientIp
+ + ", actName=" + actName + ", remark=" + remark + ", msgAppId="
+ + msgAppId + ", consumeMchId=" + consumeMchId + ", sceneType="
+ + sceneType + ", risk=" + risk + ", " + super.toString() + "]";
+ }
+}
diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/RedpacketRecord.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/RedpacketRecord.java
new file mode 100644
index 00000000..2cee591b
--- /dev/null
+++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/RedpacketRecord.java
@@ -0,0 +1,315 @@
+package com.foxinmy.weixin4j.pay.payment.mch;
+
+import com.alibaba.fastjson.annotation.JSONField;
+import com.foxinmy.weixin4j.http.weixin.XmlResult;
+import com.foxinmy.weixin4j.type.mch.RedpacketSendType;
+import com.foxinmy.weixin4j.type.mch.RedpacketStatus;
+import com.foxinmy.weixin4j.type.mch.RedpacketType;
+import com.foxinmy.weixin4j.util.DateUtil;
+
+import javax.xml.bind.annotation.*;
+import java.io.Serializable;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 红包记录
+ *
+ * @className RedpacketRecord
+ * @author jinyu(foxinmy@gmail.com)
+ * @date 2015年6月4日
+ * @since JDK 1.6
+ * @see
+ */
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.FIELD)
+public class RedpacketRecord extends XmlResult {
+
+ private static final long serialVersionUID = 929959747323918458L;
+
+ /**
+ * 商户订单号(每个订单号必须唯一) 组成: mch_id+yyyymmdd+10位一天内不能重复的数字。
+ */
+ @XmlElement(name = "mch_billno")
+ @JSONField(name = "mch_billno")
+ private String outTradeNo;
+ /**
+ * 微信支付分配的商户号
+ */
+ @XmlElement(name = "mch_id")
+ @JSONField(name = "mch_id")
+ private String mchId;
+ /**
+ * 红包单号
+ */
+ @XmlElement(name = "detail_id")
+ @JSONField(name = "detail_id")
+ private String repacketId;
+ /**
+ * 红包状态
+ */
+ @XmlElement(name = "status")
+ private String status;
+ /**
+ * 发放类型
+ */
+ @XmlElement(name = "send_type")
+ @JSONField(name = "send_type")
+ private String sendType;
+ /**
+ * 红包类型
+ */
+ @XmlElement(name = "hb_type")
+ @JSONField(name = "hb_type")
+ private String hbType;
+ /**
+ * 红包个数
+ */
+ @XmlElement(name = "total_num")
+ @JSONField(name = "total_num")
+ private int totalNum;
+ /**
+ * 红包总金额(单位分)
+ */
+ @XmlElement(name = "total_amount")
+ @JSONField(name = "total_amount")
+ private int totalAmount;
+ /**
+ * 发送失败原因
+ */
+ @XmlElement(name = "reason")
+ private String reason;
+ /**
+ * 发放时间
+ */
+ @XmlElement(name = "send_time")
+ @JSONField(name = "send_time")
+ private String sendTime;
+ /**
+ * 红包退款时间
+ */
+ @XmlElement(name = "refund_time")
+ @JSONField(name = "refund_time")
+ private String refundTime;
+ /**
+ * 红包退款金额
+ */
+ @XmlElement(name = "refund_amount")
+ @JSONField(name = "refund_amount")
+ private Integer refundAmount;
+ /**
+ * 祝福语
+ */
+ @XmlElement(name = "wishing")
+ private String wishing;
+ /**
+ * 活动描述
+ */
+ @XmlElement(name = "remark")
+ private String remark;
+ /**
+ * 活动名称
+ */
+ @XmlElement(name = "act_name")
+ @JSONField(name = "act_name")
+ private String actName;
+ /**
+ * 裂变红包领取列表
+ */
+ @XmlElement(name = "hbinfo")
+ @XmlElementWrapper(name = "hblist")
+ @JSONField(name = "hblist")
+ private List receivers;
+
+ public String getOutTradeNo() {
+ return outTradeNo;
+ }
+
+ public String getMchId() {
+ return mchId;
+ }
+
+ public String getRepacketId() {
+ return repacketId;
+ }
+
+ @JSONField(serialize = false)
+ public RedpacketStatus getFormatStatus() {
+ return status != null ? RedpacketStatus.valueOf(status.toUpperCase())
+ : null;
+ }
+
+ @JSONField(serialize = false)
+ public RedpacketSendType getFormatSendType() {
+ return sendType != null ? RedpacketSendType.valueOf(sendType) : null;
+ }
+
+ @JSONField(serialize = false)
+ public RedpacketType getFomatHbType() {
+ return hbType != null ? RedpacketType.valueOf(hbType) : null;
+ }
+
+ public String getStatus() {
+ return status;
+ }
+
+ public String getSendType() {
+ return sendType;
+ }
+
+ public String getHbType() {
+ return hbType;
+ }
+
+ public int getTotalNum() {
+ return totalNum;
+ }
+
+ public int getTotalAmount() {
+ return totalAmount;
+ }
+
+ /**
+ * 调用接口获取单位为分,get方法转换为元方便使用
+ *
+ * @return 元单位
+ */
+ @JSONField(serialize = false)
+ public double getFormatTotalAmount() {
+ return totalAmount / 100d;
+ }
+
+ public String getReason() {
+ return reason;
+ }
+
+ public String getSendTime() {
+ return sendTime;
+ }
+
+ @JSONField(serialize = false)
+ public Date getFormatSendTime() {
+ return sendTime != null ? DateUtil.parse2yyyyMMddHHmmss(sendTime)
+ : null;
+ }
+
+ public String getRefundTime() {
+ return refundTime;
+ }
+
+ @JSONField(serialize = false)
+ public Date getFormatRefundTime() {
+ return refundTime != null ? DateUtil.parse2yyyyMMddHHmmss(refundTime)
+ : null;
+ }
+
+ public Integer getRefundAmount() {
+ return refundAmount;
+ }
+
+ /**
+ * 调用接口获取单位为分,get方法转换为元方便使用
+ *
+ * @return 元单位
+ */
+ @JSONField(serialize = false)
+ public double getFormatRefundAmount() {
+ return refundAmount != null ? refundAmount.intValue() / 100d : 0d;
+ }
+
+ public String getWishing() {
+ return wishing;
+ }
+
+ public String getRemark() {
+ return remark;
+ }
+
+ public String getActName() {
+ return actName;
+ }
+
+ public List getReceivers() {
+ return receivers;
+ }
+
+ @XmlRootElement
+ @XmlAccessorType(XmlAccessType.FIELD)
+ public static class RedpacketReceiver implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 领取红包的Openid
+ */
+ @XmlElement(name = "openid")
+ private String openId;
+ /**
+ * 领取状态
+ */
+ @XmlElement(name = "status")
+ private RedpacketStatus status;
+ /**
+ * 领取金额
+ */
+ private int amount;
+ /**
+ * 领取时间
+ */
+ @XmlElement(name = "rcv_time")
+ @JSONField(name = "rcv_time")
+ private String receiveTime;
+
+ public String getOpenId() {
+ return openId;
+ }
+
+ public RedpacketStatus getStatus() {
+ return status;
+ }
+
+ public int getAmount() {
+ return amount;
+ }
+
+ public String getReceiveTime() {
+ return receiveTime;
+ }
+
+ /**
+ * 调用接口获取单位为分,get方法转换为元方便使用
+ *
+ * @return 元单位
+ */
+ @JSONField(serialize = false)
+ public double getFormatAmount() {
+ return amount / 100d;
+ }
+
+ @JSONField(serialize = false)
+ public Date getFormatReceiveTime() {
+ return receiveTime != null ? DateUtil
+ .parse2yyyyMMddHHmmss(receiveTime) : null;
+ }
+
+ @Override
+ public String toString() {
+ return "RedpacketReceiver [openId=" + openId + ", status=" + status
+ + ", amount=" + getFormatAmount() + ", receiveTime="
+ + receiveTime + "]";
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "RedpacketRecord [outTradeNo=" + outTradeNo + ", mchId=" + mchId
+ + ", repacketId=" + repacketId + ", status=" + status
+ + ", sendType=" + sendType + ", hbType=" + hbType
+ + ", totalNum=" + totalNum + ", totalAmount="
+ + getFormatTotalAmount() + ", reason=" + reason + ", sendTime="
+ + sendTime + ", refundTime=" + refundTime + ", refundAmount="
+ + getFormatRefundAmount() + ", wishing=" + wishing
+ + ", remark=" + remark + ", actName=" + actName
+ + ", receivers=" + receivers + "]";
+ }
+}
diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/RedpacketRisk.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/RedpacketRisk.java
new file mode 100644
index 00000000..05127d0b
--- /dev/null
+++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/RedpacketRisk.java
@@ -0,0 +1,85 @@
+package com.foxinmy.weixin4j.pay.payment.mch;
+
+import com.foxinmy.weixin4j.util.Consts;
+import com.foxinmy.weixin4j.util.DateUtil;
+import com.foxinmy.weixin4j.util.MapUtil;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 发送红包的活动信息
+ *
+ * @className RedpacketRisk
+ * @author jinyu(foxinmy@gmail.com)
+ * @date 2017年1月4日
+ * @since JDK 1.6
+ * @see
+ */
+public class RedpacketRisk {
+ private Map risk;
+
+ public RedpacketRisk() {
+ this.risk = new HashMap();
+ }
+
+ /**
+ * 用户操作的时间戳
+ *
+ * @return
+ */
+ public RedpacketRisk postTimestamp() {
+ risk.put("posttime", DateUtil.timestamp2string());
+ return this;
+ }
+
+ /**
+ * 业务系统账号的手机号,国家代码-手机号。不需要+号
+ *
+ * @param mobile
+ * @return
+ */
+ public RedpacketRisk mobile(String mobile) {
+ risk.put("mobile", mobile);
+ return this;
+ }
+
+ /**
+ * 用户操作的客户端版本
+ *
+ * @param clientVersion
+ * @return
+ */
+ public RedpacketRisk clientVersion(String clientVersion) {
+ risk.put("clientversion", clientVersion);
+ return this;
+ }
+
+ /**
+ * mac 地址或者设备唯一标识
+ *
+ * @param deviceid
+ * @return
+ */
+ public RedpacketRisk deviceid(String deviceid) {
+ risk.put("deviceid", deviceid);
+ return this;
+ }
+
+ public Map getRisk() {
+ return risk;
+ }
+
+ public String toContent() {
+ if (risk.isEmpty())
+ return null;
+ try {
+ return URLEncoder.encode(MapUtil.toJoinString(risk, false, false),
+ Consts.UTF_8.name());
+ } catch (UnsupportedEncodingException e) {
+ return null;
+ }
+ }
+}
diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/RedpacketSendResult.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/RedpacketSendResult.java
new file mode 100644
index 00000000..741c9e29
--- /dev/null
+++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/RedpacketSendResult.java
@@ -0,0 +1,102 @@
+package com.foxinmy.weixin4j.pay.payment.mch;
+
+import com.alibaba.fastjson.annotation.JSONField;
+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 RedpacketSendResult
+ * @author jinyu(foxinmy@gmail.com)
+ * @date 2015年4月1日
+ * @since JDK 1.6
+ * @see
+ */
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.FIELD)
+public class RedpacketSendResult extends MerchantResult {
+
+ private static final long serialVersionUID = 5611847899634131711L;
+ /**
+ * 商户订单号(每个订单号必须唯一) 组成: mch_id+yyyymmdd+10位一天内不能重复的数字。
+ */
+ @XmlElement(name = "mch_billno")
+ @JSONField(name = "mch_billno")
+ private String outTradeNo;
+ /**
+ * 接收红包的用户的openid
+ */
+ @XmlElement(name = "re_openid")
+ @JSONField(name = "re_openid")
+ private String openId;
+ /**
+ * 付款金额 单位为分
+ */
+ @XmlElement(name = "total_amount")
+ @JSONField(name = "total_amount")
+ private int totalAmount;
+ /**
+ * 发放成功时间
+ */
+ @XmlElement(name = "send_time")
+ @JSONField(name = "send_time")
+ private String sendTime;
+ /**
+ * 微信单号
+ */
+ @XmlElement(name = "send_listid")
+ @JSONField(name = "send_listid")
+ private String sendListid;
+
+ protected RedpacketSendResult() {
+ // jaxb required
+ }
+
+ public String getOutTradeNo() {
+ return outTradeNo;
+ }
+
+ public String getOpenId() {
+ return openId;
+ }
+
+ public int getTotalAmount() {
+ return totalAmount;
+ }
+
+ /**
+ * 调用接口获取单位为分,get方法转换为元方便使用
+ *
+ * @return 元单位
+ */
+ @JSONField(serialize = false)
+ public double getFormatTotalAmount() {
+ return totalAmount / 100d;
+ }
+
+ public String getSendTime() {
+ return sendTime;
+ }
+
+ @JSONField(serialize = false)
+ public Date getFormatSendTime() {
+ return DateUtil.parse2yyyyMMddHHmmss(sendTime);
+ }
+
+ public String getSendListid() {
+ return sendListid;
+ }
+
+ @Override
+ public String toString() {
+ return "RedpacketSendResult [outTradeNo=" + outTradeNo + ", openId="
+ + openId + ", totalAmount=" + totalAmount + ", "
+ + super.toString() + "]";
+ }
+}
\ No newline at end of file
diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/RefundDetail.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/RefundDetail.java
new file mode 100644
index 00000000..8d81f4ee
--- /dev/null
+++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/RefundDetail.java
@@ -0,0 +1,218 @@
+package com.foxinmy.weixin4j.pay.payment.mch;
+
+import com.alibaba.fastjson.annotation.JSONField;
+import com.foxinmy.weixin4j.pay.payment.coupon.RefundCouponInfo;
+import com.foxinmy.weixin4j.type.mch.CouponType;
+import com.foxinmy.weixin4j.type.mch.RefundChannel;
+import com.foxinmy.weixin4j.type.mch.RefundStatus;
+import com.foxinmy.weixin4j.util.DateUtil;
+import com.foxinmy.weixin4j.xml.ListsuffixResult;
+
+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;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 退款详细
+ *
+ * @className RefundDetail
+ * @author jinyu(foxinmy@gmail.com)
+ * @date 2016年7月21日
+ * @since JDK 1.6
+ */
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.FIELD)
+public class RefundDetail implements Serializable {
+ private static final long serialVersionUID = 1402738803019986864L;
+
+ protected RefundDetail() {
+ // jaxb required
+ }
+
+ /**
+ * 商户退款单号
+ */
+ @XmlElement(name = "out_refund_no")
+ @JSONField(name = "out_refund_no")
+ private String outRefundNo;
+ /**
+ * 微信退款单号
+ */
+ @XmlElement(name = "refund_id")
+ @JSONField(name = "refund_id")
+ private String refundId;
+ /**
+ * 退款渠道:ORIGINAL—原路退款,默认 BALANCE—退回到余额
+ */
+ @XmlElement(name = "refund_channel")
+ @JSONField(name = "refund_channel")
+ private String refundChannel;
+ /**
+ * 退款总金额,单位为分,可以做部分退款
+ */
+ @XmlElement(name = "refund_fee")
+ @JSONField(name = "refund_fee")
+ private int refundFee;
+ /**
+ * 退款状态
+ */
+ @XmlElement(name = "refund_status")
+ @JSONField(name = "refund_status")
+ private String refundStatus;
+ /**
+ * 退款金额:退款金额=申请退款金额-非充值代金券退款金额,退款金额<=申请退款金额
+ */
+ @XmlElement(name = "settlement_refund_fee")
+ @JSONField(name = "settlement_refund_fee")
+ private Integer settlementRefundFee;
+ /**
+ * 代金券退款金额:代金券退款金额<=退款金额,退款金额-代金券或立减优惠退款金额为现金,
+ */
+ @XmlElement(name = "coupon_refund_fee")
+ @JSONField(name = "coupon_refund_fee")
+ private Integer couponRefundFee;
+ /**
+ * 代金券或立减优惠使用数量
+ */
+ @XmlElement(name = "coupon_refund_count")
+ @JSONField(name = "coupon_refund_count")
+ private Integer couponRefundCount;
+ /**
+ * 代金券类型
+ *
+ * @see CouponType
+ */
+ @XmlElement(name = "coupon_type")
+ @JSONField(name = "coupon_type")
+ private String couponType;
+ /**
+ * 退款入账账户:取当前退款单的退款入账方 1)退回银行卡: {银行名称}{卡类型}{卡尾号} 2)退回支付用户零钱: 支付用户零钱
+ */
+ @XmlElement(name = "refund_recv_accout")
+ @JSONField(name = "refund_recv_accout")
+ private String refundRecvAccout;
+ /**
+ * 退款成功时间,当退款状态为退款成功时有返回
+ */
+ @XmlElement(name = "refund_success_time")
+ @JSONField(name = "refund_success_time")
+ private String refundSuccessTime;
+ /**
+ * 退款代金券信息
+ *
+ * @see RefundCouponInfo
+ */
+ @ListsuffixResult
+ private List couponList;
+
+ public String getOutRefundNo() {
+ return outRefundNo;
+ }
+
+ public String getRefundId() {
+ return refundId;
+ }
+
+ public String getRefundChannel() {
+ return refundChannel;
+ }
+
+ @JSONField(serialize = false)
+ public RefundChannel getFormatRefundChannel() {
+ return refundChannel != null ? RefundChannel.valueOf(refundChannel
+ .toUpperCase()) : null;
+ }
+
+ public int getRefundFee() {
+ return refundFee;
+ }
+
+ public String getRefundStatus() {
+ return refundStatus;
+ }
+
+ @JSONField(serialize = false)
+ public RefundStatus getFormatRefundStatus() {
+ return refundStatus != null ? RefundStatus.valueOf(refundStatus
+ .toUpperCase()) : null;
+ }
+
+ public List getCouponList() {
+ return couponList;
+ }
+
+ public void setCouponList(List couponList) {
+ this.couponList = couponList;
+ }
+
+ public Integer getSettlementRefundFee() {
+ return settlementRefundFee;
+ }
+
+ /**
+ * 调用接口获取单位为分,get方法转换为元方便使用
+ *
+ * @return 元单位
+ */
+ @JSONField(serialize = false)
+ public double getFormatSettlementRefundFee() {
+ return settlementRefundFee != null ? settlementRefundFee / 100d : 0d;
+ }
+
+ public Integer getCouponRefundFee() {
+ return couponRefundFee;
+ }
+
+ /**
+ * 调用接口获取单位为分,get方法转换为元方便使用
+ *
+ * @return 元单位
+ */
+ @JSONField(serialize = false)
+ public double getFormatCouponRefundFee() {
+ return couponRefundFee != null ? couponRefundFee / 100d : 0d;
+ }
+
+ public Integer getCouponRefundCount() {
+ return couponRefundCount;
+ }
+
+ public String getCouponType() {
+ return couponType;
+ }
+
+ @JSONField(serialize = false)
+ public CouponType getFormatCouponType() {
+ return couponType != null ? CouponType
+ .valueOf(couponType.toUpperCase()) : null;
+ }
+
+ public String getRefundRecvAccout() {
+ return refundRecvAccout;
+ }
+
+ public String getRefundSuccessTime() {
+ return refundSuccessTime;
+ }
+
+ @JSONField(serialize = false)
+ public Date getFormatRefundSuccessTime() {
+ return refundSuccessTime != null ? DateUtil.parse2yyyyMMddHHmmss(refundSuccessTime) : null;
+ }
+
+ @Override
+ public String toString() {
+ return "RefundDetail [outRefundNo=" + outRefundNo + ", refundId="
+ + refundId + ", refundChannel=" + refundChannel
+ + ", refundFee=" + refundFee + ", refundStatus=" + refundStatus
+ + ", settlementRefundFee=" + settlementRefundFee
+ + ", couponRefundFee=" + couponRefundFee
+ + ", couponRefundCount=" + couponRefundCount + ", couponType="
+ + couponType + ", refundRecvAccout=" + refundRecvAccout
+ + ", couponList=" + couponList + "]";
+ }
+}
diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/RefundRecord.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/RefundRecord.java
new file mode 100644
index 00000000..9de5fd05
--- /dev/null
+++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/RefundRecord.java
@@ -0,0 +1,81 @@
+package com.foxinmy.weixin4j.pay.payment.mch;
+
+import com.alibaba.fastjson.annotation.JSONField;
+import com.foxinmy.weixin4j.xml.ListsuffixResult;
+
+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.List;
+
+/**
+ * 退款记录
+ *
+ * @className RefundRecord
+ * @author jinyu(foxinmy@gmail.com)
+ * @date 2014年11月1日
+ * @since JDK 1.6
+ */
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.FIELD)
+public class RefundRecord extends MerchantTradeResult {
+
+ private static final long serialVersionUID = -2971132874939642721L;
+ /**
+ * 退款笔数
+ */
+ @XmlElement(name = "refund_count")
+ @JSONField(name = "refund_count")
+ private int refundCount;
+ /**
+ * 退款总金额,单位为分,可以做部分退款
+ */
+ @XmlElement(name = "refund_fee")
+ @JSONField(name = "refund_fee")
+ private int refundFee;
+ /**
+ * 退款详情
+ *
+ * @see RefundDetail
+ */
+ @ListsuffixResult({ ".*(_\\d)$" })
+ private List refundList;
+
+ protected RefundRecord() {
+ // jaxb required
+ }
+
+ public int getRefundCount() {
+ return refundCount;
+ }
+
+ public int getRefundFee() {
+ return refundFee;
+ }
+
+ /**
+ * 调用接口获取单位为分,get方法转换为元方便使用
+ *
+ * @return 元单位
+ */
+ @JSONField(serialize = false)
+ public double getFormatRefundFee() {
+ return refundFee / 100d;
+ }
+
+ public List getRefundList() {
+ return refundList;
+ }
+
+ public void setRefundList(List refundList) {
+ this.refundList = refundList;
+ }
+
+ @Override
+ public String toString() {
+ return "RefundRecord [refundCount=" + refundCount + ", refundFee="
+ + refundFee + ", refundList=" + refundList + ", "
+ + super.toString() + "]";
+ }
+}
diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/RefundResult.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/RefundResult.java
new file mode 100644
index 00000000..717c4bc5
--- /dev/null
+++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/RefundResult.java
@@ -0,0 +1,128 @@
+package com.foxinmy.weixin4j.pay.payment.mch;
+
+import com.alibaba.fastjson.annotation.JSONField;
+import com.foxinmy.weixin4j.type.mch.RefundChannel;
+import com.foxinmy.weixin4j.xml.ListsuffixResult;
+
+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.List;
+
+/**
+ * 退款申请结果
+ *
+ * @className RefundResult
+ * @author jinyu(foxinmy@gmail.com)
+ * @date 2014年11月6日
+ * @since JDK 1.6
+ * @see
+ */
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.FIELD)
+public class RefundResult extends MerchantTradeResult {
+
+ private static final long serialVersionUID = -3687863914168618620L;
+
+ /**
+ * 商户退款单号
+ */
+ @XmlElement(name = "out_refund_no")
+ @JSONField(name = "out_refund_no")
+ private String outRefundNo;
+ /**
+ * 微信退款单号
+ */
+ @XmlElement(name = "refund_id")
+ @JSONField(name = "refund_id")
+ private String refundId;
+ /**
+ * 退款渠道:ORIGINAL—原路退款,默认 BALANCE—退回到余额
+ */
+ @XmlElement(name = "refund_channel")
+ @JSONField(name = "refund_channel")
+ private String refundChannel;
+ /**
+ * 退款总金额,单位为分,可以做部分退款
+ */
+ @XmlElement(name = "refund_fee")
+ @JSONField(name = "refund_fee")
+ private int refundFee;
+ /**
+ * 现金退款金额
+ */
+ @XmlElement(name = "cash_refund_fee")
+ @JSONField(name = "cash_refund_fee")
+ private Integer cashRefundFee;
+ /**
+ * 退款详情
+ *
+ * @see RefundDetail
+ */
+ @ListsuffixResult({ ".*(_\\d)$" })
+ private List refundList;
+
+ protected RefundResult() {
+ // jaxb required
+ }
+
+ public String getOutRefundNo() {
+ return outRefundNo;
+ }
+
+ public String getRefundId() {
+ return refundId;
+ }
+
+ public String getRefundChannel() {
+ return refundChannel;
+ }
+
+ @JSONField(serialize = false)
+ public RefundChannel getFormatRefundChannel() {
+ return refundChannel != null ? RefundChannel.valueOf(refundChannel
+ .toUpperCase()) : null;
+ }
+
+ public int getRefundFee() {
+ return refundFee;
+ }
+
+ /**
+ * 调用接口获取单位为分,get方法转换为元方便使用
+ *
+ * @return 元单位
+ */
+ @JSONField(serialize = false)
+ public double getFormatRefundFee() {
+ return refundFee / 100d;
+ }
+
+ public Integer getCashRefundFee() {
+ return cashRefundFee;
+ }
+
+ /**
+ * 调用接口获取单位为分,get方法转换为元方便使用
+ *
+ * @return 元单位
+ */
+ @JSONField(serialize = false)
+ public double getFormatCashRefundFee() {
+ return cashRefundFee != null ? cashRefundFee.intValue() / 100d : 0d;
+ }
+
+ public List getRefundList() {
+ return refundList;
+ }
+
+ @Override
+ public String toString() {
+ return "RefundResult [" + super.toString() + ", outRefundNo="
+ + outRefundNo + ", refundId=" + refundId + ", refundChannel="
+ + refundChannel + ", refundFee=" + refundFee
+ + ", cashRefundFee=" + cashRefundFee + ", refundList="
+ + refundList + "]";
+ }
+}
diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/SceneInfoApp.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/SceneInfoApp.java
new file mode 100644
index 00000000..48a5b763
--- /dev/null
+++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/SceneInfoApp.java
@@ -0,0 +1,99 @@
+package com.foxinmy.weixin4j.pay.payment.mch;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.FIELD)
+public class SceneInfoApp {
+ /**
+ * 终端类型
+ */
+ private String type;
+ /**
+ * 应用名称
+ */
+ private String name;
+ /**
+ * 应用路径
+ */
+ private String path;
+ private String sceneInfo;
+
+ private SceneInfoApp(String type, String name, String path) {
+ this.type = type;
+ this.name = name;
+ this.path = path;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getPath() {
+ return path;
+ }
+
+ public String getSceneInfo() {
+ return sceneInfo;
+ }
+
+ public void setSceneInfo(String sceneInfo) {
+ this.sceneInfo = sceneInfo;
+ }
+
+ /**
+ * IOS应用
+ *
+ * @param appName 应用名
+ * @param bundleId 模块ID
+ * @return
+ */
+ public static SceneInfoApp createIOSAPP(String appName, String bundleId) {
+ SceneInfoApp app = new SceneInfoApp("IOS", appName, bundleId);
+ String sceneInfo = String
+ .format("{\"type\": \"%s\",\"app_name\": \"%s\",\"bundle_id\": \"%s\"}",
+ app.getType(), app.getName(), app.getPath());
+ app.setSceneInfo(sceneInfo);
+ return app;
+ }
+
+ /**
+ * Android应用
+ *
+ * @param appName 应用名
+ * @param packageName 包名
+ * @return
+ */
+ public static SceneInfoApp createAndroidAPP(String appName, String packageName) {
+ SceneInfoApp app = new SceneInfoApp("Android", appName, packageName);
+ String sceneInfo = String
+ .format("{\"type\": \"%s\",\"app_name\": \"%s\",\"package_name\": \"%s\"}",
+ app.getType(), app.getName(), app.getPath());
+ app.setSceneInfo(sceneInfo);
+ return app;
+ }
+
+ /**
+ * Wap应用
+ *
+ * @param name
+ * 网站名
+ * @param url
+ * 网站URL地址
+ * @return
+ */
+ public static SceneInfoApp createWapAPP(String name, String url) {
+ SceneInfoApp app = new SceneInfoApp("Wap", name, url);
+ String sceneInfo = String.format(
+ "{\"type\": \"%s\",\"wap_name\": \"%s\",\"wap_url\": \"%s\"}",
+ app.getType(), app.getName(), app.getPath());
+ app.setSceneInfo(sceneInfo);
+ return app;
+ }
+}
diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/SceneInfoStore.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/SceneInfoStore.java
new file mode 100644
index 00000000..550e9edd
--- /dev/null
+++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/SceneInfoStore.java
@@ -0,0 +1,75 @@
+package com.foxinmy.weixin4j.pay.payment.mch;
+
+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;
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.FIELD)
+public class SceneInfoStore {
+ /**
+ * SZTX001 门店唯一标识
+ */
+ private String id;
+ /**
+ * 腾讯大厦腾大餐厅 门店名称
+ */
+ private String name;
+ /**
+ * 门店所在地行政区划码,详细见《最新县及县以上行政区划代码》
+ */
+ @XmlElement(name = "area_code")
+ @JSONField(name = "area_code")
+ private String areaCode;
+ /**
+ * 科技园中一路腾讯大厦 门店详细地址
+ */
+ private String address;
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getAreaCode() {
+ return areaCode;
+ }
+
+ public void setAreaCode(String areaCode) {
+ this.areaCode = areaCode;
+ }
+
+ public String getAddress() {
+ return address;
+ }
+
+ public void setAddress(String address) {
+ this.address = address;
+ }
+
+ public SceneInfoStore(String id, String name) {
+ super();
+ this.id = id;
+ this.name = name;
+ }
+
+ @Override
+ public String toString() {
+ return "SceneInfoStore [id=" + id + ", name=" + name + ", areaCode="
+ + areaCode + ", address=" + address + "]";
+ }
+}
\ No newline at end of file
diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/SettlementRecord.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/SettlementRecord.java
new file mode 100644
index 00000000..501abd03
--- /dev/null
+++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/SettlementRecord.java
@@ -0,0 +1,272 @@
+package com.foxinmy.weixin4j.pay.payment.mch;
+
+import com.alibaba.fastjson.annotation.JSONField;
+import com.foxinmy.weixin4j.type.CurrencyType;
+import com.foxinmy.weixin4j.util.DateUtil;
+
+import javax.xml.bind.annotation.XmlElement;
+import java.util.Date;
+
+/**
+ * 结算资金
+ *
+ * @className Settlement
+ * @author jinyu(foxinmy@gmail.com)
+ * @date 2016年3月26日
+ * @since JDK 1.6
+ * @see
+ */
+public class SettlementRecord extends MerchantResult {
+
+ private static final long serialVersionUID = 7952659545609519979L;
+
+ /**
+ * 付款批次号
+ */
+ @XmlElement(name = "fbatchno")
+ @JSONField(name = "fbatchno")
+ private String batchNo;
+ /**
+ * 结算日期
+ */
+ @XmlElement(name = "date_settlement")
+ @JSONField(name = "date_settlement")
+ private String settleDate;
+ /**
+ * 交易开始日期
+ */
+ @XmlElement(name = "date_start")
+ @JSONField(name = "date_start")
+ private String startDate;
+ /**
+ * 交易结束日期
+ */
+ @XmlElement(name = "date_end")
+ @JSONField(name = "date_end")
+ private String endDate;
+ /**
+ * 划账金额:外币标价,外币最小单位
+ */
+ @XmlElement(name = "transaction_id")
+ @JSONField(name = "transaction_id")
+ private int settleFee;
+ /**
+ * 未划账金额:外币标价,外币最小单位
+ */
+ @XmlElement(name = "unsettlement_fee")
+ @JSONField(name = "unsettlement_fee")
+ private int unSettleFee;
+ /**
+ * 结算币种
+ */
+ @XmlElement(name = "settlementfee_type")
+ @JSONField(name = "settlementfee_type")
+ private String settleFeeType;
+ /**
+ * 支付金额:外币标价,外币最小单位
+ */
+ @XmlElement(name = "pay_fee")
+ @JSONField(name = "pay_fee")
+ private int payFee;
+ /**
+ * 退款金额:外币标价,外币最小单位
+ */
+ @XmlElement(name = "refund_fee")
+ @JSONField(name = "refund_fee")
+ private int refundFee;
+ /**
+ * 支付净额:外币标价,外币最小单位
+ */
+ @XmlElement(name = "pay_net_fee")
+ @JSONField(name = "pay_net_fee")
+ private int payNetFee;
+ /**
+ * 手续费金额:外币标价,外币最小单位
+ */
+ @XmlElement(name = "poundage_fee")
+ @JSONField(name = "poundage_fee")
+ private int poundageFee;
+
+ protected SettlementRecord() {
+ // jaxb required
+ }
+
+ public String getBatchNo() {
+ return batchNo;
+ }
+
+ public void setBatchNo(String batchNo) {
+ this.batchNo = batchNo;
+ }
+
+ public String getSettleDate() {
+ return settleDate;
+ }
+
+ @JSONField(serialize = false)
+ public Date getFormatSettleDate() {
+ return DateUtil.parse2yyyyMMddHHmmss(settleDate);
+ }
+
+ public void setSettleDate(String settleDate) {
+ this.settleDate = settleDate;
+ }
+
+ public String getStartDate() {
+ return startDate;
+ }
+
+ @JSONField(serialize = false)
+ public Date getFormatStartDate() {
+ return DateUtil.parse2yyyyMMddHHmmss(startDate);
+ }
+
+ public void setStartDate(String startDate) {
+ this.startDate = startDate;
+ }
+
+ public String getEndDate() {
+ return endDate;
+ }
+
+ @JSONField(serialize = false)
+ public Date getFormatEndDate() {
+ return DateUtil.parse2yyyyMMddHHmmss(settleDate);
+ }
+
+ public void setEndDate(String endDate) {
+ this.endDate = endDate;
+ }
+
+ public int getSettleFee() {
+ return settleFee;
+ }
+
+ /**
+ * 最小单位除100得到的值
+ *
+ * @return /100
+ */
+ @JSONField(serialize = false)
+ public double getFormatSettleFee() {
+ return settleFee / 100d;
+ }
+
+ public void setSettleFee(int settleFee) {
+ this.settleFee = settleFee;
+ }
+
+ public int getUnSettleFee() {
+ return unSettleFee;
+ }
+
+ /**
+ * 最小单位除100得到的值
+ *
+ * @return /100
+ */
+ @JSONField(serialize = false)
+ public double getFormatUnSettleFee() {
+ return unSettleFee / 100d;
+ }
+
+ public void setUnSettleFee(int unSettleFee) {
+ this.unSettleFee = unSettleFee;
+ }
+
+ public String getSettleFeeType() {
+ return settleFeeType;
+ }
+
+ @JSONField(serialize = false)
+ public CurrencyType getFormatSettleFeeType() {
+ return CurrencyType.valueOf(settleFeeType.toUpperCase());
+ }
+
+ public void setSettleFeeType(String settleFeeType) {
+ this.settleFeeType = settleFeeType;
+ }
+
+ public int getPayFee() {
+ return payFee;
+ }
+
+ /**
+ * 最小单位除100得到的值
+ *
+ * @return /100
+ */
+ @JSONField(serialize = false)
+ public double getFormatPayFee() {
+ return payFee / 100d;
+ }
+
+ public void setPayFee(int payFee) {
+ this.payFee = payFee;
+ }
+
+ public int getRefundFee() {
+ return refundFee;
+ }
+
+ /**
+ * 最小单位除100得到的值
+ *
+ * @return /100
+ */
+ @JSONField(serialize = false)
+ public double getFormatRefundFee() {
+ return refundFee / 100d;
+ }
+
+ public void setRefundFee(int refundFee) {
+ this.refundFee = refundFee;
+ }
+
+ public int getPayNetFee() {
+ return payNetFee;
+ }
+
+ public void setPayNetFee(int payNetFee) {
+ this.payNetFee = payNetFee;
+ }
+
+ /**
+ * 最小单位除100得到的值
+ *
+ * @return /100
+ */
+ @JSONField(serialize = false)
+ public double getFormatPayNetFee() {
+ return payNetFee / 100d;
+ }
+
+ public int getPoundageFee() {
+ return poundageFee;
+ }
+
+ /**
+ * 最小单位除100得到的值
+ *
+ * @return /100
+ */
+ @JSONField(serialize = false)
+ public double getFormatPoundageFee() {
+ return poundageFee / 100d;
+ }
+
+ public void setPoundageFee(int poundageFee) {
+ this.poundageFee = poundageFee;
+ }
+
+ @Override
+ public String toString() {
+ return "SettlementRecord [batchNo=" + batchNo + ", settleDate="
+ + settleDate + ", startDate=" + startDate + ", endDate="
+ + endDate + ", settleFee=" + settleFee + ", unSettleFee="
+ + unSettleFee + ", settleFeeType=" + settleFeeType
+ + ", payFee=" + payFee + ", refundFee=" + refundFee
+ + ", payNetFee=" + payNetFee + ", poundageFee=" + poundageFee
+ + ", " + super.toString() + "]";
+ }
+}
diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/WAPPayRequest.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/WAPPayRequest.java
new file mode 100644
index 00000000..f08eff1f
--- /dev/null
+++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/WAPPayRequest.java
@@ -0,0 +1,61 @@
+package com.foxinmy.weixin4j.pay.payment.mch;
+
+import com.foxinmy.weixin4j.pay.model.WeixinPayAccount;
+import com.foxinmy.weixin4j.pay.payment.PayRequest;
+import com.foxinmy.weixin4j.pay.type.TradeType;
+
+/**
+ * WAP支付
+ *
+ * @className WAPPayRequest
+ * @author jinyu(foxinmy@gmail.com)
+ * @date 2015年12月25日
+ * @since JDK 1.6
+ * @see PrePay
+ * @see PayRequest
+ * @see WAP支付
+ */
+public class WAPPayRequest extends AbstractPayRequest {
+ /**
+ * 微信支付URL
+ */
+ private final String payUrl;
+
+ public WAPPayRequest(String prePayId, String payUrl,
+ WeixinPayAccount payAccount) {
+ super(prePayId, payAccount);
+ this.payUrl = payUrl;
+
+ }
+
+ @Override
+ public TradeType getPaymentType() {
+ return TradeType.MWEB;
+ }
+
+ /**
+ * 只做查看之用,请不要尝试作为支付请求
+ */
+ @Override
+ public PayRequest toRequestObject() {
+ PayRequest payRequest = new PayRequest(getPaymentAccount().getId(),
+ getPaymentType().name());
+ payRequest.setPrepayId(getPrePayId());
+ return payRequest;
+ }
+
+ @Override
+ public String toRequestString() {
+ // PayRequest payRequest = toRequestObject();
+ // String original = MapUtil.toJoinString(payRequest, true, true);
+ // String sign = DigestUtil.MD5(
+ // String.format("%s&key=%s", original, getPaymentAccount()
+ // .getPaySignKey())).toUpperCase();
+ // return String.format("weixin://wap/pay?%s",
+ // URLEncodingUtil.encoding(
+ // String.format("%s&sign=%s", original, sign),
+ // Consts.UTF_8, true));
+ return this.payUrl;
+ }
+}
diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/sign/AbstractWeixinSignature.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/sign/AbstractWeixinSignature.java
new file mode 100644
index 00000000..6a077b99
--- /dev/null
+++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/sign/AbstractWeixinSignature.java
@@ -0,0 +1,45 @@
+package com.foxinmy.weixin4j.pay.sign;
+
+import com.foxinmy.weixin4j.util.MapUtil;
+
+/**
+ * 微信签名
+ *
+ * @className AbstractWeixinSignature
+ * @author jinyu(foxinmy@gmail.com)
+ * @date 2016年3月26日
+ * @since JDK 1.6
+ * @see
+ */
+public abstract class AbstractWeixinSignature implements WeixinSignature {
+ /**
+ * 是否编码
+ *
+ * @return 默认false不进行编码
+ */
+ @Override
+ public boolean encoder() {
+ return false;
+ }
+
+ /**
+ * 是否转换小写
+ *
+ * @return 默认false不转换小写
+ */
+ @Override
+ public boolean lowerCase() {
+ return false;
+ }
+
+ /**
+ * 拼接字符串
+ *
+ * @param obj
+ * @return
+ */
+ protected StringBuilder join(Object obj) {
+ return new StringBuilder(MapUtil.toJoinString(obj, encoder(),
+ lowerCase()));
+ }
+}
diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/sign/WeixinPaymentSignature.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/sign/WeixinPaymentSignature.java
new file mode 100644
index 00000000..98200f04
--- /dev/null
+++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/sign/WeixinPaymentSignature.java
@@ -0,0 +1,36 @@
+package com.foxinmy.weixin4j.pay.sign;
+
+import com.foxinmy.weixin4j.pay.type.SignType;
+import com.foxinmy.weixin4j.util.DigestUtil;
+
+/**
+ * 微信支付签名实现
+ *
+ * @className WeixinPaymentSignature
+ * @author jinyu(foxinmy@gmail.com)
+ * @date 2016年3月26日
+ * @since JDK 1.6
+ * @see 支付签名说明
+ */
+public class WeixinPaymentSignature extends AbstractWeixinSignature {
+ /**
+ * 支付密钥
+ */
+ private final String paySignKey;
+
+ public WeixinPaymentSignature(String paySignKey) {
+ this.paySignKey = paySignKey;
+ }
+
+ @Override
+ public SignType getSignType() {
+ return SignType.MD5;
+ }
+
+ @Override
+ public String sign(Object obj) {
+ StringBuilder sb = join(obj).append("&key=").append(paySignKey);
+ return DigestUtil.MD5(sb.toString()).toUpperCase();
+ }
+}
diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/sign/WeixinSignature.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/sign/WeixinSignature.java
new file mode 100644
index 00000000..88920e85
--- /dev/null
+++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/sign/WeixinSignature.java
@@ -0,0 +1,43 @@
+package com.foxinmy.weixin4j.pay.sign;
+
+import com.foxinmy.weixin4j.pay.type.SignType;
+
+/**
+ * 微信签名
+ *
+ * @className WeixinSignature
+ * @author jinyu(foxinmy@gmail.com)
+ * @date 2016年3月26日
+ * @since JDK 1.6
+ * @see
+ */
+public interface WeixinSignature {
+ /**
+ * 是否编码
+ *
+ * @return
+ */
+ public boolean encoder();
+
+ /**
+ * 是否转换小写
+ *
+ * @return
+ */
+ public boolean lowerCase();
+
+ /**
+ * 签名类型
+ *
+ * @return
+ */
+ public SignType getSignType();
+
+ /**
+ * 签名
+ *
+ * @param obj
+ * @return
+ */
+ public String sign(Object obj);
+}
diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/BankType.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/BankType.java
new file mode 100644
index 00000000..397f9a4e
--- /dev/null
+++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/BankType.java
@@ -0,0 +1,260 @@
+package com.foxinmy.weixin4j.pay.type;
+
+
+/**
+ * 银行类型
+ *
+ * @className BankType
+ * @author jinyu(foxinmy@gmail.com)
+ * @date 2015年8月19日
+ * @since JDK 1.6
+ * @see
+ */
+public enum BankType {
+ /**
+ * 工商银行(借记卡)
+ */
+ ICBC_DEBIT("工商银行(借记卡)"),
+ /**
+ * 工商银行(信用卡)
+ */
+ ICBC_CREDIT("工商银行(信用卡)"),
+ /**
+ * 农业银行(借记卡)
+ */
+ ABC_DEBIT("农业银行(借记卡)"),
+ /**
+ * 农业银行 (信用卡)
+ */
+ ABC_CREDIT("农业银行 (信用卡)"),
+ /**
+ * 邮政储蓄(借记卡)
+ */
+ PSBC_DEBIT("邮政储蓄(借记卡)"),
+ /**
+ * 邮政储蓄 (信用卡)
+ */
+ PSBC_CREDIT("邮政储蓄 (信用卡)"),
+ /**
+ * 建设银行(借记卡)
+ */
+ CCB_DEBIT("建设银行(借记卡)"),
+ /**
+ * 建设银行 (信用卡)
+ */
+ CCB_CREDIT("建设银行 (信用卡)"),
+ /**
+ * 招商银行(借记卡)
+ */
+ CMB_DEBIT("招商银行(借记卡)"),
+ /**
+ * 招商银行(信用卡)
+ */
+ CMB_CREDIT("招商银行(信用卡)"),
+ /**
+ * 交通银行(借记卡)
+ */
+ COMM_DEBIT("交通银行(借记卡)"),
+ /**
+ * 中国银行(信用卡)
+ */
+ BOC_CREDIT("中国银行(信用卡)"),
+ /**
+ * 浦发银行(借记卡)
+ */
+ SPDB_DEBIT("浦发银行(借记卡)"),
+ /**
+ * 浦发银行 (信用卡)
+ */
+ SPDB_CREDIT("浦发银行 (信用卡)"),
+ /**
+ * 广发银行(借记卡)
+ */
+ GDB_DEBIT("广发银行(借记卡)"),
+ /**
+ * 广发银行(信用卡)
+ */
+ GDB_CREDIT("广发银行(信用卡)"),
+ /**
+ * 民生银行(借记卡)
+ */
+ CMBC_DEBIT("民生银行(借记卡)"),
+ /**
+ * 民生银行(信用卡)
+ */
+ CMBC_CREDIT("民生银行(信用卡)"),
+ /**
+ * 平安银行(借记卡)
+ */
+ PAB_DEBIT("平安银行(借记卡)"),
+ /**
+ * 平安银行(信用卡)
+ */
+ PAB_CREDIT("平安银行(信用卡)"),
+ /**
+ * 光大银行(借记卡)
+ */
+ CEB_DEBIT("光大银行(借记卡)"),
+ /**
+ * 光大银行(信用卡)
+ */
+ CEB_CREDIT("光大银行(信用卡)"),
+ /**
+ * 兴业银行 (借记卡)
+ */
+ CIB_DEBIT("兴业银行 (借记卡)"),
+ /**
+ * 兴业银行(信用卡)
+ */
+ CIB_CREDIT("兴业银行(信用卡)"),
+ /**
+ * 中信银行(借记卡)
+ */
+ CITIC_DEBIT("中信银行(借记卡)"),
+ /**
+ * 中信银行(信用卡)
+ */
+ CITIC_CREDIT("中信银行(信用卡)"),
+ /**
+ * 深发银行(信用卡)
+ */
+ SDB_CREDIT("深发银行(信用卡)"),
+ /**
+ * 上海银行(借记卡)
+ */
+ BOSH_DEBIT("上海银行(借记卡)"),
+ /**
+ * 上海银行 (信用卡)
+ */
+ BOSH_CREDIT("上海银行 (信用卡)"),
+ /**
+ * 华润银行(借记卡)
+ */
+ CRB_DEBIT("华润银行(借记卡)"),
+ /**
+ * 杭州银行(借记卡)
+ */
+ HZB_DEBIT("杭州银行(借记卡)"),
+ /**
+ * 杭州银行(信用卡)
+ */
+ HZB_CREDIT("杭州银行(信用卡)"),
+ /**
+ * 包商银行(借记卡)
+ */
+ BSB_DEBIT("包商银行(借记卡)"),
+ /**
+ * 包商银行 (信用卡)
+ */
+ BSB_CREDIT("包商银行 (信用卡)"),
+ /**
+ * 重庆银行(借记卡)
+ */
+ CQB_DEBIT("重庆银行(借记卡)"),
+ /**
+ * 顺德农商行 (借记卡)
+ */
+ SDEB_DEBIT("顺德农商行 (借记卡)"),
+ /**
+ * 深圳农商银行(借记卡)
+ */
+ SZRCB_DEBIT("深圳农商银行(借记卡)"),
+ /**
+ * 哈尔滨银行(借记卡)
+ */
+ HRBB_DEBIT("哈尔滨银行(借记卡)"),
+ /**
+ * 成都银行(借记卡)
+ */
+ BOCD_DEBIT("成都银行(借记卡)"),
+ /**
+ * 南粤银行 (借记卡)
+ */
+ GDNYB_DEBIT("南粤银行 (借记卡)"),
+ /**
+ * 南粤银行 (信用卡)
+ */
+ GDNYB_CREDIT("南粤银行 (信用卡)"),
+ /**
+ * 广州银行(信用卡)
+ */
+ GZCB_CREDIT("广州银行(信用卡)"),
+ /**
+ * 江苏银行(借记卡)
+ */
+ JSB_DEBIT("江苏银行(借记卡)"),
+ /**
+ * 江苏银行(信用卡)
+ */
+ JSB_CREDIT("江苏银行(信用卡)"),
+ /**
+ * 宁波银行(借记卡)
+ */
+ NBCB_DEBIT("宁波银行(借记卡)"),
+ /**
+ * 宁波银行(信用卡)
+ */
+ NBCB_CREDIT("宁波银行(信用卡)"),
+ /**
+ * 南京银行(借记卡)
+ */
+ NJCB_DEBIT("南京银行(借记卡)"),
+ /**
+ * 青岛银行(借记卡)
+ */
+ QDCCB_DEBIT("青岛银行(借记卡)"),
+ /**
+ * 浙江泰隆银行(借记卡)
+ */
+ ZJTLCB_DEBIT("浙江泰隆银行(借记卡)"),
+ /**
+ * 西安银行(借记卡)
+ */
+ XAB_DEBIT("西安银行(借记卡)"),
+ /**
+ * 常熟农商银行 (借记卡)
+ */
+ CSRCB_DEBIT("常熟农商银行 (借记卡)"),
+ /**
+ * 齐鲁银行(借记卡)
+ */
+ QLB_DEBIT("齐鲁银行(借记卡)"),
+ /**
+ * 龙江银行(借记卡)
+ */
+ LJB_DEBIT("龙江银行(借记卡)"),
+ /**
+ * 华夏银行(借记卡)
+ */
+ HXB_DEBIT("华夏银行(借记卡)"),
+ /**
+ * 测试银行借记卡快捷支付 (借记卡)
+ */
+ CS_DEBIT("测试银行借记卡快捷支付 (借记卡)"),
+ /**
+ * AE (信用卡)
+ */
+ AE_CREDIT("AE (信用卡)"),
+ /**
+ * JCB (信用卡)
+ */
+ JCB_CREDIT("JCB (信用卡)"),
+ /**
+ * MASTERCARD (信用卡)
+ */
+ MASTERCARD_CREDIT("MASTERCARD (信用卡)"),
+ /**
+ * VISA (信用卡)
+ */
+ VISA_CREDIT("VISA (信用卡)");
+
+ private String desc;
+
+ BankType(String desc) {
+ this.desc = desc;
+ }
+
+ public String getDesc() {
+ return desc;
+ }
+}
diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/CredentialType.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/CredentialType.java
new file mode 100644
index 00000000..4cd93298
--- /dev/null
+++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/CredentialType.java
@@ -0,0 +1,23 @@
+package com.foxinmy.weixin4j.pay.type;
+
+/**
+ * 证件类型
+ *
+ * @className CredentialType
+ * @author jinyu(foxinmy@gmail.com)
+ * @date 2016年3月27日
+ * @since JDK 1.6
+ * @see
+ */
+public enum CredentialType {
+ IDCARD("身份证");
+ CredentialType(String name) {
+ this.name = name;
+ }
+
+ private String name;
+
+ public String getName() {
+ return this.name;
+ }
+}
diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/CurrencyType.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/CurrencyType.java
new file mode 100644
index 00000000..21c288bc
--- /dev/null
+++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/CurrencyType.java
@@ -0,0 +1,25 @@
+package com.foxinmy.weixin4j.pay.type;
+
+/**
+ * 币种
+ *
+ * @className CurrencyType
+ * @author jinyu(foxinmy@gmail.com)
+ * @date 2014年11月2日
+ * @since JDK 1.6
+ * @see
+ */
+public enum CurrencyType {
+ CNY("人民币"), HKD("港元"), TWD("台币"), EUR("欧元"), USD("美元"), GBP("英镑"), JPY("日元"), CAD(
+ "加拿大元"), AUD("澳大利亚元"), NZD("新西兰元"), KRW("韩元"), THB("泰铢");
+
+ private String desc;
+
+ CurrencyType(String desc) {
+ this.desc = desc;
+ }
+
+ public String getDesc() {
+ return desc;
+ }
+}
diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/CustomsCity.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/CustomsCity.java
new file mode 100644
index 00000000..2922c1a4
--- /dev/null
+++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/CustomsCity.java
@@ -0,0 +1,26 @@
+package com.foxinmy.weixin4j.pay.type;
+
+/**
+ * 海关
+ *
+ * @className CustomsCity
+ * @author jinyu(foxinmy@gmail.com)
+ * @date 2016年3月27日
+ * @since JDK 1.6
+ * @see
+ */
+public enum CustomsCity {
+ NO("无需上报海关"), GUANGZHOU("广州"), HANGZHOU("杭州"), NINGBO("宁波"), ZHENGZHOU_BS(
+ "郑州(保税物流中心)"), CHONGQING("重庆"), XIAN("西安"), SHANGHAI("上海"), ZHENGZHOU_ZH(
+ "郑州(综保区)");
+
+ private String name;
+
+ CustomsCity(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return this.name;
+ }
+}
diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/CustomsSatus.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/CustomsSatus.java
new file mode 100644
index 00000000..55442274
--- /dev/null
+++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/CustomsSatus.java
@@ -0,0 +1,24 @@
+package com.foxinmy.weixin4j.pay.type;
+
+/**
+ * 报关状态
+ *
+ * @className CustomsSatus
+ * @author jinyu(foxinmy@gmail.com)
+ * @date 2016年3月27日
+ * @since JDK 1.6
+ * @see
+ */
+public enum CustomsSatus {
+ UNDECLARED("未申报"), SUBMITTED("申报已提交"), PROCESSING("申报中"), SUCCESS("申报成功"), FAIL(
+ "申报失败"), EXCEPT("海关接口异常");
+ private String sate;
+
+ CustomsSatus(String sate) {
+ this.sate = sate;
+ }
+
+ public String getSate() {
+ return this.sate;
+ }
+}
diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/IdQuery.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/IdQuery.java
new file mode 100644
index 00000000..175a87ba
--- /dev/null
+++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/IdQuery.java
@@ -0,0 +1,45 @@
+package com.foxinmy.weixin4j.pay.type;
+
+import java.io.Serializable;
+
+/**
+ * ID查询
+ *
+ * @className IdQuery
+ * @author jinyu(foxinmy@gmail.com)
+ * @date 2014年11月1日
+ * @since JDK 1.6
+ * @see
+ */
+public class IdQuery implements Serializable {
+
+ private static final long serialVersionUID = -5273675987521807370L;
+ /**
+ * id值
+ */
+ private String id;
+ /**
+ * id类型
+ *
+ * @see IdType
+ */
+ private IdType type;
+
+ public IdQuery(String id, IdType idType) {
+ this.id = id;
+ this.type = idType;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public IdType getType() {
+ return type;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("%s=%s", type.getName(), id);
+ }
+}
diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/IdType.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/IdType.java
new file mode 100644
index 00000000..8af90392
--- /dev/null
+++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/IdType.java
@@ -0,0 +1,46 @@
+package com.foxinmy.weixin4j.pay.type;
+
+/**
+ * ID类型
+ *
+ * @className IdType
+ * @author jinyu(foxinmy@gmail.com)
+ * @date 2014年11月1日
+ * @since JDK 1.6
+ * @see
+ */
+public enum IdType {
+ /**
+ * 微信退款单号
+ */
+ REFUNDID("refund_id"),
+ /**
+ * 微信订单号
+ */
+ TRANSACTIONID("transaction_id"),
+ /**
+ * 商户订单号
+ */
+ TRADENO("out_trade_no"),
+ /**
+ * 商户退款号
+ */
+ REFUNDNO("out_refund_no"),
+ /**
+ * 商户子订单号
+ */
+ SUBORDERNO("sub_order_no"),
+ /**
+ * 微信子订单号
+ */
+ SUBORDERID("sub_order_id");
+ private String name;
+
+ IdType(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+}
diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/SignType.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/SignType.java
new file mode 100644
index 00000000..4335ec4b
--- /dev/null
+++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/SignType.java
@@ -0,0 +1,14 @@
+package com.foxinmy.weixin4j.pay.type;
+
+/**
+ * 签名类型
+ *
+ * @className SignType
+ * @author jinyu(foxinmy@gmail.com)
+ * @date 2014年11月5日
+ * @since JDK 1.6
+ * @see
+ */
+public enum SignType {
+ SHA1, MD5, HMAC$SHA256
+}
diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/TarType.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/TarType.java
new file mode 100644
index 00000000..bc4e32bb
--- /dev/null
+++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/TarType.java
@@ -0,0 +1,14 @@
+package com.foxinmy.weixin4j.pay.type;
+
+/**
+ * 压缩类型
+ *
+ * @className TarType
+ * @author jinyu(foxinmy@gmail.com)
+ * @date 2016年12月21日
+ * @since JDK 1.6
+ * @see
+ */
+public enum TarType {
+ GZIP
+}
diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/TradeType.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/TradeType.java
new file mode 100644
index 00000000..14e321c5
--- /dev/null
+++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/TradeType.java
@@ -0,0 +1,33 @@
+package com.foxinmy.weixin4j.pay.type;
+
+/**
+ * 微信支付类型
+ *
+ * @className TradeType
+ * @author jinyu(foxinmy@gmail.com)
+ * @date 2014年10月21日
+ * @since JDK 1.6
+ * @see
+ */
+public enum TradeType {
+ /**
+ * JS支付
+ */
+ JSAPI,
+ /**
+ * 刷卡支付
+ */
+ MICROPAY,
+ /**
+ * 扫码支付
+ */
+ NATIVE,
+ /**
+ * APP支付
+ */
+ APP,
+ /**
+ * WAP支付
+ */
+ MWEB;
+}
diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/BillType.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/BillType.java
new file mode 100644
index 00000000..85f1ab14
--- /dev/null
+++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/BillType.java
@@ -0,0 +1,34 @@
+package com.foxinmy.weixin4j.pay.type.mch;
+
+/**
+ * 对账单类型
+ *
+ * @className BillType
+ * @author jinyu(foxinmy@gmail.com)
+ * @date 2014年10月31日
+ * @since JDK 1.6
+ * @see
+ */
+public enum BillType {
+ /**
+ * 全部
+ */
+ ALL(0),
+ /**
+ * 成功订单
+ */
+ SUCCESS(1),
+ /**
+ * 退款订单
+ */
+ REFUND(2);
+ private int val;
+
+ BillType(int val) {
+ this.val = val;
+ }
+
+ public int getVal() {
+ return val;
+ }
+}
diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/CorpPaymentCheckNameType.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/CorpPaymentCheckNameType.java
new file mode 100644
index 00000000..c109432f
--- /dev/null
+++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/CorpPaymentCheckNameType.java
@@ -0,0 +1,25 @@
+package com.foxinmy.weixin4j.pay.type.mch;
+
+/**
+ * 企业付款检查收款人姓名的策略
+ *
+ * @className CorpPaymentCheckNameType
+ * @author jinyu(foxinmy@gmail.com)
+ * @date 2015年4月1日
+ * @since JDK 1.6
+ * @see
+ */
+public enum CorpPaymentCheckNameType {
+ /**
+ * 不校验真实姓名
+ */
+ NO_CHECK,
+ /**
+ * 强校验真实姓名(未实名认证的用户会校验失败,无法转账)
+ */
+ FORCE_CHECK,
+ /**
+ * 针对已实名认证的用户才校验真实姓名(未实名认证用户不校验,可以转账成功)
+ */
+ OPTION_CHECK;
+}
diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/CouponStatus.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/CouponStatus.java
new file mode 100644
index 00000000..696e073c
--- /dev/null
+++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/CouponStatus.java
@@ -0,0 +1,34 @@
+package com.foxinmy.weixin4j.pay.type.mch;
+
+/**
+ * 代金券状态
+ *
+ * @className CouponStatus
+ * @author jinyu(foxinmy@gmail.com)
+ * @date 2015年3月27日
+ * @since JDK 1.6
+ * @see
+ */
+public enum CouponStatus {
+ /**
+ * 已激活
+ */
+ ACTIVATED(2),
+ /**
+ * 已锁定
+ */
+ LOCKED(4),
+ /**
+ * 已实扣
+ */
+ USED(8);
+ private int val;
+
+ CouponStatus(int val) {
+ this.val = val;
+ }
+
+ public int getVal() {
+ return val;
+ }
+}
diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/CouponStockStatus.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/CouponStockStatus.java
new file mode 100644
index 00000000..36b6bd4b
--- /dev/null
+++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/CouponStockStatus.java
@@ -0,0 +1,42 @@
+package com.foxinmy.weixin4j.pay.type.mch;
+
+/**
+ * 代金券批次状态
+ *
+ * @className CouponStockStatus
+ * @author jinyu(foxinmy@gmail.com)
+ * @date 2015年3月27日
+ * @since JDK 1.6
+ * @see
+ */
+public enum CouponStockStatus {
+ /**
+ * 未激活
+ */
+ INACTIVE(1),
+ /**
+ * 审批中
+ */
+ APPROVAL_PROCESS(2),
+ /**
+ * 已激活
+ */
+ ACTIVATED(4),
+ /**
+ * 已作废
+ */
+ SUPERSEDED(8),
+ /**
+ * 中止发放
+ */
+ SUSPEND(16);
+ private int val;
+
+ CouponStockStatus(int val) {
+ this.val = val;
+ }
+
+ public int getVal() {
+ return val;
+ }
+}
diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/CouponStockType.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/CouponStockType.java
new file mode 100644
index 00000000..896b8d7f
--- /dev/null
+++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/CouponStockType.java
@@ -0,0 +1,30 @@
+package com.foxinmy.weixin4j.pay.type.mch;
+
+/**
+ * 代金券批次类型
+ *
+ * @className CouponStockType
+ * @author jinyu(foxinmy@gmail.com)
+ * @date 2015年3月27日
+ * @since JDK 1.6
+ * @see
+ */
+public enum CouponStockType {
+ /**
+ * 批量型
+ */
+ BATCH(1),
+ /**
+ * 触发型
+ */
+ TRIGGER(2);
+ private int val;
+
+ CouponStockType(int val) {
+ this.val = val;
+ }
+
+ public int getVal() {
+ return val;
+ }
+}
diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/CouponType.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/CouponType.java
new file mode 100644
index 00000000..6dd536fb
--- /dev/null
+++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/CouponType.java
@@ -0,0 +1,43 @@
+package com.foxinmy.weixin4j.pay.type.mch;
+
+/**
+ * 代金券类型
+ *
+ * @className CouponType
+ * @author jinyu(foxinmy@gmail.com)
+ * @date 2015年3月27日
+ * @since JDK 1.6
+ * @see
+ */
+public enum CouponType {
+ /**
+ * 使用无门槛
+ */
+ NO_THRESHOLD(1),
+ /**
+ * 使用有门槛
+ */
+ HAS_THRESHOLD(2),
+ /**
+ * 门槛叠加
+ */
+ THRESHOLD_PLUS(3),
+
+ /**
+ * 充值代金券
+ */
+ CASH(-1),
+ /**
+ * 非充值代金券
+ */
+ NO_CASH(-2);
+ private int val;
+
+ CouponType(int val) {
+ this.val = val;
+ }
+
+ public int getVal() {
+ return val;
+ }
+}
diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/RedpacketSceneType.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/RedpacketSceneType.java
new file mode 100644
index 00000000..341542b2
--- /dev/null
+++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/RedpacketSceneType.java
@@ -0,0 +1,44 @@
+package com.foxinmy.weixin4j.pay.type.mch;
+
+/**
+ * 发放红包使用场景
+ *
+ * @className RedpacketSceneType
+ * @author jinyu(foxinmy@gmail.com)
+ * @date 2017年1月4日
+ * @since JDK 1.6
+ */
+public enum RedpacketSceneType {
+ /**
+ * 商品促销
+ */
+ PRODUCT_1,
+ /**
+ * 抽奖
+ */
+ PRODUCT_2,
+ /**
+ * 虚拟物品兑奖
+ */
+ PRODUCT_3,
+ /**
+ * 企业内部福利
+ */
+ PRODUCT_4,
+ /**
+ * 渠道分润
+ */
+ PRODUCT_5,
+ /**
+ * 保险回馈
+ */
+ PRODUCT_6,
+ /**
+ * 彩票派奖
+ */
+ PRODUCT_7,
+ /**
+ * 税务刮奖
+ */
+ PRODUCT_8
+}
diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/RedpacketSendType.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/RedpacketSendType.java
new file mode 100644
index 00000000..55ba69b3
--- /dev/null
+++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/RedpacketSendType.java
@@ -0,0 +1,25 @@
+package com.foxinmy.weixin4j.pay.type.mch;
+
+/**
+ * 红包发放类型
+ *
+ * @className RedpacketSendType
+ * @author jinyu(foxinmy@gmail.com)
+ * @date 2015年6月4日
+ * @since JDK 1.6
+ * @see
+ */
+public enum RedpacketSendType {
+ /**
+ * 通过API接口发放
+ */
+ API,
+ /**
+ * 通过上传文件方式发放
+ */
+ UPLOAD,
+ /**
+ * 通过活动方式发放
+ */
+ ACTIVITY;
+}
diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/RedpacketStatus.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/RedpacketStatus.java
new file mode 100644
index 00000000..5b440ae7
--- /dev/null
+++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/RedpacketStatus.java
@@ -0,0 +1,32 @@
+package com.foxinmy.weixin4j.pay.type.mch;
+
+/**
+ * 红包状态
+ * @className RedpacketStatus
+ * @author jinyu(foxinmy@gmail.com)
+ * @date 2015年6月4日
+ * @since JDK 1.6
+ * @see
+ */
+public enum RedpacketStatus {
+ /**
+ * 发放中
+ */
+ SENDING,
+ /**
+ * 已发放待领取
+ */
+ SENT,
+ /**
+ * 发放失败
+ */
+ FAILED,
+ /**
+ * 已领取
+ */
+ RECEIVED,
+ /**
+ * 已退款
+ */
+ REFUND;
+}
diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/RedpacketType.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/RedpacketType.java
new file mode 100644
index 00000000..d59ed2c9
--- /dev/null
+++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/RedpacketType.java
@@ -0,0 +1,21 @@
+package com.foxinmy.weixin4j.pay.type.mch;
+
+/**
+ * 红包类型
+ *
+ * @className RedpacketType
+ * @author jinyu(foxinmy@gmail.com)
+ * @date 2015年6月4日
+ * @since JDK 1.6
+ * @see
+ */
+public enum RedpacketType {
+ /**
+ * 裂变红包
+ */
+ GROUP,
+ /**
+ * 普通红包
+ */
+ NORMAL;
+}
diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/RefundAccountType.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/RefundAccountType.java
new file mode 100644
index 00000000..4e64b914
--- /dev/null
+++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/RefundAccountType.java
@@ -0,0 +1,18 @@
+package com.foxinmy.weixin4j.pay.type.mch;
+
+/**
+ * 退款资金来源
+ * @className RefundAccountType
+ * @author jinyu(foxinmy@gmail.com)
+ * @date 2016年12月12日
+ */
+public enum RefundAccountType {
+ /**
+ * ---未结算资金退款(默认使用未结算资金退款)
+ */
+ REFUND_SOURCE_UNSETTLED_FUNDS,
+ /**
+ * ---可用余额退款
+ */
+ REFUND_SOURCE_RECHARGE_FUNDS
+}
diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/RefundChannel.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/RefundChannel.java
new file mode 100644
index 00000000..40b01e07
--- /dev/null
+++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/RefundChannel.java
@@ -0,0 +1,37 @@
+package com.foxinmy.weixin4j.pay.type.mch;
+
+/**
+ * 退款渠道
+ *
+ * @className RefundChannel
+ * @author jinyu(foxinmy@gmail.com)
+ * @date 2014年11月6日
+ * @since JDK 1.6
+ * @see
+ */
+public enum RefundChannel {
+ /**
+ * 原路退款
+ */
+ ORIGINAL,
+ /**
+ * 退回到余额
+ */
+ BALANCE,
+ /**
+ * 财付通
+ */
+ TENPAY,
+ /**
+ * 银行
+ */
+ BANK,
+ /**
+ * 原账户异常退到其他余额账户
+ */
+ OTHER_BALANCE,
+ /**
+ * 原银行卡异常退到其他银行卡
+ */
+ OTHER_BANKCARD
+}
diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/RefundStatus.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/RefundStatus.java
new file mode 100644
index 00000000..b4fe3e2a
--- /dev/null
+++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/RefundStatus.java
@@ -0,0 +1,34 @@
+package com.foxinmy.weixin4j.pay.type.mch;
+
+/**
+ * 退款状态
+ *
+ * @className RefundStatus
+ * @author jinyu(foxinmy@gmail.com)
+ * @date 2014年11月2日
+ * @since JDK 1.6
+ * @see
+ */
+public enum RefundStatus {
+ /**
+ * 退款成功
+ */
+ SUCCESS,
+ /**
+ * 退款失败
+ */
+ FAIL,
+ /**
+ * 退款处理中
+ */
+ PROCESSING,
+ /**
+ * 未确定,需要商户 原退款单号重新发起
+ */
+ NOTSURE,
+ /**
+ * 转入代发,退款到银行发现用户的卡作废或者冻结了,导致原路退款银行卡失败,资金回流到商户的现金帐号,需要商户人工干预,通过线下或者财付通转
+ * 账的方式进行退款。
+ */
+ CHANGE;
+}
diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/RefundType.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/RefundType.java
new file mode 100644
index 00000000..fd96a037
--- /dev/null
+++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/RefundType.java
@@ -0,0 +1,35 @@
+package com.foxinmy.weixin4j.pay.type.mch;
+
+/**
+ * 退款类型
+ *
+ * @className RefundType
+ * @author jinyu(foxinmy@gmail.com)
+ * @date 2014年12月31日
+ * @since JDK 1.6
+ * @see
+ */
+public enum RefundType {
+ /**
+ * 1:商户号余额退款;
+ */
+ BALANCE(1),
+ /**
+ * 2:现金帐号 退款;
+ */
+ CASH(2),
+ /**
+ * 3:优先商户号退款,若商户号余额不足, 再做现金帐号退款。 使用 2 或 3 时,需联系财 付通开通此功能
+ */
+ BOTH(3);
+
+ private int val;
+
+ RefundType(int val) {
+ this.val = val;
+ }
+
+ public int getVal() {
+ return val;
+ }
+}