diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/FavorCallbacksSaveRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/FavorCallbacksSaveRequest.java new file mode 100644 index 0000000000..4a0f10d315 --- /dev/null +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/FavorCallbacksSaveRequest.java @@ -0,0 +1,70 @@ +package com.github.binarywang.wxpay.bean.marketing; + +import com.google.gson.annotations.SerializedName; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +/** + * 设置消息通知地址 + *
+ * 文档地址:https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/marketing/convention/chapter3_12.shtml + *+ * + * @author thinsstar + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class FavorCallbacksSaveRequest implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + *
+ * 字段名:商户号 + * 变量名:mchid + * 是否必填:是 + * 类型:string[1,20] + * 描述: + * 微信支付商户号。 + * 示例值:9856888 + *+ */ + @SerializedName(value = "mchid") + private String mchid; + + /** + *
+ * 字段名:通知url地址 + * 变量名:notify_url + * 是否必填:是 + * 类型:string[1,256] + * 描述: + * 支付通知商户url地址。 + * 示例值:https://pay.weixin.qq.com + *+ */ + @SerializedName(value = "notify_url") + private String notifyUrl; + + /** + *
+ * 字段名:回调开关 + * 变量名:switch + * 是否必填:否 + * 类型:bool + * 描述: + * 如果商户不需要再接收营销事件通知,可通过该开关关闭。枚举值: + * true:开启推送 + * false:停止推送 + * 示例值:true + *+ */ + @SerializedName(value = "switch") + private Boolean switchBool; +} diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/FavorCallbacksSaveResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/FavorCallbacksSaveResult.java new file mode 100644 index 0000000000..55015a6ac6 --- /dev/null +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/FavorCallbacksSaveResult.java @@ -0,0 +1,38 @@ +package com.github.binarywang.wxpay.bean.marketing; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; +import lombok.NoArgsConstructor; +import me.chanjar.weixin.common.util.json.WxGsonBuilder; + +/** + * 设置消息通知地址返回结果对象 + * + * @author thinsstar + */ +@NoArgsConstructor +@Data +public class FavorCallbacksSaveResult { + + public static FavorCallbacksSaveResult fromJson(String json) { + return WxGsonBuilder.create().fromJson(json, FavorCallbacksSaveResult.class); + } + + /** + * 修改时间 + *
+ * 修改时间,遵循rfc3339标准格式,格式为YYYY-MM-DDTHH:mm:ss.sss+TIMEZONE,YYYY-MM-DD表示年月日,T出现在字符串中,表示time元素的开头,HH:mm:ss.sss表示时分秒毫秒,TIMEZONE表示时区(+08:00表示东八区时间,领先UTC 8小时,即北京时间)。例如:2015-05-20T13:29:35.120+08:00表示,北京时间2015年5月20日 13点29分35秒。 + * 示例值:2015-05-20T13:29:35.120+08:00 + */ + @SerializedName("update_time") + private String updateTime; + + /** + * 通知地址 + *
+ * 通知地址 + * 示例值:api.weixin.qq.com + */ + @SerializedName("notify_url") + private String notifyUrl; +} diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/FavorCouponsCreateRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/FavorCouponsCreateRequest.java new file mode 100644 index 0000000000..4c8d19dfe9 --- /dev/null +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/FavorCouponsCreateRequest.java @@ -0,0 +1,116 @@ +package com.github.binarywang.wxpay.bean.marketing; + +import com.google.gson.annotations.SerializedName; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +/** + * 发放代金券 + *
+ * 文档地址:https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/marketing/convention/chapter3_2.shtml + *+ * + * @author thinsstar + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class FavorCouponsCreateRequest implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + *
+ * 字段名:批次号 + * 变量名:stock_id + * 是否必填:是 + * 类型:string[1,20] + * 描述: + * 微信为每个批次分配的唯一id。 + * 校验规则:必须为代金券(全场券或单品券)批次号,不支持立减与折扣。 + * 示例值:9856000 + *+ */ + @SerializedName(value = "stock_id") + private String stockId; + + /** + *
+ * 字段名:商户单据号 + * 变量名:out_request_no + * 是否必填:是 + * 类型:string[1,128] + * 描述: + * 商户此次发放凭据号(格式:商户id+日期+流水号),可包含英文字母,数字,|,_,*,-等内容,不允许出现其他不合法符号,商户侧需保持唯一性。 + * 示例值: 89560002019101000121 + *+ */ + @SerializedName(value = "out_request_no") + private String outRequestNo; + + /** + *
+ * 字段名:公众账号ID + * 变量名:appid + * 是否必填:是 + * 类型:string[1,128] + * 描述: + * 微信为发券方商户分配的公众账号ID,接口传入的所有appid应该为公众号的appid或者小程序的appid(在mp.weixin.qq.com申请的),不能为APP的appid(在open.weixin.qq.com申请的)。。 + * 校验规则: + * 1、该appid需要与接口传入中的openid有对应关系; + * 2、该appid需要与调用接口的商户号(即请求头中的商户号)有绑定关系,若未绑定,可参考该指引完成绑定(商家商户号与AppID账号关联管理) + * 示例值:wx233544546545989 + *+ */ + @SerializedName(value = "appid") + private String appid; + + /** + *
+ * 字段名:创建批次的商户号 + * 变量名:stock_creator_mchid + * 是否必填:是 + * 类型:string[1,20] + * 描述: + * 批次创建方商户号。 + * 示例值:8956000 + *+ */ + @SerializedName(value = "stock_creator_mchid") + private String stockCreatorMchid; + + /** + *
+ * 字段名:指定面额发券,面额 + * 变量名:coupon_value + * 是否必填:否 + * 类型:uint64 + * 描述: + * 指定面额发券场景,券面额,其他场景不需要填,单位:分。 + * 校验规则:仅在发券时指定面额及门槛的场景才生效,常规发券场景请勿传入该信息。 + * 示例值:100 + *+ */ + @SerializedName(value = "coupon_value") + private Integer couponValue; + + /** + *
+ * 字段名:指定面额发券,券门槛 + * 变量名:coupon_minimum + * 是否必填:是 + * 类型:uint64 + * 描述: + * 指定面额发券批次门槛,其他场景不需要,单位:分。 + * 校验规则:仅在发券时指定面额及门槛的场景才生效,常规发券场景请勿传入该信息。 + * 示例值:100 + *+ */ + @SerializedName(value = "coupon_minimum") + private Integer couponMinimum; +} diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/FavorCouponsCreateResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/FavorCouponsCreateResult.java new file mode 100644 index 0000000000..e3530e80e1 --- /dev/null +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/FavorCouponsCreateResult.java @@ -0,0 +1,29 @@ +package com.github.binarywang.wxpay.bean.marketing; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; +import lombok.NoArgsConstructor; +import me.chanjar.weixin.common.util.json.WxGsonBuilder; + +/** + * 发放代金券返回结果对象 + * + * @author thinsstar + */ +@NoArgsConstructor +@Data +public class FavorCouponsCreateResult { + + public static FavorCouponsCreateResult fromJson(String json) { + return WxGsonBuilder.create().fromJson(json, FavorCouponsCreateResult.class); + } + + /** + * 代金券id + *
+ * 发放给用户的代金券id。 + * 示例值:9867041 + */ + @SerializedName("coupon_id") + private String couponId; +} diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/FavorCouponsGetResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/FavorCouponsGetResult.java new file mode 100644 index 0000000000..b6f6dd854b --- /dev/null +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/FavorCouponsGetResult.java @@ -0,0 +1,199 @@ +package com.github.binarywang.wxpay.bean.marketing; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; +import lombok.NoArgsConstructor; +import me.chanjar.weixin.common.util.json.WxGsonBuilder; + +import java.io.Serializable; + +/** + * 查询代金券详情结果对象 + * + * @author thinsstar + */ +@NoArgsConstructor +@Data +public class FavorCouponsGetResult { + + public static FavorCouponsGetResult fromJson(String json) { + return WxGsonBuilder.create().fromJson(json, FavorCouponsGetResult.class); + } + + /** + * 创建批次的商户号 + *
+ * 批次创建方商户号 + * 示例值:9800064 + */ + @SerializedName("stock_creator_mchid") + private String stockCreatorMchid; + + /** + * 批次号 + *
+ * 微信为每个代金券批次分配的唯一id。 + * 示例值:9865888 + */ + @SerializedName("stock_id") + private String stockId; + + /** + * 代金券id + *
+ * 微信为代金券唯一分配的id。 + * 示例值:98674556 + */ + @SerializedName("coupon_id") + private String couponId; + + /** + * 单品优惠特定信息 + *
+ * 单品优惠特定信息 + */ + @SerializedName("cut_to_message") + private CutToMessage cutToMessage; + + /** + * 代金券名称 + *
+ * 代金券名称 + * 示例值:微信支付代金券 + */ + @SerializedName("coupon_name") + private String couponName; + + /** + * 代金券状态 + *
+ * 代金券状态: + * SENDED:可用 + * USED:已实扣 + * EXPIRED:已过期 + * 示例值:EXPIRED + */ + @SerializedName("status") + private String status; + + /** + * 使用说明 + *
+ * 代金券描述说明字段。 + * 示例值:微信支付营销 + */ + @SerializedName("description") + private String description; + + /** + * 领券时间 + *
+ * 领券时间,遵循rfc3339标准格式,格式为YYYY-MM-DDTHH:mm:ss.sss+TIMEZONE,YYYY-MM-DD表示年月日,T出现在字符串中,表示time元素的开头,HH:mm:ss.sss表示时分秒毫秒,TIMEZONE表示时区(+08:00表示东八区时间,领先UTC 8小时,即北京时间)。例如:2015-05-20T13:29:35.120+08:00表示,北京时间2015年5月20日 13点29分35秒。 + * 示例值: 2015-05-20T13:29:35.120+08:00 + */ + @SerializedName("create_time") + private String createTime; + + /** + * 券类型 + *
+ * 券类型: + * NORMAL:满减券 + * CUT_TO:减至券 + * 示例值:CUT_TO + */ + @SerializedName("coupon_type") + private String couponType; + + /** + * 是否无资金流 + *
+ * 枚举值: + * true:是 + * false:否 + * 示例值:true + */ + @SerializedName("no_cash") + private Boolean noCash; + + /** + * 可用开始时间 + *
+ * 可用开始时间,遵循rfc3339标准格式,格式为YYYY-MM-DDTHH:mm:ss.sss+TIMEZONE,YYYY-MM-DD表示年月日,T出现在字符串中,表示time元素的开头,HH:mm:ss.sss表示时分秒毫秒,TIMEZONE表示时区(+08:00表示东八区时间,领先UTC 8小时,即北京时间)。例如:2015-05-20T13:29:35.120+08:00表示,北京时间2015年5月20日 13点29分35秒。 + * 示例值: 2015-05-20T13:29:35.120+08:00 + */ + @SerializedName("available_begin_time") + private String availableBeginTime; + + /** + * 可用结束时间 + *
+ * 可用结束时间,遵循rfc3339标准格式,格式为YYYY-MM-DDTHH:mm:ss.sss+TIMEZONE,YYYY-MM-DD表示年月日,T出现在字符串中,表示time元素的开头,HH:mm:ss.sss表示时分秒毫秒,TIMEZONE表示时区(+08:00表示东八区时间,领先UTC 8小时,即北京时间)。例如:2015-05-20T13:29:35.120+08:00表示,北京时间2015年5月20日 13点29分35秒。 + * 示例值: 2015-05-20T13:29:35.120+08:00 + */ + @SerializedName("available_end_time") + private String availableEndTime; + + /** + * 是否单品优惠 + *
+ * 枚举值: + * true:是 + * false:否 + * 示例值:true + */ + @SerializedName("singleitem") + private Boolean singleitem; + + /** + * 满减券信息 + *
+ * 普通满减券面额、门槛信息。 + */ + @SerializedName("normal_coupon_information") + private NormalCouponInformation normalCouponInformation; + + @Data + @NoArgsConstructor + public static class CutToMessage implements Serializable { + /** + * 可用优惠的商品最高单价 + *
+ * 可用优惠的商品最高单价,单位:分。 + * 示例值:100 + */ + @SerializedName(value = "single_price_max") + private Integer singlePriceMax; + + /** + * 减至后的优惠单价 + *
+ * 减至后的优惠单价,单位:分。 + * 示例值:100 + */ + @SerializedName(value = "cut_to_price") + private Integer cutToPrice; + } + + @Data + @NoArgsConstructor + public static class NormalCouponInformation implements Serializable { + /** + * 面额 + *
+ * 面额,单位:分。 + * 示例值:100 + */ + @SerializedName(value = "coupon_amount") + private Integer couponAmount; + + /** + * 门槛 + *
+ * 使用券金额门槛,单位:分。 + * 示例值:100 + */ + @SerializedName(value = "transaction_minimum") + private Integer transactionMinimum; + } +} diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/FavorCouponsQueryRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/FavorCouponsQueryRequest.java new file mode 100644 index 0000000000..e8d263c66c --- /dev/null +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/FavorCouponsQueryRequest.java @@ -0,0 +1,155 @@ +package com.github.binarywang.wxpay.bean.marketing; + +import com.google.gson.annotations.SerializedName; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +/** + * 根据商户号查用户的券 + *
+ * 文档地址:https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/marketing/convention/chapter3_9.shtml + *+ * + * @author thinsstar + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class FavorCouponsQueryRequest implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + *
+ * 字段名:用户标识 + * 变量名:openid + * 是否必填:是 + * 类型:string[1,128] + * 描述: + * 用户在商户appid 下的唯一标识。 + * 示例值:2323dfsdf342342 + *+ */ + @SerializedName(value = "openid") + private String openid; + + /** + *
+ * 字段名:公众账号ID + * 变量名:appid + * 是否必填:是 + * 类型:string[1,128] + * 描述: + * 微信为发券方商户分配的公众账号ID,接口传入的所有appid应该为公众号的appid(在mp.weixin.qq.com申请的),不能为APP的appid(在open.weixin.qq.com申请的)。 + * 示例值:wx233544546545989 + *+ */ + @SerializedName(value = "appid") + private String appid; + + /** + *
+ * 字段名:批次号 + * 变量名:stock_id + * 是否必填:否 + * 类型:string[1,20] + * 描述: + * 批次号,是否指定批次号查询,填写available_mchid,该字段不生效。 + * 示例值:9865000 + *+ */ + @SerializedName(value = "stock_id") + private String stockId; + + /** + *
+ * 字段名:券状态 + * 变量名:status + * 是否必填:否 + * 类型:string[1,6] + * 描述: + * 代金券状态: + * SENDED:可用 + * USED:已实扣 + * 填写available_mchid,该字段不生效。 + * 示例值:USED + *+ */ + @SerializedName(value = "status") + private String status; + + /** + *
+ * 字段名:创建批次的商户号 + * 变量名:creator_mchid + * 是否必填:否 + * 类型:string[1,20] + * 描述: + * 批次创建方商户号。 + * 示例值:9865002 + *+ */ + @SerializedName(value = "creator_mchid") + private String creatorMchid; + + /** + *
+ * 字段名:批次发放商户号 + * 变量名:sender_mchid + * 是否必填:否 + * 类型:string[1,20] + * 描述: + * 批次创建方商户号。 + * 示例值:9865002 + *+ */ + @SerializedName(value = "sender_mchid") + private String senderMchid; + + /** + *
+ * 字段名:可用商户号 + * 变量名:available_mchid + * 是否必填:否 + * 类型:string[1,20] + * 描述: + * 批次创建方商户号。 + * 示例值:9865002 + *+ */ + @SerializedName(value = "available_mchid") + private String availableMchid; + + /** + *
+ * 字段名:分页页码 + * 变量名:offset + * 是否必填:是 + * 类型:uint32 + * 描述: + * 页码从0开始,默认第0页。 + * 示例值:1 + *+ */ + @SerializedName(value = "offset") + private Integer offset; + + /** + *
+ * 字段名:分页大小 + * 变量名:limit + * 是否必填:是 + * 类型:uint32 + * 描述: + * 分页大小,最大10。 + * 示例值:8 + *+ */ + @SerializedName(value = "limit") + private Integer limit; +} diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/FavorCouponsQueryResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/FavorCouponsQueryResult.java new file mode 100644 index 0000000000..2c47a99fd5 --- /dev/null +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/FavorCouponsQueryResult.java @@ -0,0 +1,57 @@ +package com.github.binarywang.wxpay.bean.marketing; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; +import lombok.NoArgsConstructor; +import me.chanjar.weixin.common.util.json.WxGsonBuilder; + +import java.util.List; + +/** + * 条件查询代金券批次列表结果对象 + * + * @author thinsstar + */ +@NoArgsConstructor +@Data +public class FavorCouponsQueryResult { + + public static FavorCouponsQueryResult fromJson(String json) { + return WxGsonBuilder.create().fromJson(json, FavorCouponsQueryResult.class); + } + + /** + * 查询结果总数 + *
+ * 查询结果总数 + * 示例值:100 + */ + @SerializedName("total_count") + private Integer totalCount; + + /** + * 批次详情 + *
+ * 批次详情
+ */
+ @SerializedName("data")
+ private List
+ * 分页大小
+ * 示例值:10
+ */
+ @SerializedName("limit")
+ private Integer limit;
+
+ /**
+ * 分页页码
+ *
+ * 分页页码
+ * 示例值:10
+ */
+ @SerializedName("offset")
+ private Integer offset;
+}
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/FavorStocksCreateRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/FavorStocksCreateRequest.java
new file mode 100644
index 0000000000..9b75008208
--- /dev/null
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/FavorStocksCreateRequest.java
@@ -0,0 +1,736 @@
+package com.github.binarywang.wxpay.bean.marketing;
+
+import com.github.binarywang.wxpay.bean.marketing.enums.BackgroundColorEnum;
+import com.github.binarywang.wxpay.bean.marketing.enums.StockTypeEnum;
+import com.github.binarywang.wxpay.bean.marketing.enums.TradeTypeEnum;
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 创建代金券批次
+ *
+ * 微信为每个代金券批次分配的唯一ID。
+ * 示例值:98065001
+ */
+ @SerializedName("stock_id")
+ private String stockId;
+}
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/FavorStocksFlowGetResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/FavorStocksFlowGetResult.java
new file mode 100644
index 0000000000..1c7259da8f
--- /dev/null
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/FavorStocksFlowGetResult.java
@@ -0,0 +1,47 @@
+package com.github.binarywang.wxpay.bean.marketing;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import me.chanjar.weixin.common.util.json.WxGsonBuilder;
+
+/**
+ * 获取下载结果对象
+ *
+ * @author thinsstar
+ */
+@NoArgsConstructor
+@Data
+public class FavorStocksFlowGetResult {
+
+ public static FavorStocksFlowGetResult fromJson(String json) {
+ return WxGsonBuilder.create().fromJson(json, FavorStocksFlowGetResult.class);
+ }
+
+ /**
+ * 下载链接
+ *
+ * 流水文件下载链接,30s内有效。
+ * 示例值:download://example.csv
+ */
+ @SerializedName("url")
+ private String url;
+
+ /**
+ * 安全校验码
+ *
+ * 文件内容的哈希值,防止篡改。
+ * 示例值:8ae0eb442c408d2e90d669d6f4ad6b7e6e049d6f
+ */
+ @SerializedName("hash_value")
+ private String hashValue;
+
+ /**
+ * 哈希算法类型
+ *
+ * 哈希算法类型,目前只支持SHA1。
+ * 示例值:SHA1
+ */
+ @SerializedName("hash_type")
+ private String hashType;
+}
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/FavorStocksGetResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/FavorStocksGetResult.java
new file mode 100644
index 0000000000..cdde077bc7
--- /dev/null
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/FavorStocksGetResult.java
@@ -0,0 +1,319 @@
+package com.github.binarywang.wxpay.bean.marketing;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import me.chanjar.weixin.common.util.json.WxGsonBuilder;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 查询批次详情结果对象
+ *
+ * @author thinsstar
+ */
+@NoArgsConstructor
+@Data
+public class FavorStocksGetResult {
+
+ public static FavorStocksGetResult fromJson(String json) {
+ return WxGsonBuilder.create().fromJson(json, FavorStocksGetResult.class);
+ }
+
+ /**
+ * 批次号
+ *
+ * 微信为每个代金券批次分配的唯一id。
+ * 示例值:9836588
+ */
+ @SerializedName("stock_id")
+ private String stockId;
+
+ /**
+ * 创建批次的商户号
+ *
+ * 批次创建方商户号。
+ * 示例值:123456
+ */
+ @SerializedName("stock_creator_mchid")
+ private String stockCreatorMchid;
+
+ /**
+ * 批次名称
+ *
+ * 批次名称
+ * 示例值:微信支付批次
+ */
+ @SerializedName("stock_name")
+ private String stockName;
+
+ /**
+ * 批次状态
+ *
+ * 批次状态
+ * 枚举值:
+ * unactivated:未激活
+ * audit:审核中
+ * running:运行中
+ * stoped:已停止
+ * paused:暂停发放
+ * 示例值:paused
+ */
+ @SerializedName("status")
+ private String status;
+
+ /**
+ * 创建时间
+ *
+ * 批次创建时间,遵循rfc3339标准格式,格式为YYYY-MM-DDTHH:mm:ss.sss+TIMEZONE,YYYY-MM-DD表示年月日,T出现在字符串中,表示time元素的开头,HH:mm:ss.sss表示时分秒毫秒,TIMEZONE表示时区(+08:00表示东八区时间,领先UTC 8小时,即北京时间)。例如:2015-05-20T13:29:35.120+08:00表示,北京时间2015年5月20日 13点29分35秒。
+ * 示例值:2015-05-20T13:29:35.120+08:00
+ */
+ @SerializedName("create_time")
+ private String create_time;
+
+ /**
+ * 使用说明
+ *
+ * 批次描述信息
+ * 示例值:微信支付营销
+ */
+ @SerializedName("description")
+ private String description;
+
+ /**
+ * 满减券批次使用规则
+ *
+ * 普通发券批次特定信息。
+ * 示例值:1900000109
+ */
+ @SerializedName("stock_use_rule")
+ private StockUseRule stockUseRule;
+
+ /**
+ * 可用开始时间
+ *
+ * 可用开始时间,遵循rfc3339标准格式,格式为YYYY-MM-DDTHH:mm:ss.sss+TIMEZONE,YYYY-MM-DD表示年月日,T出现在字符串中,表示time元素的开头,HH:mm:ss.sss表示时分秒毫秒,TIMEZONE表示时区(+08:00表示东八区时间,领先UTC 8小时,即北京时间)。例如:2015-05-20T13:29:35.120+08:00表示,北京时间2015年5月20日 13点29分35秒。
+ * 示例值:2015-05-20T13:29:35.120+08:00
+ */
+ @SerializedName("available_begin_time")
+ private String availableBeginTime;
+
+ /**
+ * 可用结束时间
+ *
+ * 可用结束时间,遵循rfc3339标准格式,格式为YYYY-MM-DDTHH:mm:ss.sss+TIMEZONE,YYYY-MM-DD表示年月日,T出现在字符串中,表示time元素的开头,HH:mm:ss.sss表示时分秒毫秒,TIMEZONE表示时区(+08:00表示东八区时间,领先UTC 8小时,即北京时间)。例如:2015-05-20T13:29:35.120+08:00表示,北京时间2015年5月20日 13点29分35秒。
+ * 示例值:2015-05-20T13:29:35.120+08:00
+ */
+ @SerializedName("available_end_time")
+ private String availableEndTime;
+
+ /**
+ * 已发券数量
+ *
+ * 已发券数量
+ * 示例值:100
+ */
+ @SerializedName("distributed_coupons")
+ private Integer distributedCoupons;
+
+ /**
+ * 是否无资金流
+ *
+ * 是否无资金流。
+ * ture:是
+ * false:否
+ * 示例值:true
+ */
+ @SerializedName("no_cash")
+ private Boolean noCash;
+
+ /**
+ * 激活批次的时间
+ *
+ * 批次激活开启时间,遵循rfc3339标准格式,格式为YYYY-MM-DDTHH:mm:ss.sss+TIMEZONE,YYYY-MM-DD表示年月日,T出现在字符串中,表示time元素的开头,HH:mm:ss.sss表示时分秒毫秒,TIMEZONE表示时区(+08:00表示东八区时间,领先UTC 8小时,即北京时间)。例如:2015-05-20T13:29:35.120+08:00表示,北京时间2015年5月20日 13点29分35秒。
+ * 示例值:2015-05-20T13:29:35.120+08:00
+ */
+ @SerializedName("start_time")
+ private String startTime;
+
+ /**
+ * 终止批次的时间
+ *
+ * 批次永久停止时间,遵循rfc3339标准格式,格式为YYYY-MM-DDTHH:mm:ss.sss+TIMEZONE,YYYY-MM-DD表示年月日,T出现在字符串中,表示time元素的开头,HH:mm:ss.sss表示时分秒毫秒,TIMEZONE表示时区(+08:00表示东八区时间,领先UTC 8小时,即北京时间)。例如:2015-05-20T13:29:35.120+08:00表示,北京时间2015年5月20日 13点29分35秒。
+ * 示例值:2015-05-20T13:29:35.120+08:00
+ */
+ @SerializedName("stop_time")
+ private String stopTime;
+
+ /**
+ * 单品优惠特定信息
+ *
+ * 单品优惠特定信息
+ */
+ @SerializedName("cut_to_message")
+ private CutToMessage cutToMessage;
+
+ /**
+ * 是否单品优惠
+ *
+ * 枚举值:
+ * true:是
+ * false:否
+ * 示例值:true
+ */
+ @SerializedName("singleitem")
+ private Boolean singleitem;
+
+ /**
+ * 批次类型
+ *
+ * 批次类型, 枚举值:
+ * NORMAL:代金券批次
+ * DISCOUNT_CUT:立减与折扣
+ * OTHER:其他
+ * 示例值:NORMAL
+ */
+ @SerializedName("stock_type")
+ private String stockType;
+
+ @Data
+ @NoArgsConstructor
+ public static class CutToMessage implements Serializable {
+ /**
+ * 可用优惠的商品最高单价
+ *
+ * 可用优惠的商品最高单价,单位:分。
+ * 示例值:100
+ */
+ @SerializedName(value = "single_price_max")
+ private Integer singlePriceMax;
+
+ /**
+ * 减至后的优惠单价
+ *
+ * 减至后的优惠单价,单位:分。
+ * 示例值:100
+ */
+ @SerializedName(value = "cut_to_price")
+ private Integer cutToPrice;
+ }
+
+ @Data
+ @NoArgsConstructor
+ public static class StockUseRule implements Serializable {
+ /**
+ * 发放总上限
+ *
+ * 最大发券数
+ * 示例值:100
+ */
+ @SerializedName(value = "max_coupons")
+ private Integer maxCoupons;
+
+ /**
+ * 总预算
+ *
+ * 总消耗金额,单位:分。
+ * 示例值:5000
+ */
+ @SerializedName(value = "max_amount")
+ private Integer maxAmount;
+
+ /**
+ * 单天发放上限金额
+ *
+ * 单天最高消耗金额,单位:分。
+ * 示例值:400
+ */
+ @SerializedName(value = "max_amount_by_day")
+ private Integer maxAmountByDay;
+
+ /**
+ * 固定面额批次特定信息
+ *
+ * 固定面额发券批次特定信息。
+ */
+ @SerializedName(value = "fixed_normal_coupon")
+ private FixedNormalCoupon fixedNormalCoupon;
+
+ /**
+ * 单个用户可领个数
+ *
+ * 单个用户可领个数,每个用户最多100张券
+ * 示例值:3
+ */
+ @SerializedName(value = "max_coupons_per_user")
+ private Integer maxCouponsPerUser;
+
+ /**
+ * 券类型
+ *
+ * 枚举值:
+ * NORMAL:满减券
+ * CUT_TO:减至券
+ * 示例值:NORMAL
+ */
+ @SerializedName(value = "coupon_type")
+ private String couponType;
+
+ /**
+ * 订单优惠标记
+ *
+ * 订单优惠标记
+ * 特殊规则:单个优惠标记的字符长度为【1,128】,条目个数限制为【1,50】。
+ * 示例值:{'123456','23456'}
+ */
+ @SerializedName(value = "goods_tag")
+ private List
+ * 默认不限制
+ * 枚举值:
+ * MICROAPP:小程序支付
+ * APPPAY:APP支付
+ * PPAY:免密支付
+ * CARD:付款码支付
+ * FACE:人脸支付
+ * OTHER:(公众号、扫码等)
+ * 示例值:MICROAPP
+ */
+ @SerializedName(value = "trade_type")
+ private List
+ * 枚举值:
+ * true:是
+ * false:否
+ * 示例值:true
+ */
+ @SerializedName(value = "combine_use")
+ private Boolean combineUse;
+ }
+
+ @Data
+ @NoArgsConstructor
+ public static class FixedNormalCoupon implements Serializable {
+ /**
+ * 面额
+ *
+ * 面额,单位:分。
+ * 示例值:100
+ */
+ @SerializedName(value = "coupon_amount")
+ private Integer couponAmount;
+
+ /**
+ * 门槛
+ *
+ * 使用券金额门槛,单位:分。
+ * 示例值:100
+ */
+ @SerializedName(value = "transaction_minimum")
+ private Integer transactionMinimum;
+ }
+}
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/FavorStocksItemsGetResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/FavorStocksItemsGetResult.java
new file mode 100644
index 0000000000..6b3153eb48
--- /dev/null
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/FavorStocksItemsGetResult.java
@@ -0,0 +1,68 @@
+package com.github.binarywang.wxpay.bean.marketing;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import me.chanjar.weixin.common.util.json.WxGsonBuilder;
+
+import java.util.List;
+
+/**
+ * 查询批次可以单品结果对象
+ *
+ * @author thinsstar
+ */
+@NoArgsConstructor
+@Data
+public class FavorStocksItemsGetResult {
+
+ public static FavorStocksItemsGetResult fromJson(String json) {
+ return WxGsonBuilder.create().fromJson(json, FavorStocksItemsGetResult.class);
+ }
+
+ /**
+ * 可用单品编码总数
+ *
+ * 可用单品编码总数。
+ * 示例值: 200
+ */
+ @SerializedName("total_count")
+ private Integer totalCount;
+
+ /**
+ * 可用单品编码
+ *
+ * 可用单品编码
+ * 特殊规则:单个商品编码的字符长度为【1,128】,条目个数限制为【1,50】。
+ * 示例值:1232001
+ */
+ @SerializedName("data")
+ private List
+ * 分页大小,最大10。
+ * 示例值:8
+ */
+ @SerializedName("limit")
+ private Integer limit;
+
+ /**
+ * 分页页码
+ *
+ * 页码从0开始,默认第0页。
+ * 示例值:1
+ */
+ @SerializedName("offset")
+ private Integer offset;
+
+ /**
+ * 批次号
+ *
+ * 批次号
+ * 示例值: 9865000
+ */
+ @SerializedName("stock_id")
+ private String stockId;
+}
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/FavorStocksMerchantsGetResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/FavorStocksMerchantsGetResult.java
new file mode 100644
index 0000000000..0e0284b8a2
--- /dev/null
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/FavorStocksMerchantsGetResult.java
@@ -0,0 +1,68 @@
+package com.github.binarywang.wxpay.bean.marketing;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import me.chanjar.weixin.common.util.json.WxGsonBuilder;
+
+import java.util.List;
+
+/**
+ * 查询批次可以商户结果对象
+ *
+ * @author thinsstar
+ */
+@NoArgsConstructor
+@Data
+public class FavorStocksMerchantsGetResult {
+
+ public static FavorStocksMerchantsGetResult fromJson(String json) {
+ return WxGsonBuilder.create().fromJson(json, FavorStocksMerchantsGetResult.class);
+ }
+
+ /**
+ * 可用商户总数量
+ *
+ * 可用商户总数量。
+ * 示例值: 200
+ */
+ @SerializedName("total_count")
+ private Integer totalCount;
+
+ /**
+ * 可用商户列表
+ *
+ * 可用商户列表
+ * 特殊规则:单个商户号的字符长度为【1,20】,条目个数限制为【1,50】。
+ * 示例值:1232001
+ */
+ @SerializedName("data")
+ private List
+ * 分页大小,最大10。
+ * 示例值:8
+ */
+ @SerializedName("limit")
+ private Integer limit;
+
+ /**
+ * 分页页码
+ *
+ * 页码从0开始,默认第0页。
+ * 示例值:1
+ */
+ @SerializedName("offset")
+ private Integer offset;
+
+ /**
+ * 批次号
+ *
+ * 批次号
+ * 示例值: 9865000
+ */
+ @SerializedName("stock_id")
+ private String stockId;
+}
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/FavorStocksQueryRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/FavorStocksQueryRequest.java
new file mode 100644
index 0000000000..8e37d2f74c
--- /dev/null
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/FavorStocksQueryRequest.java
@@ -0,0 +1,114 @@
+package com.github.binarywang.wxpay.bean.marketing;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ * 条件查询代金券批次列表
+ *
+ * 经过条件筛选,查询到的批次总数量。
+ * 示例值:10
+ */
+ @SerializedName("total_count")
+ private Integer totalCount;
+
+ /**
+ * 批次详情
+ *
+ * 批次详情
+ */
+ @SerializedName("data")
+ private List
+ * 分页大小,最大10。
+ * 示例值:8
+ */
+ @SerializedName("limit")
+ private Integer limit;
+
+ /**
+ * 分页页码
+ *
+ * 页码从0开始,默认第0页。
+ * 示例值:1
+ */
+ @SerializedName("offset")
+ private Integer offset;
+}
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/FavorStocksSetRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/FavorStocksSetRequest.java
new file mode 100644
index 0000000000..8de99e6529
--- /dev/null
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/FavorStocksSetRequest.java
@@ -0,0 +1,45 @@
+package com.github.binarywang.wxpay.bean.marketing;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ * 激活代金券批次
+ * 暂停代金券批次
+ * 重启代金券批次
+ *
+ * 生效时间,遵循rfc3339标准格式,格式为YYYY-MM-DDTHH:mm:ss.sss+TIMEZONE,YYYY-MM-DD表示年月日,T出现在字符串中,表示time元素的开头,HH:mm:ss.sss表示时分秒毫秒,TIMEZONE表示时区(+08:00表示东八区时间,领先UTC 8小时,即北京时间)。例如:2015-05-20T13:29:35.120+08:00表示,北京时间2015年5月20日 13点29分35秒。
+ * 示例值:2015-05-20T13:29:35.120+08:00
+ */
+ @SerializedName("start_time")
+ private String startTime;
+
+ /**
+ * 批次号
+ *
+ * 微信为每个代金券批次分配的唯一ID。
+ * 示例值:98065001
+ */
+ @SerializedName("stock_id")
+ private String stockId;
+}
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/enums/BackgroundColorEnum.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/enums/BackgroundColorEnum.java
new file mode 100644
index 0000000000..d9ba753346
--- /dev/null
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/enums/BackgroundColorEnum.java
@@ -0,0 +1,75 @@
+package com.github.binarywang.wxpay.bean.marketing.enums;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * 券的背景颜色
+ *
+ * @author thinsstar
+ */
+@Getter
+@AllArgsConstructor
+public enum BackgroundColorEnum {
+
+ /**
+ * 颜色 #63B359
+ */
+ COLOR010("COLOR010", "#63B359"),
+
+ /**
+ * 颜色 #2C9F67
+ */
+ COLOR020("COLOR020", "#2C9F67"),
+
+ /**
+ * 颜色 #509FC9
+ */
+ COLOR030("COLOR030", "#509FC9"),
+
+ /**
+ * 颜色 #5885CF
+ */
+ COLOR040("COLOR040", "#5885CF"),
+
+ /**
+ * 颜色 #9062C0
+ */
+ COLOR050("COLOR050", "#9062C0"),
+
+ /**
+ * 颜色 #D09A45
+ */
+ COLOR060("COLOR060", "#D09A45"),
+
+ /**
+ * 颜色 #E4B138
+ */
+ COLOR070("COLOR070", "#E4B138"),
+
+ /**
+ * 颜色 #EE903C
+ */
+ COLOR080("COLOR080", "#EE903C"),
+
+ /**
+ * 颜色 #DD6549
+ */
+ COLOR090("COLOR090", "#DD6549"),
+
+ /**
+ * 颜色 #CC463D
+ */
+ COLOR100("COLOR100", "#CC463D"),
+ ;
+
+ /**
+ * 色值
+ */
+ private final String value;
+
+ /**
+ * 十六进制颜色码
+ */
+ private final String code;
+}
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/enums/StockTypeEnum.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/enums/StockTypeEnum.java
new file mode 100644
index 0000000000..a53c5c982b
--- /dev/null
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/enums/StockTypeEnum.java
@@ -0,0 +1,25 @@
+package com.github.binarywang.wxpay.bean.marketing.enums;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * 批次类型
+ *
+ * @author thinsstar
+ */
+@Getter
+@AllArgsConstructor
+public enum StockTypeEnum {
+
+ /**
+ * NORMAL:固定面额满减券批次
+ */
+ NORMAL("NORMAL"),
+ ;
+
+ /**
+ * 批次类型
+ */
+ private final String value;
+}
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/enums/TradeTypeEnum.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/enums/TradeTypeEnum.java
new file mode 100644
index 0000000000..5e8c96148a
--- /dev/null
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/enums/TradeTypeEnum.java
@@ -0,0 +1,45 @@
+package com.github.binarywang.wxpay.bean.marketing.enums;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * 支付方式
+ *
+ * @author thinsstar
+ */
+@Getter
+@AllArgsConstructor
+public enum TradeTypeEnum {
+
+ /**
+ * MICROAPP:小程序支付
+ */
+ MICROAPP("MICROAPP"),
+ /**
+ * APPPAY:APP支付
+ */
+ APPPAY("APPPAY"),
+ /**
+ * PPAY:免密支付
+ */
+ PPAY("PPAY"),
+ /**
+ * CARD:刷卡支付
+ */
+ CARD("CARD"),
+ /**
+ * FACE:人脸支付
+ */
+ FACE("FACE"),
+ /**
+ * OTHER:其他支付
+ */
+ OTHER("OTHER"),
+ ;
+
+ /**
+ * 支付方式
+ */
+ private final String value;
+}
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/media/MarketingImageUploadResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/media/MarketingImageUploadResult.java
new file mode 100644
index 0000000000..c0ee3e8a61
--- /dev/null
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/media/MarketingImageUploadResult.java
@@ -0,0 +1,29 @@
+package com.github.binarywang.wxpay.bean.media;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import me.chanjar.weixin.common.util.json.WxGsonBuilder;
+
+/**
+ * 媒体文件上传返回结果对象
+ *
+ * @author thinsstar
+ */
+@NoArgsConstructor
+@Data
+public class MarketingImageUploadResult {
+
+ public static MarketingImageUploadResult fromJson(String json) {
+ return WxGsonBuilder.create().fromJson(json, MarketingImageUploadResult.class);
+ }
+
+ /**
+ * 媒体文件URL地址
+ *
+ * 微信返回的媒体文件标识url。有效期为永久
+ * 示例值:https://qpic.cn/xxx
+ */
+ @SerializedName("media_url")
+ private String mediaUrl;
+}
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/MarketingFavorService.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/MarketingFavorService.java
new file mode 100644
index 0000000000..94efa81c4c
--- /dev/null
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/MarketingFavorService.java
@@ -0,0 +1,184 @@
+package com.github.binarywang.wxpay.service;
+
+import com.github.binarywang.wxpay.bean.marketing.*;
+import com.github.binarywang.wxpay.exception.WxPayException;
+
+/**
+ *
+ * 文档地址:https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/marketing/convention/chapter3_1.shtml
+ *
+ *
+ * @author thinsstar
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class FavorStocksCreateRequest implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ *
+ * 字段名:批次名称
+ * 变量名:stock_name
+ * 是否必填:是
+ * 类型:string[1,20]
+ * 描述:
+ * 批次名称
+ * 校验规则:
+ * 1、批次名称最多9个中文汉字
+ * 2、批次名称最多20个字母
+ * 3、批次名称中不能包含不当内容和特殊字符 _ , ; |
+ * 示例值:微信支付代金券批次
+ *
+ */
+ @SerializedName(value = "stock_name")
+ private String stockName;
+
+ /**
+ *
+ * 字段名:批次备注
+ * 变量名:comment
+ * 是否必填:否
+ * 类型:string[1,60]
+ * 描述:
+ * 仅制券商户可见,用于自定义信息。
+ * 校验规则:批次备注最多60个UTF8字符数
+ * 示例值:零售批次
+ *
+ */
+ @SerializedName(value = "comment")
+ private String comment;
+
+ /**
+ *
+ * 字段名:归属商户号
+ * 变量名:belong_merchant
+ * 是否必填:是
+ * 类型:string[1,20]
+ * 描述:
+ * 批次归属商户号
+ * 该字段暂未开放
+ * 示例值:98568865
+ *
+ */
+ @SerializedName(value = "belong_merchant")
+ private String belongMerchant;
+
+ /**
+ *
+ * 字段名:可用时间-开始时间
+ * 变量名:available_begin_time
+ * 是否必填:是
+ * 类型:string[1,32]
+ * 描述:
+ * 批次开始时间,遵循rfc3339标准格式,格式为YYYY-MM-DDTHH:mm:ss.sss+TIMEZONE,YYYY-MM-DD表示年月日,T出现在字符串中,表示time元素的开头,HH:mm:ss.sss表示时分秒毫秒,TIMEZONE表示时区(+08:00表示东八区时间,领先UTC 8小时,即北京时间)。例如:2015-05-20T13:29:35.120+08:00表示,北京时间2015年5月20日 13点29分35秒。
+ * 校验规则:
+ * 1、开始时间不可早于当前时间
+ * 2、不能创建365天后开始的批次
+ * 示例值:2015-05-20T13:29:35.120+08:00
+ *
+ */
+ @SerializedName(value = "available_begin_time")
+ private String availableBeginTime;
+
+ /**
+ *
+ * 字段名:可用时间-结束时间
+ * 变量名:available_end_time
+ * 是否必填:是
+ * 类型:string[1,32]
+ * 描述:
+ * 批次结束时间,遵循rfc3339标准格式,格式为YYYY-MM-DDTHH:mm:ss.sss+TIMEZONE,YYYY-MM-DD表示年月日,T出现在字符串中,表示time元素的开头,HH:mm:ss.sss表示时分秒毫秒,TIMEZONE表示时区(+08:00表示东八区时间,领先UTC 8小时,即北京时间)。例如:2015-05-20T13:29:35.120+08:00表示,北京时间2015年5月20日 13点29分35秒。
+ * 校验规则:
+ * 1、结束时间需晚于开始时间
+ * 2、可用时间最长为90天
+ * 3、有效时间间隔最短为1s
+ * 示例值:2015-05-20T13:29:35.120+08:00
+ *
+ */
+ @SerializedName(value = "available_end_time")
+ private String availableEndTime;
+
+ /**
+ *
+ * 字段名:发放规则
+ * 变量名:stock_use_rule
+ * 是否必填:是
+ * 类型:object
+ * 描述:批次使用规则
+ *
+ */
+ @SerializedName(value = "stock_use_rule")
+ private StockUseRule stockUseRule;
+
+ /**
+ *
+ * 字段名:样式设置
+ * 变量名:pattern_info
+ * 是否必填:否
+ * 类型:object
+ * 描述:代金券详情页
+ *
+ */
+ @SerializedName(value = "pattern_info")
+ private PatternInfo patternInfo;
+
+ /**
+ *
+ * 字段名:核销规则
+ * 变量名:coupon_use_rule
+ * 是否必填:是
+ * 类型:object
+ * 描述:核销规则
+ *
+ */
+ @SerializedName(value = "coupon_use_rule")
+ private CouponUseRule couponUseRule;
+
+ /**
+ *
+ * 字段名:营销经费
+ * 变量名:no_cash
+ * 是否必填:是
+ * 类型:bool
+ * 描述:
+ * 营销经费。枚举值:
+ * true:免充值
+ * false:预充值
+ * 1、免充值:制券方无需提前充值资金,用户核销代金券时,直接从订单原价中扣除优惠减价金额,最终只将用户实际支付的金额结算给核销商户,商户实收少于订单原价。
+ * 2、预充值:制券方需将优惠预算提前充值到微信支付商户可用余额中,用户核销代金券时,系统从制券方商户可用余额中扣除优惠减价部分对应的资金,连同用户实际支付的资金,一并结算给核销商户,不影响实收。
+ * 示例值:false
+ *
+ */
+ @SerializedName(value = "no_cash")
+ private Boolean noCash;
+
+ /**
+ *
+ * 字段名:批次类型
+ * 变量名:stock_type
+ * 是否必填:是
+ * 类型:string[1,16]
+ * 描述:
+ * 批次类型,仅支持:
+ * NORMAL:固定面额满减券批次
+ * 示例值:NORMAL
+ *
+ */
+ @SerializedName(value = "stock_type")
+ private StockTypeEnum stockType;
+
+ /**
+ *
+ * 字段名:商户单据号
+ * 变量名:out_request_no
+ * 是否必填:是
+ * 类型:string[1,128]
+ * 描述:
+ * 商户创建批次凭据号(格式:商户id+日期+流水号),可包含英文字母,数字,|,_,*,-等内容,不允许出现其他不合法符号,商户侧需保持商户单据号全局唯一。
+ *
+ */
+ @SerializedName(value = "out_request_no")
+ private String outRequestNo;
+
+ /**
+ *
+ * 字段名:扩展属性
+ * 变量名:ext_info
+ * 是否必填:否
+ * 类型:string[1,128]
+ * 描述:
+ * 扩展属性字段,按json格式,如无需要则不填写。
+ * 示例值:{'exinfo1':'1234','exinfo2':'3456'}
+ *
+ */
+ @SerializedName(value = "ext_info")
+ private String extInfo;
+
+ @Data
+ @NoArgsConstructor
+ public static class StockUseRule implements Serializable {
+ /**
+ *
+ * 字段名:发放总上限
+ * 变量名:max_coupons
+ * 是否必填:是
+ * 类型:uint64
+ * 描述:
+ * 最大发券数
+ * 校验规则:
+ * 1、发放总个数最少5个
+ * 2、发放总个数最多1000万个
+ * 示例值:100
+ *
+ */
+ @SerializedName(value = "max_coupons")
+ private Integer maxCoupons;
+
+ /**
+ *
+ * 字段名:总预算
+ * 变量名:max_amount
+ * 是否必填:是
+ * 类型:uint64
+ * 描述:
+ * 最大发券预算,当营销经费no_cash选择预充值false时,激活批次时会从制券商户的余额中扣除预算,请保证账户金额充足,单位:分
+ * max_amount需要等于coupon_amount(面额) * max_coupons(发放总上限)
+ * 校验规则:批次总预算最多1亿元
+ * 示例值:5000
+ *
+ */
+ @SerializedName(value = "max_amount")
+ private Integer maxAmount;
+
+ /**
+ *
+ * 字段名:单天预算发放上限
+ * 变量名:max_amount_by_day
+ * 是否必填:否
+ * 类型:uint64
+ * 描述:
+ * 设置此字段,允许指定单天最大发券预算,单位:分。
+ * 校验规则:不能大于总预算
+ * 示例值:400
+ *
+ */
+ @SerializedName(value = "max_amount_by_day")
+ private Integer maxAmountByDay;
+
+ /**
+ *
+ * 字段名:单个用户可领个数
+ * 变量名:max_coupons_per_user
+ * 是否必填:是
+ * 类型:uint32
+ * 描述:
+ * 活动期间每个用户可领个数,当开启了自然人限领时,多个微信号同属于一个身份证时,视为同一用户。
+ * 校验规则:
+ * 1、不能大于发放总个数
+ * 2、最少为1个,最多为60个
+ * 示例值:3
+ *
+ */
+ @SerializedName(value = "max_coupons_per_user")
+ private Integer maxCouponsPerUser;
+
+ /**
+ *
+ * 字段名:是否开启自然人限制
+ * 变量名:natural_person_limit
+ * 是否必填:是
+ * 类型:bool
+ * 描述:
+ * 当开启了自然人限领时,多个微信号同属于一个身份证时,视为同一用户,枚举值
+ * true:是
+ * false:否
+ * 示例值:false
+ *
+ */
+ @SerializedName(value = "natural_person_limit")
+ private Boolean naturalPersonLimit;
+
+ /**
+ *
+ * 字段名:是否开启防刷拦截
+ * 变量名:prevent_api_abuse
+ * 是否必填:是
+ * 类型:bool
+ * 描述:
+ * 若开启防刷拦截,当用户命中恶意、小号、机器、羊毛党、黑产等风险行为时,无法成功发放代金券。
+ * 枚举值
+ * true:是
+ * false:否
+ * 示例值:false
+ *
+ */
+ @SerializedName(value = "prevent_api_abuse")
+ private Boolean preventApiAbuse;
+ }
+
+ @Data
+ @NoArgsConstructor
+ public static class PatternInfo implements Serializable {
+ /**
+ *
+ * 字段名:使用说明
+ * 变量名:description
+ * 是否必填:是
+ * 类型:string[1,3000]
+ * 描述:
+ * 用于说明详细的活动规则,会展示在代金券详情页。
+ * 校验规则:最多1000个UTF8字符
+ * 示例值:微信支付营销代金券
+ *
+ */
+ @SerializedName(value = "description")
+ private String description;
+
+ /**
+ *
+ * 字段名:商户logo
+ * 变量名:merchant_logo
+ * 是否必填:否
+ * 类型:string[1,128]
+ * 描述:
+ * 商户logo ,仅支持通过《图片上传API》接口获取的图片URL地址。
+ * 1、商户logo大小需为120像素*120像素。
+ * 2、支持JPG/JPEG/PNG格式,且图片小于1M。
+ * 3、最多128个UTF8字符
+ * 示例值:https://qpic.cn/xxx
+ *
+ */
+ @SerializedName(value = "merchant_logo")
+ private String merchantLogo;
+
+ /**
+ *
+ * 字段名:品牌名称
+ * 变量名:merchant_name
+ * 是否必填:否
+ * 类型:string[1,128]
+ * 描述:
+ * 品牌名称,展示在用户卡包
+ * 校验规则:
+ * 1、最多12个中文汉字
+ * 2、最多36个英文字符
+ * 示例值:微信支付
+ *
+ */
+ @SerializedName(value = "merchant_name")
+ private String merchantName;
+
+ /**
+ *
+ * 字段名:背景颜色
+ * 变量名:background_color
+ * 是否必填:否
+ * 类型:string[1,15]
+ * 描述:
+ * 券的背景颜色,可设置10种颜色,色值请参考卡券背景颜色图。颜色取值为颜色图中的颜色名称。可选枚举字段不用则不传,不可以传空值
+ * 示例值:COLOR020
+ *
+ */
+ @SerializedName(value = "background_color")
+ private BackgroundColorEnum backgroundColor;
+
+ /**
+ *
+ * 字段名:券详情图片
+ * 变量名:coupon_image
+ * 是否必填:是
+ * 类型:string[1,128]
+ * 描述:
+ * 券详情图片, 850像素*350像素,且图片大小不超过2M,支持JPG/PNG格式,仅支持通过《图片上传API》接口获取的图片URL地址。。
+ * 示例值:https://qpic.cn/xxx
+ *
+ */
+ @SerializedName(value = "coupon_image")
+ private Boolean couponImage;
+ }
+
+ @Data
+ @NoArgsConstructor
+ public static class CouponUseRule implements Serializable {
+ /**
+ *
+ * 字段名:券生效时间
+ * 变量名:coupon_available_time
+ * 是否必填:否
+ * 类型:object
+ * 描述:
+ * 允许指定券的特殊生效时间规则。
+ * 该字段暂未开放
+ *
+ */
+// @SerializedName(value = "coupon_available_time")
+// private CouponAvailableTime couponAvailableTime;
+
+ /**
+ *
+ * 字段名:固定面额满减券使用规则
+ * 变量名:fixed_normal_coupon
+ * 是否必填:否
+ * 类型:object
+ * 描述:
+ * stock_type为NORMAL时必填。
+ *
+ */
+ @SerializedName(value = "fixed_normal_coupon")
+ private FixedNormalCoupon fixedNormalCoupon;
+
+ /**
+ *
+ * 字段名:订单优惠标记
+ * 变量名:goods_tag
+ * 是否必填:否
+ * 类型:array
+ * 描述:
+ * 订单优惠标记,按json格式。
+ * 商户下单时需要传入相同的标记(goods_tag),用户同时符合其他规则才能享受优惠
+ * 校验规则:
+ * 1、最多允许录入50个
+ * 2、每个订单优惠标记支持字母/数字/下划线,不超过128个UTF8字符。
+ * 示例值:["123321","456654"]
+ *
+ */
+ @SerializedName(value = "goods_tag")
+ private List
+ * 字段名:指定付款方式
+ * 变量名:limit_pay
+ * 是否必填:否
+ * 类型:array[1,1]
+ * 描述:
+ * 指定付款方式的交易可核销/使用代金券,可指定零钱付款、指定银行卡付款,需填入支付方式编码, 不在此列表中的银行卡,暂不支持此功能。
+ * 校验规则:条目个数限制为【1,1】。
+ * 示例值:ICBC_CREDIT
+ *
+ */
+ @SerializedName(value = "limit_pay")
+ private List
+ * 字段名:指定银行卡BIN
+ * 变量名:limit_card
+ * 是否必填:否
+ * 类型:object
+ * 描述:
+ * 指定银行卡bin付款的交易可核销/使用代金券,当批次限定了指定银行卡时方可生效
+ *
+ */
+ @SerializedName(value = "limit_card")
+ private LimitCard limitCard;
+
+ /**
+ *
+ * 字段名:支付方式
+ * 变量名:trade_type
+ * 是否必填:否
+ * 类型:array
+ * 描述:
+ * 允许指定支付方式的交易才可核销/使用代金券,不填则默认“不限”。
+ * 枚举值:
+ * MICROAPP:小程序支付
+ * APPPAY:APP支付
+ * PPAY:免密支付
+ * CARD:刷卡支付
+ * FACE:人脸支付
+ * OTHER:其他支付
+ * 示例值:["MICROAPP","APPPAY"]
+ *
+ */
+ @SerializedName(value = "trade_type")
+ private List
+ * 字段名:是否可叠加其他优惠
+ * 变量名:combine_use
+ * 是否必填:否
+ * 类型:bool
+ * 描述:
+ * 允许指定本优惠是否可以和本商户号创建的其他券同时使用,不填则默认允许同时使用。枚举值:
+ * true:是
+ * false:否
+ * 示例值:false
+ *
+ */
+ @SerializedName(value = "combine_use")
+ private Boolean combineUse;
+
+ /**
+ *
+ * 字段名:可核销商品编码
+ * 变量名:available_items
+ * 是否必填:否
+ * 类型:array
+ * 描述:
+ * 包含指定SKU商品编码的交易才可核销/使用代金券:活动商户在交易下单时,需传入用户购买的所有SKU商品编码,当命中代金券中设置的商品编码时可享受优惠。
+ * 校验规则:
+ * 1、单个商品编码的字符长度为【1,128】
+ * 2、条目个数限制为【1,50】
+ * 示例值:['123321','456654']
+ *
+ */
+ @SerializedName(value = "available_items")
+ private List
+ * 字段名:不可核销商品编码
+ * 变量名:unavailable_items
+ * 是否必填:否
+ * 类型:array
+ * 描述:
+ * 该字段暂未开放
+ * 包含指定SKU商品编码的交易不可核销/使用代金券。
+ * 校验规则:
+ * 1、单个商品编码的字符长度为【1,128】
+ * 2、条目个数限制为【1,50】
+ * 示例值:['789987','56765']
+ *
+ */
+// @SerializedName(value = "unavailable_items")
+// private List
+ * 字段名:可用商户号
+ * 变量名:available_merchants
+ * 是否必填:是
+ * 类型:array
+ * 描述:
+ * 可用商户的交易才可核销/使用代金券。当营销经费no_cash=false时,可用商户允许填入任何类型的特约商户或普通商户
+ * 当营销经费no_cash=ture时,分为以下几种情况:
+ * 1、创建商户是普通商户或服务商特约商户(子商户):可添加本商户号或同品牌商户。
+ * 说明:若可用商户中,有特约商户(子商户),那么特约商户自己发起的交易、以及服务商帮特约商户发起的交易,都可以使用代金券。
+ * 2、创建商户是普通服务商:可添加已授权的子商户,详见《申请免充值代金券产品权限》。
+ * 说明:特约商户如果有多个服务商,那么服务商为他发起的交易,只要完成了免充值授权,都可以使用代金券;特约商户自己发起的交易不可以使用代金券。
+ * 3、创建商户是渠道商、银行服务商或从业机构:可直接添加旗下任意子商户,不需要子商户授权。
+ * 示例值:['9856000','9856111']
+ *
+ */
+ @SerializedName(value = "available_merchants")
+ private List
+// * 字段名:固定时间段可用
+// * 变量名:fix_available_time
+// * 是否必填:否
+// * 类型:object
+// * 描述:
+// * 允许指定券在特殊时间段生效。当设置固定时间段可用时不可设置领取后N天有效
+// * 该字段暂未开放
+// *
+// */
+// @SerializedName(value = "fix_available_time")
+// private FixAvailableTime fixAvailableTime;
+//
+// /**
+// *
+// * 字段名:领取后N天有效
+// * 变量名:second_day_available
+// * 是否必填:否
+// * 类型:bool
+// * 描述:
+// * 领取后,券的开始时间为领券后第二天,如7月1日领券,那么在7月2日00:00:00开始。
+// * 当设置领取后N天有效时,不可设置固定时间段可用。
+// * 枚举值:
+// * true:是
+// * false:否
+// * 该字段暂未开放
+// * 示例值:false
+// *
+// */
+// @SerializedName(value = "second_day_available")
+// private Boolean secondDayAvailable;
+//
+// /**
+// *
+// * 字段名:领取后有效时间
+// * 变量名:available_time_after_receive
+// * 是否必填:否
+// * 类型:uint32
+// * 描述:
+// * 领取后,券的结束时间为领取N天后,如设置领取后7天有效,那么7月1日领券,在7月7日23:59:59失效(在可用时间内计算失效时间,若券还未到领取后N天,但是已经到了可用结束时间,那么也会过期)
+// * 领取后有效时间,单位:分钟。
+// * 该字段暂未开放
+// * 示例值:1440
+// *
+// */
+// @SerializedName(value = "available_time_after_receive")
+// private Integer availableTimeAfterReceive;
+// }
+//
+// @Data
+// @NoArgsConstructor
+// public static class FixAvailableTime implements Serializable {
+// /**
+// *
+// * 字段名:可用星期数
+// * 变量名:available_week_day
+// * 是否必填:否
+// * 类型:uint32
+// * 描述:
+// * 允许指定每周固定星期数生效,0代表周日生效,1代表周一生效,以此类推;不填则代表在可用时间内周一至周日都生效。
+// * 该字段暂未开放
+// * 示例值:1,2
+// *
+// */
+// @SerializedName(value = "available_week_day")
+// private Integer availableWeekDay;
+//
+// /**
+// *
+// * 字段名:当天开始时间
+// * 变量名:begin_time
+// * 是否必填:否
+// * 类型:uint32
+// * 描述:
+// * 允许指定特殊生效星期数中的具体生效的时间段。
+// * 当天开始时间,单位:秒。
+// * 该字段暂未开放
+// * 示例值:0
+// *
+// */
+// @SerializedName(value = "begin_time")
+// private Integer beginTime;
+//
+// /**
+// *
+// * 字段名:当天结束时间
+// * 变量名:end_time
+// * 是否必填:否
+// * 类型:uint32
+// * 描述:
+// * 允许指定特殊生效星期数中的具体生效的时间段。
+// * 当天结束时间,单位:秒,默认为23点59分59秒。
+// * 该字段暂未开放
+// * 示例值:3600
+// *
+// */
+// @SerializedName(value = "end_time")
+// private Integer endTime;
+// }
+
+ @Data
+ @NoArgsConstructor
+ public static class FixedNormalCoupon implements Serializable {
+ /**
+ *
+ * 字段名:面额
+ * 变量名:fixed_normal_coupon
+ * 是否必填:是
+ * 类型:uint64
+ * 描述:
+ * 面额,单位:分。
+ * 校验规则:
+ * 1、必须为整数
+ * 2、必须大于1分且小于等于1000元
+ * 示例值:100
+ *
+ */
+ @SerializedName(value = "coupon_amount")
+ private Integer couponAmount;
+
+ /**
+ *
+ * 字段名:门槛
+ * 变量名:transaction_minimum
+ * 是否必填:是
+ * 类型:uint64
+ * 描述:
+ * 使用券金额门槛,单位:分。
+ * 若指定可核销商品编码,门槛则为可核销商品部分的消费金额,而不是订单的消费金额。
+ * 校验规则:使用门槛必须大于优惠金额
+ * 示例值:100
+ *
+ */
+ @SerializedName(value = "transaction_minimum")
+ private Integer transactionMinimum;
+ }
+
+ @Data
+ @NoArgsConstructor
+ public static class LimitCard implements Serializable {
+ /**
+ *
+ * 字段名:银行卡名称
+ * 变量名:name
+ * 是否必填:否
+ * 类型:string[1,4]
+ * 描述:
+ * 将在微信支付收银台向用户展示,最多4个中文汉字
+ * 示例值:精粹白金
+ *
+ */
+ @SerializedName(value = "name")
+ private String name;
+
+ /**
+ *
+ * 字段名:指定卡BIN
+ * 变量名:bin
+ * 是否必填:否
+ * 类型:array
+ * 描述:
+ * 使用指定卡BIN的银行卡支付方可享受优惠,按json格式
+ * 特殊规则:单个卡BIN的字符长度为【6,9】,条目个数限制为【1,10】。
+ * 示例值:['62123456','62123457']
+ *
+ */
+ @SerializedName(value = "bin")
+ private List
+ * 文档地址:https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/marketing/convention/chapter3_4.shtml
+ *
+ *
+ * @author thinsstar
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class FavorStocksQueryRequest implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ *
+ * 字段名:分页页码
+ * 变量名:offset
+ * 是否必填:是
+ * 类型:uint32
+ * 描述:
+ * 页码从0开始,默认第0页。
+ * 示例值:1
+ *
+ */
+ @SerializedName(value = "offset")
+ private Integer offset;
+
+ /**
+ *
+ * 字段名:分页大小
+ * 变量名:limit
+ * 是否必填:是
+ * 类型:uint32
+ * 描述:
+ * 分页大小,最大10。
+ * 示例值:8
+ *
+ */
+ @SerializedName(value = "limit")
+ private Integer limit;
+
+ /**
+ *
+ * 字段名:创建批次的商户号
+ * 变量名:stock_creator_mchid
+ * 是否必填:是
+ * 类型:string[1,20]
+ * 描述:
+ * 批次创建方商户号。
+ * 示例值:9856888
+ *
+ */
+ @SerializedName(value = "stock_creator_mchid")
+ private String stockCreatorMchid;
+
+ /**
+ *
+ * 字段名:起始时间
+ * 变量名:create_start_time
+ * 是否必填:否
+ * 类型:string[1,64]
+ * 描述:
+ * 起始创建时间,遵循rfc3339标准格式,格式为YYYY-MM-DDTHH:mm:ss.sss+TIMEZONE,YYYY-MM-DD表示年月日,T出现在字符串中,表示time元素的开头,HH:mm:ss.sss表示时分秒毫秒,TIMEZONE表示时区(+08:00表示东八区时间,领先UTC 8小时,即北京时间)。例如:2015-05-20T13:29:35.120+08:00表示,北京时间2015年5月20日 13点29分35秒。
+ * 示例值:2015-05-20T13:29:35.120+08:00
+ *
+ */
+ @SerializedName(value = "create_start_time")
+ private String createStartTime;
+
+ /**
+ *
+ * 字段名:终止时间
+ * 变量名:create_end_time
+ * 是否必填:否
+ * 类型:string[1,64]
+ * 描述:
+ * 终止创建时间,遵循rfc3339标准格式,格式为YYYY-MM-DDTHH:mm:ss.sss+TIMEZONE,YYYY-MM-DD表示年月日,T出现在字符串中,表示time元素的开头,HH:mm:ss.sss表示时分秒毫秒,TIMEZONE表示时区(+08:00表示东八区时间,领先UTC 8小时,即北京时间)。例如:2015-05-20T13:29:35.120+08:00表示,北京时间2015年5月20日 13点29分35秒。
+ * 示例值:2015-05-20T13:29:35.120+08:00
+ *
+ */
+ @SerializedName(value = "create_end_time")
+ private String createEndTime;
+
+ /**
+ *
+ * 字段名:批次状态
+ * 变量名:status
+ * 是否必填:否
+ * 类型:string[1,20]
+ * 描述:
+ * 批次状态,枚举值:
+ * unactivated:未激活
+ * audit:审核中
+ * running:运行中
+ * stoped:已停止
+ * paused:暂停发放
+ *
+ */
+ @SerializedName(value = "status")
+ private String status;
+}
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/FavorStocksQueryResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/FavorStocksQueryResult.java
new file mode 100644
index 0000000000..79259206b0
--- /dev/null
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/FavorStocksQueryResult.java
@@ -0,0 +1,57 @@
+package com.github.binarywang.wxpay.bean.marketing;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import me.chanjar.weixin.common.util.json.WxGsonBuilder;
+
+import java.util.List;
+
+/**
+ * 条件查询代金券批次列表结果对象
+ *
+ * @author thinsstar
+ */
+@NoArgsConstructor
+@Data
+public class FavorStocksQueryResult {
+
+ public static FavorStocksQueryResult fromJson(String json) {
+ return WxGsonBuilder.create().fromJson(json, FavorStocksQueryResult.class);
+ }
+
+ /**
+ * 批次总数
+ *
+ * 文档地址:
+ * https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/marketing/convention/chapter3_3.shtml
+ * https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/marketing/convention/chapter3_13.shtml
+ * https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/marketing/convention/chapter3_14.shtml
+ *
+ *
+ * @author thinsstar
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class FavorStocksSetRequest implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ *
+ * 字段名:创建批次的商户号
+ * 变量名:stock_creator_mchid
+ * 是否必填:是
+ * 类型:string[1,20]
+ * 描述:
+ * 批次创建方商户号。
+ * 示例值:8956000
+ *
+ */
+ @SerializedName(value = "stock_creator_mchid")
+ private String stockCreatorMchid;
+}
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/FavorStocksStartResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/FavorStocksStartResult.java
new file mode 100644
index 0000000000..a66a1740b4
--- /dev/null
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/FavorStocksStartResult.java
@@ -0,0 +1,38 @@
+package com.github.binarywang.wxpay.bean.marketing;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import me.chanjar.weixin.common.util.json.WxGsonBuilder;
+
+/**
+ * 激活代金券批次返回结果对象
+ *
+ * @author thinsstar
+ */
+@NoArgsConstructor
+@Data
+public class FavorStocksStartResult {
+
+ public static FavorStocksStartResult fromJson(String json) {
+ return WxGsonBuilder.create().fromJson(json, FavorStocksStartResult.class);
+ }
+
+ /**
+ * 生效时间
+ *
+ * 微信支付营销代金券接口
+ *
+ *
+ * @author thinsstar
+ */
+public interface MarketingFavorService {
+ /**
+ *
+ * 代金券接口-创建代金券批次API
+ * 文档详见: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/marketing/convention/chapter3_1.shtml
+ * 接口链接:https://api.mch.weixin.qq.com/v3/marketing/favor/coupon-stocks
+ *
+ *
+ * @param request 请求对象
+ * @return FavorStocksResult 微信返回的批次号信息。
+ * @throws WxPayException the wx pay exception
+ */
+ FavorStocksCreateResult createFavorStocksV3(FavorStocksCreateRequest request) throws WxPayException;
+
+ /**
+ *
+ * 代金券接口-发放代金券API
+ * 文档详见: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/marketing/convention/chapter3_2.shtml
+ * 接口链接:https://api.mch.weixin.qq.com/v3/marketing/favor/users/{openid}/coupons
+ *
+ *
+ * @param openid 用户openid
+ * @param request 请求对象
+ * @return FavorStocksResult 微信返回的发放结果信息。
+ * @throws WxPayException the wx pay exception
+ */
+ FavorCouponsCreateResult createFavorCouponsV3(String openid, FavorCouponsCreateRequest request) throws WxPayException;
+
+ /**
+ *
+ * 代金券接口-激活代金券批次API
+ * 文档详见: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/marketing/convention/chapter3_3.shtml
+ * 接口链接:https://api.mch.weixin.qq.com/v3/marketing/favor/stocks/{stock_id}/start
+ *
+ *
+ * @param stockId 批次号
+ * @param request 请求对象
+ * @return FavorStocksStartResult 微信返回的激活信息。
+ * @throws WxPayException the wx pay exception
+ */
+ FavorStocksStartResult startFavorStocksV3(String stockId, FavorStocksSetRequest request) throws WxPayException;
+
+ /**
+ *
+ * 代金券接口-条件查询代金券批次列表API
+ * 文档详见: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/marketing/convention/chapter3_4.shtml
+ * 接口链接:https://api.mch.weixin.qq.com/v3/marketing/favor/stocks
+ *
+ *
+ * @param request 请求对象
+ * @return FavorStocksQueryResult 微信返回的批次列表信息。
+ * @throws WxPayException the wx pay exception
+ */
+ FavorStocksQueryResult queryFavorStocksV3(FavorStocksQueryRequest request) throws WxPayException;
+
+ /**
+ *
+ * 代金券接口-查询批次详情API
+ * 文档详见: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/marketing/convention/chapter3_5.shtml
+ * 接口链接:https://api.mch.weixin.qq.com/v3/marketing/favor/stocks/{stock_id}
+ *
+ *
+ * @param stockId 批次号
+ * @param stockCreatorMchid 创建批次的商户号
+ * @return FavorStocksQueryResult 微信返回的批次详情信息。
+ * @throws WxPayException the wx pay exception
+ */
+ FavorStocksGetResult getFavorStocksV3(String stockId, String stockCreatorMchid) throws WxPayException;
+
+ /**
+ *
+ * 代金券接口-查询代金券详情API
+ * 文档详见: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/marketing/convention/chapter3_6.shtml
+ * 接口链接:https://api.mch.weixin.qq.com/v3/marketing/favor/users/{openid}/coupons/{coupon_id}
+ *
+ *
+ * @param couponId 代金券id
+ * @param appid 公众账号ID
+ * @param openid 用户openid
+ * @return FavorCouponsGetResult 微信返回的代金券详情信息。
+ * @throws WxPayException the wx pay exception
+ */
+ FavorCouponsGetResult getFavorCouponsV3(String couponId, String appid, String openid) throws WxPayException;
+
+ /**
+ *
+ * 代金券接口-查询代金券可用商户API
+ * 文档详见: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/marketing/convention/chapter3_7.shtml
+ * 接口链接:https://api.mch.weixin.qq.com/v3/marketing/favor/stocks/{stock_id}/merchants
+ *
+ *
+ * @param stockId 批次号
+ * @param stockCreatorMchid 创建批次的商户号
+ * @param offset 分页大小
+ * @param limit 创建批次的商户号
+ * @return FavorStocksMerchantsGetResult 微信返回的代金券可用商户信息。
+ * @throws WxPayException the wx pay exception
+ */
+ FavorStocksMerchantsGetResult getFavorStocksMerchantsV3(String stockId, String stockCreatorMchid, Integer offset, Integer limit) throws WxPayException;
+
+ /**
+ *
+ * 代金券接口-查询代金券可用单品API
+ * 文档详见: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/marketing/convention/chapter3_8.shtml
+ * 接口链接:https://api.mch.weixin.qq.com/v3/marketing/favor/stocks/{stock_id}/items
+ *
+ *
+ * @param stockId 批次号
+ * @param stockCreatorMchid 创建批次的商户号
+ * @param offset 分页大小
+ * @param limit 创建批次的商户号
+ * @return FavorStocksItemsGetResult 微信返回的代金券可用单品信息。
+ * @throws WxPayException the wx pay exception
+ */
+ FavorStocksItemsGetResult getFavorStocksItemsV3(String stockId, String stockCreatorMchid, Integer offset, Integer limit) throws WxPayException;
+
+ /**
+ *
+ * 代金券接口-根据商户号查用户的券API
+ * 文档详见: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/marketing/convention/chapter3_9.shtml
+ * 接口链接:https://api.mch.weixin.qq.com/v3/marketing/favor/users/{openid}/coupons
+ *
+ *
+ * @param request 请求对象
+ * @return FavorCouponsQueryResult 微信返回的用户的券信息。
+ * @throws WxPayException the wx pay exception
+ */
+ FavorCouponsQueryResult queryFavorCouponsV3(FavorCouponsQueryRequest request) throws WxPayException;
+
+ /**
+ *
+ * 代金券接口-下载批次核销明细API
+ * 文档详见: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/marketing/convention/chapter3_10.shtml
+ * 接口链接:https://api.mch.weixin.qq.com/v3/marketing/favor/stocks/{stock_id}/use-flow
+ *
+ *
+ * @param stockId 批次号
+ * @return FavorStocksFlowGetResult 微信返回的下载信息。
+ * @throws WxPayException the wx pay exception
+ */
+ FavorStocksFlowGetResult getFavorStocksUseFlowV3(String stockId) throws WxPayException;
+
+ /**
+ *
+ * 代金券接口-下载批次退款明细API
+ * 文档详见: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/marketing/convention/chapter3_11.shtml
+ * 接口链接:https://api.mch.weixin.qq.com/v3/marketing/favor/stocks/{stock_id}/refund-flow
+ *
+ *
+ * @param stockId 批次号
+ * @return FavorStocksFlowGetResult 微信返回的下载信息。
+ * @throws WxPayException the wx pay exception
+ */
+ FavorStocksFlowGetResult getFavorStocksRefundFlowV3(String stockId) throws WxPayException;
+
+ /**
+ *
+ * 代金券接口-设置消息通知地址API
+ * 文档详见: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/marketing/convention/chapter3_12.shtml
+ * 接口链接:https://api.mch.weixin.qq.com/v3/marketing/favor/callbacks
+ *
+ *
+ * @param request 批次号
+ * @return FavorCallbacksSaveResult 微信返回的结果信息。
+ * @throws WxPayException the wx pay exception
+ */
+ FavorCallbacksSaveResult saveFavorCallbacksV3(FavorCallbacksSaveRequest request) throws WxPayException;
+
+ FavorStocksStartResult pauseFavorStocksV3(String stockId, FavorStocksSetRequest request) throws WxPayException;
+
+ FavorStocksStartResult restartFavorStocksV3(String stockId, FavorStocksSetRequest request) throws WxPayException;
+}
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/MarketingMediaService.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/MarketingMediaService.java
new file mode 100644
index 0000000000..895cdeff8c
--- /dev/null
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/MarketingMediaService.java
@@ -0,0 +1,46 @@
+package com.github.binarywang.wxpay.service;
+
+import com.github.binarywang.wxpay.bean.media.MarketingImageUploadResult;
+import com.github.binarywang.wxpay.exception.WxPayException;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ *
+ * 微信支付营销专用媒体接口.
+ *
+ *
+ * @author thinsstar
+ */
+public interface MarketingMediaService {
+ /**
+ *
+ * 营销专用接口-图片上传API
+ * 文档详见: https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter9_0_1.shtml
+ * 接口链接:https://api.mch.weixin.qq.com/v3/marketing/favor/media/image-upload
+ *
+ *
+ * @param imageFile 需要上传的图片文件
+ * @return ImageUploadResult 微信返回的媒体文件标识Id。示例值:6uqyGjGrCf2GtyXP8bxrbuH9-aAoTjH-rKeSl3Lf4_So6kdkQu4w8BYVP3bzLtvR38lxt4PjtCDXsQpzqge_hQEovHzOhsLleGFQVRF-U_0
+ * @throws WxPayException the wx pay exception
+ */
+ MarketingImageUploadResult imageUploadV3(File imageFile) throws WxPayException, IOException;
+
+ /**
+ *
+ * 营销专用接口-图片上传API
+ * 文档详见: https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter9_0_1.shtml
+ * 接口链接:https://api.mch.weixin.qq.com/v3/marketing/favor/media/image-upload
+ *
+ *
+ * @param inputStream 需要上传的图片文件流
+ * @param fileName 需要上传的图片文件名
+ * @return ImageUploadResult 微信返回的媒体文件标识Id。示例值:6uqyGjGrCf2GtyXP8bxrbuH9-aAoTjH-rKeSl3Lf4_So6kdkQu4w8BYVP3bzLtvR38lxt4PjtCDXsQpzqge_hQEovHzOhsLleGFQVRF-U_0
+ * @throws WxPayException the wx pay exception
+ */
+ MarketingImageUploadResult imageUploadV3(InputStream inputStream, String fileName) throws WxPayException, IOException;
+
+
+}
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxPayService.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxPayService.java
index 50ee046fee..366b2907ee 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxPayService.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxPayService.java
@@ -15,7 +15,6 @@
import java.io.File;
import java.io.InputStream;
-import java.net.URI;
import java.util.Date;
import java.util.Map;
@@ -161,6 +160,20 @@ public interface WxPayService {
*/
MerchantMediaService getMerchantMediaService();
+ /**
+ * 获取微信支付营销媒体服务类
+ *
+ * @return the marketing media service
+ */
+ MarketingMediaService getMarketingMediaService();
+
+ /**
+ * 获取微信支付营销代金券服务类
+ *
+ * @return the marketing favor service
+ */
+ MarketingFavorService getMarketingFavorService();
+
/**
* 设置企业付款服务类,允许开发者自定义实现类.
*
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/BaseWxPayServiceImpl.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/BaseWxPayServiceImpl.java
index 4c14cda096..23d06c4b46 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/BaseWxPayServiceImpl.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/BaseWxPayServiceImpl.java
@@ -61,6 +61,8 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
private final PayScoreService payScoreService = new PayScoreServiceImpl(this);
private final EcommerceService ecommerceService = new EcommerceServiceImpl(this);
private final MerchantMediaService merchantMediaService = new MerchantMediaServiceImpl(this);
+ private final MarketingMediaService marketingMediaService = new MarketingMediaServiceImpl(this);
+ private final MarketingFavorService marketingFavorService = new MarketingFavorServiceImpl(this);
protected WxPayConfig config;
@@ -94,6 +96,16 @@ public MerchantMediaService getMerchantMediaService() {
return this.merchantMediaService;
}
+ @Override
+ public MarketingMediaService getMarketingMediaService() {
+ return this.marketingMediaService;
+ }
+
+ @Override
+ public MarketingFavorService getMarketingFavorService() {
+ return this.marketingFavorService;
+ }
+
@Override
public void setEntPayService(EntPayService entPayService) {
this.entPayService = entPayService;
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/MarketingFavorServiceImpl.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/MarketingFavorServiceImpl.java
new file mode 100644
index 0000000000..c8efc20500
--- /dev/null
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/MarketingFavorServiceImpl.java
@@ -0,0 +1,164 @@
+package com.github.binarywang.wxpay.service.impl;
+
+import com.github.binarywang.wxpay.bean.marketing.*;
+import com.github.binarywang.wxpay.exception.WxPayException;
+import com.github.binarywang.wxpay.service.MarketingFavorService;
+import com.github.binarywang.wxpay.service.WxPayService;
+import com.github.binarywang.wxpay.v3.util.RsaCryptoUtil;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+
+/**
+ * 微信支付-营销代金券接口
+ *
+ * @author thinsstar
+ */
+@Slf4j
+@RequiredArgsConstructor
+public class MarketingFavorServiceImpl implements MarketingFavorService {
+ private static final Gson GSON = new GsonBuilder().create();
+ private final WxPayService payService;
+
+ @Override
+ public FavorStocksCreateResult createFavorStocksV3(FavorStocksCreateRequest request) throws WxPayException {
+ String url = String.format("%s/v3/marketing/favor/coupon-stocks", this.payService.getPayBaseUrl());
+ RsaCryptoUtil.encryptFields(request, this.payService.getConfig().getVerifier().getValidCertificate());
+ String result = this.payService.postV3WithWechatpaySerial(url, GSON.toJson(request));
+ return GSON.fromJson(result, FavorStocksCreateResult.class);
+ }
+
+ @Override
+ public FavorCouponsCreateResult createFavorCouponsV3(String openid, FavorCouponsCreateRequest request) throws WxPayException {
+ String url = String.format("%s/v3/marketing/favor/users/%s/coupons", this.payService.getPayBaseUrl(), openid);
+ RsaCryptoUtil.encryptFields(request, this.payService.getConfig().getVerifier().getValidCertificate());
+ String result = this.payService.postV3WithWechatpaySerial(url, GSON.toJson(request));
+ return GSON.fromJson(result, FavorCouponsCreateResult.class);
+ }
+
+ @Override
+ public FavorStocksStartResult startFavorStocksV3(String stockId, FavorStocksSetRequest request) throws WxPayException {
+ String url = String.format("%s/v3/marketing/favor/stocks/%s/start", this.payService.getPayBaseUrl(), stockId);
+ RsaCryptoUtil.encryptFields(request, this.payService.getConfig().getVerifier().getValidCertificate());
+ String result = this.payService.postV3WithWechatpaySerial(url, GSON.toJson(request));
+ return GSON.fromJson(result, FavorStocksStartResult.class);
+ }
+
+ @Override
+ public FavorStocksQueryResult queryFavorStocksV3(FavorStocksQueryRequest request) throws WxPayException {
+ String url = String.format("%s/v3/marketing/favor/stocks", this.payService.getPayBaseUrl());
+ String query = String.format("?offset=%s&limit=%s&stock_creator_mchid=%s", request.getOffset(), request.getLimit(), request.getStockCreatorMchid());
+ if (StringUtils.isNotBlank(request.getCreateStartTime())) {
+ query += "&create_start_time=" + request.getCreateStartTime();
+ }
+ if (StringUtils.isNotBlank(request.getCreateEndTime())) {
+ query += "&create_end_time=" + request.getCreateEndTime();
+ }
+ if (StringUtils.isNotBlank(request.getStatus())) {
+ query += "&status=" + request.getStatus();
+ }
+ String result = this.payService.getV3(url + query);
+ return GSON.fromJson(result, FavorStocksQueryResult.class);
+ }
+
+ @Override
+ public FavorStocksGetResult getFavorStocksV3(String stockId, String stockCreatorMchid) throws WxPayException {
+ String url = String.format("%s/v3/marketing/favor/stocks/%s", this.payService.getPayBaseUrl(), stockId);
+ String query = String.format("?stock_creator_mchid=%s", stockCreatorMchid);
+ String result = this.payService.getV3(url + query);
+ return GSON.fromJson(result, FavorStocksGetResult.class);
+ }
+
+ @Override
+ public FavorCouponsGetResult getFavorCouponsV3(String couponId, String appid, String openid) throws WxPayException {
+ String url = String.format("%s/v3/marketing/favor/users/%s/coupons/%s", this.payService.getPayBaseUrl(), openid, couponId);
+ String query = String.format("?appid=%s", appid);
+ String result = this.payService.getV3(url + query);
+ return GSON.fromJson(result, FavorCouponsGetResult.class);
+ }
+
+ @Override
+ public FavorStocksMerchantsGetResult getFavorStocksMerchantsV3(String stockId, String stockCreatorMchid, Integer offset, Integer limit) throws WxPayException {
+ String url = String.format("%s/v3/marketing/favor/stocks/%s/merchants", this.payService.getPayBaseUrl(), stockId);
+ String query = String.format("?stock_creator_mchid=%s&offset=%s&limit=%s", stockCreatorMchid, offset, limit);
+ String result = this.payService.getV3(url + query);
+ return GSON.fromJson(result, FavorStocksMerchantsGetResult.class);
+ }
+
+ @Override
+ public FavorStocksItemsGetResult getFavorStocksItemsV3(String stockId, String stockCreatorMchid, Integer offset, Integer limit) throws WxPayException {
+ String url = String.format("%s/v3/marketing/favor/stocks/%s/items", this.payService.getPayBaseUrl(), stockId);
+ String query = String.format("?stock_creator_mchid=%s&offset=%s&limit=%s", stockCreatorMchid, offset, limit);
+ String result = this.payService.getV3(url + query);
+ return GSON.fromJson(result, FavorStocksItemsGetResult.class);
+ }
+
+ @Override
+ public FavorCouponsQueryResult queryFavorCouponsV3(FavorCouponsQueryRequest request) throws WxPayException {
+ String url = String.format("%s/v3/marketing/favor/users/%s/coupons", this.payService.getPayBaseUrl(), request.getOpenid());
+ String query = String.format("?appid=%s", request.getAppid());
+ if (StringUtils.isNotBlank(request.getStockId())) {
+ query += "&stock_id=" + request.getStockId();
+ }
+ if (StringUtils.isNotBlank(request.getStatus())) {
+ query += "&status=" + request.getStatus();
+ }
+ if (StringUtils.isNotBlank(request.getCreatorMchid())) {
+ query += "&creator_mchid=" + request.getCreatorMchid();
+ }
+ if (StringUtils.isNotBlank(request.getSenderMchid())) {
+ query += "&sender_mchid=" + request.getSenderMchid();
+ }
+ if (StringUtils.isNotBlank(request.getAvailableMchid())) {
+ query += "&available_mchid=" + request.getAvailableMchid();
+ }
+ if (request.getOffset() != null) {
+ query += "&offset=" + request.getOffset();
+ }
+ if (request.getLimit() != null) {
+ query += "&limit=" + request.getLimit();
+ }
+ String result = this.payService.getV3(url + query);
+ return GSON.fromJson(result, FavorCouponsQueryResult.class);
+ }
+
+ @Override
+ public FavorStocksFlowGetResult getFavorStocksUseFlowV3(String stockId) throws WxPayException {
+ String url = String.format("%s/v3/marketing/favor/stocks/%s/use-flow", this.payService.getPayBaseUrl(), stockId);
+ String result = this.payService.getV3(url);
+ return GSON.fromJson(result, FavorStocksFlowGetResult.class);
+ }
+
+ @Override
+ public FavorStocksFlowGetResult getFavorStocksRefundFlowV3(String stockId) throws WxPayException {
+ String url = String.format("%s/v3/marketing/favor/stocks/%s/refund-flow", this.payService.getPayBaseUrl(), stockId);
+ String result = this.payService.getV3(url);
+ return GSON.fromJson(result, FavorStocksFlowGetResult.class);
+ }
+
+ @Override
+ public FavorCallbacksSaveResult saveFavorCallbacksV3(FavorCallbacksSaveRequest request) throws WxPayException {
+ String url = String.format("%s/v3/marketing/favor/callbacks", this.payService.getPayBaseUrl());
+ RsaCryptoUtil.encryptFields(request, this.payService.getConfig().getVerifier().getValidCertificate());
+ String result = this.payService.postV3WithWechatpaySerial(url, GSON.toJson(request));
+ return GSON.fromJson(result, FavorCallbacksSaveResult.class);
+ }
+
+ @Override
+ public FavorStocksStartResult pauseFavorStocksV3(String stockId, FavorStocksSetRequest request) throws WxPayException {
+ String url = String.format("%s/v3/marketing/favor/stocks/%s/start", this.payService.getPayBaseUrl(), stockId);
+ RsaCryptoUtil.encryptFields(request, this.payService.getConfig().getVerifier().getValidCertificate());
+ String result = this.payService.postV3WithWechatpaySerial(url, GSON.toJson(request));
+ return GSON.fromJson(result, FavorStocksStartResult.class);
+ }
+
+ @Override
+ public FavorStocksStartResult restartFavorStocksV3(String stockId, FavorStocksSetRequest request) throws WxPayException {
+ String url = String.format("%s/v3/marketing/favor/stocks/%s/start", this.payService.getPayBaseUrl(), stockId);
+ RsaCryptoUtil.encryptFields(request, this.payService.getConfig().getVerifier().getValidCertificate());
+ String result = this.payService.postV3WithWechatpaySerial(url, GSON.toJson(request));
+ return GSON.fromJson(result, FavorStocksStartResult.class);
+ }
+}
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/MarketingMediaServiceImpl.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/MarketingMediaServiceImpl.java
new file mode 100644
index 0000000000..805af6180e
--- /dev/null
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/MarketingMediaServiceImpl.java
@@ -0,0 +1,60 @@
+package com.github.binarywang.wxpay.service.impl;
+
+import com.github.binarywang.wxpay.bean.media.MarketingImageUploadResult;
+import com.github.binarywang.wxpay.exception.WxPayException;
+import com.github.binarywang.wxpay.service.MarketingMediaService;
+import com.github.binarywang.wxpay.service.WxPayService;
+import com.github.binarywang.wxpay.v3.WechatPayUploadHttpPost;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.codec.digest.DigestUtils;
+
+import java.io.*;
+import java.net.URI;
+
+/**
+ * 微信支付-营销专用媒体文件上传service
+ *
+ * @author thinsstar
+ */
+@Slf4j
+@RequiredArgsConstructor
+public class MarketingMediaServiceImpl implements MarketingMediaService {
+ private final WxPayService payService;
+
+ @Override
+ public MarketingImageUploadResult imageUploadV3(File imageFile) throws WxPayException, IOException {
+ String url = String.format("%s/v3/marketing/favor/media/image-upload", this.payService.getPayBaseUrl());
+ try (FileInputStream s1 = new FileInputStream(imageFile)) {
+ String sha256 = DigestUtils.sha256Hex(s1);
+ try (InputStream s2 = new FileInputStream(imageFile)) {
+ WechatPayUploadHttpPost request = new WechatPayUploadHttpPost.Builder(URI.create(url))
+ .withImage(imageFile.getName(), sha256, s2)
+ .build();
+ String result = this.payService.postV3(url, request);
+ return MarketingImageUploadResult.fromJson(result);
+ }
+ }
+ }
+
+ @Override
+ public MarketingImageUploadResult imageUploadV3(InputStream inputStream, String fileName) throws WxPayException, IOException {
+ String url = String.format("%s/v3/marketing/favor/media/image-upload", this.payService.getPayBaseUrl());
+ try (ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
+ byte[] buffer = new byte[2048];
+ int len;
+ while ((len = inputStream.read(buffer)) > -1) {
+ bos.write(buffer, 0, len);
+ }
+ bos.flush();
+ byte[] data = bos.toByteArray();
+ String sha256 = DigestUtils.sha256Hex(data);
+ WechatPayUploadHttpPost request = new WechatPayUploadHttpPost.Builder(URI.create(url))
+ .withImage(fileName, sha256, new ByteArrayInputStream(data))
+ .build();
+ String result = this.payService.postV3(url, request);
+ return MarketingImageUploadResult.fromJson(result);
+ }
+ }
+
+}
diff --git a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/MarketingFavorServiceImplTest.java b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/MarketingFavorServiceImplTest.java
new file mode 100644
index 0000000000..48fdf8c8e5
--- /dev/null
+++ b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/MarketingFavorServiceImplTest.java
@@ -0,0 +1,191 @@
+package com.github.binarywang.wxpay.service.impl;
+
+import com.github.binarywang.wxpay.bean.marketing.*;
+import com.github.binarywang.wxpay.bean.marketing.enums.StockTypeEnum;
+import com.github.binarywang.wxpay.exception.WxPayException;
+import com.github.binarywang.wxpay.service.MarketingFavorService;
+import com.github.binarywang.wxpay.service.WxPayService;
+import com.github.binarywang.wxpay.testbase.ApiTestModule;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.inject.Inject;
+import lombok.extern.slf4j.Slf4j;
+import org.testng.annotations.Guice;
+import org.testng.annotations.Test;
+
+import java.util.Collections;
+
+/**
+ *
+ * 营销工具代金券测试类
+ *
+ *
+ * @author thinsstar
+ */
+@Slf4j
+@Test
+@Guice(modules = ApiTestModule.class)
+public class MarketingFavorServiceImplTest {
+
+ @Inject
+ private WxPayService wxPayService;
+
+ private static final Gson GSON = new GsonBuilder().create();
+
+ private final String stockId = "批次id";
+
+ private final String appId = "公众号id";
+ private final String openId = "微信openid";
+
+ @Test
+ public void testCreateFavorStocksV3() throws WxPayException {
+ FavorStocksCreateRequest request = new FavorStocksCreateRequest();
+ request.setStockName("测试代金券");
+ request.setComment("测试代金券备注");
+ request.setBelongMerchant(wxPayService.getConfig().getMchId());
+ request.setAvailableBeginTime("2021-02-05T00:00:00.000+08:00");
+ request.setAvailableEndTime("2021-03-31T00:00:00.000+08:00");
+ request.setNoCash(false);
+ request.setStockType(StockTypeEnum.NORMAL);
+ request.setOutRequestNo(wxPayService.getConfig().getMchId() + "20210204" + "1234567890");
+ //发放规则
+ FavorStocksCreateRequest.StockUseRule stockUseRule = new FavorStocksCreateRequest.StockUseRule();
+ stockUseRule.setMaxCoupons(5);
+ stockUseRule.setMaxCouponsPerUser(5);
+ stockUseRule.setNaturalPersonLimit(true);
+ stockUseRule.setPreventApiAbuse(false);
+ stockUseRule.setMaxAmount(50);
+ request.setStockUseRule(stockUseRule);
+ //样式设置
+// FavorStocksCreateRequest.PatternInfo patternInfo = new FavorStocksCreateRequest.PatternInfo();
+// request.setPatternInfo(patternInfo);
+ //核销规则
+ FavorStocksCreateRequest.CouponUseRule couponUseRule = new FavorStocksCreateRequest.CouponUseRule();
+ FavorStocksCreateRequest.FixedNormalCoupon fixedNormalCoupon = new FavorStocksCreateRequest.FixedNormalCoupon();
+ fixedNormalCoupon.setCouponAmount(10);
+ fixedNormalCoupon.setTransactionMinimum(11);
+ couponUseRule.setFixedNormalCoupon(fixedNormalCoupon);
+ couponUseRule.setCombineUse(true);
+ couponUseRule.setAvailableMerchants(Collections.singletonList(wxPayService.getConfig().getMchId()));
+ request.setCouponUseRule(couponUseRule);
+ FavorStocksCreateResult result = wxPayService.getMarketingFavorService().createFavorStocksV3(request);
+ String stockId = result.getStockId();
+
+ log.info("stockId: [{}]", stockId);
+ }
+
+ @Test
+ public void testCreateFavorCouponsV3() throws WxPayException {
+ MarketingFavorService marketingFavorService = new MarketingFavorServiceImpl(wxPayService);
+ FavorCouponsCreateRequest request = new FavorCouponsCreateRequest();
+ request.setStockCreatorMchid(wxPayService.getConfig().getMchId());
+ request.setStockId(stockId);
+ request.setAppid(appId);
+ request.setOutRequestNo(wxPayService.getConfig().getMchId() + "20210204" + "1234567890");
+ FavorCouponsCreateResult result = wxPayService.getMarketingFavorService().createFavorCouponsV3(openId, request);
+
+ log.info("result: {}", GSON.toJson(result));
+ }
+
+ @Test
+ public void testStartFavorStocksV3() throws WxPayException {
+ FavorStocksSetRequest request = new FavorStocksSetRequest();
+ request.setStockCreatorMchid(wxPayService.getConfig().getMchId());
+ FavorStocksStartResult result = wxPayService.getMarketingFavorService().startFavorStocksV3(stockId, request);
+
+ log.info("result: {}", GSON.toJson(result));
+ }
+
+ @Test
+ public void testQueryFavorStocksV3() throws WxPayException {
+ FavorStocksQueryRequest request = new FavorStocksQueryRequest();
+ request.setOffset(0);
+ request.setLimit(10);
+ request.setStockCreatorMchid(wxPayService.getConfig().getMchId());
+ FavorStocksQueryResult result = wxPayService.getMarketingFavorService().queryFavorStocksV3(request);
+
+ log.info("result: {}", GSON.toJson(result));
+ }
+
+ @Test
+ public void testGetFavorStocksV3() throws WxPayException {
+ FavorStocksGetResult result = wxPayService.getMarketingFavorService().getFavorStocksV3(stockId, wxPayService.getConfig().getMchId());
+
+ log.info("result: {}", GSON.toJson(result));
+ }
+
+ @Test
+ public void testGetFavorCouponsV3() throws WxPayException {
+ FavorCouponsGetResult result = wxPayService.getMarketingFavorService().getFavorCouponsV3("20387541242", appId, openId);
+
+ log.info("result: {}", GSON.toJson(result));
+ }
+
+ @Test
+ public void testGetFavorStocksMerchantsV3() throws WxPayException {
+ FavorStocksMerchantsGetResult result = wxPayService.getMarketingFavorService().getFavorStocksMerchantsV3(stockId, wxPayService.getConfig().getMchId(), 0, 50);
+
+ log.info("result: {}", GSON.toJson(result));
+ }
+
+ @Test
+ public void testGetFavorStocksItemsV3() throws WxPayException {
+ FavorStocksItemsGetResult result = wxPayService.getMarketingFavorService().getFavorStocksItemsV3(stockId, wxPayService.getConfig().getMchId(), 0, 100);
+
+ log.info("result: {}", GSON.toJson(result));
+ }
+
+ @Test
+ public void testQueryFavorCouponsV3() throws WxPayException {
+ FavorCouponsQueryRequest request = new FavorCouponsQueryRequest();
+ request.setAppid(appId);
+ request.setOpenid(openId);
+ request.setAvailableMchid(wxPayService.getConfig().getMchId());
+ FavorCouponsQueryResult result = wxPayService.getMarketingFavorService().queryFavorCouponsV3(request);
+
+ log.info("result: {}", GSON.toJson(result));
+ }
+
+ @Test
+ public void testGetFavorStocksUseFlowV3() throws WxPayException {
+ FavorStocksFlowGetResult result = wxPayService.getMarketingFavorService().getFavorStocksUseFlowV3(stockId);
+
+ log.info("result: {}", GSON.toJson(result));
+ }
+
+ @Test
+ public void testGetFavorStocksRefundFlowV3() throws WxPayException {
+ FavorStocksFlowGetResult result = wxPayService.getMarketingFavorService().getFavorStocksRefundFlowV3(stockId);
+
+ log.info("result: {}", GSON.toJson(result));
+ }
+
+ @Test
+ public void testSaveFavorCallbacksV3() throws WxPayException {
+ FavorCallbacksSaveRequest request = new FavorCallbacksSaveRequest();
+ request.setMchid(wxPayService.getConfig().getMchId());
+ request.setNotifyUrl("你的回调地址");
+ request.setSwitchBool(false);
+ FavorCallbacksSaveResult result = wxPayService.getMarketingFavorService().saveFavorCallbacksV3(request);
+
+ log.info("result: {}", GSON.toJson(result));
+ }
+
+ @Test
+ public void testPauseFavorStocksV3() throws WxPayException {
+ FavorStocksSetRequest request = new FavorStocksSetRequest();
+ request.setStockCreatorMchid(wxPayService.getConfig().getMchId());
+ FavorStocksStartResult result = wxPayService.getMarketingFavorService().pauseFavorStocksV3(stockId, request);
+
+ log.info("result: {}", GSON.toJson(result));
+ }
+
+ @Test
+ public void testRestartFavorStocksV3() throws WxPayException {
+ FavorStocksSetRequest request = new FavorStocksSetRequest();
+ request.setStockCreatorMchid(wxPayService.getConfig().getMchId());
+ FavorStocksStartResult result = wxPayService.getMarketingFavorService().restartFavorStocksV3(stockId, request);
+
+ log.info("result: {}", GSON.toJson(result));
+ }
+}
diff --git a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/MarketingMediaServiceImplTest.java b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/MarketingMediaServiceImplTest.java
new file mode 100644
index 0000000000..c03ed0d31c
--- /dev/null
+++ b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/MarketingMediaServiceImplTest.java
@@ -0,0 +1,49 @@
+package com.github.binarywang.wxpay.service.impl;
+
+import com.github.binarywang.wxpay.bean.media.MarketingImageUploadResult;
+import com.github.binarywang.wxpay.exception.WxPayException;
+import com.github.binarywang.wxpay.service.WxPayService;
+import com.github.binarywang.wxpay.testbase.ApiTestModule;
+import com.google.inject.Inject;
+import lombok.extern.slf4j.Slf4j;
+import org.testng.annotations.Guice;
+import org.testng.annotations.Test;
+
+import java.io.File;
+import java.io.IOException;
+
+/**
+ *
+ * 营销专用媒体文件上传测试类
+ *
+ *
+ * @author thinsstar
+ */
+@Slf4j
+@Test
+@Guice(modules = ApiTestModule.class)
+public class MarketingMediaServiceImplTest {
+
+ @Inject
+ private WxPayService wxPayService;
+
+ @Test
+ public void testMarketingImageUploadV3() throws WxPayException, IOException {
+ String filePath = "你的图片文件的路径地址";
+
+ File file = new File(filePath);
+
+ MarketingImageUploadResult imageUploadResult = wxPayService.getMarketingMediaService().imageUploadV3(file);
+ String mediaUrl = imageUploadResult.getMediaUrl();
+
+ log.info("mediaUrl:[{}]", mediaUrl);
+
+ File file2 = new File(filePath);
+
+ MarketingImageUploadResult imageUploadResult2 = wxPayService.getMarketingMediaService().imageUploadV3(file2);
+ String mediaUrl2 = imageUploadResult2.getMediaUrl();
+
+ log.info("mediaUrl2:[{}]", mediaUrl2);
+
+ }
+}