【单券-单品-兑换券】API请求示例
更新时间:2025.12.25||
curl
Java
Go
1## 场景5: 单券-单品-兑换券 (usage_mode=SINGLE, scope=SINGLE, type=EXCHANGE) 2 3 4```bash 5curl -X POST \ 6 https://api.mch.weixin.qq.com/v3/marketing/partner/product-coupon/product-coupons \ 7 -H "Authorization: WECHATPAY2-SHA256-RSA2048 mchid=\"服务商商户号\",..." \ 8 -H "Accept: application/json" \ 9 -H "Content-Type: application/json" \ 10 -d '{ 11 "out_request_no": "SINGLE_SINGLE_EXCHANGE_20250101_005", # 必填,创建请求单号 12 "brand_id": "120344", # 必填,品牌ID 13 "scope": "SINGLE", # 必填,优惠范围:SINGLE=单品券(兑换券仅支持单品) 14 "type": "EXCHANGE", # 必填,商品券类型:EXCHANGE=兑换券(仅scope=SINGLE时可用) 15 "usage_mode": "SINGLE", # 必填,使用模式:SINGLE=单券模式 16 17 # 注意:scope=SINGLE时,不在single_usage_info中配置优惠规则 18 19 "display_info": { # 必填,商品券展示信息 20 "name": "9.9元兑换原价99元商品", # 必填,商品券名称 21 "image_url": "https://wxpaylogo.qpic.cn/wxpaylogo/xxxxx/xxx", # 必填,商品图片URL 22 "background_url": "https://wxpaylogo.qpic.cn/wxpaylogo/xxxxx/xxx", # 必填,背景图URL 23 "detail_image_url_list": [ # 选填,详情图URL列表 24 "https://wxpaylogo.qpic.cn/wxpaylogo/xxxxx/xxx" 25 ], 26 "original_price": 9900, # 当scope=SINGLE时必填,商品原价,单位为分(99元) 27 "combo_package_list": [ # 当scope=SINGLE时选填,套餐组合列表 28 { 29 "name": "超值套餐", # 必填,套餐名称 30 "pick_count": 3, # 必填,可选单品数量 31 "choice_list": [ # 必填,单品列表 32 { 33 "name": "汉堡", # 必填,单品名称 34 "price": 1500, # 必填,单品价格,单位为分(15元) 35 "count": 1, # 必填,单品数量 36 "image_url": "https://wxpaylogo.qpic.cn/wxpaylogo/xxxxx/xxx", # 选填 37 "mini_program_appid": "wx1234567890", # 选填 38 "mini_program_path": "/pages/index/product" # 选填 39 }, 40 { 41 "name": "鸡翅", # 必填,单品名称 42 "price": 1200, # 必填,单品价格,单位为分 43 "count": 1, # 必填,单品数量 44 "image_url": "https://wxpaylogo.qpic.cn/wxpaylogo/xxxxx/xxx", # 选填 45 "mini_program_appid": "wx1234567890", # 选填 46 "mini_program_path": "/pages/index/product" # 选填 47 }, 48 { 49 "name": "可乐", # 必填,单品名称 50 "price": 500, # 必填,单品价格,单位为分 51 "count": 1, # 必填,单品数量 52 "image_url": "https://wxpaylogo.qpic.cn/wxpaylogo/xxxxx/xxx", # 选填 53 "mini_program_appid": "wx1234567890", # 选填 54 "mini_program_path": "/pages/index/product" # 选填 55 } 56 ] 57 } 58 ] 59 }, 60 61 "out_product_no": "Product_SINGLE_005", # 选填,外部商品ID 62 63 "stock": { # 必填,批次信息 64 "remark": "8月单品兑换批次", # 选填,备注 65 "coupon_code_mode": "WECHATPAY", # 必填,券Code分配模式 66 67 "stock_send_rule": { # 必填,发放规则 68 "max_count": 10000000, # 必填,总发放次数上限 69 "max_count_per_day": 100000, # 选填,每日发放上限 70 "max_count_per_user": 1 # 必填,每用户领取上限 71 }, 72 73 "single_usage_rule": { # 当usage_mode=SINGLE时必填,单券使用规则 74 "coupon_available_period": { # 必填,券可核销时间 75 "available_begin_time": "2025-08-01T00:00:00+08:00", # 必填,开始时间 76 "available_end_time": "2025-08-31T23:59:59+08:00", # 必填,结束时间 77 "available_days": 30, # 选填,生效后N天有效 78 "wait_days_after_receive": 0, # 选填,领取后N天生效 79 "weekly_available_period": { # 选填,每周可用时间 80 "day_list": ["MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY"] # 当配置此对象时必填 81 }, 82 "irregular_available_period_list": [ # 选填,无规律可用时间段 83 { 84 "begin_time": "2025-08-15T00:00:00+08:00", # 当配置此列表时必填 85 "end_time": "2025-08-15T23:59:59+08:00" # 当配置此列表时必填 86 } 87 ] 88 }, 89 "exchange_coupon": { # 当type=EXCHANGE时必填,兑换券使用规则 90 "threshold": 0, # 必填,门槛金额,单位为分,兑换券通常为0 91 "exchange_price": 990 # 必填,兑换价格,单位为分,9.9元兑换填990 92 } 93 }, 94 95 "usage_rule_display_info": { # 必填,使用规则展示信息 96 "coupon_usage_method_list": ["OFFLINE", "MINI_PROGRAM", "PAYMENT_CODE"], # 必填,使用方式 97 "mini_program_appid": "wx1234567890", # 当coupon_usage_method_list包含MINI_PROGRAM时必填 98 "mini_program_path": "/pages/index/product", # 当coupon_usage_method_list包含MINI_PROGRAM时必填 99 "usage_description": "用9.9元兑换原价99元商品", # 必填,使用说明 100 "coupon_available_store_info": { # 选填,可用门店信息 101 "description": "所有门店可用", # 当配置此对象时必填 102 "mini_program_appid": "wx1234567890", # 选填 103 "mini_program_path": "/pages/index/store-list" # 选填 104 } 105 }, 106 107 "coupon_display_info": { # 必填,用户券展示信息 108 "code_display_mode": "QRCODE", # 必填,Code展示模式 109 "background_color": "Color010", # 选填,背景颜色 110 "entrance_mini_program": { # 选填,小程序入口 111 "appid": "wx1234567890", # 当配置此对象时必填 112 "path": "/pages/index/product", # 当配置此对象时必填 113 "entrance_wording": "立即兑换", # 当配置此对象时必填 114 "guidance_wording": "获取更多优惠" # 当配置此对象时必填 115 }, 116 "entrance_official_account": { # 选填,公众号入口 117 "appid": "wx1234567890" # 当配置此对象时必填 118 }, 119 "entrance_finder": { # 选填,视频号入口 120 "finder_id": "gh_12345678", # 当配置此对象时必填 121 "finder_video_id": "UDFsdf24df34dD456Hdf34", # 当配置此对象时必填 122 "finder_video_cover_image_url": "https://wxpaylogo.qpic.cn/wxpaylogo/xxxxx/xxx" # 当配置此对象时必填 123 } 124 }, 125 126 "notify_config": { # 必填,事件通知配置 127 "notify_appid": "wx4fd12345678" # 必填 128 }, 129 130 "store_scope": "NONE" # 必填,可用门店范围 131 } 132 }' 133```
需配合微信支付工具库 WXPayUtility 使用,请参考 Java
1package com.java.demo; 2 3import com.java.utils.WXPayUtility; // 引用微信支付工具库,参考:https://pay.weixin.qq.com/doc/v3/partner/4014985777 4import com.google.gson.annotations.SerializedName; 5import com.google.gson.annotations.Expose; 6import okhttp3.MediaType; 7import okhttp3.OkHttpClient; 8import okhttp3.Request; 9import okhttp3.RequestBody; 10import okhttp3.Response; 11 12import java.io.IOException; 13import java.io.UncheckedIOException; 14import java.security.PrivateKey; 15import java.security.PublicKey; 16import java.util.ArrayList; 17import java.util.HashMap; 18import java.util.List; 19import java.util.Map; 20 21/** 22 * 场景5:创建商品券 - 单券-单品-兑换券 23 * 24 * 场景说明: 25 * - usage_mode: SINGLE(单券模式) 26 * - scope: SINGLE(单品券) 27 * - type: EXCHANGE(兑换券) 28 * 29 * 优惠规则配置位置:stock.single_usage_rule.exchange_coupon(单品券在single_usage_rule中配置) 30 */ 31public class SingleExchangeSingleJava { 32 private static String HOST = "https://api.mch.weixin.qq.com"; 33 private static String METHOD = "POST"; 34 private static String PATH = "/v3/marketing/partner/product-coupon/product-coupons"; 35 36 public static void main(String[] args) { 37 // TODO: 请准备商户开发必要参数,参考:https://pay.weixin.qq.com/doc/v3/partner/4013080340 38 SingleExchangeSingleJava client = new SingleExchangeSingleJava( 39 "19xxxxxxxx", // 商户号,是由微信支付系统生成并分配给每个商户的唯一标识符,商户号获取方式参考 https://pay.weixin.qq.com/doc/v3/partner/4013080340 40 "1DDE55AD98Exxxxxxxxxx", // 商户API证书序列号,如何获取请参考 https://pay.weixin.qq.com/doc/v3/partner/4013058924 41 "/path/to/apiclient_key.pem", // 商户API证书私钥文件路径,本地文件路径 42 "PUB_KEY_ID_xxxxxxxxxxxxx", // 微信支付公钥ID,如何获取请参考 https://pay.weixin.qq.com/doc/v3/partner/4013038589 43 "/path/to/wxp_pub.pem" // 微信支付公钥文件路径,本地文件路径 44 ); 45 46 CreateProductCouponRequest request = new CreateProductCouponRequest(); 47 // 必填,创建请求单号,6-40个字符,品牌侧需保持唯一性 48 request.outRequestNo = "SINGLE_SINGLE_EXCHANGE_20250101_005"; 49 // 必填,品牌ID,由微信支付分配 50 request.brandId = "120344"; 51 // 必填,优惠范围:SINGLE-单品券(兑换券仅支持单品券) 52 request.scope = ProductCouponScope.SINGLE; 53 // 必填,商品券类型:NORMAL-满减券, DISCOUNT-折扣券, EXCHANGE-兑换券(仅单品券) 54 request.type = ProductCouponType.EXCHANGE; 55 // 必填,使用模式:SINGLE-单券, PROGRESSIVE_BUNDLE-多次优惠 56 request.usageMode = UsageMode.SINGLE; 57 // 选填,商户侧商品券唯一标识 58 request.outProductNo = "Product_SINGLE_005"; 59 60 // 必填,商品券展示信息 61 request.displayInfo = new ProductCouponDisplayInfo(); 62 // 必填,商品券名称,最多12个字符 63 request.displayInfo.name = "9.9元兑换原价99元商品"; 64 // 必填,商品券图片URL 65 request.displayInfo.imageUrl = "https://wxpaylogo.qpic.cn/wxpaylogo/xxxxx/xxx"; 66 // 选填,背景图URL 67 request.displayInfo.backgroundUrl = "https://wxpaylogo.qpic.cn/wxpaylogo/xxxxx/xxx"; 68 // 选填,详情图URL列表,最多6张 69 request.displayInfo.detailImageUrlList = new ArrayList<>(); 70 { 71 request.displayInfo.detailImageUrlList.add("https://wxpaylogo.qpic.cn/wxpaylogo/xxxxx/xxx"); 72 }; 73 // 条件必填(单品券),商品原价(单位:分),scope=SINGLE时必填 74 request.displayInfo.originalPrice = 9900L; 75 // 条件必填(单品券),套餐组合,scope=SINGLE时必填 76 request.displayInfo.comboPackageList = new ArrayList<>(); 77 { 78 ComboPackage comboPackage = new ComboPackage(); 79 comboPackage.name = "超值套餐"; 80 comboPackage.pickCount = 1L; 81 comboPackage.choiceList = new ArrayList<>(); 82 ComboPackageChoice choice = new ComboPackageChoice(); 83 choice.name = "指定商品"; 84 choice.price = 9900L; 85 choice.count = 1L; 86 choice.imageUrl = "https://wxpaylogo.qpic.cn/wxpaylogo/xxxxx/xxx"; 87 comboPackage.choiceList.add(choice); 88 request.displayInfo.comboPackageList.add(comboPackage); 89 }; 90 91 // 条件必填,批次信息(当usage_mode=SINGLE时必填) 92 request.stock = new StockForCreate(); 93 request.stock.remark = "8月单品兑换批次"; 94 request.stock.couponCodeMode = CouponCodeMode.WECHATPAY; 95 request.stock.stockSendRule = new StockSendRule(); 96 request.stock.stockSendRule.maxCount = 10000000L; 97 request.stock.stockSendRule.maxCountPerDay = 100000L; 98 request.stock.stockSendRule.maxCountPerUser = 1L; 99 100 // 单券使用规则(scope=SINGLE时在此配置优惠规则) 101 request.stock.singleUsageRule = new SingleUsageRule(); 102 request.stock.singleUsageRule.couponAvailablePeriod = new CouponAvailablePeriod(); 103 request.stock.singleUsageRule.couponAvailablePeriod.availableBeginTime = "2025-08-01T00:00:00+08:00"; 104 request.stock.singleUsageRule.couponAvailablePeriod.availableEndTime = "2025-08-31T23:59:59+08:00"; 105 request.stock.singleUsageRule.couponAvailablePeriod.availableDays = 30L; 106 request.stock.singleUsageRule.couponAvailablePeriod.waitDaysAfterReceive = 0L; 107 request.stock.singleUsageRule.couponAvailablePeriod.weeklyAvailablePeriod = new FixedWeekPeriod(); 108 request.stock.singleUsageRule.couponAvailablePeriod.weeklyAvailablePeriod.dayList = new ArrayList<>(); 109 { 110 request.stock.singleUsageRule.couponAvailablePeriod.weeklyAvailablePeriod.dayList.add(WeekEnum.MONDAY); 111 request.stock.singleUsageRule.couponAvailablePeriod.weeklyAvailablePeriod.dayList.add(WeekEnum.TUESDAY); 112 request.stock.singleUsageRule.couponAvailablePeriod.weeklyAvailablePeriod.dayList.add(WeekEnum.WEDNESDAY); 113 request.stock.singleUsageRule.couponAvailablePeriod.weeklyAvailablePeriod.dayList.add(WeekEnum.THURSDAY); 114 request.stock.singleUsageRule.couponAvailablePeriod.weeklyAvailablePeriod.dayList.add(WeekEnum.FRIDAY); 115 }; 116 // 条件必填,兑换券使用规则(当type=EXCHANGE时在此配置) 117 request.stock.singleUsageRule.exchangeCoupon = new ExchangeCouponUsageRule(); 118 // 必填,门槛金额(单位:分),0表示无门槛 119 request.stock.singleUsageRule.exchangeCoupon.threshold = 0L; 120 // 必填,兑换价格(单位:分),用户实际支付金额 121 request.stock.singleUsageRule.exchangeCoupon.exchangePrice = 990L; 122 123 // 使用规则展示信息 124 request.stock.usageRuleDisplayInfo = new UsageRuleDisplayInfo(); 125 request.stock.usageRuleDisplayInfo.couponUsageMethodList = new ArrayList<>(); 126 { 127 request.stock.usageRuleDisplayInfo.couponUsageMethodList.add(CouponUsageMethod.OFFLINE); 128 request.stock.usageRuleDisplayInfo.couponUsageMethodList.add(CouponUsageMethod.MINI_PROGRAM); 129 request.stock.usageRuleDisplayInfo.couponUsageMethodList.add(CouponUsageMethod.PAYMENT_CODE); 130 }; 131 request.stock.usageRuleDisplayInfo.miniProgramAppid = "wx1234567890"; 132 request.stock.usageRuleDisplayInfo.miniProgramPath = "/pages/index/product"; 133 request.stock.usageRuleDisplayInfo.usageDescription = "用9.9元兑换原价99元商品"; 134 request.stock.usageRuleDisplayInfo.couponAvailableStoreInfo = new CouponAvailableStoreInfo(); 135 request.stock.usageRuleDisplayInfo.couponAvailableStoreInfo.description = "所有门店可用,可使用小程序查看门店列表"; 136 request.stock.usageRuleDisplayInfo.couponAvailableStoreInfo.miniProgramAppid = "wx1234567890"; 137 request.stock.usageRuleDisplayInfo.couponAvailableStoreInfo.miniProgramPath = "/pages/index/store-list"; 138 139 // 用户券展示信息 140 request.stock.couponDisplayInfo = new CouponDisplayInfo(); 141 request.stock.couponDisplayInfo.codeDisplayMode = CouponCodeDisplayMode.QRCODE; 142 request.stock.couponDisplayInfo.backgroundColor = "Color010"; 143 request.stock.couponDisplayInfo.entranceMiniProgram = new EntranceMiniProgram(); 144 request.stock.couponDisplayInfo.entranceMiniProgram.appid = "wx1234567890"; 145 request.stock.couponDisplayInfo.entranceMiniProgram.path = "/pages/index/product"; 146 request.stock.couponDisplayInfo.entranceMiniProgram.entranceWording = "立即兑换"; 147 request.stock.couponDisplayInfo.entranceMiniProgram.guidanceWording = "获取更多优惠"; 148 request.stock.couponDisplayInfo.entranceOfficialAccount = new EntranceOfficialAccount(); 149 request.stock.couponDisplayInfo.entranceOfficialAccount.appid = "wx1234567890"; 150 request.stock.couponDisplayInfo.entranceFinder = new EntranceFinder(); 151 request.stock.couponDisplayInfo.entranceFinder.finderId = "gh_12345678"; 152 request.stock.couponDisplayInfo.entranceFinder.finderVideoId = "UDFsdf24df34dD456Hdf34"; 153 request.stock.couponDisplayInfo.entranceFinder.finderVideoCoverImageUrl = "https://wxpaylogo.qpic.cn/wxpaylogo/xxxxx/xxx"; 154 155 // 事件通知配置 156 request.stock.notifyConfig = new NotifyConfig(); 157 request.stock.notifyConfig.notifyAppid = "wx4fd12345678"; 158 request.stock.storeScope = StockStoreScope.NONE; 159 160 try { 161 CreateProductCouponResponse response = client.run(request); 162 // TODO: 请求成功,继续业务逻辑 163 System.out.println(response); 164 } catch (WXPayUtility.ApiException e) { 165 // TODO: 请求失败,根据状态码执行不同的逻辑 166 e.printStackTrace(); 167 } 168 } 169 170 public CreateProductCouponResponse run(CreateProductCouponRequest request) { 171 String uri = PATH; 172 String reqBody = WXPayUtility.toJson(request); 173 174 Request.Builder reqBuilder = new Request.Builder().url(HOST + uri); 175 reqBuilder.addHeader("Accept", "application/json"); 176 reqBuilder.addHeader("Wechatpay-Serial", wechatPayPublicKeyId); 177 reqBuilder.addHeader("Authorization", WXPayUtility.buildAuthorization(mchid, certificateSerialNo, privateKey, METHOD, uri, reqBody)); 178 reqBuilder.addHeader("Content-Type", "application/json"); 179 RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), reqBody); 180 reqBuilder.method(METHOD, requestBody); 181 Request httpRequest = reqBuilder.build(); 182 183 // 发送HTTP请求 184 OkHttpClient client = new OkHttpClient.Builder().build(); 185 try (Response httpResponse = client.newCall(httpRequest).execute()) { 186 String respBody = WXPayUtility.extractBody(httpResponse); 187 if (httpResponse.code() >= 200 && httpResponse.code() < 300) { 188 // 2XX 成功,验证应答签名 189 WXPayUtility.validateResponse(this.wechatPayPublicKeyId, this.wechatPayPublicKey, 190 httpResponse.headers(), respBody); 191 192 // 从HTTP应答报文构建返回数据 193 return WXPayUtility.fromJson(respBody, CreateProductCouponResponse.class); 194 } else { 195 throw new WXPayUtility.ApiException(httpResponse.code(), respBody, httpResponse.headers()); 196 } 197 } catch (IOException e) { 198 throw new UncheckedIOException("Sending request to " + uri + " failed.", e); 199 } 200 } 201 202 private final String mchid; 203 private final String certificateSerialNo; 204 private final PrivateKey privateKey; 205 private final String wechatPayPublicKeyId; 206 private final PublicKey wechatPayPublicKey; 207 208 public SingleExchangeSingleJava(String mchid, String certificateSerialNo, String privateKeyFilePath, String wechatPayPublicKeyId, String wechatPayPublicKeyFilePath) { 209 this.mchid = mchid; 210 this.certificateSerialNo = certificateSerialNo; 211 this.privateKey = WXPayUtility.loadPrivateKeyFromPath(privateKeyFilePath); 212 this.wechatPayPublicKeyId = wechatPayPublicKeyId; 213 this.wechatPayPublicKey = WXPayUtility.loadPublicKeyFromPath(wechatPayPublicKeyFilePath); 214 } 215 216 public static class CreateProductCouponRequest { 217 @SerializedName("out_request_no") 218 public String outRequestNo; 219 220 @SerializedName("scope") 221 public ProductCouponScope scope; 222 223 @SerializedName("type") 224 public ProductCouponType type; 225 226 @SerializedName("usage_mode") 227 public UsageMode usageMode; 228 229 @SerializedName("single_usage_info") 230 public SingleUsageInfo singleUsageInfo; 231 232 @SerializedName("progressive_bundle_usage_info") 233 public ProgressiveBundleUsageInfo progressiveBundleUsageInfo; 234 235 @SerializedName("display_info") 236 public ProductCouponDisplayInfo displayInfo; 237 238 @SerializedName("out_product_no") 239 public String outProductNo; 240 241 @SerializedName("stock") 242 public StockForCreate stock; 243 244 @SerializedName("stock_bundle") 245 public StockBundleForCreate stockBundle; 246 247 @SerializedName("brand_id") 248 public String brandId; 249 } 250 251 public static class CreateProductCouponResponse { 252 @SerializedName("product_coupon_id") 253 public String productCouponId; 254 255 @SerializedName("scope") 256 public ProductCouponScope scope; 257 258 @SerializedName("type") 259 public ProductCouponType type; 260 261 @SerializedName("usage_mode") 262 public UsageMode usageMode; 263 264 @SerializedName("single_usage_info") 265 public SingleUsageInfo singleUsageInfo; 266 267 @SerializedName("progressive_bundle_usage_info") 268 public ProgressiveBundleUsageInfo progressiveBundleUsageInfo; 269 270 @SerializedName("display_info") 271 public ProductCouponDisplayInfo displayInfo; 272 273 @SerializedName("out_product_no") 274 public String outProductNo; 275 276 @SerializedName("state") 277 public ProductCouponState state; 278 279 @SerializedName("stock") 280 public StockEntity stock; 281 282 @SerializedName("stock_bundle") 283 public StockBundleEntity stockBundle; 284 285 @SerializedName("brand_id") 286 public String brandId; 287 } 288 289 public enum ProductCouponScope { 290 @SerializedName("ALL") 291 ALL, 292 @SerializedName("SINGLE") 293 SINGLE 294 } 295 296 public enum ProductCouponType { 297 @SerializedName("NORMAL") 298 NORMAL, 299 @SerializedName("DISCOUNT") 300 DISCOUNT, 301 @SerializedName("EXCHANGE") 302 EXCHANGE 303 } 304 305 public enum UsageMode { 306 @SerializedName("SINGLE") 307 SINGLE, 308 @SerializedName("PROGRESSIVE_BUNDLE") 309 PROGRESSIVE_BUNDLE 310 } 311 312 public static class SingleUsageInfo { 313 @SerializedName("normal_coupon") 314 public NormalCouponUsageRule normalCoupon; 315 316 @SerializedName("discount_coupon") 317 public DiscountCouponUsageRule discountCoupon; 318 } 319 320 public static class ProgressiveBundleUsageInfo { 321 @SerializedName("count") 322 public Long count; 323 324 @SerializedName("interval_days") 325 public Long intervalDays; 326 } 327 328 public static class ProductCouponDisplayInfo { 329 @SerializedName("name") 330 public String name; 331 332 @SerializedName("image_url") 333 public String imageUrl; 334 335 @SerializedName("background_url") 336 public String backgroundUrl; 337 338 @SerializedName("detail_image_url_list") 339 public List<String> detailImageUrlList; 340 341 @SerializedName("original_price") 342 public Long originalPrice; 343 344 @SerializedName("combo_package_list") 345 public List<ComboPackage> comboPackageList; 346 } 347 348 public static class StockForCreate { 349 @SerializedName("remark") 350 public String remark; 351 352 @SerializedName("coupon_code_mode") 353 public CouponCodeMode couponCodeMode; 354 355 @SerializedName("stock_send_rule") 356 public StockSendRule stockSendRule; 357 358 @SerializedName("single_usage_rule") 359 public SingleUsageRule singleUsageRule; 360 361 @SerializedName("usage_rule_display_info") 362 public UsageRuleDisplayInfo usageRuleDisplayInfo; 363 364 @SerializedName("coupon_display_info") 365 public CouponDisplayInfo couponDisplayInfo; 366 367 @SerializedName("notify_config") 368 public NotifyConfig notifyConfig; 369 370 @SerializedName("store_scope") 371 public StockStoreScope storeScope; 372 } 373 374 public static class StockBundleForCreate { 375 @SerializedName("remark") 376 public String remark; 377 378 @SerializedName("coupon_code_mode") 379 public CouponCodeMode couponCodeMode; 380 381 @SerializedName("stock_send_rule") 382 public StockSendRule stockSendRule; 383 384 @SerializedName("progressive_bundle_usage_rule") 385 public StockBundleUsageRule progressiveBundleUsageRule; 386 387 @SerializedName("usage_rule_display_info") 388 public UsageRuleDisplayInfo usageRuleDisplayInfo; 389 390 @SerializedName("coupon_display_info") 391 public CouponDisplayInfo couponDisplayInfo; 392 393 @SerializedName("notify_config") 394 public NotifyConfig notifyConfig; 395 396 @SerializedName("store_scope") 397 public StockStoreScope storeScope; 398 } 399 400 public enum ProductCouponState { 401 @SerializedName("AUDITING") 402 AUDITING, 403 @SerializedName("EFFECTIVE") 404 EFFECTIVE, 405 @SerializedName("DEACTIVATED") 406 DEACTIVATED 407 } 408 409 public static class StockEntity { 410 @SerializedName("product_coupon_id") 411 public String productCouponId; 412 413 @SerializedName("stock_id") 414 public String stockId; 415 416 @SerializedName("remark") 417 public String remark; 418 419 @SerializedName("coupon_code_mode") 420 public CouponCodeMode couponCodeMode; 421 422 @SerializedName("coupon_code_count_info") 423 public CouponCodeCountInfo couponCodeCountInfo; 424 425 @SerializedName("stock_send_rule") 426 public StockSendRule stockSendRule; 427 428 @SerializedName("single_usage_rule") 429 public SingleUsageRule singleUsageRule; 430 431 @SerializedName("usage_rule_display_info") 432 public UsageRuleDisplayInfo usageRuleDisplayInfo; 433 434 @SerializedName("coupon_display_info") 435 public CouponDisplayInfo couponDisplayInfo; 436 437 @SerializedName("notify_config") 438 public NotifyConfig notifyConfig; 439 440 @SerializedName("store_scope") 441 public StockStoreScope storeScope; 442 443 @SerializedName("sent_count_info") 444 public StockSentCountInfo sentCountInfo; 445 446 @SerializedName("state") 447 public StockState state; 448 449 @SerializedName("deactivate_request_no") 450 public String deactivateRequestNo; 451 452 @SerializedName("deactivate_time") 453 public String deactivateTime; 454 455 @SerializedName("deactivate_reason") 456 public String deactivateReason; 457 458 @SerializedName("brand_id") 459 public String brandId; 460 } 461 462 public static class StockBundleEntity { 463 @SerializedName("stock_bundle_id") 464 public String stockBundleId; 465 466 @SerializedName("stock_list") 467 public List<StockEntityInBundle> stockList = new ArrayList<StockEntityInBundle>(); 468 } 469 470 public static class NormalCouponUsageRule { 471 @SerializedName("threshold") 472 public Long threshold; 473 474 @SerializedName("discount_amount") 475 public Long discountAmount; 476 } 477 478 public static class DiscountCouponUsageRule { 479 @SerializedName("threshold") 480 public Long threshold; 481 482 @SerializedName("percent_off") 483 public Long percentOff; 484 } 485 486 public static class ComboPackage { 487 @SerializedName("name") 488 public String name; 489 490 @SerializedName("pick_count") 491 public Long pickCount; 492 493 @SerializedName("choice_list") 494 public List<ComboPackageChoice> choiceList = new ArrayList<ComboPackageChoice>(); 495 } 496 497 public enum CouponCodeMode { 498 @SerializedName("WECHATPAY") 499 WECHATPAY, 500 @SerializedName("UPLOAD") 501 UPLOAD, 502 @SerializedName("API_ASSIGN") 503 API_ASSIGN 504 } 505 506 public static class StockSendRule { 507 @SerializedName("max_count") 508 public Long maxCount; 509 510 @SerializedName("max_count_per_day") 511 public Long maxCountPerDay; 512 513 @SerializedName("max_count_per_user") 514 public Long maxCountPerUser; 515 } 516 517 public static class SingleUsageRule { 518 @SerializedName("coupon_available_period") 519 public CouponAvailablePeriod couponAvailablePeriod; 520 521 @SerializedName("normal_coupon") 522 public NormalCouponUsageRule normalCoupon; 523 524 @SerializedName("discount_coupon") 525 public DiscountCouponUsageRule discountCoupon; 526 527 @SerializedName("exchange_coupon") 528 public ExchangeCouponUsageRule exchangeCoupon; 529 } 530 531 public static class UsageRuleDisplayInfo { 532 @SerializedName("coupon_usage_method_list") 533 public List<CouponUsageMethod> couponUsageMethodList = new ArrayList<CouponUsageMethod>(); 534 535 @SerializedName("mini_program_appid") 536 public String miniProgramAppid; 537 538 @SerializedName("mini_program_path") 539 public String miniProgramPath; 540 541 @SerializedName("app_path") 542 public String appPath; 543 544 @SerializedName("usage_description") 545 public String usageDescription; 546 547 @SerializedName("coupon_available_store_info") 548 public CouponAvailableStoreInfo couponAvailableStoreInfo; 549 } 550 551 public static class CouponDisplayInfo { 552 @SerializedName("code_display_mode") 553 public CouponCodeDisplayMode codeDisplayMode; 554 555 @SerializedName("background_color") 556 public String backgroundColor; 557 558 @SerializedName("entrance_mini_program") 559 public EntranceMiniProgram entranceMiniProgram; 560 561 @SerializedName("entrance_official_account") 562 public EntranceOfficialAccount entranceOfficialAccount; 563 564 @SerializedName("entrance_finder") 565 public EntranceFinder entranceFinder; 566 } 567 568 public static class NotifyConfig { 569 @SerializedName("notify_appid") 570 public String notifyAppid; 571 } 572 573 public enum StockStoreScope { 574 @SerializedName("NONE") 575 NONE, 576 @SerializedName("ALL") 577 ALL, 578 @SerializedName("SPECIFIC") 579 SPECIFIC 580 } 581 582 public static class StockBundleUsageRule { 583 @SerializedName("coupon_available_period") 584 public CouponAvailablePeriod couponAvailablePeriod; 585 586 @SerializedName("normal_coupon_list") 587 public List<NormalCouponUsageRule> normalCouponList; 588 589 @SerializedName("discount_coupon_list") 590 public List<DiscountCouponUsageRule> discountCouponList; 591 592 @SerializedName("exchange_coupon_list") 593 public List<ExchangeCouponUsageRule> exchangeCouponList; 594 } 595 596 public static class CouponCodeCountInfo { 597 @SerializedName("total_count") 598 public Long totalCount; 599 600 @SerializedName("available_count") 601 public Long availableCount; 602 } 603 604 public static class StockSentCountInfo { 605 @SerializedName("total_count") 606 public Long totalCount; 607 608 @SerializedName("today_count") 609 public Long todayCount; 610 } 611 612 public enum StockState { 613 @SerializedName("AUDITING") 614 AUDITING, 615 @SerializedName("SENDING") 616 SENDING, 617 @SerializedName("PAUSED") 618 PAUSED, 619 @SerializedName("STOPPED") 620 STOPPED, 621 @SerializedName("DEACTIVATED") 622 DEACTIVATED 623 } 624 625 public static class StockEntityInBundle { 626 @SerializedName("product_coupon_id") 627 public String productCouponId; 628 629 @SerializedName("stock_id") 630 public String stockId; 631 632 @SerializedName("remark") 633 public String remark; 634 635 @SerializedName("coupon_code_mode") 636 public CouponCodeMode couponCodeMode; 637 638 @SerializedName("coupon_code_count_info") 639 public CouponCodeCountInfo couponCodeCountInfo; 640 641 @SerializedName("stock_send_rule") 642 public StockSendRule stockSendRule; 643 644 @SerializedName("progressive_bundle_usage_rule") 645 public StockUsageRule progressiveBundleUsageRule; 646 647 @SerializedName("stock_bundle_info") 648 public StockBundleInfo stockBundleInfo; 649 650 @SerializedName("usage_rule_display_info") 651 public UsageRuleDisplayInfo usageRuleDisplayInfo; 652 653 @SerializedName("coupon_display_info") 654 public CouponDisplayInfo couponDisplayInfo; 655 656 @SerializedName("notify_config") 657 public NotifyConfig notifyConfig; 658 659 @SerializedName("store_scope") 660 public StockStoreScope storeScope; 661 662 @SerializedName("sent_count_info") 663 public StockSentCountInfo sentCountInfo; 664 665 @SerializedName("state") 666 public StockState state; 667 668 @SerializedName("deactivate_request_no") 669 public String deactivateRequestNo; 670 671 @SerializedName("deactivate_time") 672 public String deactivateTime; 673 674 @SerializedName("deactivate_reason") 675 public String deactivateReason; 676 677 @SerializedName("brand_id") 678 public String brandId; 679 } 680 681 public static class ComboPackageChoice { 682 @SerializedName("name") 683 public String name; 684 685 @SerializedName("price") 686 public Long price; 687 688 @SerializedName("count") 689 public Long count; 690 691 @SerializedName("image_url") 692 public String imageUrl; 693 694 @SerializedName("mini_program_appid") 695 public String miniProgramAppid; 696 697 @SerializedName("mini_program_path") 698 public String miniProgramPath; 699 } 700 701 public static class CouponAvailablePeriod { 702 @SerializedName("available_begin_time") 703 public String availableBeginTime; 704 705 @SerializedName("available_end_time") 706 public String availableEndTime; 707 708 @SerializedName("available_days") 709 public Long availableDays; 710 711 @SerializedName("wait_days_after_receive") 712 public Long waitDaysAfterReceive; 713 714 @SerializedName("weekly_available_period") 715 public FixedWeekPeriod weeklyAvailablePeriod; 716 717 @SerializedName("irregular_available_period_list") 718 public List<TimePeriod> irregularAvailablePeriodList; 719 } 720 721 public static class ExchangeCouponUsageRule { 722 @SerializedName("threshold") 723 public Long threshold; 724 725 @SerializedName("exchange_price") 726 public Long exchangePrice; 727 } 728 729 public enum CouponUsageMethod { 730 @SerializedName("OFFLINE") 731 OFFLINE, 732 @SerializedName("MINI_PROGRAM") 733 MINI_PROGRAM, 734 @SerializedName("APP") 735 APP, 736 @SerializedName("PAYMENT_CODE") 737 PAYMENT_CODE 738 } 739 740 public static class CouponAvailableStoreInfo { 741 @SerializedName("description") 742 public String description; 743 744 @SerializedName("mini_program_appid") 745 public String miniProgramAppid; 746 747 @SerializedName("mini_program_path") 748 public String miniProgramPath; 749 } 750 751 public enum CouponCodeDisplayMode { 752 @SerializedName("INVISIBLE") 753 INVISIBLE, 754 @SerializedName("BARCODE") 755 BARCODE, 756 @SerializedName("QRCODE") 757 QRCODE 758 } 759 760 public static class EntranceMiniProgram { 761 @SerializedName("appid") 762 public String appid; 763 764 @SerializedName("path") 765 public String path; 766 767 @SerializedName("entrance_wording") 768 public String entranceWording; 769 770 @SerializedName("guidance_wording") 771 public String guidanceWording; 772 } 773 774 public static class EntranceOfficialAccount { 775 @SerializedName("appid") 776 public String appid; 777 } 778 779 public static class EntranceFinder { 780 @SerializedName("finder_id") 781 public String finderId; 782 783 @SerializedName("finder_video_id") 784 public String finderVideoId; 785 786 @SerializedName("finder_video_cover_image_url") 787 public String finderVideoCoverImageUrl; 788 } 789 790 public static class StockUsageRule { 791 @SerializedName("coupon_available_period") 792 public CouponAvailablePeriod couponAvailablePeriod; 793 794 @SerializedName("normal_coupon") 795 public NormalCouponUsageRule normalCoupon; 796 797 @SerializedName("discount_coupon") 798 public DiscountCouponUsageRule discountCoupon; 799 800 @SerializedName("exchange_coupon") 801 public ExchangeCouponUsageRule exchangeCoupon; 802 } 803 804 public static class StockBundleInfo { 805 @SerializedName("stock_bundle_id") 806 public String stockBundleId; 807 808 @SerializedName("stock_bundle_index") 809 public Long stockBundleIndex; 810 } 811 812 public static class FixedWeekPeriod { 813 @SerializedName("day_list") 814 public List<WeekEnum> dayList; 815 816 @SerializedName("day_period_list") 817 public List<PeriodOfTheDay> dayPeriodList; 818 } 819 820 public static class TimePeriod { 821 @SerializedName("begin_time") 822 public String beginTime; 823 824 @SerializedName("end_time") 825 public String endTime; 826 } 827 828 public enum WeekEnum { 829 @SerializedName("MONDAY") 830 MONDAY, 831 @SerializedName("TUESDAY") 832 TUESDAY, 833 @SerializedName("WEDNESDAY") 834 WEDNESDAY, 835 @SerializedName("THURSDAY") 836 THURSDAY, 837 @SerializedName("FRIDAY") 838 FRIDAY, 839 @SerializedName("SATURDAY") 840 SATURDAY, 841 @SerializedName("SUNDAY") 842 SUNDAY 843 } 844 845 public static class PeriodOfTheDay { 846 @SerializedName("begin_time") 847 public Long beginTime; 848 849 @SerializedName("end_time") 850 public Long endTime; 851 } 852 853}
需配合微信支付工具库 wxpay_utility 使用,请参考 Go
1package main 2 3import ( 4 "bytes" 5 "demo/wxpay_utility" // 引用微信支付工具库,参考 https://pay.weixin.qq.com/doc/v3/partner/4015119446 6 "encoding/json" 7 "fmt" 8 "net/http" 9 "net/url" 10) 11 12// 场景5:创建商品券 - 单券-单品-兑换券 13// 14// 场景说明: 15// - usage_mode: SINGLE(单券模式) 16// - scope: SINGLE(单品券) 17// - type: EXCHANGE(兑换券) 18// 19// ⚠️ 重要: 20// 1. 兑换券仅支持单品券(scope=SINGLE) 21// 2. 单品券的优惠规则配置在 stock.single_usage_rule.exchange_coupon 中(不是single_usage_info) 22// 23// 接口文档:https://pay.weixin.qq.com/doc/v3/partner/4015781289 24 25func main() { 26 // TODO: 请准备商户开发必要参数,参考:https://pay.weixin.qq.com/doc/v3/partner/4013080340 27 config, err := wxpay_utility.CreateMchConfig( 28 "19xxxxxxxx", // 商户号,是由微信支付系统生成并分配给每个商户的唯一标识符,商户号获取方式参考 https://pay.weixin.qq.com/doc/v3/partner/4013080340 29 "1DDE55AD98Exxxxxxxxxx", // 商户API证书序列号,如何获取请参考 https://pay.weixin.qq.com/doc/v3/partner/4013058924 30 "/path/to/apiclient_key.pem", // 商户API证书私钥文件路径,本地文件路径 31 "PUB_KEY_ID_xxxxxxxxxxxxx", // 微信支付公钥ID,如何获取请参考 https://pay.weixin.qq.com/doc/v3/partner/4013038589 32 "/path/to/wxp_pub.pem", // 微信支付公钥文件路径,本地文件路径 33 ) 34 if err != nil { 35 fmt.Println(err) 36 return 37 } 38 39 request := &CreateProductCouponRequest{ 40 // ==================== 一级参数 ==================== 41 // 必填:创建请求单号,品牌侧需保持唯一性,6-40个字符 42 OutRequestNo: wxpay_utility.String("SINGLE_SINGLE_EXCHANGE_20250101_005"), 43 // 必填:品牌ID,由微信支付分配 44 BrandId: wxpay_utility.String("120344"), 45 // 必填:优惠范围,SINGLE=单品券(兑换券仅支持单品券) 46 Scope: PRODUCTCOUPONSCOPE_SINGLE.Ptr(), 47 // 必填:商品券类型,EXCHANGE=兑换券(仅单品券支持) 48 Type: PRODUCTCOUPONTYPE_EXCHANGE.Ptr(), 49 // 必填:使用模式,SINGLE=单券模式 50 UsageMode: USAGEMODE_SINGLE.Ptr(), 51 // 选填:商户侧商品券唯一标识 52 OutProductNo: wxpay_utility.String("Product_SINGLE_005"), 53 54 // ⚠️ scope=SINGLE时,不在single_usage_info中配置优惠规则 55 // 优惠规则在 stock.single_usage_rule 中配置 56 57 // ==================== 必填:商品券展示信息 ==================== 58 DisplayInfo: &ProductCouponDisplayInfo{ 59 // 必填:商品券名称,最多20个字符 60 Name: wxpay_utility.String("9.9元兑换原价99元商品"), 61 // 必填:商品图片URL,需通过图片上传接口获取 62 ImageUrl: wxpay_utility.String("https://wxpaylogo.qpic.cn/wxpaylogo/xxxxx/xxx"), 63 // 选填:背景图URL 64 BackgroundUrl: wxpay_utility.String("https://wxpaylogo.qpic.cn/wxpaylogo/xxxxx/xxx"), 65 // 选填:详情图URL列表,最多6张 66 DetailImageUrlList: []string{ 67 "https://wxpaylogo.qpic.cn/wxpaylogo/xxxxx/xxx", 68 }, 69 // 条件必填(单品券):商品原价(单位:分),scope=SINGLE时必填 70 OriginalPrice: wxpay_utility.Int64(9900), 71 // 条件必填(单品券):套餐组合,scope=SINGLE时必填 72 ComboPackageList: []ComboPackage{ 73 { 74 Name: wxpay_utility.String("超值套餐"), 75 PickCount: wxpay_utility.Int64(1), 76 ChoiceList: []ComboPackageChoice{ 77 { 78 Name: wxpay_utility.String("指定商品"), 79 Price: wxpay_utility.Int64(9900), 80 Count: wxpay_utility.Int64(1), 81 ImageUrl: wxpay_utility.String("https://wxpaylogo.qpic.cn/wxpaylogo/xxxxx/xxx"), 82 }, 83 }, 84 }, 85 }, 86 }, 87 88 // ==================== 批次信息(必填) ==================== 89 Stock: &StockForCreate{ 90 // 选填:备注 91 Remark: wxpay_utility.String("8月单品兑换批次"), 92 // 必填:券Code分配模式,WECHATPAY=微信支付生成 93 CouponCodeMode: COUPONCODEMODE_WECHATPAY.Ptr(), 94 95 // ---------- 发放规则(必填) ---------- 96 StockSendRule: &StockSendRule{ 97 // 必填:总发放次数上限 98 MaxCount: wxpay_utility.Int64(10000000), 99 // 选填:每日发放上限 100 MaxCountPerDay: wxpay_utility.Int64(100000), 101 // 必填:每用户领取上限 102 MaxCountPerUser: wxpay_utility.Int64(1), 103 }, 104 105 // ---------- 单券使用规则(scope=SINGLE时在此配置优惠规则) ---------- 106 SingleUsageRule: &SingleUsageRule{ 107 // 券可核销时间(必填) 108 CouponAvailablePeriod: &CouponAvailablePeriod{ 109 // 必填:开始时间,RFC3339格式 110 AvailableBeginTime: wxpay_utility.String("2025-08-01T00:00:00+08:00"), 111 // 必填:结束时间 112 AvailableEndTime: wxpay_utility.String("2025-08-31T23:59:59+08:00"), 113 // 选填:生效后N天有效,最多365天 114 AvailableDays: wxpay_utility.Int64(30), 115 // 选填:领取后N天生效,最多30天,0表示立即生效 116 WaitDaysAfterReceive: wxpay_utility.Int64(0), 117 // 选填:每周可用时间 118 WeeklyAvailablePeriod: &FixedWeekPeriod{ 119 // 当配置weekly_available_period时必填:可用星期列表 120 DayList: []WeekEnum{ 121 WEEKENUM_MONDAY, 122 WEEKENUM_TUESDAY, 123 WEEKENUM_WEDNESDAY, 124 WEEKENUM_THURSDAY, 125 WEEKENUM_FRIDAY, 126 }, 127 }, 128 }, 129 // ⚠️【关键】当type=EXCHANGE时,在此配置兑换券优惠规则 130 ExchangeCoupon: &ExchangeCouponUsageRule{ 131 // 必填:门槛金额,单位为分,0表示无门槛 132 Threshold: wxpay_utility.Int64(0), 133 // 必填:兑换价格,单位为分,9.9元填990 134 ExchangePrice: wxpay_utility.Int64(990), 135 }, 136 }, 137 138 // ---------- 使用规则展示信息(必填) ---------- 139 UsageRuleDisplayInfo: &UsageRuleDisplayInfo{ 140 // 必填:券使用方式列表 141 CouponUsageMethodList: []CouponUsageMethod{ 142 COUPONUSAGEMETHOD_OFFLINE, // 线下滴码核销 143 COUPONUSAGEMETHOD_MINI_PROGRAM, // 线上小程序核销 144 COUPONUSAGEMETHOD_PAYMENT_CODE, // 微信支付付款码核销 145 }, 146 // 当coupon_usage_method_list包含MINI_PROGRAM时必填:核销小程序AppID 147 MiniProgramAppid: wxpay_utility.String("wx1234567890"), 148 // 当coupon_usage_method_list包含MINI_PROGRAM时必填:核销小程序路径 149 MiniProgramPath: wxpay_utility.String("/pages/index/product"), 150 // 必填:使用说明 151 UsageDescription: wxpay_utility.String("用9.9元兑换原价99元商品"), 152 // 选填:可用门店信息 153 CouponAvailableStoreInfo: &CouponAvailableStoreInfo{ 154 // 当配置coupon_available_store_info时必填:门店描述 155 Description: wxpay_utility.String("所有门店可用"), 156 // 选填:查看门店的小程序AppID 157 MiniProgramAppid: wxpay_utility.String("wx1234567890"), 158 // 选填:查看门店的小程序路径 159 MiniProgramPath: wxpay_utility.String("/pages/index/store-list"), 160 }, 161 }, 162 163 // ---------- 用户券展示信息(必填) ---------- 164 CouponDisplayInfo: &CouponDisplayInfo{ 165 // 必填:Code展示模式,QRCODE=二维码 166 CodeDisplayMode: COUPONCODEDISPLAYMODE_QRCODE.Ptr(), 167 // 选填:背景颜色 168 BackgroundColor: wxpay_utility.String("Color010"), 169 // 选填:小程序入口 170 EntranceMiniProgram: &EntranceMiniProgram{ 171 Appid: wxpay_utility.String("wx1234567890"), 172 Path: wxpay_utility.String("/pages/index/product"), 173 EntranceWording: wxpay_utility.String("立即兑换"), 174 GuidanceWording: wxpay_utility.String("获取更多优惠"), 175 }, 176 // 选填:公众号入口 177 EntranceOfficialAccount: &EntranceOfficialAccount{ 178 Appid: wxpay_utility.String("wx1234567890"), 179 }, 180 // 选填:视频号入口 181 EntranceFinder: &EntranceFinder{ 182 FinderId: wxpay_utility.String("gh_12345678"), 183 FinderVideoId: wxpay_utility.String("UDFsdf24df34dD456Hdf34"), 184 FinderVideoCoverImageUrl: wxpay_utility.String("https://wxpaylogo.qpic.cn/wxpaylogo/xxxxx/xxx"), 185 }, 186 }, 187 188 // ---------- 事件通知配置(必填) ---------- 189 NotifyConfig: &NotifyConfig{ 190 // 必填:事件通知AppID 191 NotifyAppid: wxpay_utility.String("wx4fd12345678"), 192 }, 193 194 // 必填:可用门店范围,NONE=不限制 195 StoreScope: STOCKSTORESCOPE_NONE.Ptr(), 196 }, 197 } 198 199 response, err := CreateProductCoupon(config, request) 200 if err != nil { 201 fmt.Printf("请求失败: %+v\n", err) 202 // TODO: 请求失败,根据状态码执行不同的处理 203 return 204 } 205 206 // TODO: 请求成功,继续业务逻辑 207 fmt.Printf("请求成功: %+v\n", response) 208} 209 210func CreateProductCoupon(config *wxpay_utility.MchConfig, request *CreateProductCouponRequest) (response *CreateProductCouponResponse, err error) { 211 const ( 212 host = "https://api.mch.weixin.qq.com" 213 method = "POST" 214 path = "/v3/marketing/partner/product-coupon/product-coupons" 215 ) 216 217 reqUrl, err := url.Parse(fmt.Sprintf("%s%s", host, path)) 218 if err != nil { 219 return nil, err 220 } 221 reqBody, err := json.Marshal(request) 222 if err != nil { 223 return nil, err 224 } 225 httpRequest, err := http.NewRequest(method, reqUrl.String(), bytes.NewReader(reqBody)) 226 if err != nil { 227 return nil, err 228 } 229 httpRequest.Header.Set("Accept", "application/json") 230 httpRequest.Header.Set("Wechatpay-Serial", config.WechatPayPublicKeyId()) 231 httpRequest.Header.Set("Content-Type", "application/json") 232 authorization, err := wxpay_utility.BuildAuthorization(config.MchId(), config.CertificateSerialNo(), config.PrivateKey(), method, reqUrl.RequestURI(), reqBody) 233 if err != nil { 234 return nil, err 235 } 236 httpRequest.Header.Set("Authorization", authorization) 237 238 client := &http.Client{} 239 httpResponse, err := client.Do(httpRequest) 240 if err != nil { 241 return nil, err 242 } 243 respBody, err := wxpay_utility.ExtractResponseBody(httpResponse) 244 if err != nil { 245 return nil, err 246 } 247 if httpResponse.StatusCode >= 200 && httpResponse.StatusCode < 300 { 248 // 2XX 成功,验证应答签名 249 err = wxpay_utility.ValidateResponse( 250 config.WechatPayPublicKeyId(), 251 config.WechatPayPublicKey(), 252 &httpResponse.Header, 253 respBody, 254 ) 255 if err != nil { 256 return nil, err 257 } 258 response := &CreateProductCouponResponse{} 259 if err := json.Unmarshal(respBody, response); err != nil { 260 return nil, err 261 } 262 return response, nil 263 } else { 264 return nil, wxpay_utility.NewApiException( 265 httpResponse.StatusCode, 266 httpResponse.Header, 267 respBody, 268 ) 269 } 270} 271 272// ==================== 请求/响应结构体定义 ==================== 273 274type CreateProductCouponRequest struct { 275 OutRequestNo *string `json:"out_request_no,omitempty"` 276 BrandId *string `json:"brand_id,omitempty"` 277 Scope *ProductCouponScope `json:"scope,omitempty"` 278 Type *ProductCouponType `json:"type,omitempty"` 279 UsageMode *UsageMode `json:"usage_mode,omitempty"` 280 SingleUsageInfo *SingleUsageInfo `json:"single_usage_info,omitempty"` 281 DisplayInfo *ProductCouponDisplayInfo `json:"display_info,omitempty"` 282 OutProductNo *string `json:"out_product_no,omitempty"` 283 Stock *StockForCreate `json:"stock,omitempty"` 284} 285 286type CreateProductCouponResponse struct { 287 ProductCouponId *string `json:"product_coupon_id,omitempty"` 288 Scope *ProductCouponScope `json:"scope,omitempty"` 289 Type *ProductCouponType `json:"type,omitempty"` 290 UsageMode *UsageMode `json:"usage_mode,omitempty"` 291 SingleUsageInfo *SingleUsageInfo `json:"single_usage_info,omitempty"` 292 DisplayInfo *ProductCouponDisplayInfo `json:"display_info,omitempty"` 293 OutProductNo *string `json:"out_product_no,omitempty"` 294 State *ProductCouponState `json:"state,omitempty"` 295 Stock *StockEntity `json:"stock,omitempty"` 296 BrandId *string `json:"brand_id,omitempty"` 297} 298 299// ==================== 枚举类型定义 ==================== 300 301type ProductCouponScope string 302 303func (e ProductCouponScope) Ptr() *ProductCouponScope { return &e } 304 305const ( 306 PRODUCTCOUPONSCOPE_ALL ProductCouponScope = "ALL" 307 PRODUCTCOUPONSCOPE_SINGLE ProductCouponScope = "SINGLE" 308) 309 310type ProductCouponType string 311 312func (e ProductCouponType) Ptr() *ProductCouponType { return &e } 313 314const ( 315 PRODUCTCOUPONTYPE_NORMAL ProductCouponType = "NORMAL" 316 PRODUCTCOUPONTYPE_DISCOUNT ProductCouponType = "DISCOUNT" 317 PRODUCTCOUPONTYPE_EXCHANGE ProductCouponType = "EXCHANGE" 318) 319 320type UsageMode string 321 322func (e UsageMode) Ptr() *UsageMode { return &e } 323 324const ( 325 USAGEMODE_SINGLE UsageMode = "SINGLE" 326 USAGEMODE_PROGRESSIVE_BUNDLE UsageMode = "PROGRESSIVE_BUNDLE" 327) 328 329type ProductCouponState string 330 331func (e ProductCouponState) Ptr() *ProductCouponState { return &e } 332 333const ( 334 PRODUCTCOUPONSTATE_AUDITING ProductCouponState = "AUDITING" 335 PRODUCTCOUPONSTATE_EFFECTIVE ProductCouponState = "EFFECTIVE" 336 PRODUCTCOUPONSTATE_DEACTIVATED ProductCouponState = "DEACTIVATED" 337) 338 339type CouponCodeMode string 340 341func (e CouponCodeMode) Ptr() *CouponCodeMode { return &e } 342 343const ( 344 COUPONCODEMODE_WECHATPAY CouponCodeMode = "WECHATPAY" 345 COUPONCODEMODE_UPLOAD CouponCodeMode = "UPLOAD" 346 COUPONCODEMODE_API_ASSIGN CouponCodeMode = "API_ASSIGN" 347) 348 349type StockStoreScope string 350 351func (e StockStoreScope) Ptr() *StockStoreScope { return &e } 352 353const ( 354 STOCKSTORESCOPE_NONE StockStoreScope = "NONE" 355 STOCKSTORESCOPE_ALL StockStoreScope = "ALL" 356 STOCKSTORESCOPE_SPECIFIC StockStoreScope = "SPECIFIC" 357) 358 359type CouponUsageMethod string 360 361func (e CouponUsageMethod) Ptr() *CouponUsageMethod { return &e } 362 363const ( 364 COUPONUSAGEMETHOD_OFFLINE CouponUsageMethod = "OFFLINE" 365 COUPONUSAGEMETHOD_MINI_PROGRAM CouponUsageMethod = "MINI_PROGRAM" 366 COUPONUSAGEMETHOD_APP CouponUsageMethod = "APP" 367 COUPONUSAGEMETHOD_PAYMENT_CODE CouponUsageMethod = "PAYMENT_CODE" 368) 369 370type CouponCodeDisplayMode string 371 372func (e CouponCodeDisplayMode) Ptr() *CouponCodeDisplayMode { return &e } 373 374const ( 375 COUPONCODEDISPLAYMODE_INVISIBLE CouponCodeDisplayMode = "INVISIBLE" 376 COUPONCODEDISPLAYMODE_BARCODE CouponCodeDisplayMode = "BARCODE" 377 COUPONCODEDISPLAYMODE_QRCODE CouponCodeDisplayMode = "QRCODE" 378) 379 380type WeekEnum string 381 382func (e WeekEnum) Ptr() *WeekEnum { return &e } 383 384const ( 385 WEEKENUM_MONDAY WeekEnum = "MONDAY" 386 WEEKENUM_TUESDAY WeekEnum = "TUESDAY" 387 WEEKENUM_WEDNESDAY WeekEnum = "WEDNESDAY" 388 WEEKENUM_THURSDAY WeekEnum = "THURSDAY" 389 WEEKENUM_FRIDAY WeekEnum = "FRIDAY" 390 WEEKENUM_SATURDAY WeekEnum = "SATURDAY" 391 WEEKENUM_SUNDAY WeekEnum = "SUNDAY" 392) 393 394type StockState string 395 396func (e StockState) Ptr() *StockState { return &e } 397 398const ( 399 STOCKSTATE_AUDITING StockState = "AUDITING" 400 STOCKSTATE_SENDING StockState = "SENDING" 401 STOCKSTATE_PAUSED StockState = "PAUSED" 402 STOCKSTATE_STOPPED StockState = "STOPPED" 403 STOCKSTATE_DEACTIVATED StockState = "DEACTIVATED" 404) 405 406// ==================== 数据模型结构体定义 ==================== 407 408// 单券模式优惠信息(scope=ALL时使用) 409type SingleUsageInfo struct { 410 NormalCoupon *NormalCouponUsageRule `json:"normal_coupon,omitempty"` 411 DiscountCoupon *DiscountCouponUsageRule `json:"discount_coupon,omitempty"` 412} 413 414type ProductCouponDisplayInfo struct { 415 Name *string `json:"name,omitempty"` 416 ImageUrl *string `json:"image_url,omitempty"` 417 BackgroundUrl *string `json:"background_url,omitempty"` 418 DetailImageUrlList []string `json:"detail_image_url_list,omitempty"` 419 OriginalPrice *int64 `json:"original_price,omitempty"` 420 ComboPackageList []ComboPackage `json:"combo_package_list,omitempty"` 421} 422 423type StockForCreate struct { 424 Remark *string `json:"remark,omitempty"` 425 CouponCodeMode *CouponCodeMode `json:"coupon_code_mode,omitempty"` 426 StockSendRule *StockSendRule `json:"stock_send_rule,omitempty"` 427 SingleUsageRule *SingleUsageRule `json:"single_usage_rule,omitempty"` 428 UsageRuleDisplayInfo *UsageRuleDisplayInfo `json:"usage_rule_display_info,omitempty"` 429 CouponDisplayInfo *CouponDisplayInfo `json:"coupon_display_info,omitempty"` 430 NotifyConfig *NotifyConfig `json:"notify_config,omitempty"` 431 StoreScope *StockStoreScope `json:"store_scope,omitempty"` 432} 433 434type StockEntity struct { 435 ProductCouponId *string `json:"product_coupon_id,omitempty"` 436 StockId *string `json:"stock_id,omitempty"` 437 Remark *string `json:"remark,omitempty"` 438 CouponCodeMode *CouponCodeMode `json:"coupon_code_mode,omitempty"` 439 StockSendRule *StockSendRule `json:"stock_send_rule,omitempty"` 440 SingleUsageRule *SingleUsageRule `json:"single_usage_rule,omitempty"` 441 UsageRuleDisplayInfo *UsageRuleDisplayInfo `json:"usage_rule_display_info,omitempty"` 442 CouponDisplayInfo *CouponDisplayInfo `json:"coupon_display_info,omitempty"` 443 NotifyConfig *NotifyConfig `json:"notify_config,omitempty"` 444 StoreScope *StockStoreScope `json:"store_scope,omitempty"` 445 State *StockState `json:"state,omitempty"` 446 BrandId *string `json:"brand_id,omitempty"` 447} 448 449type NormalCouponUsageRule struct { 450 Threshold *int64 `json:"threshold,omitempty"` 451 DiscountAmount *int64 `json:"discount_amount,omitempty"` 452} 453 454type DiscountCouponUsageRule struct { 455 Threshold *int64 `json:"threshold,omitempty"` 456 PercentOff *int64 `json:"percent_off,omitempty"` 457} 458 459type ExchangeCouponUsageRule struct { 460 Threshold *int64 `json:"threshold,omitempty"` 461 ExchangePrice *int64 `json:"exchange_price,omitempty"` 462} 463 464type ComboPackage struct { 465 Name *string `json:"name,omitempty"` 466 PickCount *int64 `json:"pick_count,omitempty"` 467 ChoiceList []ComboPackageChoice `json:"choice_list,omitempty"` 468} 469 470type ComboPackageChoice struct { 471 Name *string `json:"name,omitempty"` 472 Price *int64 `json:"price,omitempty"` 473 Count *int64 `json:"count,omitempty"` 474 ImageUrl *string `json:"image_url,omitempty"` 475 MiniProgramAppid *string `json:"mini_program_appid,omitempty"` 476 MiniProgramPath *string `json:"mini_program_path,omitempty"` 477} 478 479type StockSendRule struct { 480 MaxCount *int64 `json:"max_count,omitempty"` 481 MaxCountPerDay *int64 `json:"max_count_per_day,omitempty"` 482 MaxCountPerUser *int64 `json:"max_count_per_user,omitempty"` 483} 484 485// 单券使用规则(scope=ALL时只配置CouponAvailablePeriod,scope=SINGLE时还需配置优惠规则) 486type SingleUsageRule struct { 487 CouponAvailablePeriod *CouponAvailablePeriod `json:"coupon_available_period,omitempty"` 488 NormalCoupon *NormalCouponUsageRule `json:"normal_coupon,omitempty"` 489 DiscountCoupon *DiscountCouponUsageRule `json:"discount_coupon,omitempty"` 490 ExchangeCoupon *ExchangeCouponUsageRule `json:"exchange_coupon,omitempty"` 491} 492 493type CouponAvailablePeriod struct { 494 AvailableBeginTime *string `json:"available_begin_time,omitempty"` 495 AvailableEndTime *string `json:"available_end_time,omitempty"` 496 AvailableDays *int64 `json:"available_days,omitempty"` 497 WaitDaysAfterReceive *int64 `json:"wait_days_after_receive,omitempty"` 498 WeeklyAvailablePeriod *FixedWeekPeriod `json:"weekly_available_period,omitempty"` 499 IrregularAvailablePeriodList []TimePeriod `json:"irregular_available_period_list,omitempty"` 500} 501 502type FixedWeekPeriod struct { 503 DayList []WeekEnum `json:"day_list,omitempty"` 504} 505 506type TimePeriod struct { 507 BeginTime *string `json:"begin_time,omitempty"` 508 EndTime *string `json:"end_time,omitempty"` 509} 510 511type UsageRuleDisplayInfo struct { 512 CouponUsageMethodList []CouponUsageMethod `json:"coupon_usage_method_list,omitempty"` 513 MiniProgramAppid *string `json:"mini_program_appid,omitempty"` 514 MiniProgramPath *string `json:"mini_program_path,omitempty"` 515 UsageDescription *string `json:"usage_description,omitempty"` 516 CouponAvailableStoreInfo *CouponAvailableStoreInfo `json:"coupon_available_store_info,omitempty"` 517} 518 519type CouponAvailableStoreInfo struct { 520 Description *string `json:"description,omitempty"` 521 MiniProgramAppid *string `json:"mini_program_appid,omitempty"` 522 MiniProgramPath *string `json:"mini_program_path,omitempty"` 523} 524 525type CouponDisplayInfo struct { 526 CodeDisplayMode *CouponCodeDisplayMode `json:"code_display_mode,omitempty"` 527 BackgroundColor *string `json:"background_color,omitempty"` 528 EntranceMiniProgram *EntranceMiniProgram `json:"entrance_mini_program,omitempty"` 529 EntranceOfficialAccount *EntranceOfficialAccount `json:"entrance_official_account,omitempty"` 530 EntranceFinder *EntranceFinder `json:"entrance_finder,omitempty"` 531} 532 533type EntranceMiniProgram struct { 534 Appid *string `json:"appid,omitempty"` 535 Path *string `json:"path,omitempty"` 536 EntranceWording *string `json:"entrance_wording,omitempty"` 537 GuidanceWording *string `json:"guidance_wording,omitempty"` 538} 539 540type EntranceOfficialAccount struct { 541 Appid *string `json:"appid,omitempty"` 542} 543 544type EntranceFinder struct { 545 FinderId *string `json:"finder_id,omitempty"` 546 FinderVideoId *string `json:"finder_video_id,omitempty"` 547 FinderVideoCoverImageUrl *string `json:"finder_video_cover_image_url,omitempty"` 548} 549 550type NotifyConfig struct { 551 NotifyAppid *string `json:"notify_appid,omitempty"` 552}
文档是否有帮助

