risk;
diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/mch/RedpacketSendResult.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/mch/RedpacketSendResult.java
index bc64471a..1dd05939 100644
--- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/mch/RedpacketSendResult.java
+++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/mch/RedpacketSendResult.java
@@ -18,7 +18,9 @@ import com.foxinmy.weixin4j.util.DateUtil;
* @date 2015年4月1日
* @since JDK 1.6
* @see
+ * @deprecated 迁移到子模块weixin4j-pay
*/
+@Deprecated
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class RedpacketSendResult extends MerchantResult {
diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/mch/RefundDetail.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/mch/RefundDetail.java
index 2ac72095..aaec86a4 100644
--- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/mch/RefundDetail.java
+++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/mch/RefundDetail.java
@@ -24,7 +24,9 @@ import com.foxinmy.weixin4j.xml.ListsuffixResult;
* @author jinyu(foxinmy@gmail.com)
* @date 2016年7月21日
* @since JDK 1.6
+ * @deprecated 迁移到子模块weixin4j-pay
*/
+@Deprecated
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class RefundDetail implements Serializable {
diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/mch/RefundRecord.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/mch/RefundRecord.java
index 945b4e64..3ed978f0 100644
--- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/mch/RefundRecord.java
+++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/mch/RefundRecord.java
@@ -17,7 +17,9 @@ import com.foxinmy.weixin4j.xml.ListsuffixResult;
* @author jinyu(foxinmy@gmail.com)
* @date 2014年11月1日
* @since JDK 1.6
+ * @deprecated 迁移到子模块weixin4j-pay
*/
+@Deprecated
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class RefundRecord extends MerchantTradeResult {
diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/mch/RefundResult.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/mch/RefundResult.java
index 2b46cafa..9768a341 100644
--- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/mch/RefundResult.java
+++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/mch/RefundResult.java
@@ -19,7 +19,9 @@ import com.foxinmy.weixin4j.xml.ListsuffixResult;
* @date 2014年11月6日
* @since JDK 1.6
* @see
+ * @deprecated 迁移到子模块weixin4j-pay
*/
+@Deprecated
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class RefundResult extends MerchantTradeResult {
diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/mch/SceneInfoApp.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/mch/SceneInfoApp.java
index 62912079..29a7992a 100644
--- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/mch/SceneInfoApp.java
+++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/mch/SceneInfoApp.java
@@ -4,6 +4,7 @@ import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
+@Deprecated
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class SceneInfoApp {
diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/mch/SceneInfoStore.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/mch/SceneInfoStore.java
index 23674a6b..a4bd7698 100644
--- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/mch/SceneInfoStore.java
+++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/mch/SceneInfoStore.java
@@ -7,6 +7,7 @@ import javax.xml.bind.annotation.XmlRootElement;
import com.alibaba.fastjson.annotation.JSONField;
+@Deprecated
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class SceneInfoStore {
diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/mch/SettlementRecord.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/mch/SettlementRecord.java
index ffb2d678..46811a65 100644
--- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/mch/SettlementRecord.java
+++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/mch/SettlementRecord.java
@@ -17,6 +17,7 @@ import com.foxinmy.weixin4j.util.DateUtil;
* @since JDK 1.6
* @see
*/
+@Deprecated
public class SettlementRecord extends MerchantResult {
private static final long serialVersionUID = 7952659545609519979L;
diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/mch/WAPPayRequest.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/mch/WAPPayRequest.java
index 17ce2bad..2895d30e 100644
--- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/mch/WAPPayRequest.java
+++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/mch/WAPPayRequest.java
@@ -16,6 +16,7 @@ import com.foxinmy.weixin4j.type.TradeType;
* @see WAP支付
*/
+@Deprecated
public class WAPPayRequest extends AbstractPayRequest {
/**
* 微信支付URL
diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/sign/AbstractWeixinSignature.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/sign/AbstractWeixinSignature.java
index 946066cc..de91afe1 100644
--- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/sign/AbstractWeixinSignature.java
+++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/sign/AbstractWeixinSignature.java
@@ -10,7 +10,9 @@ import com.foxinmy.weixin4j.util.MapUtil;
* @date 2016年3月26日
* @since JDK 1.6
* @see
+ * @deprecated 迁移到子模块weixin4j-pay
*/
+@Deprecated
public abstract class AbstractWeixinSignature implements WeixinSignature {
/**
* 是否编码
diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/sign/WeixinPaymentSignature.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/sign/WeixinPaymentSignature.java
index 9d32ef29..1905ad58 100644
--- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/sign/WeixinPaymentSignature.java
+++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/sign/WeixinPaymentSignature.java
@@ -12,7 +12,9 @@ import com.foxinmy.weixin4j.util.DigestUtil;
* @since JDK 1.6
* @see 支付签名说明
+ * @deprecated 迁移到子模块weixin4j-pay
*/
+@Deprecated
public class WeixinPaymentSignature extends AbstractWeixinSignature {
/**
* 支付密钥
diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/sign/WeixinSignature.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/sign/WeixinSignature.java
index 2b7574da..da133527 100644
--- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/sign/WeixinSignature.java
+++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/sign/WeixinSignature.java
@@ -10,7 +10,9 @@ import com.foxinmy.weixin4j.type.SignType;
* @date 2016年3月26日
* @since JDK 1.6
* @see
+ * @deprecated 迁移到子模块weixin4j-pay
*/
+@Deprecated
public interface WeixinSignature {
/**
* 是否编码
diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/BankType.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/BankType.java
index f0db2a69..70cd9f72 100644
--- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/BankType.java
+++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/BankType.java
@@ -9,7 +9,9 @@ package com.foxinmy.weixin4j.type;
* @date 2015年8月19日
* @since JDK 1.6
* @see
+ * @deprecated 迁移到子模块weixin4j-pay
*/
+@Deprecated
public enum BankType {
/**
* 工商银行(借记卡)
diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/CredentialType.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/CredentialType.java
index 4340c827..1d46317d 100644
--- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/CredentialType.java
+++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/CredentialType.java
@@ -8,7 +8,9 @@ package com.foxinmy.weixin4j.type;
* @date 2016年3月27日
* @since JDK 1.6
* @see
+ * @deprecated 迁移到子模块weixin4j-pay
*/
+@Deprecated
public enum CredentialType {
IDCARD("身份证");
CredentialType(String name) {
diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/CurrencyType.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/CurrencyType.java
index 26baf846..a846033b 100644
--- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/CurrencyType.java
+++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/CurrencyType.java
@@ -8,7 +8,9 @@ package com.foxinmy.weixin4j.type;
* @date 2014年11月2日
* @since JDK 1.6
* @see
+ * @deprecated 迁移到子模块weixin4j-pay
*/
+@Deprecated
public enum CurrencyType {
CNY("人民币"), HKD("港元"), TWD("台币"), EUR("欧元"), USD("美元"), GBP("英镑"), JPY("日元"), CAD(
"加拿大元"), AUD("澳大利亚元"), NZD("新西兰元"), KRW("韩元"), THB("泰铢");
diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/CustomsCity.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/CustomsCity.java
index 874446d4..9ed49d60 100644
--- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/CustomsCity.java
+++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/CustomsCity.java
@@ -8,7 +8,9 @@ package com.foxinmy.weixin4j.type;
* @date 2016年3月27日
* @since JDK 1.6
* @see
+ * @deprecated 迁移到子模块weixin4j-pay
*/
+@Deprecated
public enum CustomsCity {
NO("无需上报海关"), GUANGZHOU("广州"), HANGZHOU("杭州"), NINGBO("宁波"), ZHENGZHOU_BS(
"郑州(保税物流中心)"), CHONGQING("重庆"), XIAN("西安"), SHANGHAI("上海"), ZHENGZHOU_ZH(
diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/CustomsSatus.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/CustomsSatus.java
index 50437bda..a807c23d 100644
--- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/CustomsSatus.java
+++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/CustomsSatus.java
@@ -8,7 +8,9 @@ package com.foxinmy.weixin4j.type;
* @date 2016年3月27日
* @since JDK 1.6
* @see
+ * @deprecated 迁移到子模块weixin4j-pay
*/
+@Deprecated
public enum CustomsSatus {
UNDECLARED("未申报"), SUBMITTED("申报已提交"), PROCESSING("申报中"), SUCCESS("申报成功"), FAIL(
"申报失败"), EXCEPT("海关接口异常");
diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/IdQuery.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/IdQuery.java
index 4757dce7..e1470413 100644
--- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/IdQuery.java
+++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/IdQuery.java
@@ -10,7 +10,9 @@ import java.io.Serializable;
* @date 2014年11月1日
* @since JDK 1.6
* @see
+ * @deprecated 迁移到子模块weixin4j-pay
*/
+@Deprecated
public class IdQuery implements Serializable {
private static final long serialVersionUID = -5273675987521807370L;
diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/IdType.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/IdType.java
index 70c1f105..3a475d57 100644
--- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/IdType.java
+++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/IdType.java
@@ -8,7 +8,9 @@ package com.foxinmy.weixin4j.type;
* @date 2014年11月1日
* @since JDK 1.6
* @see
+ * @deprecated 迁移到子模块weixin4j-pay
*/
+@Deprecated
public enum IdType {
/**
* 微信退款单号
diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/SignType.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/SignType.java
index 60cb1526..fff58546 100644
--- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/SignType.java
+++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/SignType.java
@@ -8,7 +8,9 @@ package com.foxinmy.weixin4j.type;
* @date 2014年11月5日
* @since JDK 1.6
* @see
+ * @deprecated 迁移到子模块weixin4j-pay
*/
+@Deprecated
public enum SignType {
SHA1, MD5, HMAC$SHA256
}
diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/TarType.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/TarType.java
index 1e48af17..efffde26 100644
--- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/TarType.java
+++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/TarType.java
@@ -8,7 +8,9 @@ package com.foxinmy.weixin4j.type;
* @date 2016年12月21日
* @since JDK 1.6
* @see
+ * @deprecated 迁移到子模块weixin4j-pay
*/
+@Deprecated
public enum TarType {
GZIP
}
diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/TradeState.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/TradeState.java
index 2d974e0f..2ec5b42c 100644
--- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/TradeState.java
+++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/TradeState.java
@@ -8,7 +8,9 @@ package com.foxinmy.weixin4j.type;
* @date 2014年11月2日
* @since JDK 1.6
* @see
+ * @deprecated 迁移到子模块weixin4j-pay
*/
+@Deprecated
public enum TradeState {
/**
* 支付成功
diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/TradeType.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/TradeType.java
index c660a2ec..b77fa3fb 100644
--- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/TradeType.java
+++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/TradeType.java
@@ -8,7 +8,9 @@ package com.foxinmy.weixin4j.type;
* @date 2014年10月21日
* @since JDK 1.6
* @see
+ * @deprecated 迁移到weixin4j-pay子模块
*/
+@Deprecated
public enum TradeType {
/**
* JS支付
diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/mch/BillType.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/mch/BillType.java
index d0951468..baace932 100644
--- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/mch/BillType.java
+++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/mch/BillType.java
@@ -8,7 +8,9 @@ package com.foxinmy.weixin4j.type.mch;
* @date 2014年10月31日
* @since JDK 1.6
* @see
+ * @deprecated 迁移到子模块weixin4j-pay
*/
+@Deprecated
public enum BillType {
/**
* 全部
diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/mch/CorpPaymentCheckNameType.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/mch/CorpPaymentCheckNameType.java
index 593e5872..40631c48 100644
--- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/mch/CorpPaymentCheckNameType.java
+++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/mch/CorpPaymentCheckNameType.java
@@ -8,7 +8,9 @@ package com.foxinmy.weixin4j.type.mch;
* @date 2015年4月1日
* @since JDK 1.6
* @see
+ * @deprecated 迁移到子模块weixin4j-pay
*/
+@Deprecated
public enum CorpPaymentCheckNameType {
/**
* 不校验真实姓名
diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/mch/CouponStatus.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/mch/CouponStatus.java
index 18060971..38956878 100644
--- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/mch/CouponStatus.java
+++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/mch/CouponStatus.java
@@ -8,7 +8,9 @@ package com.foxinmy.weixin4j.type.mch;
* @date 2015年3月27日
* @since JDK 1.6
* @see
+ * @deprecated 迁移到子模块weixin4j-pay
*/
+@Deprecated
public enum CouponStatus {
/**
* 已激活
diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/mch/CouponStockStatus.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/mch/CouponStockStatus.java
index 946966d8..765502c4 100644
--- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/mch/CouponStockStatus.java
+++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/mch/CouponStockStatus.java
@@ -8,7 +8,9 @@ package com.foxinmy.weixin4j.type.mch;
* @date 2015年3月27日
* @since JDK 1.6
* @see
+ * @deprecated 迁移到子模块weixin4j-pay
*/
+@Deprecated
public enum CouponStockStatus {
/**
* 未激活
diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/mch/CouponStockType.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/mch/CouponStockType.java
index 94d088b3..adf7be50 100644
--- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/mch/CouponStockType.java
+++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/mch/CouponStockType.java
@@ -8,7 +8,9 @@ package com.foxinmy.weixin4j.type.mch;
* @date 2015年3月27日
* @since JDK 1.6
* @see
+ * @deprecated 迁移到子模块weixin4j-pay
*/
+@Deprecated
public enum CouponStockType {
/**
* 批量型
diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/mch/CouponType.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/mch/CouponType.java
index 76d979f6..116c980c 100644
--- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/mch/CouponType.java
+++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/mch/CouponType.java
@@ -8,7 +8,9 @@ package com.foxinmy.weixin4j.type.mch;
* @date 2015年3月27日
* @since JDK 1.6
* @see
+ * @deprecated 迁移到子模块weixin4j-pay
*/
+@Deprecated
public enum CouponType {
/**
* 使用无门槛
diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/mch/RedpacketSceneType.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/mch/RedpacketSceneType.java
index 0da68f68..a477bd7e 100644
--- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/mch/RedpacketSceneType.java
+++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/mch/RedpacketSceneType.java
@@ -7,7 +7,9 @@ package com.foxinmy.weixin4j.type.mch;
* @author jinyu(foxinmy@gmail.com)
* @date 2017年1月4日
* @since JDK 1.6
+ * @deprecated 迁移到子模块weixin4j-pay
*/
+@Deprecated
public enum RedpacketSceneType {
/**
* 商品促销
diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/mch/RedpacketSendType.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/mch/RedpacketSendType.java
index b446458d..265b15ca 100644
--- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/mch/RedpacketSendType.java
+++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/mch/RedpacketSendType.java
@@ -8,7 +8,9 @@ package com.foxinmy.weixin4j.type.mch;
* @date 2015年6月4日
* @since JDK 1.6
* @see
+ * @deprecated 迁移到子模块weixin4j-pay
*/
+@Deprecated
public enum RedpacketSendType {
/**
* 通过API接口发放
diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/mch/RedpacketStatus.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/mch/RedpacketStatus.java
index afa49e52..4fc6d723 100644
--- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/mch/RedpacketStatus.java
+++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/mch/RedpacketStatus.java
@@ -7,7 +7,9 @@ package com.foxinmy.weixin4j.type.mch;
* @date 2015年6月4日
* @since JDK 1.6
* @see
+ * @deprecated 迁移到子模块weixin4j-pay
*/
+@Deprecated
public enum RedpacketStatus {
/**
* 发放中
diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/mch/RedpacketType.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/mch/RedpacketType.java
index 70056054..be34cc78 100644
--- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/mch/RedpacketType.java
+++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/mch/RedpacketType.java
@@ -8,7 +8,9 @@ package com.foxinmy.weixin4j.type.mch;
* @date 2015年6月4日
* @since JDK 1.6
* @see
+ * @deprecated 迁移到子模块weixin4j-pay
*/
+@Deprecated
public enum RedpacketType {
/**
* 裂变红包
diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/mch/RefundAccountType.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/mch/RefundAccountType.java
index af10c2e1..d4088929 100644
--- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/mch/RefundAccountType.java
+++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/mch/RefundAccountType.java
@@ -5,7 +5,9 @@ package com.foxinmy.weixin4j.type.mch;
* @className RefundAccountType
* @author jinyu(foxinmy@gmail.com)
* @date 2016年12月12日
+ * @deprecated 迁移到子模块weixin4j-pay
*/
+@Deprecated
public enum RefundAccountType {
/**
* ---未结算资金退款(默认使用未结算资金退款)
diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/mch/RefundChannel.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/mch/RefundChannel.java
index 144e49ab..ae729875 100644
--- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/mch/RefundChannel.java
+++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/mch/RefundChannel.java
@@ -8,7 +8,9 @@ package com.foxinmy.weixin4j.type.mch;
* @date 2014年11月6日
* @since JDK 1.6
* @see
+ * @deprecated 迁移到子模块weixin4j-pay
*/
+@Deprecated
public enum RefundChannel {
/**
* 原路退款
diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/mch/RefundStatus.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/mch/RefundStatus.java
index dc294571..7c645ed3 100644
--- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/mch/RefundStatus.java
+++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/mch/RefundStatus.java
@@ -8,7 +8,9 @@ package com.foxinmy.weixin4j.type.mch;
* @date 2014年11月2日
* @since JDK 1.6
* @see
+ * @deprecated 迁移到子模块weixin4j-pay
*/
+@Deprecated
public enum RefundStatus {
/**
* 退款成功
diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/mch/RefundType.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/mch/RefundType.java
index 1724db2c..1e62943d 100644
--- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/mch/RefundType.java
+++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/mch/RefundType.java
@@ -8,7 +8,9 @@ package com.foxinmy.weixin4j.type.mch;
* @date 2014年12月31日
* @since JDK 1.6
* @see
+ * @deprecated 迁移到子模块weixin4j-pay
*/
+@Deprecated
public enum RefundType {
/**
* 1:商户号余额退款;
diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/util/DigestUtil.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/util/DigestUtil.java
index 0d30578b..defa1b13 100644
--- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/util/DigestUtil.java
+++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/util/DigestUtil.java
@@ -1,5 +1,8 @@
package com.foxinmy.weixin4j.util;
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
+import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
@@ -57,4 +60,26 @@ public final class DigestUtil {
byte[] data = StringUtil.getBytesUtf8(content);
return HexUtil.encodeHexString(getDigest(Consts.MD5).digest(data));
}
+
+ /**
+ * HMAC-SHA256签名
+ *
+ * @param content
+ * 待签名字符串
+ * @param key
+ * 支付密钥
+ * @return
+ * @throws InvalidKeyException
+ */
+ public static String HMACSHA256(String content, String key) throws InvalidKeyException{
+ try {
+ Mac mac = Mac.getInstance("HmacSHA256");
+ SecretKeySpec secret_key = new SecretKeySpec(key.getBytes(), "HmacSHA256");
+ mac.init(secret_key);
+ byte[] bytes = mac.doFinal(content.getBytes());
+ return HexUtil.encodeHexString(bytes);
+ } catch (NoSuchAlgorithmException e) {
+ }
+ return null;
+ }
}
diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/util/MapUtil.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/util/MapUtil.java
index b25d6f02..acd13f81 100644
--- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/util/MapUtil.java
+++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/util/MapUtil.java
@@ -29,8 +29,6 @@ public class MapUtil {
* 是否编码
* @param lowerCase
* 是否转换小写
- * @param extra
- * 附加对象
* @return
*/
public static String toJoinString(Object object, boolean encoder,
diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/util/Weixin4jConfigUtil.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/util/Weixin4jConfigUtil.java
index ea3d502e..302ee867 100644
--- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/util/Weixin4jConfigUtil.java
+++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/util/Weixin4jConfigUtil.java
@@ -2,6 +2,7 @@ package com.foxinmy.weixin4j.util;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
+import java.util.logging.Level;
import com.alibaba.fastjson.JSON;
import com.foxinmy.weixin4j.model.WeixinAccount;
@@ -112,4 +113,13 @@ public class Weixin4jConfigUtil {
}
return account;
}
+
+ public static Level getJdkLoggerLevel(){
+ try {
+ Level level = Level.parse(getValue("jdkLogger.level", "OFF"));
+ return level;
+ }catch (IllegalArgumentException ex){
+ return Level.OFF;
+ }
+ }
}
diff --git a/weixin4j-base/src/main/resources/com/foxinmy/weixin4j/payment/weixin.properties b/weixin4j-base/src/main/resources/com/foxinmy/weixin4j/payment/weixin.properties
index 68ed23ca..635bb53b 100644
--- a/weixin4j-base/src/main/resources/com/foxinmy/weixin4j/payment/weixin.properties
+++ b/weixin4j-base/src/main/resources/com/foxinmy/weixin4j/payment/weixin.properties
@@ -1,59 +1,64 @@
-# \u5fae\u4fe1\u5546\u6237\u5e73\u53f0\u6587\u6863\u8bf4\u660e
+# \u5FAE\u4FE1\u5546\u6237\u5E73\u53F0\u6587\u6863\u8BF4\u660E
# https://pay.weixin.qq.com/
# https://pay.weixin.qq.com/wiki/doc/api/index.php
# ----------------------------------------------------------------------------
mch_base_url=https://api.mch.weixin.qq.com
+payapp_base_url=https://payapp.weixin.qq.com
-# \u53d1\u9001\u73b0\u91d1\u7ea2\u5305
+# \u53D1\u9001\u73B0\u91D1\u7EA2\u5305
redpack_send_uri={mch_base_url}/mmpaymkttransfers/sendredpack
-# \u53d1\u9001\u73b0\u91d1\u88c2\u53d8\u7ea2\u5305
+# \u53D1\u9001\u73B0\u91D1\u88C2\u53D8\u7EA2\u5305
groupredpack_send_uri={mch_base_url}/mmpaymkttransfers/sendgroupredpack
-# \u67e5\u8be2\u73b0\u91d1\u7ea2\u5305
+# \u67E5\u8BE2\u73B0\u91D1\u7EA2\u5305
redpack_query_uri={mch_base_url}/mmpaymkttransfers/gethbinfo
-# \u7edf\u4e00\u8ba2\u5355\u751f\u6210
+# \u7EDF\u4E00\u8BA2\u5355\u751F\u6210
order_create_uri={mch_base_url}/pay/unifiedorder
-# \u88ab\u626b\u652f\u4ed8
+# \u88AB\u626B\u652F\u4ED8
micropay_uri={mch_base_url}/pay/micropay
-# \u8ba2\u5355\u67e5\u8be2
+# \u8BA2\u5355\u67E5\u8BE2
order_query_uri={mch_base_url}/pay/orderquery
-# \u5173\u95ed\u8ba2\u5355
+# \u5173\u95ED\u8BA2\u5355
order_close_uri={mch_base_url}/pay/closeorder
-# \u5bf9\u8d26\u5355\u4e0b\u8f7d
+# \u5BF9\u8D26\u5355\u4E0B\u8F7D
downloadbill_uri={mch_base_url}/pay/downloadbill
-# \u9000\u6b3e\u67e5\u8be2
+# \u9000\u6B3E\u67E5\u8BE2
refund_query_uri={mch_base_url}/pay/refundquery
-# \u9000\u6b3e\u7533\u8bf7
+# \u9000\u6B3E\u7533\u8BF7
refund_apply_uri={mch_base_url}/secapi/pay/refund
-# \u51b2\u6b63\u64a4\u9500
+# \u51B2\u6B63\u64A4\u9500
order_reverse_uri={mch_base_url}/secapi/pay/reverse
-# \u957f\u94fe\u63a5\u8f6c\u6362
+# \u957F\u94FE\u63A5\u8F6C\u6362
longurl_convert_uri={mch_base_url}/tools/shorturl
-# \u53d1\u653e\u4ee3\u91d1\u5238
+# \u53D1\u653E\u4EE3\u91D1\u5238
coupon_send_uri={mch_base_url}/mmpaymkttransfers/send_coupon
-# \u67e5\u8be2\u4ee3\u91d1\u5238\u6279\u6b21\u4fe1\u606f
+# \u67E5\u8BE2\u4EE3\u91D1\u5238\u6279\u6B21\u4FE1\u606F
couponstock_query_uri={mch_base_url}/mmpaymkttransfers/query_coupon_stock
-# \u67e5\u8be2\u4ee3\u91d1\u5238\u8be6\u7ec6\u4fe1\u606f
+# \u67E5\u8BE2\u4EE3\u91D1\u5238\u8BE6\u7EC6\u4FE1\u606F
coupondetail_query_uri={mch_base_url}/mmpaymkttransfers/querycouponsinfo
-# \u53d1\u9001\u73b0\u91d1\u7ea2\u5305
-redpack_send_uri={mch_base_url}/mmpaymkttransfers/sendredpack
-# \u67e5\u8be2\u73b0\u91d1\u7ea2\u5305
-redpack_query_uri={mch_base_url}/mmpaymkttransfers/gethbinfo
-# \u4f01\u4e1a\u5411\u4e2a\u4eba\u4ed8\u6b3e
+# \u4F01\u4E1A\u5411\u4E2A\u4EBA\u4ED8\u6B3E
corppayment_send_uri={mch_base_url}/mmpaymkttransfers/promotion/transfers
-# \u4f01\u4e1a\u4ed8\u6b3e\u67e5\u8be2
+# \u4F01\u4E1A\u4ED8\u6B3E\u67E5\u8BE2
corppayment_query_uri={mch_base_url}/mmpaymkttransfers/gettransferinfo
-# \u63a5\u53e3\u4e0a\u62a5
+# \u63A5\u53E3\u4E0A\u62A5
interface_report_uri={mch_base_url}/payitil/report
-# \u6388\u6743\u7801\u67e5\u8be2OPENID\u63a5\u53e3
+# \u6388\u6743\u7801\u67E5\u8BE2OPENID\u63A5\u53E3
authcode_openid_uri={mch_base_url}/tools/authcodetoopenid
-# native\u652f\u4ed8url(\u6a21\u5f0f1)
+# native\u652F\u4ED8url(\u6A21\u5F0F1)
native_pay_uri=weixin://wxpay/bizpayurl?sign=%s&appid=%s&mch_id=%s&product_id=%s&time_stamp=%s&nonce_str=%s
-# \u67e5\u8be2\u7ed3\u7b97\u8d44\u91d1
+# \u67E5\u8BE2\u7ED3\u7B97\u8D44\u91D1
settlement_query_uri={mch_base_url}/pay/settlementquery
-# \u67e5\u8be2\u6c47\u7387
+# \u67E5\u8BE2\u6C47\u7387
exchagerate_query_uri={mch_base_url}/pay/queryexchagerate
-# \u8ba2\u5355\u9644\u52a0\u4fe1\u606f\u63d0\u4ea4
+# \u8BA2\u5355\u9644\u52A0\u4FE1\u606F\u63D0\u4EA4
customsorder_declare_uri={mch_base_url}/mch/customs/customdeclareorder
-# \u8ba2\u5355\u9644\u52a0\u4fe1\u606f\u67e5\u8be2
-customsorder_query_uri={mch_base_url}/mch/customs/customdeclarequery
\ No newline at end of file
+# \u8BA2\u5355\u9644\u52A0\u4FE1\u606F\u67E5\u8BE2
+customsorder_query_uri={mch_base_url}/mch/customs/customdeclarequery
+# \u5237\u8138\u652F\u4ED8\u4EA4\u4E92\u6D41\u7A0B--\u83B7\u53D6\u8C03\u7528\u51ED\u8BC1
+get_wxpayface_authinfo_uri={payapp_base_url}/face/get_wxpayface_authinfo
+# \u65E7\u7248\u5237\u8138\u652F\u4ED8\u63A5\u53E3
+facepay_url={mch_base_url}/pay/facepay
+# \u652F\u4ED8\u62BC\u91D1\uFF08\u4EBA\u8138\uFF09
+deposit_facepay_uri={mch_base_url}/deposit/facepay
+# \u652F\u4ED8\u62BC\u91D1\uFF08\u4ED8\u6B3E\u7801\uFF09
+deposit_micropay_uri={mch_base_url}/deposit/micropay
\ No newline at end of file
diff --git a/weixin4j-pay/pom.xml b/weixin4j-pay/pom.xml
new file mode 100644
index 00000000..aa887ef8
--- /dev/null
+++ b/weixin4j-pay/pom.xml
@@ -0,0 +1,47 @@
+
+
+
+ weixin4j
+ com.foxinmy
+ 1.9.0-SNAPSHOT
+
+ 4.0.0
+ weixin4j-pay
+ weixin4j-pay
+ 1.0.0-SNAPSHOT
+ https://github.com/foxinmy/weixin4j/tree/master/weixin4j-pay
+ 微信支付商户平台API
+
+
+ kit-lee
+ Kit lee
+ ryuji.cn@gmail.com
+ https://github.com/kit-lee
+
+ kit_21cn@21cn.com
+ https://github.com/kit-lee/weixin4j
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-assembly-plugin
+
+
+
+
+
+ com.foxinmy
+ weixin4j-base
+ 1.9.0-SNAPSHOT
+
+
+ junit
+ junit
+
+
+
\ No newline at end of file
diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/README.md b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/README.md
new file mode 100644
index 00000000..1792dfa0
--- /dev/null
+++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/README.md
@@ -0,0 +1,47 @@
+支付模块【JSAPI】【NATIVE】【MICROPAY】
+
+微信公众平台[V2版本支付](https://mp.weixin.qq.com/paymch/readtemplate?t=mp/business/course2_tmpl&lang=zh_CN)文档
+
+微信公众平台[V3版本支付](https://mp.weixin.qq.com/paymch/readtemplate?t=mp/business/course3_tmpl&lang=zh_CN)文档
+
+**在`2014年10月9号`之前申请并审核通过的支付接口应该属于`V2版本`支付,而之后申请的接口则为`V3版本(商户平台)`支付**
+
+
+[WeixinPayProxy](WeixinPayProxy.java)
+-------------------------
+
+* createPayJsRequestJson: 创建V3版本(商户平台)的JSAPI支付串
+
+* createNativePayRequestURL: 创建V3版本(商户平台)的扫码支付链接
+
+* createPrePay: 调用V3版本(商户平台)的统一订单接口生成预订单数据
+
+* createMicroPay: 创建刷卡支付(商户平台)请求
+
+* orderQuery: 订单查询接口
+
+* refundOrder: 退款申请接口
+
+* reverseOrder: 冲正订单接口
+
+* closeOrder: 关闭订单接口
+
+* downloadBill: 下载对账单接口
+
+* refundQuery: 退款查询接口
+
+
+[Pay2Api](https://github.com/foxinmy/weixin4j/blob/master/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/Pay2Api.java)
+-------------------------
+
+* createPayJsRequestJson: 创建V2版本的JSAPI支付串
+
+* createNativePayRequestURL: 创建V2版本的扫码支付链接
+
+* orderQuery: 订单查询接口
+
+* refundOrder: 退款申请接口
+
+* downloadBill: 下载对账单接口
+
+* refundQuery: 退款查询接口
diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/WeixinPayProxy.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/WeixinPayProxy.java
new file mode 100644
index 00000000..563d62d4
--- /dev/null
+++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/WeixinPayProxy.java
@@ -0,0 +1,890 @@
+package com.foxinmy.weixin4j.pay;
+
+import com.alibaba.fastjson.JSON;
+import com.foxinmy.weixin4j.pay.api.*;
+import com.foxinmy.weixin4j.exception.WeixinException;
+import com.foxinmy.weixin4j.http.weixin.XmlResult;
+import com.foxinmy.weixin4j.pay.model.WeixinPayAccount;
+import com.foxinmy.weixin4j.model.paging.Pageable;
+import com.foxinmy.weixin4j.pay.payment.coupon.*;
+import com.foxinmy.weixin4j.pay.payment.face.PayfaceAuthinfo;
+import com.foxinmy.weixin4j.pay.payment.face.PayfaceAuthinfoRequest;
+import com.foxinmy.weixin4j.pay.payment.mch.*;
+import com.foxinmy.weixin4j.pay.sign.WeixinSignature;
+import com.foxinmy.weixin4j.pay.type.*;
+import com.foxinmy.weixin4j.pay.type.mch.BillType;
+import com.foxinmy.weixin4j.pay.type.mch.RefundAccountType;
+import com.foxinmy.weixin4j.util.Consts;
+import com.foxinmy.weixin4j.util.Weixin4jConfigUtil;
+
+import java.io.OutputStream;
+import java.util.Date;
+import java.util.List;
+import java.util.concurrent.Future;
+
+/**
+ * 微信支付接口实现
+ *
+ * @className WeixinPayProxy
+ * @author jinyu(foxinmy@gmail.com)
+ * @date 2015年1月3日
+ * @since JDK 1.6
+ * @see 商户平台支付API
+ */
+public class WeixinPayProxy {
+
+ /**
+ * 微信支付API:js支付、扫码支付等接口
+ */
+ private final PayApi payApi;
+ /**
+ * 代金券API
+ */
+ private final CouponApi couponApi;
+ /**
+ * 现金API
+ */
+ private final CashApi cashApi;
+ /**
+ * 海关API
+ */
+ private final CustomsApi customsApi;
+ /**
+ * 商户信息
+ */
+ private final WeixinPayAccount weixinPayAccount;
+
+ /**
+ * 微信支付接口实现(使用weixin4j.properties配置的account商户信息)
+ */
+ public WeixinPayProxy() {
+ this(JSON.parseObject(Weixin4jConfigUtil.getValue("account"),
+ WeixinPayAccount.class));
+ }
+
+ /**
+ * 微信支付接口实现
+ *
+ * @param weixinPayAccount
+ * 微信商户信息
+ */
+ public WeixinPayProxy(WeixinPayAccount weixinPayAccount) {
+ if (weixinPayAccount == null) {
+ throw new IllegalArgumentException(
+ "weixinPayAccount must not be empty");
+ }
+ this.weixinPayAccount = weixinPayAccount;
+ this.payApi = new PayApi(weixinPayAccount);
+ this.couponApi = new CouponApi(weixinPayAccount);
+ this.cashApi = new CashApi(weixinPayAccount);
+ this.customsApi = new CustomsApi(weixinPayAccount);
+ }
+
+ /**
+ * 获取微信商户账号信息
+ *
+ * @return
+ */
+ public WeixinPayAccount getWeixinPayAccount() {
+ return weixinPayAccount;
+ }
+
+ /**
+ * 获取微信签名类
+ *
+ * @return
+ */
+ public WeixinSignature getWeixinSignature() {
+ return payApi.getWeixinSignature();
+ }
+
+ /**
+ * 统一下单接口
+ * 除被扫支付场景以外,商户系统先调用该接口在微信支付服务后台生成预支付交易单,返回正确的预支付交易回话标识后再按扫码、JSAPI
+ * 、APP等不同场景生成交易串调起支付。
+ *
+ * @param payPackage
+ * 包含订单信息的对象
+ * @see PayApi
+ * @see MchPayPackage
+ * @see PrePay
+ * @see 统一下单接口
+ *
+ * @return 预支付对象
+ */
+ public PrePay createPrePay(MchPayPackage payPackage) throws WeixinException {
+ return payApi.createPrePay(payPackage);
+ }
+
+ /**
+ * 创建支付请求对象
+ *
+ * @param payPackage
+ * 支付详情
+ * @return 支付请求对象
+ * @see PayApi
+ * @see JSAPIPayRequest JS支付
+ * @see NATIVEPayRequest 扫码支付
+ * @see MICROPayRequest 刷卡支付
+ * @see APPPayRequest APP支付
+ * @see WAPPayRequest WAP支付
+ * @see MchPayRequest#toRequestString()
+ * @throws WeixinException
+ */
+ public MchPayRequest createPayRequest(MchPayPackage payPackage)
+ throws WeixinException {
+ return payApi.createPayRequest(payPackage);
+ }
+
+ /**
+ * 创建JSAPI支付请求对象
+ *
+ * @param openId
+ * 用户ID
+ * @param body
+ * 订单描述
+ * @param outTradeNo
+ * 订单号
+ * @param totalFee
+ * 订单总额(元)
+ * @param notifyUrl
+ * 支付通知地址
+ * @param createIp
+ * ip地址
+ * @param attach
+ * 附加数据 非必填
+ * @see PayApi
+ * @see JSAPIPayRequest
+ * @see MchPayRequest#toRequestString()
+ * @return JSAPI支付对象
+ * @throws WeixinException
+ */
+ public MchPayRequest createJSPayRequest(String openId, String body,
+ String outTradeNo, double totalFee, String notifyUrl,
+ String createIp, String attach) throws WeixinException {
+ return payApi.createJSPayRequest(openId, body, outTradeNo, totalFee,
+ notifyUrl, createIp, attach);
+ }
+
+ /**
+ * 创建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);
+ }
+
+ /**
+ * 旧版刷脸支付接口
+ *
+ * @param faceCode
+ * 人脸凭证
+ * @param body
+ * 商品或支付单简要描述,格式要求:门店品牌名-城市分店名-实际商品名称
+ * @param outTradeNo
+ * 商户系统内部的订单号,32个字符内、可包含字母;更换授权码必须要换新的商户订单号
+ * @param totalFee
+ * 订单总金额,单位元
+ * @param createIp
+ * 调用微信支付API的机器IP
+ * @param openId
+ * 用户在商户appid 下的唯一标识
+ * @param attach
+ * 附加数据,在查询API和支付通知中原样返回,该字段主要用于商户携带订单的自定义数据
+ * @return
+ * @throws WeixinException
+ * @see
+ * 刷脸支付后端接口
+ * @see
+ */
+ public MchPayRequest createFacePayRequest(String faceCode, String body,
+ String outTradeNo, double totalFee, String createIp, String openId,
+ String attach) throws WeixinException {
+ return payApi.createFacePayRequest(faceCode, body, outTradeNo,
+ totalFee, createIp, openId, attach);
+ }
+
+ /**
+ * 押金支付请求
+ *
+ * @param code
+ * 授权码/人脸凭证
+ * @param body
+ * 商品或支付单简要描述,格式要求:门店品牌名-城市分店名-实际商品名称
+ * @param outTradeNo
+ * 商户系统内部的订单号,32个字符内、可包含字母;更换授权码必须要换新的商户订单号
+ * @param totalFee
+ * 订单总金额,单位元
+ * @param createIp
+ * 调用微信支付API的机器IP
+ * @param openId
+ * 用户在商户appid 下的唯一标识,人脸支付押金时提供
+ * @param attach
+ * 附加数据,在查询API和支付通知中原样返回,该字段主要用于商户携带订单的自定义数据,非必填
+ * @param store
+ * 门店信息,仅在付款码支付押金时提供,非必填
+ * @param isFacePay
+ * 是否人脸押金支付,否则是付款码押金支付
+ * @return
+ * @throws WeixinException
+ */
+ public MchPayRequest createDepositPayRequest(String code, String body,
+ String outTradeNo, double totalFee, String createIp, String openId,
+ String attach, SceneInfoStore store, boolean isFacePay) throws WeixinException{
+
+ return payApi.createDepositPayRequest(code, body, outTradeNo, totalFee, createIp, openId, attach, store, isFacePay);
+ }
+
+ /**
+ * 订单查询
+ *
+ * 当商户后台、网络、服务器等出现异常,商户系统最终未接收到支付通知; 调用支付接口后,返回系统错误或未知交易状态情况;
+ * 调用被扫支付API,返回USERPAYING的状态; 调用关单或撤销接口API之前,需确认支付状态;
+ *
+ *
+ * @param idQuery
+ * 商户系统内部的订单号, transaction_id、out_trade_no 二 选一,如果同时存在优先级:
+ * transaction_id> out_trade_no
+ * @since V3
+ * @see Order
+ * @see PayApi
+ * @see
+ * 订单查询API
+ * @return 订单详情
+ * @throws WeixinException
+ */
+ public Order queryOrder(IdQuery idQuery) throws WeixinException {
+ return payApi.queryOrder(idQuery);
+ }
+
+ /**
+ * 申请退款
+ *
+ * @see PayApi#applyRefund(IdQuery, String, double, double, CurrencyType, String, String, RefundAccountType)
+ */
+ public RefundResult applyRefund(IdQuery idQuery, String outRefundNo,
+ double totalFee, double refundFee, CurrencyType refundFeeType,
+ String opUserId, String refundDesc,
+ RefundAccountType refundAccountType) throws WeixinException {
+ return payApi.applyRefund(idQuery, outRefundNo, totalFee, refundFee,
+ refundFeeType, opUserId, refundDesc, refundAccountType);
+ }
+
+ /**
+ * 申请退款
+ *
+ * @see PayApi#applyRefund(IdQuery, String, double)
+ */
+ public RefundResult applyRefund(IdQuery idQuery, String outRefundNo,
+ double totalFee) throws WeixinException {
+ return payApi.applyRefund(idQuery, outRefundNo, totalFee);
+ }
+
+ /**
+ * 退款查询
+ *
+ * 提交退款申请后,通过调用该接口查询退款状态。退款有一定延时,用零钱支付的退款20分钟内到账,银行卡支付的退款3个工作日后重新查询退款状态。
+ *
+ *
+ * @param idQuery
+ * 单号 refund_id、out_refund_no、 out_trade_no 、 transaction_id
+ * 四个参数必填一个,优先级为:
+ * refund_id>out_refund_no>transaction_id>out_trade_no
+ * @return 退款记录
+ * @see PayApi
+ * @see RefundRecord
+ * @see
+ * 退款查询API
+ * @since V3
+ * @throws WeixinException
+ */
+ public RefundRecord queryRefund(IdQuery idQuery) throws WeixinException {
+ return payApi.queryRefund(idQuery);
+ }
+
+ /**
+ * 下载对账单
+ * 1.微信侧未成功下单的交易不会出现在对账单中。支付成功后撤销的交易会出现在对账 单中,跟原支付单订单号一致,bill_type 为
+ * REVOKED;
+ * 2.微信在次日 9 点启动生成前一天的对账单,建议商户 9 点半后再获取;
+ * 3.对账单中涉及金额的字段单位为“元”。
+ *
+ * @param billDate
+ * 下载对账单的日期
+ * @param billType
+ * 下载对账单的类型 ALL,返回当日所有订单信息, 默认值 SUCCESS,返回当日成功支付的订单
+ * REFUND,返回当日退款订单
+ * @para outputStream 输出流
+ * @param tarType
+ * 非必传参数,固定值:GZIP,返回格式为.gzip的压缩包账单。不传则默认为数据流形式。
+ * @since V2 & V3
+ * @see PayApi
+ * @see
+ * 下载对账单API
+ * @throws WeixinException
+ */
+ public void downloadBill(Date billDate, BillType billType,
+ OutputStream outputStream, TarType tarType) throws WeixinException {
+ payApi.downloadBill(billDate, billType, outputStream, tarType);
+ }
+
+ /**
+ * 冲正订单(需要证书) 当支付返回失败,或收银系统超时需要取消交易,可以调用该接口 接口逻辑:支
+ * 付失败的关单,支付成功的撤销支付 7天以内的单可撤销,其他正常支付的单
+ * 如需实现相同功能请调用退款接口 调用扣款接口后请勿立即调用撤销,需要等待5秒以上。先调用查单接口,如果没有确切的返回,再调用撤销
+ *
+ * @param idQuery
+ * 商户系统内部的订单号, transaction_id 、 out_trade_no 二选一,如果同时存在优先级:
+ * transaction_id> out_trade_no
+ * @return 撤销结果
+ * @see PayApi
+ * @since V3
+ * @throws WeixinException
+ */
+ public MerchantResult reverseOrder(IdQuery idQuery) throws WeixinException {
+ return payApi.reverseOrder(idQuery);
+ }
+
+ /**
+ * 关闭订单
+ *
+ * 商户订单支付失败需要生成新单号重新发起支付,要对原订单号调用关单,避免重复支付;系统下单后,用户支付超时,系统退出不再受理,避免用户继续
+ * ,请调用关单接口,如果关单失败,返回已完 成支付请按正常支付处理。如果出现银行掉单,调用关单成功后,微信后台会主动发起退款。
+ *
+ *
+ * @param outTradeNo
+ * 商户系统内部的订单号
+ * @return 执行结果
+ * @see PayApi
+ * @since V3
+ * @throws WeixinException
+ * @see
+ * 关闭订单API
+ */
+ public MerchantResult closeOrder(String outTradeNo) throws WeixinException {
+ return payApi.closeOrder(outTradeNo);
+ }
+
+ /**
+ * native支付URL转短链接:用于扫码原生支付模式一中的二维码链接转成短链接(weixin://wxpay/s/XXXXXX),减小二维码数据量
+ * ,提升扫描速度和精确度。
+ *
+ * @param url
+ * 具有native标识的支付URL
+ * @return 转换后的短链接
+ * @see PayApi
+ * @see
+ * 转换短链接API
+ * @since V3
+ * @throws WeixinException
+ */
+ public String getPayShorturl(String url) throws WeixinException {
+ return payApi.getShorturl(url);
+ }
+
+ /**
+ * 接口上报
+ *
+ * @param interfaceUrl
+ * 上报对应的接口的完整 URL, 类似: https://api.mch.weixin.q
+ * q.com/pay/unifiedorder
+ * @param executeTime
+ * 接口耗时情况,单位为毫秒
+ * @param outTradeNo
+ * 商户系统内部的订单号,商 户可以在上报时提供相关商户订单号方便微信支付更好 的提高服务质量。
+ * @param ip
+ * 发起接口调用时的机器 IP
+ * @param time
+ * 商户调用该接口时商户自己 系统的时间
+ * @param returnXml
+ * 调用接口返回的基本数据
+ * @return 处理结果
+ * @see PayApi
+ * @see
+ * 接口测试上报API
+ * @throws WeixinException
+ */
+ public XmlResult reportInterface(String interfaceUrl, int executeTime,
+ String outTradeNo, String ip, Date time, XmlResult returnXml)
+ throws WeixinException {
+ return payApi.reportInterface(interfaceUrl, executeTime, outTradeNo,
+ ip, time, returnXml);
+ }
+
+ /**
+ * 发放代金券(需要证书)
+ *
+ * @param couponStockId
+ * 代金券批次id
+ * @param partnerTradeNo
+ * 商户发放凭据号(格式:商户id+日期+流水号),商户侧需保持唯一性
+ * @param openId
+ * 用户的openid
+ * @param opUserId
+ * 操作员帐号, 默认为商户号 可在商户平台配置操作员对应的api权限 可为空
+ * @return 发放结果
+ * @see CouponApi
+ * @see CouponResult
+ * @see
+ * 发放代金券接口
+ * @throws WeixinException
+ */
+ public CouponResult sendCoupon(String couponStockId, String partnerTradeNo,
+ String openId, String opUserId) throws WeixinException {
+ return couponApi.sendCoupon(couponStockId, partnerTradeNo, openId,
+ opUserId);
+ }
+
+ /**
+ * 查询代金券批次
+ *
+ * @param couponStockId
+ * 代金券批次ID
+ * @return 代金券批次信息
+ * @see CouponApi
+ * @see CouponStock
+ * @see
+ * 查询代金券批次信息接口
+ * @throws WeixinException
+ */
+ public CouponStock queryCouponStock(String couponStockId)
+ throws WeixinException {
+ return couponApi.queryCouponStock(couponStockId);
+ }
+
+ /**
+ * 查询代金券详细
+ *
+ * @param openId
+ * 用户ID
+ * @param couponId
+ * 代金券ID
+ * @param stockId
+ * 代金劵对应的批次号
+ * @return 代金券详细信息
+ * @see CouponApi
+ * @see CouponDetail
+ * @see
+ * 查询代金券详细信息接口
+ * @throws WeixinException
+ */
+ public CouponDetail queryCouponDetail(String openId, String couponId,
+ String stockId) throws WeixinException {
+ return couponApi.queryCouponDetail(openId, couponId, stockId);
+ }
+
+ /**
+ * 发放红包 企业向微信用户个人发现金红包
+ *
+ * @param redpacket
+ * 红包信息
+ * @return 发放结果
+ * @see CashApi
+ * @see Redpacket
+ * @see RedpacketSendResult
+ * @see
+ * 发放现金红包接口
+ * @see
+ * 发放裂变红包接口
+ * @throws WeixinException
+ */
+ public RedpacketSendResult sendRedpack(Redpacket redpacket)
+ throws WeixinException {
+ return cashApi.sendRedpack(redpacket);
+ }
+
+ /**
+ * 批量发放红包 企业向微信用户个人发现金红包
+ *
+ * @param redpackets
+ * 多个红包信息
+ * @return 发放结果
+ * @see CashApi
+ * @see #sendRedpacks(Redpacket...)
+ * @throws WeixinException
+ */
+ public List> sendRedpacks(
+ Redpacket... redpackets) {
+ return cashApi.sendRedpacks(redpackets);
+ }
+
+ /**
+ * 查询红包记录
+ *
+ * @param outTradeNo
+ * 商户发放红包的商户订单号
+ * @return 红包记录
+ * @see CashApi
+ * @see RedpacketRecord
+ * @see
+ * 查询现金红包接口
+ * @see
+ * 查询裂变红包接口
+ * @throws WeixinException
+ */
+ public RedpacketRecord queryRedpack(String outTradeNo)
+ throws WeixinException {
+ return cashApi.queryRedpack(outTradeNo);
+ }
+
+ /**
+ * 企业付款
+ *
+ * @see CashApi#sendCorpPayment(CorpPayment)
+ */
+ public CorpPaymentResult sendCorpPayment(CorpPayment payment)
+ throws WeixinException {
+ return cashApi.sendCorpPayment(payment);
+ }
+
+ /**
+ * 企业付款查询 用于商户的企业付款操作进行结果查询,返回付款操作详细结果
+ *
+ * @param outTradeNo
+ * 商户调用企业付款API时使用的商户订单号
+ * @return 付款记录
+ * @see CashApi
+ * @see CorpPaymentRecord
+ * @see
+ * 企业付款查询接口
+ * @throws WeixinException
+ */
+ public CorpPaymentRecord queryCorpPayment(String outTradeNo)
+ throws WeixinException {
+ return cashApi.queryCorpPayment(outTradeNo);
+ }
+
+ /**
+ * 授权码查询OPENID
+ *
+ * @param authCode
+ * 扫码支付授权码,设备读取用户微信中的条码或者二维码信息
+ * @return 查询结果
+ * @see CashApi
+ * @see OpenIdResult
+ * @see
+ * 授权码查询OPENID
+ * @throws WeixinException
+ */
+ public OpenIdResult authCode2openId(String authCode) throws WeixinException {
+ return payApi.authCode2openId(authCode);
+ }
+
+ /**
+ * 查询结算资金
+ *
+ * @param status
+ * 是否结算
+ * @param pageable
+ * 分页数据
+ * @param start
+ * 开始日期 查询未结算记录时,该字段可不传
+ * @param end
+ * 结束日期 查询未结算记录时,该字段可不传
+ * @return 结算金额记录
+ * @throws WeixinException
+ * @see CashApi
+ * @see SettlementRecord
+ * @see
+ * 查询结算资金接口
+ */
+ public SettlementRecord querySettlement(boolean status, Pageable pageable,
+ Date start, Date end) throws WeixinException {
+ return cashApi.querySettlement(status, pageable, start, end);
+ }
+
+ /**
+ * 查询汇率
+ *
+ * @param currencyType
+ * 外币币种
+ * @param date
+ * 日期 不填则默认当天
+ * @return 汇率对象
+ * @throws WeixinException
+ * @see CashApi
+ * @see
+ * 查询汇率接口
+ */
+ public double queryExchageRate(CurrencyType currencyType, Date date)
+ throws WeixinException {
+ return cashApi.queryExchageRate(currencyType, date);
+ }
+
+ /**
+ * 订单附加信息提交
+ *
+ * @param customsOrder
+ * 附加订单信息
+ * @return 报关结果
+ * @see CustomsApi
+ * @see CustomsOrder
+ * @see CustomsOrderResult
+ * @see
+ * 附加订单信息提交接口
+ * @throws WeixinException
+ */
+ public CustomsOrderResult declareCustomsOrder(CustomsOrder customsOrder)
+ throws WeixinException {
+ return customsApi.declareCustomsOrder(customsOrder);
+ }
+
+ /**
+ * 订单附加信息查询
+ *
+ * @param idQuery
+ * out_trade_no,transaction_id,sub_order_no,sub_order_id四选一
+ * @param customsCity
+ * 海关
+ * @return 报关记录
+ * @see CustomsOrderRecord
+ * @see CustomsApi
+ * @see
+ * 附加订单信息查询接口
+ * @throws WeixinException
+ */
+ public CustomsOrderRecord queryCustomsOrder(IdQuery idQuery,
+ CustomsCity customsCity) throws WeixinException {
+ return customsApi.queryCustomsOrder(idQuery, customsCity);
+ }
+
+ /**
+ * 微信刷脸支付,获取调用凭证
+ *
+ * @param storeId
+ * 门店编号, 由商户定义, 各门店唯一。
+ * @param storeName
+ * 门店名称,由商户定义。(可用于展示)
+ * @param deviceId
+ * 终端设备编号,由商户定义。
+ * @param attach
+ * 附加字段。字段格式使用Json, 非必填
+ * @param rawdata
+ * 初始化数据。由微信人脸SDK的接口返回。
+ * @return SDK调用凭证
+ * @throws WeixinException
+ * @see
+ * 获取数据-getwxpayfacerawdata
+ * @see
+ * 获取调用凭证-get-wxpayface-authinfo
+ * @see PayfaceAuthinfo
+ */
+ public PayfaceAuthinfo getWxPayfaceAuthinfo(String storeId, String storeName, String deviceId,
+ String attach, String rawdata) throws WeixinException {
+ PayfaceAuthinfoRequest request = new PayfaceAuthinfoRequest(this.weixinPayAccount, storeId, storeName, deviceId,
+ attach, rawdata);
+ return payApi.getWxPayfaceAuthinfo(request);
+ }
+
+ public final static String VERSION = Consts.VERSION;
+}
diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/api/CashApi.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/api/CashApi.java
new file mode 100644
index 00000000..c02b7b0e
--- /dev/null
+++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/api/CashApi.java
@@ -0,0 +1,269 @@
+package com.foxinmy.weixin4j.pay.api;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.alibaba.fastjson.TypeReference;
+import com.foxinmy.weixin4j.exception.WeixinException;
+import com.foxinmy.weixin4j.http.weixin.WeixinResponse;
+import com.foxinmy.weixin4j.pay.model.WeixinPayAccount;
+import com.foxinmy.weixin4j.model.paging.Pageable;
+import com.foxinmy.weixin4j.pay.payment.mch.*;
+import com.foxinmy.weixin4j.pay.type.CurrencyType;
+import com.foxinmy.weixin4j.util.DateUtil;
+import com.foxinmy.weixin4j.util.RandomUtil;
+import com.foxinmy.weixin4j.util.StringUtil;
+import com.foxinmy.weixin4j.xml.XmlStream;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.*;
+
+/**
+ * 现金API
+ *
+ * @className CashApi
+ * @author jinyu(foxinmy@gmail.com)
+ * @date 2015年3月28日
+ * @since JDK 1.6
+ * @see
+ * 现金红包
+ * @see
+ * 企业付款
+ */
+public class CashApi extends MchApi {
+
+ public CashApi(WeixinPayAccount weixinAccount) {
+ super(weixinAccount);
+ }
+
+ /**
+ * 发放红包 企业向微信用户个人发现金红包
+ *
+ * @param redpacket
+ * 红包信息
+ * @return 发放结果
+ * @see Redpacket
+ * @see RedpacketSendResult
+ * @see
+ * 发放现金红包接口
+ * @see
+ * 发放裂变红包接口
+ * @throws WeixinException
+ */
+ public RedpacketSendResult sendRedpack(Redpacket redpacket)
+ throws WeixinException {
+ String appId = redpacket.getAppId();
+ super.declareMerchant(redpacket);
+ final JSONObject obj = (JSONObject) JSON.toJSON(redpacket);
+ if (StringUtil.isNotBlank(appId)) {
+ obj.put("appid", appId);
+ }
+ obj.put("wxappid", obj.remove("appid"));
+ final String redpack_uri = redpacket.getTotalNum() > 1 ? getRequestUri("groupredpack_send_uri")
+ : getRequestUri("redpack_send_uri");
+ obj.put("sign", weixinSignature.sign(obj));
+ String param = XmlStream.map2xml(obj);
+ WeixinResponse response = getWeixinSSLExecutor().post(redpack_uri,
+ param);
+ String text = response.getAsString()
+ .replaceFirst("", "")
+ .replaceFirst("", "");
+ return XmlStream.fromXML(text, RedpacketSendResult.class);
+ }
+
+ /**
+ * 批量发放红包 企业向微信用户个人发现金红包
+ *
+ * 多个红包信息
+ * @return 发放结果
+ * @see #sendRedpacks(Redpacket...)
+ * @throws WeixinException
+ */
+ public List> sendRedpacks(
+ Redpacket... redpackets) {
+ ExecutorService sendExecutor = Executors.newFixedThreadPool(Math.max(1,
+ redpackets.length / 10)); // 十分之一?
+ CompletionService completion = new ExecutorCompletionService(
+ sendExecutor);
+ List> callSendList = new ArrayList>(
+ redpackets.length);
+ for (final Redpacket redpacket : redpackets) {
+ Future futureSend = completion
+ .submit(new Callable() {
+ @Override
+ public RedpacketSendResult call() throws Exception {
+ return sendRedpack(redpacket);
+ }
+ });
+ callSendList.add(futureSend);
+ }
+ // 关闭启动线程,不再接受新的任务
+ sendExecutor.shutdown();
+ return callSendList;
+ }
+
+ /**
+ * 查询红包记录
+ *
+ * @param outTradeNo
+ * 商户发放红包的商户订单号
+ * @return 红包记录
+ * @see RedpacketRecord
+ * @see
+ * 查询现金红包接口
+ * @see
+ * 查询裂变红包接口
+ * @throws WeixinException
+ */
+ public RedpacketRecord queryRedpack(String outTradeNo)
+ throws WeixinException {
+ Map para = createBaseRequestMap(null);
+ para.put("bill_type", "MCHT");
+ para.put("mch_billno", outTradeNo);
+ para.put("sign", weixinSignature.sign(para));
+ String param = XmlStream.map2xml(para);
+ WeixinResponse response = getWeixinSSLExecutor().post(
+ getRequestUri("redpack_query_uri"), param);
+ return response.getAsObject(new TypeReference() {
+ });
+ }
+
+ /**
+ * 企业付款为企业提供付款至用户零钱的能力
+ *
+ * @param payment 付款信息
+ * @return 付款结果
+ * @see CorpPayment
+ * @see CorpPaymentResult
+ * @see 企业付款
+ * @see 场景介绍(使用条件、付款资金、付款规则等)
+ * @throws WeixinException
+ */
+ public CorpPaymentResult sendCorpPayment(CorpPayment payment)
+ throws WeixinException {
+ super.declareMerchant(payment);
+ JSONObject obj = (JSONObject) JSON.toJSON(payment);
+ obj.put("mchid", obj.remove("mch_id"));
+ obj.put("mch_appid", obj.remove("appid"));
+ obj.put("sign", weixinSignature.sign(obj));
+ String param = XmlStream.map2xml(obj);
+ WeixinResponse response = getWeixinSSLExecutor().post(
+ getRequestUri("corppayment_send_uri"), param);
+ String text = response.getAsString()
+ .replaceFirst("", "")
+ .replaceFirst("", "")
+ .replaceFirst("", "")
+ .replaceFirst("", "");
+ return XmlStream.fromXML(text, CorpPaymentResult.class);
+ }
+
+ /**
+ * 企业付款查询 用于商户的企业付款操作进行结果查询,返回付款操作详细结果
+ *
+ * @param outTradeNo
+ * 商户调用企业付款API时使用的商户订单号
+ * @return 付款记录
+ * @see CorpPaymentRecord
+ * @see
+ * 企业付款查询接口
+ * @throws WeixinException
+ */
+ public CorpPaymentRecord queryCorpPayment(String outTradeNo)
+ throws WeixinException {
+ JSONObject obj = new JSONObject();
+ obj.put("nonce_str", RandomUtil.generateString(16));
+ obj.put("mch_id", weixinAccount.getMchId());
+ obj.put("appid", weixinAccount.getId());
+ obj.put("partner_trade_no", outTradeNo);
+ obj.put("sign", weixinSignature.sign(obj));
+ String param = XmlStream.map2xml(obj);
+ WeixinResponse response = getWeixinSSLExecutor().post(
+ getRequestUri("corppayment_query_uri"), param);
+ return response.getAsObject(new TypeReference() {
+ });
+ }
+
+ /**
+ * 查询结算资金
+ *
+ * @param status
+ * 是否结算
+ * @param pageable
+ * 分页数据
+ * @param start
+ * 开始日期 查询未结算记录时,该字段可不传
+ * @param end
+ * 结束日期 查询未结算记录时,该字段可不传
+ * @return 结算金额记录
+ * @throws WeixinException
+ * @see SettlementRecord
+ * @see
+ * 查询结算资金接口
+ */
+ public SettlementRecord querySettlement(boolean status, Pageable pageable,
+ Date start, Date end) throws WeixinException {
+ JSONObject obj = new JSONObject();
+ obj.put("nonce_str", RandomUtil.generateString(16));
+ obj.put("mch_id", weixinAccount.getMchId());
+ obj.put("appid", weixinAccount.getId());
+ obj.put("usetag", status ? 1 : 2);
+ obj.put("offset", pageable.getOffset());
+ obj.put("limit", pageable.getPageSize());
+ if (start != null) {
+ obj.put("date_start", DateUtil.fortmat2yyyyMMdd(start));
+ }
+ if (end != null) {
+ obj.put("date_end", DateUtil.fortmat2yyyyMMdd(end));
+ }
+ obj.put("sign", weixinSignature.sign(obj));
+ String param = XmlStream.map2xml(obj);
+ WeixinResponse response = weixinExecutor.post(
+ getRequestUri("settlement_query_uri"), param);
+ return response.getAsObject(new TypeReference() {
+ });
+ }
+
+ /**
+ * 查询汇率
+ *
+ * @param currencyType
+ * 外币币种
+ * @param date
+ * 日期 不填则默认当天
+ * @return 汇率 例如美元兑换人民币的比例为6.5
+ * @throws WeixinException
+ * @see
+ * 查询汇率接口
+ */
+ public double queryExchageRate(CurrencyType currencyType, Date date)
+ throws WeixinException {
+ if (date == null) {
+ date = new Date();
+ }
+ JSONObject obj = new JSONObject();
+ obj.put("mch_id", weixinAccount.getMchId());
+ obj.put("appid", weixinAccount.getId());
+ obj.put("sub_mch_id", weixinAccount.getSubMchId());
+ obj.put("fee_type", currencyType.name());
+ obj.put("date", DateUtil.fortmat2yyyyMMdd(date));
+ obj.put("sign", weixinSignature.sign(obj));
+ String param = XmlStream.map2xml(obj);
+ WeixinResponse response = weixinExecutor.post(
+ getRequestUri("exchagerate_query_uri"), param);
+ BigDecimal rate = new BigDecimal(XmlStream.xml2map(
+ response.getAsString()).get("rate"));
+ return rate.divide(new BigDecimal(100000000d)).doubleValue();
+ }
+}
diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/api/CouponApi.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/api/CouponApi.java
new file mode 100644
index 00000000..67c80c13
--- /dev/null
+++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/api/CouponApi.java
@@ -0,0 +1,122 @@
+package com.foxinmy.weixin4j.pay.api;
+
+import com.alibaba.fastjson.TypeReference;
+import com.foxinmy.weixin4j.exception.WeixinException;
+import com.foxinmy.weixin4j.http.weixin.WeixinResponse;
+import com.foxinmy.weixin4j.pay.model.WeixinPayAccount;
+import com.foxinmy.weixin4j.pay.payment.coupon.CouponDetail;
+import com.foxinmy.weixin4j.pay.payment.coupon.CouponResult;
+import com.foxinmy.weixin4j.pay.payment.coupon.CouponStock;
+import com.foxinmy.weixin4j.util.StringUtil;
+import com.foxinmy.weixin4j.xml.XmlStream;
+
+import java.util.Map;
+
+/**
+ * 代金券API
+ *
+ * @className CouponApi
+ * @author jinyu(foxinmy@gmail.com)
+ * @date 2015年3月25日
+ * @since JDK 1.6
+ * @see 代金券
+ */
+public class CouponApi extends MchApi {
+
+ public CouponApi(WeixinPayAccount weixinAccount) {
+ super(weixinAccount);
+ }
+
+ /**
+ * 发放代金券(需要证书)
+ *
+ * @param couponStockId
+ * 代金券批次id
+ * @param partnerTradeNo
+ * 商户发放凭据号(格式:商户id+日期+流水号),商户侧需保持唯一性
+ * @param openId
+ * 用户的openid
+ * @param opUserId
+ * 操作员帐号, 默认为商户号 可在商户平台配置操作员对应的api权限 可为空
+ * @return 发放结果
+ * @see CouponResult
+ * @see 发放代金券接口
+ * @throws WeixinException
+ */
+ public CouponResult sendCoupon(String couponStockId, String partnerTradeNo,
+ String openId, String opUserId) throws WeixinException {
+ Map map = createBaseRequestMap(null);
+ map.put("coupon_stock_id", couponStockId);
+ map.put("partner_trade_no", partnerTradeNo);
+ map.put("openid", openId);
+ // openid记录数(目前支持num=1)
+ map.put("openid_count", "1");
+ // 操作员帐号, 默认为商户号 可在商户平台配置操作员对应的api权限
+ if (StringUtil.isBlank(opUserId)) {
+ opUserId = weixinAccount.getMchId();
+ }
+ map.put("op_user_id", opUserId);
+ map.put("version", "1.0");
+ map.put("type", "XML");
+ map.put("sign", weixinSignature.sign(map));
+ String param = XmlStream.map2xml(map);
+ WeixinResponse response = getWeixinSSLExecutor().post(
+ getRequestUri("coupon_send_uri"), param);
+ return response.getAsObject(new TypeReference() {
+ });
+ }
+
+ /**
+ * 查询代金券批次
+ *
+ * @param couponStockId
+ * 代金券批次ID
+ * @return 代金券批次信息
+ * @see CouponStock
+ * @see 查询代金券批次信息接口
+ * @throws WeixinException
+ */
+ public CouponStock queryCouponStock(String couponStockId)
+ throws WeixinException {
+ Map map = createBaseRequestMap(null);
+ map.put("coupon_stock_id", couponStockId);
+ map.put("sign", weixinSignature.sign(map));
+ String param = XmlStream.map2xml(map);
+ WeixinResponse response = weixinExecutor.post(
+ getRequestUri("couponstock_query_uri"), param);
+ return response.getAsObject(new TypeReference() {
+ });
+ }
+
+ /**
+ * 查询代金券详细
+ *
+ * @param openId
+ * 用户ID
+ * @param couponId
+ * 代金券ID
+ * @param stockId
+ * 代金劵对应的批次号
+ * @return 代金券详细信息
+ * @see CouponDetail
+ * @see 查询代金券详细信息接口
+ * @throws WeixinException
+ */
+ public CouponDetail queryCouponDetail(String openId, String couponId,
+ String stockId) throws WeixinException {
+ Map map = createBaseRequestMap(null);
+ map.put("openid", openId);
+ map.put("coupon_id", couponId);
+ map.put("stock_id", stockId);
+ map.put("sign", weixinSignature.sign(map));
+ String param = XmlStream.map2xml(map);
+ WeixinResponse response = weixinExecutor.post(
+ getRequestUri("coupondetail_query_uri"), param);
+ return response.getAsObject(new TypeReference() {
+ });
+ }
+}
\ No newline at end of file
diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/api/CustomsApi.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/api/CustomsApi.java
new file mode 100644
index 00000000..258396dc
--- /dev/null
+++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/api/CustomsApi.java
@@ -0,0 +1,84 @@
+package com.foxinmy.weixin4j.pay.api;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.alibaba.fastjson.TypeReference;
+import com.foxinmy.weixin4j.exception.WeixinException;
+import com.foxinmy.weixin4j.http.weixin.WeixinResponse;
+import com.foxinmy.weixin4j.pay.model.WeixinPayAccount;
+import com.foxinmy.weixin4j.pay.payment.mch.CustomsOrder;
+import com.foxinmy.weixin4j.pay.payment.mch.CustomsOrderRecord;
+import com.foxinmy.weixin4j.pay.payment.mch.CustomsOrderResult;
+import com.foxinmy.weixin4j.pay.type.CustomsCity;
+import com.foxinmy.weixin4j.pay.type.IdQuery;
+import com.foxinmy.weixin4j.xml.ListsuffixResultDeserializer;
+import com.foxinmy.weixin4j.xml.XmlStream;
+
+/**
+ * 报关接口
+ *
+ * @className CustomsApi
+ * @author jinyu(foxinmy@gmail.com)
+ * @date 2016年3月67日
+ * @since JDK 1.6
+ * @see
+ */
+public class CustomsApi extends MchApi {
+
+ public CustomsApi(WeixinPayAccount weixinAccount) {
+ super(weixinAccount);
+ }
+
+ /**
+ * 订单附加信息提交
+ *
+ * @param customsOrder
+ * 附加订单信息
+ * @return 报关结果
+ * @see CustomsOrder
+ * @see CustomsOrderResult
+ * @see 附加订单信息提交接口
+ * @throws WeixinException
+ */
+ public CustomsOrderResult declareCustomsOrder(CustomsOrder customsOrder)
+ throws WeixinException {
+ JSONObject para = (JSONObject) JSON.toJSON(customsOrder);
+ para.put("appid", weixinAccount.getId());
+ para.put("mch_id", weixinAccount.getMchId());
+ para.put("sign", weixinSignature.sign(para));
+ String param = XmlStream.map2xml(para);
+ WeixinResponse response = weixinExecutor.post(
+ getRequestUri("customsorder_declare_uri"), param);
+ return response.getAsObject(new TypeReference() {
+ });
+ }
+
+ /**
+ * 订单附加信息查询
+ *
+ * @param idQuery
+ * out_trade_no,transaction_id,sub_order_no,sub_order_id四选一
+ * @param customsCity
+ * 海关
+ * @return 报关记录
+ * @see CustomsOrderRecord
+ * @see 附加订单信息查询接口
+ * @throws WeixinException
+ */
+ public CustomsOrderRecord queryCustomsOrder(IdQuery idQuery,
+ CustomsCity customsCity) throws WeixinException {
+ JSONObject para = new JSONObject();
+ para.put("appid", weixinAccount.getId());
+ para.put("mch_id", weixinAccount.getMchId());
+ para.put(idQuery.getType().getName(), idQuery.getId());
+ para.put("customs", customsCity.name());
+ para.put("sign", weixinSignature.sign(para));
+ String param = XmlStream.map2xml(para);
+ WeixinResponse response = weixinExecutor.post(
+ getRequestUri("customsorder_query_uri"), param);
+ return ListsuffixResultDeserializer.deserialize(response.getAsString(),
+ CustomsOrderRecord.class);
+ }
+}
diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/api/MchApi.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/api/MchApi.java
new file mode 100644
index 00000000..104efa19
--- /dev/null
+++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/api/MchApi.java
@@ -0,0 +1,138 @@
+package com.foxinmy.weixin4j.pay.api;
+
+import com.foxinmy.weixin4j.api.BaseApi;
+import com.foxinmy.weixin4j.exception.WeixinException;
+import com.foxinmy.weixin4j.http.weixin.WeixinRequestExecutor;
+import com.foxinmy.weixin4j.pay.model.WeixinPayAccount;
+import com.foxinmy.weixin4j.pay.payment.mch.MerchantResult;
+import com.foxinmy.weixin4j.pay.sign.WeixinPaymentSignature;
+import com.foxinmy.weixin4j.pay.type.IdQuery;
+import com.foxinmy.weixin4j.pay.sign.WeixinSignature;
+import com.foxinmy.weixin4j.util.RandomUtil;
+import com.foxinmy.weixin4j.util.StringUtil;
+import com.foxinmy.weixin4j.util.Weixin4jConfigUtil;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.ResourceBundle;
+
+/**
+ * 商户支付
+ *
+ * @className MchApi
+ * @author jinyu(foxinmy@gmail.com)
+ * @date 2016年3月26日
+ * @since JDK 1.6
+ * @see 商户支付平台
+ */
+public class MchApi extends BaseApi {
+ private final static ResourceBundle WEIXIN_BUNDLE;
+
+ private final static String PEM_CERT_PREFIX = "-----BEGIN CERTIFICATE-----";
+
+ static {
+ WEIXIN_BUNDLE = ResourceBundle.getBundle("com/foxinmy/weixin4j/payment/weixin");
+ }
+
+ protected final WeixinPayAccount weixinAccount;
+ protected final WeixinSignature weixinSignature;
+ private volatile WeixinRequestExecutor weixinSSLExecutor;
+
+ public MchApi(WeixinPayAccount weixinAccount) {
+ this.weixinAccount = weixinAccount;
+ this.weixinSignature = new WeixinPaymentSignature(weixinAccount.getPaySignKey());
+ }
+
+ @Override
+ protected ResourceBundle weixinBundle() {
+ return WEIXIN_BUNDLE;
+ }
+
+ /**
+ * 支付接口请求基本数据
+ *
+ * @param idQuery
+ * ID信息 可为空
+ * @return 基础map
+ */
+ protected Map createBaseRequestMap(IdQuery idQuery) {
+ Map map = new HashMap();
+ map.put("appid", weixinAccount.getId());
+ map.put("mch_id", weixinAccount.getMchId());
+ map.put("nonce_str", RandomUtil.generateString(16));
+ if (StringUtil.isNotBlank(weixinAccount.getDeviceInfo())) {
+ map.put("device_info", weixinAccount.getDeviceInfo());
+ }
+ if (StringUtil.isNotBlank(weixinAccount.getSubId())) {
+ map.put("sub_appid", weixinAccount.getSubId());
+ }
+ if (StringUtil.isNotBlank(weixinAccount.getSubMchId())) {
+ map.put("sub_mch_id", weixinAccount.getSubMchId());
+ }
+ if (idQuery != null) {
+ map.put(idQuery.getType().getName(), idQuery.getId());
+ }
+ return map;
+ }
+
+ /**
+ * 微信签名类
+ *
+ * @return
+ */
+ public WeixinSignature getWeixinSignature() {
+ return this.weixinSignature;
+ }
+
+ /**
+ * 微信SSL
+ *
+ * @return
+ */
+ protected WeixinRequestExecutor getWeixinSSLExecutor() throws WeixinException {
+ if (weixinSSLExecutor == null) {
+ if(weixinAccount.getCertificateFile().startsWith(PEM_CERT_PREFIX)){
+ // 证书是PEM格式,直接使用PEM内容生成请求执行类
+ this.weixinSSLExecutor = weixinExecutor.createSSLRequestExecutor(weixinAccount.getMchId(),
+ weixinAccount.getCertificateFile(), weixinAccount.getCertificateKey());
+ }else {
+ // 证书是p12格式,读取证书文件并生成请求执行类
+ try {
+ InputStream is = null;
+ File certificate = new File(
+ Weixin4jConfigUtil.replaceClassPathValue(weixinAccount.getCertificateFile()));
+ if (!certificate.exists() || !certificate.isFile()) {
+ is = Weixin4jConfigUtil.CLASSLOADER.getResourceAsStream(certificate.getName());
+ } else {
+ is = new FileInputStream(certificate);
+ }
+ if (is == null) {
+ throw new WeixinException("Invalid certificate file : " + certificate.toString());
+ }
+ this.weixinSSLExecutor = weixinExecutor.createSSLRequestExecutor(weixinAccount.getCertificateKey(), is);
+ } catch (IOException e) {
+ throw new WeixinException("IO Error on createSSLRequestExecutor", e);
+ }
+ }
+ }
+ return this.weixinSSLExecutor;
+ }
+
+ /**
+ * 设置商户信息
+ *
+ * @param merchant
+ */
+ protected void declareMerchant(T merchant) {
+ merchant.setAppId(weixinAccount.getId());
+ merchant.setMchId(weixinAccount.getMchId());
+ merchant.setDeviceInfo(weixinAccount.getDeviceInfo());
+ merchant.setSubAppId(weixinAccount.getSubId());
+ merchant.setSubMchId(weixinAccount.getSubMchId());
+ merchant.setNonceStr(RandomUtil.generateString(16));
+ }
+}
diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/api/PayApi.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/api/PayApi.java
new file mode 100644
index 00000000..4ad38149
--- /dev/null
+++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/api/PayApi.java
@@ -0,0 +1,815 @@
+package com.foxinmy.weixin4j.pay.api;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.TypeReference;
+import com.foxinmy.weixin4j.exception.WeixinException;
+import com.foxinmy.weixin4j.http.weixin.WeixinResponse;
+import com.foxinmy.weixin4j.http.weixin.XmlResult;
+import com.foxinmy.weixin4j.pay.model.WeixinPayAccount;
+import com.foxinmy.weixin4j.pay.payment.face.PayfaceAuthinfo;
+import com.foxinmy.weixin4j.pay.payment.face.PayfaceAuthinfoRequest;
+import com.foxinmy.weixin4j.pay.payment.mch.*;
+import com.foxinmy.weixin4j.pay.type.mch.BillType;
+import com.foxinmy.weixin4j.pay.type.mch.DepositType;
+import com.foxinmy.weixin4j.pay.type.mch.RefundAccountType;
+import com.foxinmy.weixin4j.pay.type.*;
+import com.foxinmy.weixin4j.util.*;
+import com.foxinmy.weixin4j.xml.ListsuffixResultDeserializer;
+import com.foxinmy.weixin4j.xml.XmlStream;
+
+import java.io.*;
+import java.net.URLEncoder;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 支付API
+ *
+ * @className PayApi
+ * @author jinyu(foxinmy@gmail.com)
+ * @date 2014年10月28日
+ * @since JDK 1.6
+ */
+public class PayApi extends MchApi {
+
+ public PayApi(WeixinPayAccount weixinAccount) {
+ super(weixinAccount);
+ }
+
+ /**
+ * 统一下单接口
+ * 除被扫支付场景以外,商户系统先调用该接口在微信支付服务后台生成预支付交易单,返回正确的预支付交易回话标识后再按扫码、JSAPI
+ * 、APP等不同场景生成交易串调起支付。
+ *
+ * @param payPackage
+ * 包含订单信息的对象
+ * @see MchPayPackage
+ * @see PrePay
+ * @see 统一下单接口
+ *
+ * @return 预支付对象
+ */
+ public PrePay createPrePay(MchPayPackage payPackage) throws WeixinException {
+ super.declareMerchant(payPackage);
+ payPackage.setSign(weixinSignature.sign(payPackage));
+ String payJsRequestXml = XmlStream.toXML(payPackage);
+ WeixinResponse response = weixinExecutor.post(
+ getRequestUri("order_create_uri"), payJsRequestXml);
+ return response.getAsObject(new TypeReference() {
+ });
+ }
+
+ /**
+ * 创建支付请求对象
+ *
+ * @param payPackage
+ * 支付详情
+ * @return 支付请求对象
+ * @see JSAPIPayRequest JS支付
+ * @see NATIVEPayRequest 扫码支付
+ * @see MICROPayRequest 刷卡支付
+ * @see APPPayRequest APP支付
+ * @see WAPPayRequest WAP支付
+ * @throws WeixinException
+ */
+ public MchPayRequest createPayRequest(MchPayPackage payPackage)
+ throws WeixinException {
+ if (StringUtil.isBlank(payPackage.getTradeType())) {
+ throw new WeixinException("tradeType not be empty");
+ }
+ String tradeType = payPackage.getTradeType().toUpperCase();
+ if (TradeType.MICROPAY.name().equals(tradeType) || TradeType.FACEPAY.name().equals(tradeType)) {
+ MchPayPackage _payPackage = new MchPayPackage(payPackage.getBody(),
+ payPackage.getDetail(), payPackage.getOutTradeNo(),
+ DateUtil.formatFee2Yuan(payPackage.getTotalFee()), null,
+ null, payPackage.getCreateIp(), null, payPackage.getOpenId(),
+ payPackage.getAuthCode(), null, payPackage.getAttach(),
+ null, null, payPackage.getGoodsTag(),
+ payPackage.getLimitPay(), payPackage.getSubAppId(), payPackage.getFaceCode(),
+ payPackage.getDeposit());
+ // 默认为MD5签名
+ SignType signType= SignType.MD5;
+ super.declareMerchant(_payPackage);
+ // 默认为刷卡支付(付款码支付)的API地址
+ String url = getRequestUri("micropay_uri");
+ if(payPackage.getDeposit()==DepositType.Y){
+ // 押金支付只支持HMAC-SHA256签名
+ signType = SignType.HMAC$SHA256;
+ _payPackage.setSignType("HMAC-SHA256");
+ // 如果是押金支付,改为押金支付的API地址
+ url = TradeType.MICROPAY.name().equals(tradeType) ? getRequestUri("deposit_micropay_uri") :
+ getRequestUri("deposit_facepay_uri");
+ }else if(TradeType.FACEPAY.name().equals(tradeType)){
+ url = getRequestUri("facepay_url");
+ }
+ _payPackage.setSign(weixinSignature.sign(_payPackage, signType));
+ String para = XmlStream.toXML(_payPackage);
+
+ WeixinResponse response = weixinExecutor.post(url, para);
+ MICROPayRequest microPayRequest = response.getAsObject(new TypeReference() {});
+ microPayRequest.setPaymentAccount(weixinAccount);
+ return microPayRequest;
+ }
+ PrePay prePay = createPrePay(payPackage);
+ if (TradeType.APP.name().equals(tradeType)) {
+ return new APPPayRequest(prePay.getPrepayId(), weixinAccount);
+ } else if (TradeType.JSAPI.name().equals(tradeType)) {
+ return new JSAPIPayRequest(prePay.getPrepayId(), weixinAccount);
+ } else if (TradeType.NATIVE.name().equals(tradeType)) {
+ return new NATIVEPayRequest(prePay.getPrepayId(),
+ prePay.getPayUrl(), weixinAccount);
+ } else if (TradeType.MWEB.name().equals(tradeType)) {
+ return new WAPPayRequest(prePay.getPrepayId(), prePay.getPayUrl(),
+ weixinAccount);
+ } else {
+ throw new WeixinException("unknown tradeType:" + tradeType);
+ }
+ }
+
+ /**
+ * 创建JSAPI支付请求对象
+ *
+ * @param openId
+ * 用户ID
+ * @param body
+ * 订单描述
+ * @param outTradeNo
+ * 订单号
+ * @param totalFee
+ * 订单总额(元)
+ * @param notifyUrl
+ * 支付通知地址
+ * @param createIp
+ * ip地址
+ * @param attach
+ * 附加数据 非必填
+ * @see JSAPIPayRequest
+ * @return JSAPI支付对象
+ * @throws WeixinException
+ */
+ public MchPayRequest createJSPayRequest(String openId, String body,
+ String outTradeNo, double totalFee, String notifyUrl,
+ String createIp, String attach) throws WeixinException {
+ MchPayPackage payPackage = new MchPayPackage(body, outTradeNo,
+ totalFee, notifyUrl, createIp, TradeType.JSAPI, openId, null,
+ null, attach);
+ return createPayRequest(payPackage);
+ }
+
+ /**
+ * 创建Native支付(扫码支付)链接【模式一】
+ *
+ * @param productId
+ * 与订单ID等价
+ * @return 支付链接
+ * @see 扫码支付
+ *
+ * @see 模式一
+ *
+ */
+ public String createNativePayRequest(String productId) {
+ Map map = new HashMap();
+ String timestamp = DateUtil.timestamp2string();
+ String noncestr = RandomUtil.generateString(16);
+ map.put("appid", weixinAccount.getId());
+ map.put("mch_id", weixinAccount.getMchId());
+ map.put("time_stamp", timestamp);
+ map.put("nonce_str", noncestr);
+ map.put("product_id", productId);
+ String sign = weixinSignature.sign(map);
+ return String.format(getRequestUri("native_pay_uri"), sign,
+ weixinAccount.getId(), weixinAccount.getMchId(), productId,
+ timestamp, noncestr);
+ }
+
+ /**
+ * 创建Native支付(扫码支付)回调对象【模式一】
+ *
+ * @param productId
+ * 商品ID
+ * @param body
+ * 商品描述
+ * @param outTradeNo
+ * 商户内部唯一订单号
+ * @param totalFee
+ * 商品总额 单位元
+ * @param notifyUrl
+ * 支付回调URL
+ * @param createIp
+ * 订单生成的机器 IP
+ * @param attach
+ * 附加数据 非必填
+ * @return Native回调对象
+ * @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 {
+ MchPayPackage payPackage = new MchPayPackage(body, outTradeNo,
+ totalFee, notifyUrl, createIp, TradeType.NATIVE, null, null,
+ productId, attach);
+ PrePay prePay = createPrePay(payPackage);
+ return new NativePayResponse(weixinAccount, prePay.getPrepayId());
+ }
+
+ /**
+ * 创建Native支付(扫码支付)链接【模式二】
+ *
+ * @param productId
+ * 商品ID
+ * @param body
+ * 商品描述
+ * @param outTradeNo
+ * 商户内部唯一订单号
+ * @param totalFee
+ * 商品总额 单位元
+ * @param notifyUrl
+ * 支付回调URL
+ * @param createIp
+ * 订单生成的机器 IP
+ * @param attach
+ * 附加数据 非必填
+ * @return Native支付对象
+ * @see NATIVEPayRequest
+ * @see 扫码支付
+ *
+ * @see 模式二
+ *
+ * @throws WeixinException
+ */
+ public MchPayRequest createNativePayRequest(String productId, String body,
+ String outTradeNo, double totalFee, String notifyUrl,
+ String createIp, String attach) throws WeixinException {
+ MchPayPackage payPackage = new MchPayPackage(body, outTradeNo,
+ totalFee, notifyUrl, createIp, TradeType.NATIVE, null, null,
+ productId, attach);
+ return createPayRequest(payPackage);
+ }
+
+ /**
+ * 创建APP支付请求对象
+ *
+ * @param body
+ * 商品描述
+ * @param outTradeNo
+ * 商户内部唯一订单号
+ * @param totalFee
+ * 商品总额 单位元
+ * @param notifyUrl
+ * 支付回调URL
+ * @param createIp
+ * 订单生成的机器 IP
+ * @param attach
+ * 附加数据 非必填
+ * @param store
+ * 门店信息 非必填
+ * @return APP支付对象
+ * @see SceneInfoStore
+ * @see APPPayRequest
+ * @see
+ * APP支付
+ * @throws WeixinException
+ */
+ public MchPayRequest createAppPayRequest(String body, String outTradeNo,
+ double totalFee, String notifyUrl, String createIp, String attach,
+ SceneInfoStore store) throws WeixinException {
+ MchPayPackage payPackage = new MchPayPackage(body, outTradeNo,
+ totalFee, notifyUrl, createIp, TradeType.APP, null, null, null,
+ attach);
+ if (store != null) {
+ payPackage.setSceneInfo(String.format(
+ "{\"store_id\": \"%s\", \"store_name\":\"%s\"}",
+ store.getId(), store.getName()));
+ }
+ return createPayRequest(payPackage);
+ }
+
+ /**
+ * 创建WAP支付请求对象:正常流程用户支付完成后会返回至发起支付的页面,如需返回至指定页面,
+ * 则可以在MWEB_URL后拼接上redirect_url参数,来指定回调页面
+ *
+ * @param body
+ * 商品描述
+ * @param outTradeNo
+ * 商户内部唯一订单号
+ * @param totalFee
+ * 商品总额 单位元
+ * @param notifyUrl
+ * 支付回调URL
+ * @param createIp
+ * 订单生成的机器 IP
+ * @param attach
+ * 附加数据 非必填
+ * @param app
+ * 应用信息
+ * @return WAP支付对象
+ * @see SceneInfoApp
+ * @see WAPPayRequest
+ * @see WAP支付
+ *
+ * @throws WeixinException
+ */
+ public MchPayRequest createWapPayRequest(String body, String outTradeNo,
+ double totalFee, String notifyUrl, String createIp, String attach,
+ SceneInfoApp app) throws WeixinException {
+ MchPayPackage payPackage = new MchPayPackage(body, outTradeNo,
+ totalFee, notifyUrl, createIp, TradeType.MWEB, null, null,
+ null, attach);
+ if (app != null) {
+ payPackage.setSceneInfo(String.format("{\"h5_info\":\"%s\"}",
+ app.getSceneInfo()));
+ }
+ return createPayRequest(payPackage);
+ }
+
+ /**
+ * 提交被扫支付
+ *
+ * @param authCode
+ * 扫码支付授权码 ,设备读取用户微信中的条码或者二维码信息
+ * @param body
+ * 商品描述
+ * @param outTradeNo
+ * 商户内部唯一订单号
+ * @param totalFee
+ * 商品总额 单位元
+ * @param createIp
+ * 订单生成的机器 IP
+ * @param attach
+ * 附加数据 非必填
+ * @param store
+ * 门店信息 非必填
+ * @return 支付的订单信息
+ * @see MICROPayRequest
+ * @see Order
+ * @see SceneInfoStore
+ * @see
+ * 提交被扫支付API
+ * @throws WeixinException
+ */
+ public MchPayRequest createMicroPayRequest(String authCode, String body,
+ String outTradeNo, double totalFee, String createIp, String attach,
+ SceneInfoStore store) throws WeixinException {
+ MchPayPackage payPackage = new MchPayPackage(body, outTradeNo,
+ totalFee, null, createIp, TradeType.MICROPAY, null, authCode,
+ null, attach);
+ if (store != null) {
+ payPackage.setSceneInfo(String.format("{\"store_info\":\"%s\"}",
+ JSON.toJSONString(store)));
+ }
+ return createPayRequest(payPackage);
+ }
+
+ /**
+ * 订单查询
+ *
+ * 当商户后台、网络、服务器等出现异常,商户系统最终未接收到支付通知; 调用支付接口后,返回系统错误或未知交易状态情况;
+ * 调用被扫支付API,返回USERPAYING的状态; 调用关单或撤销接口API之前,需确认支付状态;
+ *
+ *
+ * @param idQuery
+ * 商户系统内部的订单号, transaction_id、out_trade_no 二 选一,如果同时存在优先级:
+ * transaction_id> out_trade_no
+ * @return 订单信息
+ * @see Order
+ * @see
+ * 订单查询API
+ * @since V3
+ * @throws WeixinException
+ */
+ public Order queryOrder(IdQuery idQuery) throws WeixinException {
+ Map map = createBaseRequestMap(idQuery);
+ map.put("sign", weixinSignature.sign(map));
+ String param = XmlStream.map2xml(map);
+ WeixinResponse response = weixinExecutor.post(
+ getRequestUri("order_query_uri"), param);
+ return ListsuffixResultDeserializer.deserialize(response.getAsString(),
+ Order.class);
+ }
+
+ /**
+ * 申请退款(请求需要双向证书)
+ *
+ *
+ * 当交易发生之后一段时间内,由于买家或者卖家的原因需要退款时,卖家可以通过退款接口将支付款退还给买家,微信支付将在收到退款请求并且验证成功之后,
+ * 按照退款规则将支付款按原路退到买家帐号上。
+ *
+ *
+ *
+ * - 交易时间超过一年的订单无法提交退款;
+ * -
+ * 微信支付退款支持单笔交易分多次退款,多次退款需要提交原支付订单的商户订单号和设置不同的退款单号。
+ * 申请退款总金额不能超过订单金额。
+ * 一笔退款失败后重新提交,请不要更换退款单号,请使用原商户退款单号。
+ *
+ * -
+ * 请求频率限制:150qps,即每秒钟正常的申请退款请求次数不超过150次。
+ * 错误或无效请求频率限制:6qps,即每秒钟异常或错误的退款申请请求不超过6次。
+ *
+ * - 每个支付订单的部分退款次数不能超过50次。
+ *
+ *
+ * @param idQuery
+ * 商户系统内部的订单号, transaction_id 、 out_trade_no 二选一,如果同时存在优先级:
+ * transaction_id> out_trade_no
+ * @param outRefundNo
+ * 商户系统内部的退款单号,商 户系统内部唯一,同一退款单号多次请求只退一笔
+ * @param totalFee
+ * 订单总金额,单位为元
+ * @param refundFee
+ * 退款总金额,单位为元,可以做部分退款
+ * @param refundFeeType
+ * 货币类型,符合ISO 4217标准的三位字母代码,默认人民币:CNY
+ * @param opUserId
+ * 操作员帐号, 默认为商户号
+ * @param refundDesc
+ * 退款原因,若商户传入,会在下发给用户的退款消息中体现退款原因
+ * @param refundAccountType
+ * 退款资金来源,默认使用未结算资金退款:REFUND_SOURCE_UNSETTLED_FUNDS
+ * @return 退款申请结果
+ * @see RefundResult
+ * @see
+ * 申请退款API
+ * @since V3
+ * @throws WeixinException
+ */
+ public RefundResult applyRefund(IdQuery idQuery, String outRefundNo,
+ double totalFee, double refundFee, CurrencyType refundFeeType,
+ String opUserId, String refundDesc,
+ RefundAccountType refundAccountType) throws WeixinException {
+ Map map = createBaseRequestMap(idQuery);
+ map.put("out_refund_no", outRefundNo);
+ map.put("total_fee",
+ Integer.toString(DateUtil.formatYuan2Fen(totalFee)));
+ map.put("refund_fee",
+ Integer.toString(DateUtil.formatYuan2Fen(refundFee)));
+ if (StringUtil.isBlank(opUserId)) {
+ opUserId = weixinAccount.getMchId();
+ }
+ map.put("op_user_id", opUserId);
+ if (refundFeeType == null) {
+ refundFeeType = CurrencyType.CNY;
+ }
+ if (refundAccountType == null) {
+ refundAccountType = RefundAccountType.REFUND_SOURCE_UNSETTLED_FUNDS;
+ }
+ if (StringUtil.isNotBlank(refundDesc)) {
+ map.put("refund_desc", refundDesc);
+ }
+ map.put("refund_fee_type", refundFeeType.name());
+ map.put("refund_account", refundAccountType.name());
+ map.put("sign", weixinSignature.sign(map));
+ String param = XmlStream.map2xml(map);
+ WeixinResponse response = getWeixinSSLExecutor().post(
+ getRequestUri("refund_apply_uri"), param);
+ return response.getAsObject(new TypeReference() {
+ });
+ }
+
+ /**
+ * 退款申请(全额退款)
+ *
+ * @param idQuery
+ * 商户系统内部的订单号, transaction_id 、 out_trade_no 二选一,如果同时存在优先级:
+ * transaction_id> out_trade_no
+ * @param outRefundNo
+ * 商户系统内部的退款单号,商 户系统内部唯一,同一退款单号多次请求只退一笔
+ * @param totalFee
+ * 订单总金额,单位为元
+ * @see #applyRefund(IdQuery, String, double, double, CurrencyType, String, String, RefundAccountType)
+ */
+ public RefundResult applyRefund(IdQuery idQuery, String outRefundNo,
+ double totalFee) throws WeixinException {
+ return applyRefund(idQuery, outRefundNo, totalFee, totalFee, null,
+ null, null, null);
+ }
+
+ /**
+ * 冲正订单(需要证书) 当支付返回失败,或收银系统超时需要取消交易,可以调用该接口 接口逻辑:支
+ * 付失败的关单,支付成功的撤销支付 7天以内的单可撤销,其他正常支付的单
+ * 如需实现相同功能请调用退款接口 调用扣款接口后请勿立即调用撤销,需要等待5秒以上。先调用查单接口,如果没有确切的返回,再调用撤销
+ *
+ * @param idQuery
+ * 商户系统内部的订单号, transaction_id 、 out_trade_no 二选一,如果同时存在优先级:
+ * transaction_id> out_trade_no
+ * @return 撤销结果
+ * @since V3
+ * @throws WeixinException
+ */
+ public MerchantResult reverseOrder(IdQuery idQuery) throws WeixinException {
+ Map map = createBaseRequestMap(idQuery);
+ map.put("sign", weixinSignature.sign(map));
+ String param = XmlStream.map2xml(map);
+ WeixinResponse response = getWeixinSSLExecutor().post(
+ getRequestUri("order_reverse_uri"), param);
+ return response.getAsObject(new TypeReference() {
+ });
+ }
+
+ /**
+ * native支付URL转短链接:用于扫码原生支付模式一中的二维码链接转成短链接(weixin://wxpay/s/XXXXXX),减小二维码数据量
+ * ,提升扫描速度和精确度。
+ *
+ * @param url
+ * 具有native标识的支付URL
+ * @return 转换后的短链接
+ * @throws WeixinException
+ * @see
+ * 转换短链接API
+ */
+ public String getShorturl(String url) throws WeixinException {
+ Map map = createBaseRequestMap(null);
+ try {
+ map.put("long_url", URLEncoder.encode(url, Consts.UTF_8.name()));
+ } catch (UnsupportedEncodingException e) {
+ ;
+ }
+ map.put("sign", weixinSignature.sign(map));
+ String param = XmlStream.map2xml(map);
+ WeixinResponse response = weixinExecutor.post(
+ getRequestUri("longurl_convert_uri"), param);
+ map = XmlStream.xml2map(response.getAsString());
+ return map.get("short_url");
+ }
+
+ /**
+ * 关闭订单
+ *
+ * 商户订单支付失败需要生成新单号重新发起支付,要对原订单号调用关单,避免重复支付;系统下单后,用户支付超时,系统退出不再受理,避免用户继续
+ * ,请调用关单接口,如果关单失败,返回已完 成支付请按正常支付处理。如果出现银行掉单,调用关单成功后,微信后台会主动发起退款。
+ *
+ *
+ * @param outTradeNo
+ * 商户系统内部的订单号
+ * @return 处理结果
+ * @since V3
+ * @throws WeixinException
+ * @see
+ * 关闭订单API
+ */
+ public MerchantResult closeOrder(String outTradeNo) throws WeixinException {
+ Map map = createBaseRequestMap(new IdQuery(outTradeNo,
+ IdType.TRADENO));
+ map.put("sign", weixinSignature.sign(map));
+ String param = XmlStream.map2xml(map);
+ WeixinResponse response = weixinExecutor.post(
+ getRequestUri("order_close_uri"), param);
+ return response.getAsObject(new TypeReference() {
+ });
+ }
+
+ /**
+ * 下载对账单
+ * 1.微信侧未成功下单的交易不会出现在对账单中。支付成功后撤销的交易会出现在对账 单中,跟原支付单订单号一致,bill_type 为
+ * REVOKED;
+ * 2.微信在次日 9 点启动生成前一天的对账单,建议商户 9 点半后再获取;
+ * 3.对账单中涉及金额的字段单位为“元”。
+ *
+ * @param billDate
+ * 下载对账单的日期
+ * @param billType
+ * 下载对账单的类型 ALL,返回当日所有订单信息, 默认值 SUCCESS,返回当日成功支付的订单
+ * REFUND,返回当日退款订单
+ * @param outputStream
+ * 输出流
+ * @param tarType
+ * 非必传参数,固定值:GZIP,返回格式为.gzip的压缩包账单。不传则默认为数据流形式。
+ * @since V3
+ * @see
+ * 下载对账单API
+ * @throws WeixinException
+ */
+ public void downloadBill(Date billDate, BillType billType,
+ OutputStream outputStream, TarType tarType) throws WeixinException {
+ if (billDate == null) {
+ Calendar now = Calendar.getInstance();
+ now.add(Calendar.DAY_OF_MONTH, -1);
+ billDate = now.getTime();
+ }
+ if (billType == null) {
+ billType = BillType.ALL;
+ }
+ String formatBillDate = DateUtil.fortmat2yyyyMMdd(billDate);
+ Map map = createBaseRequestMap(null);
+ map.put("bill_date", formatBillDate);
+ map.put("bill_type", billType.name());
+ if (tarType != null) {
+ map.put("tar_type", tarType.name());
+ }
+ map.put("sign", weixinSignature.sign(map));
+ String param = XmlStream.map2xml(map);
+ WeixinResponse response = weixinExecutor.post(
+ getRequestUri("downloadbill_uri"), param);
+
+ if (TarType.GZIP == tarType) {
+ try {
+ IOUtil.copy(response.getBody(), outputStream);
+ } catch (IOException e) {
+ ;
+ }
+ } else {
+ BufferedReader reader = null;
+ BufferedWriter writer = null;
+ try {
+ writer = new BufferedWriter(new OutputStreamWriter(
+ outputStream, Consts.UTF_8));
+ reader = new BufferedReader(new InputStreamReader(
+ response.getBody(), Consts.UTF_8));
+ String line = null;
+ while ((line = reader.readLine()) != null) {
+ writer.write(line);
+ writer.newLine();
+ }
+ } catch (IOException e) {
+ throw new WeixinException(e);
+ } finally {
+ try {
+ if (reader != null) {
+ reader.close();
+ }
+ if (writer != null) {
+ writer.close();
+ }
+ } catch (IOException ignore) {
+ ;
+ }
+ }
+ }
+ }
+
+ /**
+ * 退款查询
+ *
+ *
+ * 提交退款申请后,通过调用该接口查询退款状态。退款有一定延时,用零钱支付的退款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 RefundRecord
+ * @see com.foxinmy.weixin4j.payment.mch.RefundDetail
+ * @see
+ * 退款查询API
+ * @since V3
+ * @throws WeixinException
+ */
+ public RefundRecord queryRefund(IdQuery idQuery) throws WeixinException {
+ Map map = createBaseRequestMap(idQuery);
+ map.put("sign", weixinSignature.sign(map));
+ String param = XmlStream.map2xml(map);
+ WeixinResponse response = weixinExecutor.post(
+ getRequestUri("refund_query_uri"), param);
+ return ListsuffixResultDeserializer.deserialize(response.getAsString(),
+ RefundRecord.class);
+ }
+
+ /**
+ * 接口上报
+ *
+ * @param interfaceUrl
+ * 上报对应的接口的完整 URL, 类似: https://api.mch.weixin.q
+ * q.com/pay/unifiedorder
+ * @param executeTime
+ * 接口耗时情况,单位为毫秒
+ * @param outTradeNo
+ * 商户系统内部的订单号,商 户可以在上报时提供相关商户订单号方便微信支付更好 的提高服务质量。
+ * @param ip
+ * 发起接口调用时的机器 IP
+ * @param time
+ * 商户调用该接口时商户自己 系统的时间
+ * @param returnXml
+ * 调用接口返回的基本数据
+ * @return 处理结果
+ * @throws WeixinException
+ * @see
+ * 交易保障
+ */
+ @SuppressWarnings("unchecked")
+ public XmlResult reportInterface(String interfaceUrl, int executeTime,
+ String outTradeNo, String ip, Date time, XmlResult returnXml)
+ throws WeixinException {
+ Map map = createBaseRequestMap(null);
+ map.put("interface_url", interfaceUrl);
+ map.put("execute_time_", Integer.toString(executeTime));
+ map.put("out_trade_no", outTradeNo);
+ map.put("user_ip", ip);
+ map.put("time", DateUtil.fortmat2yyyyMMddHHmmss(time));
+ map.putAll((Map) JSON.toJSON(returnXml));
+ map.put("sign", weixinSignature.sign(map));
+ String param = XmlStream.map2xml(map);
+ WeixinResponse response = weixinExecutor.post(
+ getRequestUri("interface_report_uri"), param);
+ return response.getAsXml();
+ }
+
+ /**
+ * 授权码查询OPENID接口
+ *
+ * @param authCode
+ * 扫码支付授权码,设备读取用户微信中的条码或者二维码信息
+ * @return 查询结果
+ * @see OpenIdResult
+ * @see
+ * 授权码查询OPENID
+ * @throws WeixinException
+ */
+ public OpenIdResult authCode2openId(String authCode) throws WeixinException {
+ Map map = createBaseRequestMap(null);
+ map.put("auth_code", authCode);
+ map.put("sign", weixinSignature.sign(map));
+ String param = XmlStream.map2xml(map);
+ WeixinResponse response = weixinExecutor.post(
+ getRequestUri("authcode_openid_uri"), param);
+ return response.getAsObject(new TypeReference() {
+ });
+ }
+
+ /**
+ * 微信刷脸支付,获取调用凭证
+ *
+ * @param request
+ * @return
+ * @see
+ * 获取调用凭证-get-wxpayface-authinfo
+ */
+ public PayfaceAuthinfo getWxPayfaceAuthinfo(PayfaceAuthinfoRequest request) throws WeixinException {
+ WeixinResponse response = weixinExecutor.post(
+ getRequestUri("get_wxpayface_authinfo_uri"), request.toRequestString());
+ return response.getAsObject(new TypeReference() {});
+ }
+
+ /**
+ * 微信旧版刷脸支付
+ *
+ * @param faceCode
+ * @param body
+ * @param outTradeNo
+ * @param totalFee
+ * @param createIp
+ * @param openId
+ * @param attach
+ * @return
+ * @throws WeixinException
+ */
+ public MchPayRequest createFacePayRequest(String faceCode, String body,
+ String outTradeNo, double totalFee, String createIp, String openId,
+ String attach) throws WeixinException {
+ MchPayPackage payPackage = new MchPayPackage(body, outTradeNo,
+ totalFee, null, createIp, TradeType.FACEPAY, openId, null,
+ null, attach);
+ payPackage.setFaceCode(faceCode);
+ return createPayRequest(payPackage);
+ }
+
+ public MchPayRequest createDepositPayRequest(String code, String body, String outTradeNo, double totalFee,
+ String createIp, String openId, String attach, SceneInfoStore store,
+ boolean isFacePay) throws WeixinException {
+ MchPayPackage payPackage;
+ if(isFacePay) {
+ payPackage = new MchPayPackage(body, outTradeNo, totalFee, null, createIp, TradeType.FACEPAY,
+ openId, null, null, attach);
+ payPackage.setFaceCode(code);
+ payPackage.setDeposit(DepositType.Y);
+ return createPayRequest(payPackage);
+ }else{
+ payPackage = new MchPayPackage(body, outTradeNo, totalFee, null, createIp, TradeType.MICROPAY,
+ openId, code, null, attach);
+ payPackage.setDeposit(DepositType.Y);
+ if (store != null) {
+ payPackage.setSceneInfo(String.format("{\"store_info\":\"%s\"}",
+ JSON.toJSONString(store)));
+ }
+ return createPayRequest(payPackage);
+ }
+ }
+}
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/coupon/CouponDetail.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/coupon/CouponDetail.java
new file mode 100644
index 00000000..949e02bb
--- /dev/null
+++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/coupon/CouponDetail.java
@@ -0,0 +1,377 @@
+package com.foxinmy.weixin4j.pay.payment.coupon;
+
+import com.alibaba.fastjson.annotation.JSONField;
+import com.foxinmy.weixin4j.pay.payment.mch.MerchantResult;
+import com.foxinmy.weixin4j.pay.type.mch.CouponStatus;
+import com.foxinmy.weixin4j.pay.type.mch.CouponStockType;
+import com.foxinmy.weixin4j.pay.type.mch.CouponType;
+import com.foxinmy.weixin4j.util.DateUtil;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import java.util.Date;
+
+/**
+ * 代金券详细
+ *
+ * @className CouponDetail
+ * @author jinyu(foxinmy@gmail.com)
+ * @date 2015年3月27日
+ * @since JDK 1.6
+ * @see
+ */
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.FIELD)
+public class CouponDetail extends MerchantResult {
+
+ private static final long serialVersionUID = -311265355895457070L;
+
+ /**
+ * 代金券批次Id
+ */
+ @XmlElement(name = "coupon_stock_id")
+ @JSONField(name = "coupon_stock_id")
+ private String couponStockId;
+
+ /**
+ * 批次类型;1-批量型,2-触发型
+ */
+ @XmlElement(name = "coupon_stock_type")
+ @JSONField(name = "coupon_stock_type")
+ private int couponStockType;
+
+ /**
+ * 代金券id
+ */
+ @XmlElement(name = "coupon_id")
+ @JSONField(name = "coupon_id")
+ private String couponId;
+ /**
+ * 代金券面值,单位是分
+ */
+ @XmlElement(name = "coupon_value")
+ @JSONField(name = "coupon_value")
+ private int couponValue;
+
+ /**
+ * 代金券使用最低限额,单位是分
+ */
+ @XmlElement(name = "coupon_mininum")
+ @JSONField(name = "coupon_mininum")
+ private int couponMininum;
+ /**
+ * 代金券名称
+ */
+ @XmlElement(name = "coupon_name")
+ @JSONField(name = "coupon_name")
+ private String couponName;
+ /**
+ * 代金券状态:2-已激活,4-已锁定,8-已实扣
+ */
+ @XmlElement(name = "coupon_state")
+ @JSONField(name = "coupon_state")
+ private int couponStatus;
+ /**
+ * 代金券类型:1-代金券无门槛,2-代金券有门槛互斥,3-代金券有门槛叠加,
+ */
+ @XmlElement(name = "coupon_type")
+ @JSONField(name = "coupon_type")
+ private int couponType;
+ /**
+ * 代金券描述
+ */
+ @XmlElement(name = "coupon_desc")
+ @JSONField(name = "coupon_desc")
+ private String couponDesc;
+
+ /**
+ * 代金券实际使用金额
+ */
+ @XmlElement(name = "coupon_use_value")
+ @JSONField(name = "coupon_use_value")
+ private int couponUseValue;
+
+ /**
+ * 代金券剩余金额:部分使用情况下,可能会存在券剩余金额
+ */
+ @XmlElement(name = "coupon_remain_value")
+ @JSONField(name = "coupon_remain_value")
+ private int couponRemainValue;
+
+ /**
+ * 生效开始时间:格式为yyyyMMddhhmmss,如2009年12月27日9点10分10秒表示为20091227091010。
+ */
+ @XmlElement(name = "begin_time")
+ @JSONField(name = "begin_time")
+ private String beginTime;
+
+ /**
+ * 生效结束时间:格式为yyyyMMddhhmmss,如2009年12月27日9点10分10秒表示为20091227091010。
+ */
+ @XmlElement(name = "end_time")
+ @JSONField(name = "end_time")
+ private String endTime;
+
+ /**
+ * 发放时间:格式为yyyyMMddhhmmss,如2009年12月27日9点10分10秒表示为20091227091010。
+ */
+ @XmlElement(name = "send_time")
+ @JSONField(name = "send_time")
+ private String sendTime;
+
+ /**
+ * 使用时间:格式为yyyyMMddhhmmss,如2009年12月27日9点10分10秒表示为20091227091010。
+ */
+ @XmlElement(name = "use_time")
+ @JSONField(name = "use_time")
+ private String useTime;
+
+ /**
+ * 使用单号:代金券使用后,关联的大单收单单号
+ */
+ @XmlElement(name = "trade_no")
+ @JSONField(name = "trade_no")
+ private String tradeNo;
+
+ /**
+ * 消耗方商户id:代金券使用后,消耗方商户id
+ */
+ @XmlElement(name = "consumer_mch_id")
+ @JSONField(name = "consumer_mch_id")
+ private String consumerMchId;
+
+ /**
+ * 消耗方商户名称:代金券使用后,消耗方商户名称
+ */
+ @XmlElement(name = "consumer_mch_name")
+ @JSONField(name = "consumer_mch_name")
+ private String consumerMchName;
+
+ /**
+ * 消耗方商户appid:代金券使用后,消耗方商户appid
+ */
+ @XmlElement(name = "consumer_mch_appid")
+ @JSONField(name = "consumer_mch_appid")
+ private String consumerMchAppid;
+
+ /**
+ * 发放来源:代金券发放来源
+ */
+ @XmlElement(name = "send_source")
+ @JSONField(name = "send_source")
+ private String sendSource;
+
+ /**
+ * 是否允许部分使用:该代金券是否允许部分使用标识:1-表示支持部分使用
+ */
+ @XmlElement(name = "is_partial_use")
+ @JSONField(name = "is_partial_use")
+ private int isPartialUse;
+
+ public CouponDetail() {
+
+ }
+
+ public String getCouponStockId() {
+ return couponStockId;
+ }
+
+ public int getCouponStockType() {
+ return couponStockType;
+ }
+
+ @JSONField(serialize = false)
+ public CouponStockType getFormatCouponStockType() {
+ for (CouponStockType couponStockType : CouponStockType.values()) {
+ if (couponStockType.getVal() == this.couponStockType) {
+ return couponStockType;
+ }
+ }
+ return null;
+ }
+
+ public String getCouponId() {
+ return couponId;
+ }
+
+ public int getCouponValue() {
+ return couponValue;
+ }
+
+ /**
+ * 调用接口获取单位为分,get方法转换为元方便使用
+ *
+ * @return 元单位
+ */
+ @JSONField(serialize = false)
+ public double getFormatCouponValue() {
+ return couponValue / 100d;
+ }
+
+ public int getCouponMininum() {
+ return couponMininum;
+ }
+
+ /**
+ * 调用接口获取单位为分,get方法转换为元方便使用
+ *
+ * @return 元单位
+ */
+ @JSONField(serialize = false)
+ public double getFormatCouponMininum() {
+ return couponMininum / 100d;
+ }
+
+ public String getCouponName() {
+ return couponName;
+ }
+
+ public int getCouponStatus() {
+ return couponStatus;
+ }
+
+ @JSONField(serialize = false)
+ public CouponStatus getFormatCouponStatus() {
+ for (CouponStatus couponStatus : CouponStatus.values()) {
+ if (couponStatus.getVal() == this.couponStatus) {
+ return couponStatus;
+ }
+ }
+ return null;
+ }
+
+ public int getCouponType() {
+ return couponType;
+ }
+
+ @JSONField(deserialize = false, serialize = false)
+ public CouponType getFormatCouponType() {
+ for (CouponType couponType : CouponType.values()) {
+ if (couponType.getVal() == this.couponType) {
+ return couponType;
+ }
+ }
+ return null;
+ }
+
+ public String getCouponDesc() {
+ return couponDesc;
+ }
+
+ public int getCouponUseValue() {
+ return couponUseValue;
+ }
+
+ /**
+ * 调用接口获取单位为分,get方法转换为元方便使用
+ *
+ * @return 元单位
+ */
+ @JSONField(serialize = false)
+ public double getFormatCouponUseValue() {
+ return couponUseValue / 100d;
+ }
+
+ public int getCouponRemainValue() {
+ return couponRemainValue;
+ }
+
+ /**
+ * 调用接口获取单位为分,get方法转换为元方便使用
+ *
+ * @return 元单位
+ */
+ @JSONField(serialize = false)
+ public double getFormatCouponRemainValue() {
+ return couponRemainValue / 100d;
+ }
+
+ public String getBeginTime() {
+ return beginTime;
+ }
+
+ @JSONField(serialize = false)
+ public Date getFormatBeginTime() {
+ return beginTime != null ? DateUtil.parse2yyyyMMddHHmmss(beginTime)
+ : null;
+ }
+
+ public String getEndTime() {
+ return endTime;
+ }
+
+ @JSONField(serialize = false)
+ public Date getFormatEndTime() {
+ return endTime != null ? DateUtil.parse2yyyyMMddHHmmss(endTime) : null;
+ }
+
+ public String getSendTime() {
+ return sendTime;
+ }
+
+ @JSONField(serialize = false)
+ public Date getFormatSendTime() {
+ return sendTime != null ? DateUtil.parse2yyyyMMddHHmmss(sendTime)
+ : null;
+ }
+
+ public String getUseTime() {
+ return useTime;
+ }
+
+ @JSONField(serialize = false)
+ public Date getFormatUseTime() {
+ return useTime != null ? DateUtil.parse2yyyyMMddHHmmss(useTime) : null;
+ }
+
+ public String getTradeNo() {
+ return tradeNo;
+ }
+
+ public String getConsumerMchId() {
+ return consumerMchId;
+ }
+
+ public String getConsumerMchName() {
+ return consumerMchName;
+ }
+
+ public String getConsumerMchAppid() {
+ return consumerMchAppid;
+ }
+
+ public String getSendSource() {
+ return sendSource;
+ }
+
+ public int getIsPartialUse() {
+ return isPartialUse;
+ }
+
+ @JSONField(serialize = false)
+ public boolean getFormatIsPartialUse() {
+ return isPartialUse == 1;
+ }
+
+ @Override
+ public String toString() {
+ return "CouponDetail [couponStockId=" + couponStockId
+ + ", couponStockType=" + getFormatCouponStockType()
+ + ", couponId=" + couponId + ", couponValue="
+ + getFormatCouponValue() + ", couponMininum="
+ + getFormatCouponMininum() + ", couponName=" + couponName
+ + ", couponStatus=" + getCouponStatus() + ", couponType="
+ + getFormatCouponType() + ", couponDesc=" + couponDesc
+ + ", couponUseValue=" + getFormatCouponUseValue()
+ + ", couponRemainValue=" + getFormatCouponRemainValue()
+ + ", beginTime=" + getFormatBeginTime() + ", endTime="
+ + getFormatEndTime() + ", sendTime=" + getFormatSendTime()
+ + ", useTime=" + getFormatUseTime() + ", tradeNo=" + tradeNo
+ + ", consumerMchId=" + consumerMchId + ", consumerMchName="
+ + consumerMchName + ", consumerMchAppid=" + consumerMchAppid
+ + ", sendSource=" + sendSource + ", isPartialUse="
+ + getFormatIsPartialUse() + ", " + super.toString() + "]";
+ }
+}
diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/coupon/CouponResult.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/coupon/CouponResult.java
new file mode 100644
index 00000000..afe82022
--- /dev/null
+++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/coupon/CouponResult.java
@@ -0,0 +1,119 @@
+package com.foxinmy.weixin4j.pay.payment.coupon;
+
+import com.alibaba.fastjson.annotation.JSONField;
+import com.foxinmy.weixin4j.pay.payment.mch.MerchantResult;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+/**
+ * 代金券发放结果
+ *
+ * @className CouponResult
+ * @author jinyu(foxinmy@gmail.com)
+ * @date 2015年3月25日
+ * @since JDK 1.6
+ * @see
+ */
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.FIELD)
+public class CouponResult extends MerchantResult {
+
+ private static final long serialVersionUID = -1996967923720149124L;
+
+ /**
+ * 代金券批次id
+ */
+ @XmlElement(name = "coupon_stock_id")
+ @JSONField(name = "coupon_stock_id")
+ private String couponStockId;
+ /**
+ * 返回记录数
+ */
+ @XmlElement(name = "resp_count")
+ @JSONField(name = "resp_count")
+ private int responseCount;
+ /**
+ * 成功记录数
+ */
+ @XmlElement(name = "success_count")
+ @JSONField(name = "success_count")
+ private int successCount;
+ /**
+ * 失败记录数
+ */
+ @XmlElement(name = "failed_count")
+ @JSONField(name = "failed_count")
+ private int failedCount;
+ /**
+ * 用户在商户appid下的唯一标识
+ */
+ @XmlElement(name = "openid")
+ @JSONField(name = "openid")
+ private String openId;
+ /**
+ * 返回码 SUCCESS或者FAILED
+ */
+ @XmlElement(name = "ret_code")
+ @JSONField(name = "ret_code")
+ private String retCode;
+ /**
+ * 代金券id
+ */
+ @XmlElement(name = "coupon_id")
+ @JSONField(name = "coupon_id")
+ private String couponId;
+ /**
+ * 失败描述信息,例如:“用户已达领用上限”
+ */
+ @XmlElement(name = "ret_msg")
+ @JSONField(name = "ret_msg")
+ private String retMsg;
+
+ public CouponResult() {
+
+ }
+
+ public String getCouponStockId() {
+ return couponStockId;
+ }
+
+ public int getResponseCount() {
+ return responseCount;
+ }
+
+ public int getSuccessCount() {
+ return successCount;
+ }
+
+ public int getFailedCount() {
+ return failedCount;
+ }
+
+ public String getOpenId() {
+ return openId;
+ }
+
+ public String getRetCode() {
+ return retCode;
+ }
+
+ public String getCouponId() {
+ return couponId;
+ }
+
+ public String getRetMsg() {
+ return retMsg;
+ }
+
+ @Override
+ public String toString() {
+ return "CouponResult [couponStockId=" + couponStockId
+ + ", responseCount=" + responseCount + ", successCount="
+ + successCount + ", failedCount=" + failedCount + ", openId="
+ + openId + ", retCode=" + retCode + ", couponId=" + couponId
+ + ", retMsg=" + retMsg + "]";
+ }
+}
diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/coupon/CouponStock.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/coupon/CouponStock.java
new file mode 100644
index 00000000..d1d2be64
--- /dev/null
+++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/coupon/CouponStock.java
@@ -0,0 +1,307 @@
+package com.foxinmy.weixin4j.pay.payment.coupon;
+
+import com.alibaba.fastjson.annotation.JSONField;
+import com.foxinmy.weixin4j.pay.payment.mch.MerchantResult;
+import com.foxinmy.weixin4j.pay.type.mch.CouponStockStatus;
+import com.foxinmy.weixin4j.pay.type.mch.CouponType;
+import com.foxinmy.weixin4j.util.DateUtil;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import java.util.Date;
+
+/**
+ * 代金券信息
+ *
+ * @className CouponStock
+ * @author jinyu(foxinmy@gmail.com)
+ * @date 2015年3月27日
+ * @since JDK 1.6
+ * @see
+ */
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.FIELD)
+public class CouponStock extends MerchantResult {
+
+ private static final long serialVersionUID = -8627202879200080499L;
+
+ /**
+ * 代金券批次ID
+ */
+ @XmlElement(name = "coupon_stock_id")
+ @JSONField(name = "coupon_stock_id")
+ private String couponStockId;
+ /**
+ * 代金券名称
+ */
+ @XmlElement(name = "coupon_name")
+ @JSONField(name = "coupon_name")
+ private String couponName;
+ /**
+ * 代金券面额
+ */
+ @XmlElement(name = "coupon_value")
+ @JSONField(name = "coupon_value")
+ private int couponValue;
+ /**
+ * 代金券使用最低限额
+ */
+ @XmlElement(name = "coupon_mininumn")
+ @JSONField(name = "coupon_mininumn")
+ private Integer couponMininumn;
+ /**
+ * 代金券类型:1-代金券无门槛,2-代金券有门槛互斥,3-代金券有门槛叠加
+ */
+ @XmlElement(name = "coupon_type")
+ @JSONField(name = "coupon_type")
+ private int couponType;
+ /**
+ * 批次状态: 1-未激活;2-审批中;4-已激活;8-已作废;16-中止发放;
+ */
+ @XmlElement(name = "coupon_stock_status")
+ @JSONField(name = "coupon_stock_status")
+ private int couponStockStatus;
+ /**
+ * 代金券数量
+ */
+ @XmlElement(name = "coupon_total")
+ @JSONField(name = "coupon_total")
+ private int couponTotal;
+ /**
+ * 代金券每个人最多能领取的数量, 如果为0,则表示没有限制
+ */
+ @XmlElement(name = "max_quota")
+ @JSONField(name = "max_quota")
+ private Integer maxQuota;
+ /**
+ * 代金券锁定数量
+ */
+ @XmlElement(name = "locked_num")
+ @JSONField(name = "locked_num")
+ private Integer lockedNum;
+ /**
+ * 代金券已使用数量
+ */
+ @XmlElement(name = "used_num")
+ @JSONField(name = "used_num")
+ private Integer usedNum;
+ /**
+ * 代金券已经发送的数量
+ */
+ @XmlElement(name = "is_send_num")
+ @JSONField(name = "is_send_num")
+ private Integer sendNum;
+ /**
+ * 生效开始时间 格式为yyyyMMddhhmmss,如2009年12月27日9点10分10秒表示为20091227091010。
+ */
+ @XmlElement(name = "begin_time")
+ @JSONField(name = "begin_time")
+ private String beginTime;
+ /**
+ * 生效结束时间 格式为yyyyMMddhhmmss,如2009年12月27日9点10分10秒表示为20091227091010。
+ */
+ @XmlElement(name = "end_time")
+ @JSONField(name = "end_time")
+ private String endTime;
+ /**
+ * 创建时间 格式为yyyyMMddhhmmss,如2009年12月27日9点10分10秒表示为20091227091010。
+ */
+ @XmlElement(name = "create_time")
+ @JSONField(name = "create_time")
+ private String createTime;
+ /**
+ * 代金券预算额度
+ */
+ @XmlElement(name = "coupon_budget")
+ @JSONField(name = "coupon_budget")
+ private Integer couponBudget;
+
+ public CouponStock() {
+
+ }
+
+ public String getCouponStockId() {
+ return couponStockId;
+ }
+
+ public String getCouponName() {
+ return couponName;
+ }
+
+ public int getCouponValue() {
+ return couponValue;
+ }
+
+ /**
+ * 调用接口获取单位为分,get方法转换为元方便使用
+ *
+ * @return 元单位
+ */
+ @JSONField(serialize = false)
+ public double getFormatCouponValue() {
+ return couponValue / 100d;
+ }
+
+ public Integer getCouponMininumn() {
+ return couponMininumn;
+ }
+
+ /**
+ * 调用接口获取单位为分,get方法转换为元方便使用
+ *
+ * @return 元单位
+ */
+ @JSONField(serialize = false)
+ public double getFormatCouponMininumn() {
+ return couponMininumn != null ? couponMininumn.intValue() / 100d : 0d;
+ }
+
+ public int getCouponType() {
+ return couponType;
+ }
+
+ @JSONField(serialize = false)
+ public CouponType getFormatCouponType() {
+ for (CouponType couponType : CouponType.values()) {
+ if (couponType.getVal() == this.couponType) {
+ return couponType;
+ }
+ }
+ return null;
+ }
+
+ public int getCouponStockStatus() {
+ return couponStockStatus;
+ }
+
+ @JSONField(serialize = false)
+ public CouponStockStatus getFormatCouponStockStatus() {
+ for (CouponStockStatus couponStockStatus : CouponStockStatus.values()) {
+ if (couponStockStatus.getVal() == this.couponStockStatus) {
+ return couponStockStatus;
+ }
+ }
+ return null;
+ }
+
+ public int getCouponTotal() {
+ return couponTotal;
+ }
+
+ public Integer getMaxQuota() {
+ return maxQuota;
+ }
+
+ /**
+ * 调用接口获取单位为分,get方法转换为元方便使用
+ *
+ * @return 元单位
+ */
+ @JSONField(serialize = false)
+ public double getFormatMaxQuota() {
+ return maxQuota != null ? maxQuota.intValue() / 100d : 0d;
+ }
+
+ public Integer getLockedNum() {
+ return lockedNum;
+ }
+
+ /**
+ * 调用接口获取单位为分,get方法转换为元方便使用
+ *
+ * @return 元单位
+ */
+ @JSONField(serialize = false)
+ public double getFormatLockedNum() {
+ return lockedNum != null ? lockedNum.intValue() / 100d : 0d;
+ }
+
+ public Integer getUsedNum() {
+ return usedNum;
+ }
+
+ /**
+ * 调用接口获取单位为分,get方法转换为元方便使用
+ *
+ * @return 元单位
+ */
+ @JSONField(serialize = false)
+ public double getFormatUsedNum() {
+ return usedNum != null ? usedNum.intValue() / 100d : 0d;
+ }
+
+ public Integer getSendNum() {
+ return sendNum;
+ }
+
+ /**
+ * 调用接口获取单位为分,get方法转换为元方便使用
+ *
+ * @return 元单位
+ */
+ @JSONField(serialize = false)
+ public double getFormatSendNum() {
+ return sendNum != null ? sendNum.intValue() / 100d : 0d;
+ }
+
+ public String getBeginTime() {
+ return beginTime;
+ }
+
+ @JSONField(serialize = false)
+ public Date getFormatBeginTime() {
+ return beginTime != null ? DateUtil.parse2yyyyMMddHHmmss(beginTime)
+ : null;
+ }
+
+ public String getEndTime() {
+ return endTime;
+ }
+
+ @JSONField(serialize = false)
+ public Date getFormatEndTime() {
+ return endTime != null ? DateUtil.parse2yyyyMMddHHmmss(endTime) : null;
+ }
+
+ public String getCreateTime() {
+ return createTime;
+ }
+
+ @JSONField(serialize = false)
+ public Date getFormatCreateTime() {
+ return createTime != null ? DateUtil.parse2yyyyMMddHHmmss(createTime)
+ : null;
+ }
+
+ public Integer getCouponBudget() {
+ return couponBudget;
+ }
+
+ /**
+ * 调用接口获取单位为分,get方法转换为元方便使用
+ *
+ * @return 元单位
+ */
+ @JSONField(serialize = false)
+ public double getFormatCouponBudget() {
+ return couponBudget != null ? couponBudget.intValue() / 100d : 0d;
+ }
+
+ @Override
+ public String toString() {
+ return "CouponDetail [couponStockId=" + couponStockId + ", couponName="
+ + couponName + ", couponValue=" + getFormatCouponValue()
+ + ", couponMininumn=" + getFormatCouponMininumn()
+ + ", couponType=" + getFormatCouponType()
+ + ", couponStockStatus=" + getFormatCouponStockStatus()
+ + ", couponTotal=" + couponTotal + ", maxQuota="
+ + getFormatMaxQuota() + ", lockedNum=" + getFormatLockedNum()
+ + ", usedNum=" + getFormatUsedNum() + ", sendNum="
+ + getFormatSendNum() + ", beginTime=" + beginTime
+ + ", endTime=" + endTime + ", createTime=" + createTime
+ + ", couponBudget=" + getFormatCouponBudget() + ", "
+ + super.toString() + "]";
+ }
+}
diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/coupon/OrderCouponInfo.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/coupon/OrderCouponInfo.java
new file mode 100644
index 00000000..eb53a222
--- /dev/null
+++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/coupon/OrderCouponInfo.java
@@ -0,0 +1,95 @@
+package com.foxinmy.weixin4j.pay.payment.coupon;
+
+import com.alibaba.fastjson.annotation.JSONField;
+import com.foxinmy.weixin4j.pay.type.mch.CouponType;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import java.io.Serializable;
+
+/**
+ * 订单代金券信息
+ *
+ * @className OrderCouponInfo
+ * @author jinyu(foxinmy@gmail.com)
+ * @date 2015年3月24日
+ * @since JDK 1.6
+ * @see
+ */
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.FIELD)
+public class OrderCouponInfo implements Serializable {
+
+ private static final long serialVersionUID = -8744999305258786901L;
+
+ /**
+ * 代金券或立减优惠批次ID
+ */
+ @XmlElement(name = "coupon_batch_id")
+ @JSONField(name = "coupon_batch_id")
+ private String couponBatchId;
+ /**
+ * 代金券类型
+ *
+ * @see CouponType
+ */
+ @XmlElement(name = "coupon_type")
+ @JSONField(name = "coupon_type")
+ private String couponType;
+ /**
+ * 代金券或立减优惠ID
+ */
+ @XmlElement(name = "coupon_id")
+ @JSONField(name = "coupon_id")
+ private String couponId;
+ /**
+ * 单个代金券或立减优惠支付金额
+ */
+ @XmlElement(name = "coupon_fee")
+ @JSONField(name = "coupon_fee")
+ private Integer couponFee;
+
+ protected OrderCouponInfo() {
+ // jaxb requried
+ }
+
+ public String getCouponBatchId() {
+ return couponBatchId;
+ }
+
+ public String getCouponType() {
+ return couponType;
+ }
+
+ @JSONField(serialize = false)
+ public CouponType getFormatCouponType() {
+ return couponType != null ? CouponType
+ .valueOf(couponType.toUpperCase()) : null;
+ }
+
+ public String getCouponId() {
+ return couponId;
+ }
+
+ public Integer getCouponFee() {
+ return couponFee;
+ }
+
+ /**
+ * 调用接口获取单位为分,get方法转换为元方便使用
+ *
+ * @return 元单位
+ */
+ @JSONField(serialize = false)
+ public double getFormatCouponFee() {
+ return couponFee != null ? couponFee.doubleValue() / 100d : 0d;
+ }
+
+ @Override
+ public String toString() {
+ return "couponBatchId=" + couponBatchId + ", couponType=" + couponType
+ + ", couponId=" + couponId + ", couponFee=" + couponFee;
+ }
+}
diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/coupon/RefundCouponInfo.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/coupon/RefundCouponInfo.java
new file mode 100644
index 00000000..796bea15
--- /dev/null
+++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/coupon/RefundCouponInfo.java
@@ -0,0 +1,76 @@
+package com.foxinmy.weixin4j.pay.payment.coupon;
+
+import com.alibaba.fastjson.annotation.JSONField;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import java.io.Serializable;
+
+/**
+ * 退款代金券信息
+ *
+ * @className RefundCouponInfo
+ * @author jinyu(foxinmy@gmail.com)
+ * @date 2015年3月24日
+ * @since JDK 1.6
+ * @see
+ */
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.FIELD)
+public class RefundCouponInfo implements Serializable {
+
+ private static final long serialVersionUID = -8744999305258786901L;
+
+ /**
+ * 代金券或立减优惠批次ID
+ */
+ @XmlElement(name = "coupon_refund_batch_id")
+ @JSONField(name = "coupon_refund_batch_id")
+ private String couponBatchId;
+ /**
+ * 退款代金券ID
+ */
+ @XmlElement(name = "coupon_refund_id")
+ @JSONField(name = "coupon_refund_id")
+ private String couponId;
+ /**
+ * 单个代金券或立减优惠支付金额
+ */
+ @XmlElement(name = "coupon_refund_fee")
+ @JSONField(name = "coupon_refund_fee")
+ private Integer couponFee;
+
+ protected RefundCouponInfo() {
+ // jaxb requried
+ }
+
+ public String getCouponBatchId() {
+ return couponBatchId;
+ }
+
+ public String getCouponId() {
+ return couponId;
+ }
+
+ public Integer getCouponFee() {
+ return couponFee;
+ }
+
+ /**
+ * 调用接口获取单位为分,get方法转换为元方便使用
+ *
+ * @return 元单位
+ */
+ @JSONField(serialize = false)
+ public double getFormatCouponFee() {
+ return couponFee != null ? couponFee.doubleValue() / 100d : 0d;
+ }
+
+ @Override
+ public String toString() {
+ return "couponBatchId=" + couponBatchId + ", couponId=" + couponId
+ + ", couponFee=" + couponFee;
+ }
+}
diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/face/PayfaceAuthinfo.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/face/PayfaceAuthinfo.java
new file mode 100644
index 00000000..2fdd46bf
--- /dev/null
+++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/face/PayfaceAuthinfo.java
@@ -0,0 +1,44 @@
+package com.foxinmy.weixin4j.pay.payment.face;
+
+import com.alibaba.fastjson.annotation.JSONField;
+import com.foxinmy.weixin4j.pay.payment.mch.MerchantResult;
+
+import javax.xml.bind.annotation.XmlElement;
+
+/**
+ * 微信刷脸支付交互流程--获取调用凭证(get_wxpayface_authinfo)接口响应结果
+ *
+ * @className PayfaceAuthinfo
+ * @author kit(kit_21cn@21cn.com)
+ * @date 2019年9月17日
+ * @since JDK 1.6
+ * @see
+ */
+public class PayfaceAuthinfo extends MerchantResult {
+ /**
+ * authinfo的有效时间, 单位秒。 例如: 3600
+ * 在有效时间内, 对于同一台终端设备,相同的参数的前提下(如:相同的公众号、商户号、 门店编号等),可以用同一个authinfo,
+ * 多次调用SDK的getWxpayfaceCode接口。
+ *
+ * @see
+ * 人脸支付凭证(getWxpayfaceCode)
+ */
+ @JSONField(name = "expires_in")
+ @XmlElement(name = "expires_in")
+ private int expiresIn;
+ /**
+ * SDK调用凭证。用于调用SDK的人脸识别接口。
+ *
+ * @see
+ * 人脸支付凭证(getWxpayfaceCode)
+ */
+ private String authinfo;
+
+ @Override
+ public String toString() {
+ return "PayfaceAuthinfo{" +
+ "expiresIn=" + expiresIn +
+ ", authinfo='" + authinfo + '\'' +
+ '}';
+ }
+}
diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/face/PayfaceAuthinfoRequest.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/face/PayfaceAuthinfoRequest.java
new file mode 100644
index 00000000..6a3c27e1
--- /dev/null
+++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/face/PayfaceAuthinfoRequest.java
@@ -0,0 +1,96 @@
+package com.foxinmy.weixin4j.pay.payment.face;
+
+import com.foxinmy.weixin4j.pay.model.WeixinPayAccount;
+import com.foxinmy.weixin4j.pay.sign.WeixinPaymentSignature;
+import com.foxinmy.weixin4j.pay.type.SignType;
+import com.foxinmy.weixin4j.util.*;
+import com.foxinmy.weixin4j.xml.XmlStream;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 微信刷脸支付, 获取调用凭证(get_wxpayface_authinfo)API接口请求参数封装
+ *
+ * @className PayfaceAuthinfoRequest
+ * @author kit(kit_21cn@21cn.com)
+ * @date 2019年9月18日
+ * @since JDK 1.6
+ * @see
+ * 获取调用凭证-get-wxpayface-authinfo
+ */
+public class PayfaceAuthinfoRequest {
+ private WeixinPayAccount payAccount;
+ /**
+ * 门店编号, 由商户定义, 各门店唯一。
+ */
+ private String storeId;
+ /**
+ * 门店名称,由商户定义。(可用于展示)
+ */
+ private String storeName;
+ /**
+ * 终端设备编号,由商户定义。
+ */
+ private String deviceId;
+ /**
+ * 附加字段。字段格式使用Json
+ */
+ private String attach;
+
+ private String nonceStr = RandomUtil.generateString(16);
+
+ private String now = DateUtil.timestamp2string();
+ /**
+ * 初始化数据。由微信人脸SDK的接口返回。
+ *
+ * @see
+ * * 获取数据-getwxpayfacerawdata
+ */
+ private String rawdata;
+
+ private WeixinPaymentSignature paymentSignature;
+
+ public PayfaceAuthinfoRequest(WeixinPayAccount account, String storeId, String storeName, String deviceId,
+ String attach, String rawdata){
+ this.payAccount = account;
+ this.deviceId = deviceId;
+ this.rawdata = rawdata;
+ this.storeId = storeId;
+ this.storeName = storeName;
+ this.attach = attach;
+ this.paymentSignature = new WeixinPaymentSignature(account.getPaySignKey());
+ }
+
+ public String toRequestString(){
+ Map paramsMap = getRequestParam();
+ return XmlStream.map2xml(paramsMap);
+ }
+
+ private Map getRequestParam(){
+ Map map = new HashMap();
+ map.put("appid", payAccount.getId());
+ map.put("mch_id", payAccount.getMchId());
+ if(StringUtil.isNotBlank(payAccount.getSubId())) {
+ map.put("sub_appid", payAccount.getSubId());
+ }
+ if(StringUtil.isNotBlank(payAccount.getSubMchId())){
+ map.put("sub_mch_id", payAccount.getSubMchId());
+ }
+ map.put("now", now);
+ map.put("version", "1");
+ map.put("sign_type", SignType.MD5.name());
+ map.put("nonce_str", nonceStr);
+ map.put("store_id", storeId);
+ map.put("store_name", storeName);
+ map.put("device_id", deviceId);
+ map.put("rawdata", rawdata);
+ if(StringUtil.isNotBlank(attach)) {
+ map.put("attach", attach);
+ }
+ String sign = paymentSignature.sign(map);
+ map.put("sign", sign);
+
+ return map;
+ }
+}
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..8bf5d703
--- /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.pay.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..1934e8fc
--- /dev/null
+++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/MchPayPackage.java
@@ -0,0 +1,267 @@
+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 com.foxinmy.weixin4j.pay.type.mch.DepositType;
+
+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;
+ /**
+ * 人脸凭证,用于旧版人脸支付。
+ */
+ @XmlElement(name = "face_code")
+ @JSONField(name = "face_code")
+ private String faceCode;
+ /**
+ * 是否押金人脸支付,Y-是,N-普通人脸支付
+ */
+ @XmlElement(name = "deposit")
+ @JSONField(name = "deposit")
+ private DepositType deposit;
+
+ 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, 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
+ * @param faceCode
+ * 人脸凭证,用于旧版刷脸支付。
+ * @param depositType
+ * 是否押金支付
+ */
+ 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, String faceCode,
+ DepositType depositType) {
+ 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;
+ this.faceCode = faceCode;
+ this.deposit = depositType;
+ }
+
+ 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;
+ }
+
+ public String getFaceCode() {
+ return faceCode;
+ }
+
+ public void setFaceCode(String faceCode) {
+ this.faceCode = faceCode;
+ }
+
+ public DepositType getDeposit() {
+ return deposit;
+ }
+
+ public void setDeposit(DepositType deposit) {
+ this.deposit = deposit;
+ }
+
+ @Override
+ public String toString() {
+ return "MchPayPackage{" +
+ "tradeType='" + tradeType + '\'' +
+ ", feeType='" + feeType + '\'' +
+ ", openId='" + openId + '\'' +
+ ", productId='" + productId + '\'' +
+ ", authCode='" + authCode + '\'' +
+ ", limitPay='" + limitPay + '\'' +
+ ", subOpenId='" + subOpenId + '\'' +
+ ", sceneInfo='" + sceneInfo + '\'' +
+ ", faceCode='" + faceCode + '\'' +
+ ", deposit=" + deposit +
+ '}';
+ }
+}
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..ddebf2e2
--- /dev/null
+++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/MerchantResult.java
@@ -0,0 +1,170 @@
+package com.foxinmy.weixin4j.pay.payment.mch;
+
+import com.alibaba.fastjson.annotation.JSONField;
+import com.foxinmy.weixin4j.http.weixin.XmlResult;
+import com.foxinmy.weixin4j.pay.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;
+ }
+
+ 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..d257f11b
--- /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.pay.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..9265c63c
--- /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.pay.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..45b8aa10
--- /dev/null
+++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/sign/WeixinPaymentSignature.java
@@ -0,0 +1,52 @@
+package com.foxinmy.weixin4j.pay.sign;
+
+import com.foxinmy.weixin4j.exception.WeixinException;
+import com.foxinmy.weixin4j.pay.type.SignType;
+import com.foxinmy.weixin4j.util.DigestUtil;
+
+import java.security.InvalidKeyException;
+
+/**
+ * 微信支付签名实现
+ *
+ * @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 String sign(Object obj) {
+ StringBuilder sb = join(obj).append("&key=").append(paySignKey);
+ return DigestUtil.MD5(sb.toString()).toUpperCase();
+ }
+
+ @Override
+ public String sign(Object obj, SignType signType) {
+ if(signType==null){
+ return sign(obj);
+ }
+ switch (signType){
+ case HMAC$SHA256:
+ StringBuilder sb = join(obj).append("&key=").append(paySignKey);
+ try {
+ return DigestUtil.HMACSHA256(sb.toString(), paySignKey).toUpperCase();
+ }catch (InvalidKeyException e){
+ throw new RuntimeException("商户支付密钥有误", e);
+ }
+ default:
+ return sign(obj);
+ }
+ }
+}
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..8c02344f
--- /dev/null
+++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/sign/WeixinSignature.java
@@ -0,0 +1,45 @@
+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
+ */
+ boolean encoder();
+
+ /**
+ * 是否转换小写
+ *
+ * @return
+ */
+ boolean lowerCase();
+
+ /**
+ * 签名(默认的MD5签名)
+ *
+ * @param obj
+ * @return
+ */
+ String sign(Object obj);
+
+ /**
+ * 签名(指定签名算法)
+ *
+ * @param obj
+ * @param signType
+ * @return
+ */
+ String sign(Object obj, SignType signType);
+}
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..d961b1c1
--- /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 {
+ 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/TradeState.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/TradeState.java
new file mode 100644
index 00000000..14a30e3c
--- /dev/null
+++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/TradeState.java
@@ -0,0 +1,46 @@
+package com.foxinmy.weixin4j.pay.type;
+
+/**
+ * 交易状态
+ *
+ * @className TradeState
+ * @author jinyu(foxinmy@gmail.com)
+ * @date 2014年11月2日
+ * @since JDK 1.6
+ * @see
+ * @deprecated 迁移到子模块weixin4j-pay
+ */
+public enum TradeState {
+ /**
+ * 支付成功
+ */
+ SUCCESS,
+ /**
+ * 转入退款
+ */
+ REFUND,
+ /**
+ * 未支付
+ */
+ NOTPAY,
+ /**
+ * 已关闭
+ */
+ CLOSED,
+ /**
+ * 已撤销
+ */
+ REVOKED,
+ /**
+ * 用户支付中
+ */
+ USERPAYING,
+ /**
+ * 未支付(输入密码或 确认支付超时)
+ */
+ NOPAY,
+ /**
+ * 支付失败(其他 原因,如银行返回失败)
+ */
+ PAYERROR;
+}
diff --git a/weixin4j-pay/src/main/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..c9bfc2e2
--- /dev/null
+++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/TradeType.java
@@ -0,0 +1,37 @@
+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,
+ /**
+ * 刷脸支付
+ */
+ FACEPAY;
+}
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/DepositType.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/DepositType.java
new file mode 100644
index 00000000..08524415
--- /dev/null
+++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/DepositType.java
@@ -0,0 +1,20 @@
+package com.foxinmy.weixin4j.pay.type.mch;
+
+/**
+ * 是否押金支付
+ *
+ * @className DepositType
+ * @author kit(kit_21cn@21cn.com)
+ * @date 2019年9月21日
+ * @since JDK 1.6
+ */
+public enum DepositType {
+ /**
+ * 是
+ */
+ Y,
+ /**
+ * 否
+ */
+ N;
+}
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;
+ }
+}
diff --git a/weixin4j-pay/src/main/resources/com/foxinmy/weixin4j/payment/weixin.properties b/weixin4j-pay/src/main/resources/com/foxinmy/weixin4j/payment/weixin.properties
new file mode 100644
index 00000000..635bb53b
--- /dev/null
+++ b/weixin4j-pay/src/main/resources/com/foxinmy/weixin4j/payment/weixin.properties
@@ -0,0 +1,64 @@
+# \u5FAE\u4FE1\u5546\u6237\u5E73\u53F0\u6587\u6863\u8BF4\u660E
+# https://pay.weixin.qq.com/
+# https://pay.weixin.qq.com/wiki/doc/api/index.php
+# ----------------------------------------------------------------------------
+
+mch_base_url=https://api.mch.weixin.qq.com
+payapp_base_url=https://payapp.weixin.qq.com
+
+# \u53D1\u9001\u73B0\u91D1\u7EA2\u5305
+redpack_send_uri={mch_base_url}/mmpaymkttransfers/sendredpack
+# \u53D1\u9001\u73B0\u91D1\u88C2\u53D8\u7EA2\u5305
+groupredpack_send_uri={mch_base_url}/mmpaymkttransfers/sendgroupredpack
+# \u67E5\u8BE2\u73B0\u91D1\u7EA2\u5305
+redpack_query_uri={mch_base_url}/mmpaymkttransfers/gethbinfo
+# \u7EDF\u4E00\u8BA2\u5355\u751F\u6210
+order_create_uri={mch_base_url}/pay/unifiedorder
+# \u88AB\u626B\u652F\u4ED8
+micropay_uri={mch_base_url}/pay/micropay
+# \u8BA2\u5355\u67E5\u8BE2
+order_query_uri={mch_base_url}/pay/orderquery
+# \u5173\u95ED\u8BA2\u5355
+order_close_uri={mch_base_url}/pay/closeorder
+# \u5BF9\u8D26\u5355\u4E0B\u8F7D
+downloadbill_uri={mch_base_url}/pay/downloadbill
+# \u9000\u6B3E\u67E5\u8BE2
+refund_query_uri={mch_base_url}/pay/refundquery
+# \u9000\u6B3E\u7533\u8BF7
+refund_apply_uri={mch_base_url}/secapi/pay/refund
+# \u51B2\u6B63\u64A4\u9500
+order_reverse_uri={mch_base_url}/secapi/pay/reverse
+# \u957F\u94FE\u63A5\u8F6C\u6362
+longurl_convert_uri={mch_base_url}/tools/shorturl
+# \u53D1\u653E\u4EE3\u91D1\u5238
+coupon_send_uri={mch_base_url}/mmpaymkttransfers/send_coupon
+# \u67E5\u8BE2\u4EE3\u91D1\u5238\u6279\u6B21\u4FE1\u606F
+couponstock_query_uri={mch_base_url}/mmpaymkttransfers/query_coupon_stock
+# \u67E5\u8BE2\u4EE3\u91D1\u5238\u8BE6\u7EC6\u4FE1\u606F
+coupondetail_query_uri={mch_base_url}/mmpaymkttransfers/querycouponsinfo
+# \u4F01\u4E1A\u5411\u4E2A\u4EBA\u4ED8\u6B3E
+corppayment_send_uri={mch_base_url}/mmpaymkttransfers/promotion/transfers
+# \u4F01\u4E1A\u4ED8\u6B3E\u67E5\u8BE2
+corppayment_query_uri={mch_base_url}/mmpaymkttransfers/gettransferinfo
+# \u63A5\u53E3\u4E0A\u62A5
+interface_report_uri={mch_base_url}/payitil/report
+# \u6388\u6743\u7801\u67E5\u8BE2OPENID\u63A5\u53E3
+authcode_openid_uri={mch_base_url}/tools/authcodetoopenid
+# native\u652F\u4ED8url(\u6A21\u5F0F1)
+native_pay_uri=weixin://wxpay/bizpayurl?sign=%s&appid=%s&mch_id=%s&product_id=%s&time_stamp=%s&nonce_str=%s
+# \u67E5\u8BE2\u7ED3\u7B97\u8D44\u91D1
+settlement_query_uri={mch_base_url}/pay/settlementquery
+# \u67E5\u8BE2\u6C47\u7387
+exchagerate_query_uri={mch_base_url}/pay/queryexchagerate
+# \u8BA2\u5355\u9644\u52A0\u4FE1\u606F\u63D0\u4EA4
+customsorder_declare_uri={mch_base_url}/mch/customs/customdeclareorder
+# \u8BA2\u5355\u9644\u52A0\u4FE1\u606F\u67E5\u8BE2
+customsorder_query_uri={mch_base_url}/mch/customs/customdeclarequery
+# \u5237\u8138\u652F\u4ED8\u4EA4\u4E92\u6D41\u7A0B--\u83B7\u53D6\u8C03\u7528\u51ED\u8BC1
+get_wxpayface_authinfo_uri={payapp_base_url}/face/get_wxpayface_authinfo
+# \u65E7\u7248\u5237\u8138\u652F\u4ED8\u63A5\u53E3
+facepay_url={mch_base_url}/pay/facepay
+# \u652F\u4ED8\u62BC\u91D1\uFF08\u4EBA\u8138\uFF09
+deposit_facepay_uri={mch_base_url}/deposit/facepay
+# \u652F\u4ED8\u62BC\u91D1\uFF08\u4ED8\u6B3E\u7801\uFF09
+deposit_micropay_uri={mch_base_url}/deposit/micropay
\ No newline at end of file
diff --git a/weixin4j-pay/src/main/resources/weixin4j.properties b/weixin4j-pay/src/main/resources/weixin4j.properties
new file mode 100644
index 00000000..1f14b8bc
--- /dev/null
+++ b/weixin4j-pay/src/main/resources/weixin4j.properties
@@ -0,0 +1,2 @@
+# \u914D\u7F6E\u5F53\u4F7F\u7528jdkLogger\u65F6\uFF0C\u65E5\u5FD7\u7684\u7EA7\u522B
+# weixin4j.jdkLogger.level=INFO
diff --git a/weixin4j-pay/src/test/java/com/foxinmy/weixin4j/pay/test/TestDepositPay.java b/weixin4j-pay/src/test/java/com/foxinmy/weixin4j/pay/test/TestDepositPay.java
new file mode 100644
index 00000000..13ef92bb
--- /dev/null
+++ b/weixin4j-pay/src/test/java/com/foxinmy/weixin4j/pay/test/TestDepositPay.java
@@ -0,0 +1,26 @@
+package com.foxinmy.weixin4j.pay.test;
+
+import com.foxinmy.weixin4j.exception.WeixinException;
+import com.foxinmy.weixin4j.pay.WeixinPayProxy;
+import com.foxinmy.weixin4j.pay.model.WeixinPayAccount;
+import com.foxinmy.weixin4j.pay.payment.mch.MchPayRequest;
+import org.junit.Test;
+
+public class TestDepositPay {
+ @Test
+ public void test() throws WeixinException {
+ String appid = "";
+ String mchid = "";
+ String paySignKey = "";
+ String code = "";
+ boolean isFacePay = false; //true - 人脸押金支付,false - 付款码押金支付
+
+ WeixinPayAccount payAccount = new WeixinPayAccount(appid, paySignKey, mchid);
+ payAccount.setSubMchId(mchid);
+ WeixinPayProxy proxy = new WeixinPayProxy(payAccount);
+
+ MchPayRequest payRequest = proxy.createDepositPayRequest(code, "测试押金支付", "TESTORDER20190921001", 0.01,
+ "127.0.0.1", null, null, null, isFacePay);
+ System.out.println(payRequest.toRequestString());
+ }
+}
diff --git a/weixin4j-pay/src/test/java/com/foxinmy/weixin4j/pay/test/TestFacePay.java b/weixin4j-pay/src/test/java/com/foxinmy/weixin4j/pay/test/TestFacePay.java
new file mode 100644
index 00000000..8b3145c1
--- /dev/null
+++ b/weixin4j-pay/src/test/java/com/foxinmy/weixin4j/pay/test/TestFacePay.java
@@ -0,0 +1,31 @@
+package com.foxinmy.weixin4j.pay.test;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.foxinmy.weixin4j.exception.WeixinException;
+import com.foxinmy.weixin4j.pay.WeixinPayProxy;
+import com.foxinmy.weixin4j.pay.model.WeixinPayAccount;
+import com.foxinmy.weixin4j.pay.payment.mch.MchPayRequest;
+import com.foxinmy.weixin4j.pay.type.mch.DepositType;
+import org.junit.Test;
+
+public class TestFacePay {
+ @Test
+ public void test() throws WeixinException {
+ String appid = "";
+ String mchid = "";
+ String paySignKey = "";
+ WeixinPayAccount payAccount = new WeixinPayAccount(appid, paySignKey, mchid);
+ WeixinPayProxy proxy = new WeixinPayProxy(payAccount);
+
+ String orderNo = "TESTORDER2019092001";
+ String openId = "oguJRswolIOGg7Vd1VaqGJuDBFAE";
+ String faceCode = "0f879a6c-5fff-421c-a233-5fac0f4aad12";
+
+ MchPayRequest rsp = proxy.createFacePayRequest(faceCode, "测试的人脸支付",
+ orderNo, 1,
+ "127.0.0.1", openId, null);
+
+ JSONObject obj = (JSONObject) JSON.toJSON(rsp);
+ }
+}
\ No newline at end of file
diff --git a/weixin4j-pay/src/test/java/com/foxinmy/weixin4j/pay/test/TestGetPayFaceAuthInfo.java b/weixin4j-pay/src/test/java/com/foxinmy/weixin4j/pay/test/TestGetPayFaceAuthInfo.java
new file mode 100644
index 00000000..57ac56a7
--- /dev/null
+++ b/weixin4j-pay/src/test/java/com/foxinmy/weixin4j/pay/test/TestGetPayFaceAuthInfo.java
@@ -0,0 +1,24 @@
+package com.foxinmy.weixin4j.pay.test;
+
+import com.foxinmy.weixin4j.exception.WeixinException;
+import com.foxinmy.weixin4j.pay.WeixinPayProxy;
+import com.foxinmy.weixin4j.pay.model.WeixinPayAccount;
+import com.foxinmy.weixin4j.pay.payment.face.PayfaceAuthinfo;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class TestGetPayFaceAuthInfo {
+ @Test
+ public void test() throws WeixinException {
+ String appid = "";
+ String mchid = "";
+ String paySignKey = "";
+ String rawData = "7rfwfRXEDBBbs5MjHW67ritEHtQ7AchIcd0E1zfBxmxyIEXA3aiPTdtrZ1I1fXn6Mpyln11al546YOfNK/HXe81b589a9EyAHuoziZmoe+qJFf2ulkwBWOFffnSN05Qy/ykboG4PciO5yvIMlKEEdmqEjj4ck9oBmAKCqXCM2bRDqNEQOuckZGqGsJsM4xyKEZmlL4cLk+/l9xtvOseJccBeDJfkg5fAdwG1z7lX1DThdyb8uRuE3UCvVghQ21KslyIrF9G6rhh3bP83sD//QklJsdf/dapidxkCACfZkGyNl7wFDnjj5bUgwj9pYW3gQBUff606pI9Eh7VoLwFb768DGfSGHVTwQOPeq+Ldu0bAFyuTNFZUBETYnOCZx0ue7ehDmfmFSxyqVfLRhmlMTPHC/AHRVp6wwg1EnQUTRpUltHdn4O3w5B0PRDVlXogdri0WaTDyrYo18GaZvUdCWld09NZboEPknWEgfQfwaF4vow6R4negvKCVna5kNbjDlDRWNaN+AKtHIznnPKWipc6UunBKeMw/kNTced2f73dUEDALGLPE41nnxA7y1uePWMXVJyNGnWxk461/nz6g/NfyJAgIOILrO1wThEhBd6tFAJGQwu366fnN/5eU9XfBzApHE+OIrtYyRLYJHVaAsAeXOy+PvVqMUFkEWJ3iSLJUZhLJYUbnqVEZaIeAvMY0NJ5+E26WvXXhIGr91gPq35aEjuPu4LKbGTw1jgM=";
+
+ WeixinPayAccount payAccount = new WeixinPayAccount(appid, paySignKey, mchid);
+ WeixinPayProxy proxy = new WeixinPayProxy(payAccount);
+ PayfaceAuthinfo info = proxy.getWxPayfaceAuthinfo("TEST01", "甘坑客家小镇", "TESTDEVICE01", rawData);
+ System.out.print(info);
+ Assert.assertEquals("SUCCESS", info.getReturnCode());
+ }
+}
diff --git a/weixin4j-pay/src/test/java/com/foxinmy/weixin4j/pay/test/TestHmacSHA256Sign.java b/weixin4j-pay/src/test/java/com/foxinmy/weixin4j/pay/test/TestHmacSHA256Sign.java
new file mode 100644
index 00000000..b8a9a775
--- /dev/null
+++ b/weixin4j-pay/src/test/java/com/foxinmy/weixin4j/pay/test/TestHmacSHA256Sign.java
@@ -0,0 +1,24 @@
+package com.foxinmy.weixin4j.pay.test;
+
+import com.alibaba.fastjson.JSONObject;
+import com.foxinmy.weixin4j.pay.sign.WeixinPaymentSignature;
+import com.foxinmy.weixin4j.pay.type.SignType;
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * HmacSHA256签名算法测试
+ * @author kit (kit_21cn@21cn.com)
+ */
+public class TestHmacSHA256Sign {
+ @Test
+ public void test(){
+ WeixinPaymentSignature signature = new WeixinPaymentSignature("muses");
+ JSONObject json = new JSONObject();
+ json.put("appid", "1");
+ json.put("mch_id", "2");
+ String sign = signature.sign(json, SignType.HMAC$SHA256);
+
+ Assert.assertEquals("637CF27B23F731398B2BE0118F484191B3728749C25D1EEF7479B6E93033602C", sign);
+ }
+}