---
url: "https://pay.weixin.qq.com/doc/v3/partner/4016756286.md"
title: "【多次优惠-单品-满减券】API请求示例"
doc_id: 4016756286
---

>更新时间：2025.12.04

curlJavaGo

```


## 场景4: 多次优惠-单品-满减券

```
curl -X POST \
  https://api.mch.weixin.qq.com/v3/marketing/partner/product-coupon/product-coupons \
  -H "Authorization: WECHATPAY2-SHA256-RSA2048 mchid=\"1900000001\",..." \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
    "out_request_no" : "MANY_SINGLE_NORMAL_20250101_004",  # 必填，创建请求单号，品牌侧需保持唯一性，长度6-40个字符
    "brand_id" : "120344",  # 必填，品牌ID
    "out_product_no" : "Product_1234567890",  # 选填，外部商品ID
    "scope" : "SINGLE",  # 必填，优惠范围：SINGLE=单品券
    "type" : "NORMAL",  # 必填，商品券类型：NORMAL=满减券
    "usage_mode" : "PROGRESSIVE_BUNDLE",  # 必填，使用模式：PROGRESSIVE_BUNDLE=多次优惠模式（阶梯模式）
    "progressive_bundle_usage_info" : {  # 条件必填：当usage_mode="PROGRESSIVE_BUNDLE"时必填，多次优惠模式配置信息
      "count" : 3,  # 必填，可使用次数，最少3次，最多15次
      "interval_days" : 2  # 选填，多次优惠使用间隔天数，2=使用后需等到第三天00:00:00才能使用下一次
    },
    "display_info" : {  # 必填，商品券展示信息
      "name" : "指定商品立减15(可用3次)",  # 必填，商品券名称
      "image_url" : "https://wxpaylogo.qpic.cn/wxpaylogo/xxxxx/xxx",  # 必填，商品图片URL
      "background_url" : "https://wxpaylogo.qpic.cn/wxpaylogo/xxxxx/xxx",  # 必填，背景图URL
      "detail_image_url_list" : [  # 选填，详情图URL列表
        "https://wxpaylogo.qpic.cn/wxpaylogo/xxxxx/xxx"
      ],
      "original_price" : 9900,  # 条件必填：当scope="SINGLE"时，与combo_package_list二选一必填，商品原价，单位为分
      "combo_package_list" : [  # 条件必填：当scope="SINGLE"时，与original_price二选一必填，套餐组合列表
        {
          "name" : "套餐A",  # 条件必填：当配置combo_package_list数组时必填，套餐名称
          "pick_count" : 2,  # 条件必填：当配置combo_package_list数组时必填，可选单品数量
          "choice_list" : [  # 条件必填：当配置combo_package_list数组时必填，单品列表
            { "name" : "鸡腿饭", "price" : 2000, "count" : 1, "image_url" : "https://wxpaylogo.qpic.cn/wxpaylogo/xxxxx/chicken" },  # name/price/count必填，image_url选填
            { "name" : "牛肉饭", "price" : 2500, "count" : 1, "image_url" : "https://wxpaylogo.qpic.cn/wxpaylogo/xxxxx/beef" }
          ]
        }
      ]
    },
    "stock_bundle" : {  # 条件必填：当usage_mode="PROGRESSIVE_BUNDLE"时必填，批次组信息
        "remark" : "指定商品立减15批次",  # 选填，批次备注
        "coupon_code_mode" : "WECHATPAY",  # 必填，券Code分配模式
        "stock_send_rule" : {  # 必填，发放规则
          "max_count" : 10000000,  # 必填，总发放次数上限
          "max_count_per_user" : 1  # 必填，每用户领取上限
        },
        "progressive_bundle_usage_rule" : {  # 条件必填：当usage_mode="PROGRESSIVE_BUNDLE"时必填，多次优惠使用规则
          "coupon_available_period" : {  # 必填，券可核销时间
            "available_begin_time" : "2025-08-01T00:00:00+08:00",  # 必填，开始时间
            "available_end_time" : "2025-08-31T23:59:59+08:00",  # 必填，结束时间
            "available_days" : 30,  # 选填，生效后N天有效
            "weekly_available_period" : {  # 选填，每周可用时间。若配置此对象，则day_list必填
              "day_list" : ["MONDAY","TUESDAY","WEDNESDAY","THURSDAY","FRIDAY"]  # 条件必填：当配置weekly_available_period对象时必填
            }
          },
          "normal_coupon" : {  # 条件必填：当type="NORMAL"时必填，满减券使用规则
            "threshold" : 0,  # 必填，门槛金额，单位为分，0表示无门槛
            "discount_amount" : 1500  # 必填，固定减免金额，单位为分，减15元填1500
          }
        },
        "usage_rule_display_info" : {  # 必填，使用规则展示信息
          "coupon_usage_method_list" : ["OFFLINE","MINI_PROGRAM","PAYMENT_CODE"],  # 必填，券使用方式列表
          "mini_program_appid" : "wx1234567890",  # 条件必填：当coupon_usage_method_list包含"MINI_PROGRAM"时必填
          "mini_program_path" : "/pages/index/product",  # 条件必填：当coupon_usage_method_list包含"MINI_PROGRAM"时必填
          "usage_description" : "指定商品可用，立减15元",  # 必填，使用说明
          "coupon_available_store_info" : {  # 选填，可用门店信息
            "description" : "所有门店可用，可使用小程序查看门店列表",  # 条件必填：当配置coupon_available_store_info对象时必填
            "mini_program_appid" : "wx1234567890",  # 选填
            "mini_program_path" : "/pages/index/store-list"  # 选填
          }
        },
        "coupon_display_info" : {  # 必填，用户券展示信息
          "code_display_mode" : "QRCODE",  # 必填，Code展示模式
          "background_color" : "Color010",  # 选填，背景颜色
          "entrance_mini_program" : {  # 选填，小程序入口。若配置此对象，则appid/path/entrance_wording/guidance_wording均必填
            "appid" : "wx1234567890",  # 条件必填：当配置entrance_mini_program对象时必填
            "path" : "/pages/index/product",  # 条件必填：当配置entrance_mini_program对象时必填
            "entrance_wording" : "欢迎选购",  # 条件必填：当配置entrance_mini_program对象时必填
            "guidance_wording" : "获取更多优惠"  # 条件必填：当配置entrance_mini_program对象时必填
          },
          "entrance_official_account" : { "appid" : "wx1234567890" },  # 选填
          "entrance_finder" : {  # 选填，视频号入口。若配置此对象，则finder_id/finder_video_id/finder_video_cover_image_url均必填
            "finder_id" : "gh_12345678",  # 条件必填：当配置entrance_finder对象时必填
            "finder_video_id" : "UDFsdf24df34dD456Hdf34",  # 条件必填：当配置entrance_finder对象时必填
            "finder_video_cover_image_url" : "https://wxpaylogo.qpic.cn/wxpaylogo/xxxxx/xxx"  # 条件必填：当配置entrance_finder对象时必填
          }
        },
        "store_scope" : "NONE",  # 必填，可用门店范围
        "notify_config" : { "notify_appid" : "wx4fd12345678" }  # 必填，事件通知配置
    }
  }'
```
```

需配合微信支付工具库 WXPayUtility 使用，请参考 [Java](https://pay.weixin.qq.com/doc/v3/partner/4014985777.md)

```
package com.java.demo;

import com.java.utils.WXPayUtility; // 引用微信支付工具库，参考：https://pay.weixin.qq.com/doc/v3/partner/4014985777
import com.google.gson.annotations.SerializedName;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.ArrayList;
import java.util.List;

/**
 * 创建商品券 - 场景4：多次优惠-单品-满减券
 *
 * 场景说明：单品券（适用于指定商品）+ 满减券（满足门槛后减固定金额）+ 阶梯模式（可多次使用）
 *
 * 关键参数：
 * - scope = SINGLE（单品券）
 * - type = NORMAL（满减券）
 * - usage_mode = PROGRESSIVE_BUNDLE（阶梯模式）
 */
public class SingleNormalManyJava {
  private static String HOST = "https://api.mch.weixin.qq.com";
  private static String METHOD = "POST";
  private static String PATH = "/v3/marketing/partner/product-coupon/product-coupons";

  public static void main(String[] args) {
    // TODO: 请准备商户开发必要参数，参考：https://pay.weixin.qq.com/doc/v3/partner/4013080340
    SingleNormalManyJava client = new SingleNormalManyJava(
      "19xxxxxxxx",                    // 商户号
      "1DDE55AD98Exxxxxxxxxx",         // 商户API证书序列号
      "/path/to/apiclient_key.pem",    // 商户API证书私钥文件路径
      "PUB_KEY_ID_xxxxxxxxxxxxx",      // 微信支付公钥ID
      "/path/to/wxp_pub.pem"           // 微信支付公钥文件路径
    );

    CreateProductCouponRequest request = new CreateProductCouponRequest();
    // 必填，创建请求单号，6-40个字符，品牌侧需保持唯一性
    request.outRequestNo = "MANY_SINGLE_NORMAL_20250101_004";
    // 必填，品牌ID，由微信支付分配
    request.brandId = "120344";
    // 选填，商户侧商品券唯一标识
    request.outProductNo = "Product_1234567890";
    // 必填，优惠范围：ALL-全场券(仅支持NORMAL/DISCOUNT), SINGLE-单品券(支持NORMAL/DISCOUNT/EXCHANGE)
    request.scope = ProductCouponScope.SINGLE;
    // 必填，商品券类型：NORMAL-满减券, DISCOUNT-折扣券, EXCHANGE-兑换券(仅单品券)
    request.type = ProductCouponType.NORMAL;
    // 必填，使用模式：SINGLE-单券, PROGRESSIVE_BUNDLE-多次优惠
    request.usageMode = UsageMode.PROGRESSIVE_BUNDLE;

    // 条件必填，多次优惠模式配置信息(当usage_mode=PROGRESSIVE_BUNDLE时必填)
    request.progressiveBundleUsageInfo = new ProgressiveBundleUsageInfo();
    // 必填，可使用次数，最少3次，最多15次
    request.progressiveBundleUsageInfo.count = 3L;
    // 选填，多次优惠使用间隔天数(2表示使用后需等到第三天00:00:00才能使用下一次)，最高7天，默认0
    request.progressiveBundleUsageInfo.intervalDays = 2L;  // 使用后需等到第三天00:00:00才能使用下一次

    // 必填，商品券展示信息
    request.displayInfo = new ProductCouponDisplayInfo();
    // 必填，商品券名称，最多12个字符
    request.displayInfo.name = "指定商品立减15(可用3次)";
    // 必填，商品券图片URL
    request.displayInfo.imageUrl = "https://wxpaylogo.qpic.cn/wxpaylogo/xxxxx/xxx";
    // 选填，背景图URL
    request.displayInfo.backgroundUrl = "https://wxpaylogo.qpic.cn/wxpaylogo/xxxxx/xxx";
    // 选填，详情图URL列表，最多6张
    request.displayInfo.detailImageUrlList = new ArrayList<>();
    request.displayInfo.detailImageUrlList.add("https://wxpaylogo.qpic.cn/wxpaylogo/xxxxx/xxx");
    // 条件必填(单品券)，商品原价(单位：分)，与combo_package_list二选一
    request.displayInfo.originalPrice = 9900L;

    // 条件必填(单品券)，套餐组合列表，与original_price二选一
    request.displayInfo.comboPackageList = new ArrayList<>();
    ComboPackage combo = new ComboPackage();
    combo.name = "套餐A";     // 必填，套餐名称
    combo.pickCount = 2L;     // 必填，可选商品数量
    combo.choiceList = new ArrayList<>();  // 必填，可选商品列表
    ComboPackageChoice choice1 = new ComboPackageChoice();
    choice1.name = "鸡腿饭";   // 必填，商品名称
    choice1.price = 2000L;    // 必填，商品价格(单位：分)
    choice1.count = 1L;       // 必填，商品数量
    choice1.imageUrl = "https://wxpaylogo.qpic.cn/wxpaylogo/xxxxx/chicken";  // 必填，商品图片URL
    combo.choiceList.add(choice1);
    ComboPackageChoice choice2 = new ComboPackageChoice();
    choice2.name = "牛肉饭";   // 必填，商品名称
    choice2.price = 2500L;    // 必填，商品价格(单位：分)
    choice2.count = 1L;       // 必填，商品数量
    choice2.imageUrl = "https://wxpaylogo.qpic.cn/wxpaylogo/xxxxx/beef";  // 必填，商品图片URL
    combo.choiceList.add(choice2);
    request.displayInfo.comboPackageList.add(combo);

    // 条件必填，批次信息(当usage_mode=PROGRESSIVE_BUNDLE时必填)
    request.stockBundle = createStock("指定商品立减15批次", 0, 1500);

    try {
      CreateProductCouponResponse response = client.run(request);
      System.out.println(response);
    } catch (WXPayUtility.ApiException e) {
      e.printStackTrace();
    }
  }

  /**
   * 创建满减券批次
   */
  private static StockForProgressiveBundle createStock(String remark, long threshold, long discountAmount) {
    StockForProgressiveBundle stock = new StockForProgressiveBundle();
    stock.remark = remark;
    stock.couponCodeMode = CouponCodeMode.WECHATPAY;

    stock.stockSendRule = new StockSendRule();
    stock.stockSendRule.maxCount = 10000000L;
    stock.stockSendRule.maxCountPerUser = 1L;

    stock.progressiveBundleUsageRule = new ProgressiveBundleUsageRule();
    stock.progressiveBundleUsageRule.couponAvailablePeriod = new CouponAvailablePeriod();
    stock.progressiveBundleUsageRule.couponAvailablePeriod.availableBeginTime = "2025-08-01T00:00:00+08:00";
    stock.progressiveBundleUsageRule.couponAvailablePeriod.availableEndTime = "2025-08-31T23:59:59+08:00";
    stock.progressiveBundleUsageRule.couponAvailablePeriod.availableDays = 30L;
    stock.progressiveBundleUsageRule.couponAvailablePeriod.weeklyAvailablePeriod = new FixedWeekPeriod();
    stock.progressiveBundleUsageRule.couponAvailablePeriod.weeklyAvailablePeriod.dayList = new ArrayList<>();
    stock.progressiveBundleUsageRule.couponAvailablePeriod.weeklyAvailablePeriod.dayList.add(WeekEnum.MONDAY);
    stock.progressiveBundleUsageRule.couponAvailablePeriod.weeklyAvailablePeriod.dayList.add(WeekEnum.TUESDAY);
    stock.progressiveBundleUsageRule.couponAvailablePeriod.weeklyAvailablePeriod.dayList.add(WeekEnum.WEDNESDAY);
    stock.progressiveBundleUsageRule.couponAvailablePeriod.weeklyAvailablePeriod.dayList.add(WeekEnum.THURSDAY);
    stock.progressiveBundleUsageRule.couponAvailablePeriod.weeklyAvailablePeriod.dayList.add(WeekEnum.FRIDAY);

    // 满减券规则
    stock.progressiveBundleUsageRule.normalCoupon = new NormalCouponUsageRule();
    stock.progressiveBundleUsageRule.normalCoupon.threshold = threshold;
    stock.progressiveBundleUsageRule.normalCoupon.discountAmount = discountAmount;

    stock.usageRuleDisplayInfo = new UsageRuleDisplayInfo();
    stock.usageRuleDisplayInfo.couponUsageMethodList = new ArrayList<>();
    stock.usageRuleDisplayInfo.couponUsageMethodList.add(CouponUsageMethod.OFFLINE);
    stock.usageRuleDisplayInfo.couponUsageMethodList.add(CouponUsageMethod.MINI_PROGRAM);
    stock.usageRuleDisplayInfo.couponUsageMethodList.add(CouponUsageMethod.PAYMENT_CODE);
    stock.usageRuleDisplayInfo.miniProgramAppid = "wx1234567890";
    stock.usageRuleDisplayInfo.miniProgramPath = "/pages/index/product";
    stock.usageRuleDisplayInfo.usageDescription = "指定商品可用，立减15元";
    stock.usageRuleDisplayInfo.couponAvailableStoreInfo = new CouponAvailableStoreInfo();
    stock.usageRuleDisplayInfo.couponAvailableStoreInfo.description = "所有门店可用，可使用小程序查看门店列表";
    stock.usageRuleDisplayInfo.couponAvailableStoreInfo.miniProgramAppid = "wx1234567890";
    stock.usageRuleDisplayInfo.couponAvailableStoreInfo.miniProgramPath = "/pages/index/store-list";

    stock.couponDisplayInfo = new CouponDisplayInfo();
    stock.couponDisplayInfo.codeDisplayMode = CouponCodeDisplayMode.QRCODE;
    stock.couponDisplayInfo.backgroundColor = "Color010";
    stock.couponDisplayInfo.entranceMiniProgram = new EntranceMiniProgram();
    stock.couponDisplayInfo.entranceMiniProgram.appid = "wx1234567890";
    stock.couponDisplayInfo.entranceMiniProgram.path = "/pages/index/product";
    stock.couponDisplayInfo.entranceMiniProgram.entranceWording = "欢迎选购";
    stock.couponDisplayInfo.entranceMiniProgram.guidanceWording = "获取更多优惠";
    stock.couponDisplayInfo.entranceOfficialAccount = new EntranceOfficialAccount();
    stock.couponDisplayInfo.entranceOfficialAccount.appid = "wx1234567890";
    stock.couponDisplayInfo.entranceFinder = new EntranceFinder();
    stock.couponDisplayInfo.entranceFinder.finderId = "gh_12345678";
    stock.couponDisplayInfo.entranceFinder.finderVideoId = "UDFsdf24df34dD456Hdf34";
    stock.couponDisplayInfo.entranceFinder.finderVideoCoverImageUrl = "https://wxpaylogo.qpic.cn/wxpaylogo/xxxxx/xxx";

    stock.storeScope = StockStoreScope.NONE;
    stock.notifyConfig = new NotifyConfig();
    stock.notifyConfig.notifyAppid = "wx4fd12345678";

    return stock;
  }

  public CreateProductCouponResponse run(CreateProductCouponRequest request) {
    String uri = PATH;
    String reqBody = WXPayUtility.toJson(request);
    Request.Builder reqBuilder = new Request.Builder().url(HOST + uri);
    reqBuilder.addHeader("Accept", "application/json");
    reqBuilder.addHeader("Wechatpay-Serial", wechatPayPublicKeyId);
    reqBuilder.addHeader("Authorization", WXPayUtility.buildAuthorization(mchid, certificateSerialNo, privateKey, METHOD, uri, reqBody));
    reqBuilder.addHeader("Content-Type", "application/json");
    RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), reqBody);
    reqBuilder.method(METHOD, requestBody);
    Request httpRequest = reqBuilder.build();

    OkHttpClient client = new OkHttpClient.Builder().build();
    try (Response httpResponse = client.newCall(httpRequest).execute()) {
      String respBody = WXPayUtility.extractBody(httpResponse);
      if (httpResponse.code() >= 200 && httpResponse.code() < 300) {
        WXPayUtility.validateResponse(this.wechatPayPublicKeyId, this.wechatPayPublicKey,
            httpResponse.headers(), respBody);
        return WXPayUtility.fromJson(respBody, CreateProductCouponResponse.class);
      } else {
        throw new WXPayUtility.ApiException(httpResponse.code(), respBody, httpResponse.headers());
      }
    } catch (IOException e) {
      throw new UncheckedIOException("Sending request to " + uri + " failed.", e);
    }
  }

  private final String mchid;
  private final String certificateSerialNo;
  private final PrivateKey privateKey;
  private final String wechatPayPublicKeyId;
  private final PublicKey wechatPayPublicKey;

  public SingleNormalManyJava(String mchid, String certificateSerialNo, String privateKeyFilePath, String wechatPayPublicKeyId, String wechatPayPublicKeyFilePath) {
    this.mchid = mchid;
    this.certificateSerialNo = certificateSerialNo;
    this.privateKey = WXPayUtility.loadPrivateKeyFromPath(privateKeyFilePath);
    this.wechatPayPublicKeyId = wechatPayPublicKeyId;
    this.wechatPayPublicKey = WXPayUtility.loadPublicKeyFromPath(wechatPayPublicKeyFilePath);
  }

  // ==================== 请求/响应类定义 ====================

  public static class CreateProductCouponRequest {
    @SerializedName("out_request_no")
    public String outRequestNo;

    @SerializedName("brand_id")
    public String brandId;

    @SerializedName("out_product_no")
    public String outProductNo;

    @SerializedName("scope")
    public ProductCouponScope scope;

    @SerializedName("type")
    public ProductCouponType type;

    @SerializedName("usage_mode")
    public UsageMode usageMode;

    @SerializedName("progressive_bundle_usage_info")
    public ProgressiveBundleUsageInfo progressiveBundleUsageInfo;

    @SerializedName("display_info")
    public ProductCouponDisplayInfo displayInfo;

    @SerializedName("stock_bundle")
    public StockForProgressiveBundle stockBundle;
  }

  public static class CreateProductCouponResponse {
    @SerializedName("product_coupon_id")
    public String productCouponId;

    @SerializedName("scope")
    public ProductCouponScope scope;

    @SerializedName("type")
    public ProductCouponType type;

    @SerializedName("usage_mode")
    public UsageMode usageMode;

    @SerializedName("progressive_bundle_usage_info")
    public ProgressiveBundleUsageInfo progressiveBundleUsageInfo;

    @SerializedName("display_info")
    public ProductCouponDisplayInfo displayInfo;

    @SerializedName("out_product_no")
    public String outProductNo;

    @SerializedName("state")
    public ProductCouponState state;

    @SerializedName("stock_bundle")
    public StockBundleEntity stockBundle;

    @SerializedName("brand_id")
    public String brandId;
  }

  // ==================== 枚举类型定义 ====================

  public enum ProductCouponScope {
    @SerializedName("ALL") ALL,
    @SerializedName("SINGLE") SINGLE
  }

  public enum ProductCouponType {
    @SerializedName("NORMAL") NORMAL,
    @SerializedName("DISCOUNT") DISCOUNT,
    @SerializedName("EXCHANGE") EXCHANGE
  }

  public enum UsageMode {
    @SerializedName("SINGLE") SINGLE,
    @SerializedName("PROGRESSIVE_BUNDLE") PROGRESSIVE_BUNDLE
  }

  public enum ProductCouponState {
    @SerializedName("AUDITING") AUDITING,
    @SerializedName("EFFECTIVE") EFFECTIVE,
    @SerializedName("DEACTIVATED") DEACTIVATED
  }

  public enum CouponCodeMode {
    @SerializedName("WECHATPAY") WECHATPAY,
    @SerializedName("UPLOAD") UPLOAD,
    @SerializedName("API_ASSIGN") API_ASSIGN
  }

  public enum StockStoreScope {
    @SerializedName("NONE") NONE,
    @SerializedName("ALL") ALL,
    @SerializedName("SPECIFIC") SPECIFIC
  }

  public enum CouponUsageMethod {
    @SerializedName("OFFLINE") OFFLINE,
    @SerializedName("MINI_PROGRAM") MINI_PROGRAM,
    @SerializedName("APP") APP,
    @SerializedName("PAYMENT_CODE") PAYMENT_CODE
  }

  public enum CouponCodeDisplayMode {
    @SerializedName("INVISIBLE") INVISIBLE,
    @SerializedName("BARCODE") BARCODE,
    @SerializedName("QRCODE") QRCODE
  }

  public enum WeekEnum {
    @SerializedName("MONDAY") MONDAY,
    @SerializedName("TUESDAY") TUESDAY,
    @SerializedName("WEDNESDAY") WEDNESDAY,
    @SerializedName("THURSDAY") THURSDAY,
    @SerializedName("FRIDAY") FRIDAY,
    @SerializedName("SATURDAY") SATURDAY,
    @SerializedName("SUNDAY") SUNDAY
  }

  // ==================== 模型类定义 ====================

  public static class ProgressiveBundleUsageInfo {
    @SerializedName("count")
    public Long count;

    @SerializedName("interval_days")
    public Long intervalDays;
  }

  public static class ProductCouponDisplayInfo {
    @SerializedName("name")
    public String name;

    @SerializedName("image_url")
    public String imageUrl;

    @SerializedName("background_url")
    public String backgroundUrl;

    @SerializedName("detail_image_url_list")
    public List<String> detailImageUrlList;

    @SerializedName("original_price")
    public Long originalPrice;

    @SerializedName("combo_package_list")
    public List<ComboPackage> comboPackageList;
  }

  public static class ComboPackage {
    @SerializedName("name")
    public String name;

    @SerializedName("pick_count")
    public Long pickCount;

    @SerializedName("choice_list")
    public List<ComboPackageChoice> choiceList;
  }

  public static class ComboPackageChoice {
    @SerializedName("name")
    public String name;

    @SerializedName("price")
    public Long price;

    @SerializedName("count")
    public Long count;

    @SerializedName("image_url")
    public String imageUrl;

    @SerializedName("mini_program_appid")
    public String miniProgramAppid;

    @SerializedName("mini_program_path")
    public String miniProgramPath;
  }

  public static class StockForProgressiveBundle {
    @SerializedName("remark")
    public String remark;

    @SerializedName("coupon_code_mode")
    public CouponCodeMode couponCodeMode;

    @SerializedName("stock_send_rule")
    public StockSendRule stockSendRule;

    @SerializedName("progressive_bundle_usage_rule")
    public ProgressiveBundleUsageRule progressiveBundleUsageRule;

    @SerializedName("usage_rule_display_info")
    public UsageRuleDisplayInfo usageRuleDisplayInfo;

    @SerializedName("coupon_display_info")
    public CouponDisplayInfo couponDisplayInfo;

    @SerializedName("notify_config")
    public NotifyConfig notifyConfig;

    @SerializedName("store_scope")
    public StockStoreScope storeScope;
  }

  public static class StockSendRule {
    @SerializedName("max_count")
    public Long maxCount;

    @SerializedName("max_count_per_day")
    public Long maxCountPerDay;

    @SerializedName("max_count_per_user")
    public Long maxCountPerUser;
  }

  public static class ProgressiveBundleUsageRule {
    @SerializedName("coupon_available_period")
    public CouponAvailablePeriod couponAvailablePeriod;

    @SerializedName("normal_coupon")
    public NormalCouponUsageRule normalCoupon;

    @SerializedName("discount_coupon")
    public DiscountCouponUsageRule discountCoupon;

    @SerializedName("exchange_coupon")
    public ExchangeCouponUsageRule exchangeCoupon;
  }

  public static class CouponAvailablePeriod {
    @SerializedName("available_begin_time")
    public String availableBeginTime;

    @SerializedName("available_end_time")
    public String availableEndTime;

    @SerializedName("available_days")
    public Long availableDays;

    @SerializedName("wait_days_after_receive")
    public Long waitDaysAfterReceive;

    @SerializedName("weekly_available_period")
    public FixedWeekPeriod weeklyAvailablePeriod;
  }

  public static class FixedWeekPeriod {
    @SerializedName("day_list")
    public List<WeekEnum> dayList;
  }

  public static class NormalCouponUsageRule {
    @SerializedName("threshold")
    public Long threshold;

    @SerializedName("discount_amount")
    public Long discountAmount;
  }

  public static class DiscountCouponUsageRule {
    @SerializedName("threshold")
    public Long threshold;

    @SerializedName("percent_off")
    public Long percentOff;
  }

  public static class ExchangeCouponUsageRule {
    @SerializedName("threshold")
    public Long threshold;

    @SerializedName("exchange_price")
    public Long exchangePrice;
  }

  public static class UsageRuleDisplayInfo {
    @SerializedName("coupon_usage_method_list")
    public List<CouponUsageMethod> couponUsageMethodList;

    @SerializedName("mini_program_appid")
    public String miniProgramAppid;

    @SerializedName("mini_program_path")
    public String miniProgramPath;

    @SerializedName("app_path")
    public String appPath;

    @SerializedName("usage_description")
    public String usageDescription;

    @SerializedName("coupon_available_store_info")
    public CouponAvailableStoreInfo couponAvailableStoreInfo;
  }

  public static class CouponAvailableStoreInfo {
    @SerializedName("description")
    public String description;

    @SerializedName("mini_program_appid")
    public String miniProgramAppid;

    @SerializedName("mini_program_path")
    public String miniProgramPath;
  }

  public static class CouponDisplayInfo {
    @SerializedName("code_display_mode")
    public CouponCodeDisplayMode codeDisplayMode;

    @SerializedName("background_color")
    public String backgroundColor;

    @SerializedName("entrance_mini_program")
    public EntranceMiniProgram entranceMiniProgram;

    @SerializedName("entrance_official_account")
    public EntranceOfficialAccount entranceOfficialAccount;

    @SerializedName("entrance_finder")
    public EntranceFinder entranceFinder;
  }

  public static class EntranceMiniProgram {
    @SerializedName("appid")
    public String appid;

    @SerializedName("path")
    public String path;

    @SerializedName("entrance_wording")
    public String entranceWording;

    @SerializedName("guidance_wording")
    public String guidanceWording;
  }

  public static class EntranceOfficialAccount {
    @SerializedName("appid")
    public String appid;
  }

  public static class EntranceFinder {
    @SerializedName("finder_id")
    public String finderId;

    @SerializedName("finder_video_id")
    public String finderVideoId;

    @SerializedName("finder_video_cover_image_url")
    public String finderVideoCoverImageUrl;
  }

  public static class NotifyConfig {
    @SerializedName("notify_appid")
    public String notifyAppid;
  }

  public static class StockBundleEntity {
    @SerializedName("stock_bundle_id")
    public String stockBundleId;

    @SerializedName("stock_list")
    public List<StockEntityInBundle> stockList;
  }

  public static class StockEntityInBundle {
    @SerializedName("product_coupon_id")
    public String productCouponId;

    @SerializedName("stock_id")
    public String stockId;

    @SerializedName("remark")
    public String remark;
  }
}

```

需配合微信支付工具库 wxpay\_utility 使用，请参考 [Go](https://pay.weixin.qq.com/doc/v3/partner/4015119446.md)

```
package main

import (
	"bytes"
	"demo/wxpay_utility" // 引用微信支付工具库，参考 https://pay.weixin.qq.com/doc/v3/partner/4015119446
	"encoding/json"
	"fmt"
	"net/http"
	"net/url"
)

// 创建商品券 - 场景4：多次优惠-单品-满减券
//
// 场景说明：单品券（适用于指定商品）+ 满减券（满足门槛后减固定金额）+ 阶梯模式（可多次使用）
//
// 关键参数：
// - scope = SINGLE（单品券）
// - type = NORMAL（满减券）
// - usage_mode = PROGRESSIVE_BUNDLE（阶梯模式）

func main() {
	// TODO: 请准备商户开发必要参数，参考：https://pay.weixin.qq.com/doc/v3/partner/4013080340
	config, err := wxpay_utility.CreateMchConfig(
		"19xxxxxxxx",                 // 商户号
		"1DDE55AD98Exxxxxxxxxx",      // 商户API证书序列号
		"/path/to/apiclient_key.pem", // 商户API证书私钥文件路径
		"PUB_KEY_ID_xxxxxxxxxxxxx",   // 微信支付公钥ID
		"/path/to/wxp_pub.pem",       // 微信支付公钥文件路径
	)
	if err != nil {
		fmt.Println(err)
		return
	}

	request := &CreateProductCouponRequest{
		OutRequestNo: wxpay_utility.String("MANY_SINGLE_NORMAL_20250101_004"), // 必填，创建请求单号，6-40个字符，品牌侧需保持唯一性
		BrandId:      wxpay_utility.String("120344"),                          // 必填，品牌ID，由微信支付分配
		OutProductNo: wxpay_utility.String("Product_1234567890"),              // 选填，商户侧商品券唯一标识
		Scope:        PRODUCTCOUPONSCOPE_SINGLE.Ptr(),                         // 必填，优惠范围：ALL-全场券, SINGLE-单品券(支持NORMAL/DISCOUNT/EXCHANGE)
		Type:         PRODUCTCOUPONTYPE_NORMAL.Ptr(),                          // 必填，商品券类型：NORMAL-满减券, DISCOUNT-折扣券, EXCHANGE-兑换券(仅单品券)
		UsageMode:    USAGEMODE_PROGRESSIVE_BUNDLE.Ptr(),                      // 必填，使用模式：SINGLE-单券, PROGRESSIVE_BUNDLE-多次优惠
		// 条件必填，多次优惠模式配置信息(当usage_mode=PROGRESSIVE_BUNDLE时必填)
		ProgressiveBundleUsageInfo: &ProgressiveBundleUsageInfo{
			Count:        wxpay_utility.Int64(3), // 必填，可使用次数，最少3次，最多15次
			IntervalDays: wxpay_utility.Int64(2), // 选填，多次优惠使用间隔天数(2表示使用后需等到第三天00:00:00才能使用下一次)，最高7天，默认0
		},
		// 必填，商品券展示信息
		DisplayInfo: &ProductCouponDisplayInfo{
			Name:          wxpay_utility.String("指定商品立减15(可用3次)"),                     // 必填，商品券名称，最多12个字符
			ImageUrl:      wxpay_utility.String("https://wxpaylogo.qpic.cn/wxpaylogo/xxxxx/xxx"), // 必填，商品券图片URL
			BackgroundUrl: wxpay_utility.String("https://wxpaylogo.qpic.cn/wxpaylogo/xxxxx/xxx"), // 选填，背景图URL
			DetailImageUrlList: []string{ // 选填，详情图URL列表，最多6张
				"https://wxpaylogo.qpic.cn/wxpaylogo/xxxxx/xxx",
			},
			OriginalPrice: wxpay_utility.Int64(9900), // 条件必填(单品券)，商品原价(单位：分)，与combo_package_list二选一
			// 条件必填(单品券)，套餐组合列表，与original_price二选一
			ComboPackageList: []ComboPackage{
				{
					Name:      wxpay_utility.String("套餐A"), // 必填，套餐名称
					PickCount: wxpay_utility.Int64(2),      // 必填，可选商品数量
					ChoiceList: []ComboPackageChoice{ // 必填，可选商品列表
						{
							Name:     wxpay_utility.String("鸡腿饭"),                                           // 必填，商品名称
							Price:    wxpay_utility.Int64(2000),                                              // 必填，商品价格(单位：分)
							Count:    wxpay_utility.Int64(1),                                                 // 必填，商品数量
							ImageUrl: wxpay_utility.String("https://wxpaylogo.qpic.cn/wxpaylogo/xxxxx/chicken"), // 必填，商品图片URL
						},
						{
							Name:     wxpay_utility.String("牛肉饭"),                                        // 必填，商品名称
							Price:    wxpay_utility.Int64(2500),                                           // 必填，商品价格(单位：分)
							Count:    wxpay_utility.Int64(1),                                              // 必填，商品数量
							ImageUrl: wxpay_utility.String("https://wxpaylogo.qpic.cn/wxpaylogo/xxxxx/beef"), // 必填，商品图片URL
						},
					},
				},
			},
		},
		// 条件必填，批次信息(当usage_mode=PROGRESSIVE_BUNDLE时必填)
		Stock: createNormalStockPtr("指定商品立减15批次", 0, 1500),
	}

	response, err := CreateProductCoupon(config, request)
	if err != nil {
		fmt.Printf("请求失败: %+v\n", err)
		return
	}
	fmt.Printf("请求成功: %+v\n", response)
}

// createNormalStockPtr 创建满减券批次(返回指针)
func createNormalStockPtr(remark string, threshold, discountAmount int64) *StockForProgressiveBundle {
	stock := createNormalStock(remark, threshold, discountAmount)
	return &stock
}

// createNormalStock 创建满减券批次
func createNormalStock(remark string, threshold, discountAmount int64) StockForProgressiveBundle {
	return StockForProgressiveBundle{
		Remark:         wxpay_utility.String(remark),
		CouponCodeMode: COUPONCODEMODE_WECHATPAY.Ptr(),
		StockSendRule: &StockSendRule{
			MaxCount:        wxpay_utility.Int64(10000000),
			MaxCountPerUser: wxpay_utility.Int64(1),
		},
		ProgressiveBundleUsageRule: &ProgressiveBundleUsageRule{
			CouponAvailablePeriod: &CouponAvailablePeriod{
				AvailableBeginTime: wxpay_utility.String("2025-08-01T00:00:00+08:00"),
				AvailableEndTime:   wxpay_utility.String("2025-08-31T23:59:59+08:00"),
				AvailableDays:      wxpay_utility.Int64(30),
				WeeklyAvailablePeriod: &FixedWeekPeriod{
					DayList: []WeekEnum{
						WEEKENUM_MONDAY,
						WEEKENUM_TUESDAY,
						WEEKENUM_WEDNESDAY,
						WEEKENUM_THURSDAY,
						WEEKENUM_FRIDAY,
					},
				},
			},
			NormalCoupon: &NormalCouponUsageRule{
				Threshold:      wxpay_utility.Int64(threshold),
				DiscountAmount: wxpay_utility.Int64(discountAmount),
			},
		},
		UsageRuleDisplayInfo: &UsageRuleDisplayInfo{
			CouponUsageMethodList: []CouponUsageMethod{
				COUPONUSAGEMETHOD_OFFLINE,
				COUPONUSAGEMETHOD_MINI_PROGRAM,
				COUPONUSAGEMETHOD_PAYMENT_CODE,
			},
			MiniProgramAppid: wxpay_utility.String("wx1234567890"),
			MiniProgramPath:  wxpay_utility.String("/pages/index/product"),
			UsageDescription: wxpay_utility.String("指定商品可用，立减15元"),
			CouponAvailableStoreInfo: &CouponAvailableStoreInfo{
				Description:      wxpay_utility.String("所有门店可用，可使用小程序查看门店列表"),
				MiniProgramAppid: wxpay_utility.String("wx1234567890"),
				MiniProgramPath:  wxpay_utility.String("/pages/index/store-list"),
			},
		},
		CouponDisplayInfo: &CouponDisplayInfo{
			CodeDisplayMode: COUPONCODEDISPLAYMODE_QRCODE.Ptr(),
			BackgroundColor: wxpay_utility.String("Color010"),
			EntranceMiniProgram: &EntranceMiniProgram{
				Appid:           wxpay_utility.String("wx1234567890"),
				Path:            wxpay_utility.String("/pages/index/product"),
				EntranceWording: wxpay_utility.String("欢迎选购"),
				GuidanceWording: wxpay_utility.String("获取更多优惠"),
			},
			EntranceOfficialAccount: &EntranceOfficialAccount{
				Appid: wxpay_utility.String("wx1234567890"),
			},
			EntranceFinder: &EntranceFinder{
				FinderId:                 wxpay_utility.String("gh_12345678"),
				FinderVideoId:            wxpay_utility.String("UDFsdf24df34dD456Hdf34"),
				FinderVideoCoverImageUrl: wxpay_utility.String("https://wxpaylogo.qpic.cn/wxpaylogo/xxxxx/xxx"),
			},
		},
		StoreScope: STOCKSTORESCOPE_NONE.Ptr(),
		NotifyConfig: &NotifyConfig{
			NotifyAppid: wxpay_utility.String("wx4fd12345678"),
		},
	}
}

func CreateProductCoupon(config *wxpay_utility.MchConfig, request *CreateProductCouponRequest) (response *CreateProductCouponResponse, err error) {
	const (
		host   = "https://api.mch.weixin.qq.com"
		method = "POST"
		path   = "/v3/marketing/partner/product-coupon/product-coupons"
	)
	reqUrl, err := url.Parse(fmt.Sprintf("%s%s", host, path))
	if err != nil {
		return nil, err
	}
	reqBody, err := json.Marshal(request)
	if err != nil {
		return nil, err
	}
	httpRequest, err := http.NewRequest(method, reqUrl.String(), bytes.NewReader(reqBody))
	if err != nil {
		return nil, err
	}
	httpRequest.Header.Set("Accept", "application/json")
	httpRequest.Header.Set("Wechatpay-Serial", config.WechatPayPublicKeyId())
	httpRequest.Header.Set("Content-Type", "application/json")
	authorization, err := wxpay_utility.BuildAuthorization(config.MchId(), config.CertificateSerialNo(), config.PrivateKey(), method, reqUrl.RequestURI(), reqBody)
	if err != nil {
		return nil, err
	}
	httpRequest.Header.Set("Authorization", authorization)
	client := &http.Client{}
	httpResponse, err := client.Do(httpRequest)
	if err != nil {
		return nil, err
	}
	respBody, err := wxpay_utility.ExtractResponseBody(httpResponse)
	if err != nil {
		return nil, err
	}
	if httpResponse.StatusCode >= 200 && httpResponse.StatusCode < 300 {
		err = wxpay_utility.ValidateResponse(
			config.WechatPayPublicKeyId(),
			config.WechatPayPublicKey(),
			&httpResponse.Header,
			respBody,
		)
		if err != nil {
			return nil, err
		}
		response := &CreateProductCouponResponse{}
		if err := json.Unmarshal(respBody, response); err != nil {
			return nil, err
		}
		return response, nil
	} else {
		return nil, wxpay_utility.NewApiException(
			httpResponse.StatusCode,
			httpResponse.Header,
			respBody,
		)
	}
}

// ==================== 请求/响应结构体定义 ====================

type CreateProductCouponRequest struct {
	OutRequestNo               *string                     `json:"out_request_no,omitempty"`
	BrandId                    *string                     `json:"brand_id,omitempty"`
	OutProductNo               *string                     `json:"out_product_no,omitempty"`
	Scope                      *ProductCouponScope         `json:"scope,omitempty"`
	Type                       *ProductCouponType          `json:"type,omitempty"`
	UsageMode                  *UsageMode                  `json:"usage_mode,omitempty"`
	ProgressiveBundleUsageInfo *ProgressiveBundleUsageInfo `json:"progressive_bundle_usage_info,omitempty"`
	DisplayInfo                *ProductCouponDisplayInfo   `json:"display_info,omitempty"`
	StockBundle                *StockForProgressiveBundle  `json:"stock_bundle,omitempty"`
}

type CreateProductCouponResponse struct {
	ProductCouponId            *string                     `json:"product_coupon_id,omitempty"`
	Scope                      *ProductCouponScope         `json:"scope,omitempty"`
	Type                       *ProductCouponType          `json:"type,omitempty"`
	UsageMode                  *UsageMode                  `json:"usage_mode,omitempty"`
	ProgressiveBundleUsageInfo *ProgressiveBundleUsageInfo `json:"progressive_bundle_usage_info,omitempty"`
	DisplayInfo                *ProductCouponDisplayInfo   `json:"display_info,omitempty"`
	OutProductNo               *string                     `json:"out_product_no,omitempty"`
	State                      *ProductCouponState         `json:"state,omitempty"`
	StockBundle                *StockBundleEntity          `json:"stock_bundle,omitempty"`
	BrandId                    *string                     `json:"brand_id,omitempty"`
}

// ==================== 枚举类型定义 ====================

type ProductCouponScope string

func (e ProductCouponScope) Ptr() *ProductCouponScope { return &e }

const (
	PRODUCTCOUPONSCOPE_ALL    ProductCouponScope = "ALL"
	PRODUCTCOUPONSCOPE_SINGLE ProductCouponScope = "SINGLE"
)

type ProductCouponType string

func (e ProductCouponType) Ptr() *ProductCouponType { return &e }

const (
	PRODUCTCOUPONTYPE_NORMAL   ProductCouponType = "NORMAL"
	PRODUCTCOUPONTYPE_DISCOUNT ProductCouponType = "DISCOUNT"
	PRODUCTCOUPONTYPE_EXCHANGE ProductCouponType = "EXCHANGE"
)

type UsageMode string

func (e UsageMode) Ptr() *UsageMode { return &e }

const (
	USAGEMODE_SINGLE             UsageMode = "SINGLE"
	USAGEMODE_PROGRESSIVE_BUNDLE UsageMode = "PROGRESSIVE_BUNDLE"
)

type ProductCouponState string

func (e ProductCouponState) Ptr() *ProductCouponState { return &e }

const (
	PRODUCTCOUPONSTATE_AUDITING    ProductCouponState = "AUDITING"
	PRODUCTCOUPONSTATE_EFFECTIVE   ProductCouponState = "EFFECTIVE"
	PRODUCTCOUPONSTATE_DEACTIVATED ProductCouponState = "DEACTIVATED"
)

type CouponCodeMode string

func (e CouponCodeMode) Ptr() *CouponCodeMode { return &e }

const (
	COUPONCODEMODE_WECHATPAY  CouponCodeMode = "WECHATPAY"
	COUPONCODEMODE_UPLOAD     CouponCodeMode = "UPLOAD"
	COUPONCODEMODE_API_ASSIGN CouponCodeMode = "API_ASSIGN"
)

type StockStoreScope string

func (e StockStoreScope) Ptr() *StockStoreScope { return &e }

const (
	STOCKSTORESCOPE_NONE     StockStoreScope = "NONE"
	STOCKSTORESCOPE_ALL      StockStoreScope = "ALL"
	STOCKSTORESCOPE_SPECIFIC StockStoreScope = "SPECIFIC"
)

type CouponUsageMethod string

func (e CouponUsageMethod) Ptr() *CouponUsageMethod { return &e }

const (
	COUPONUSAGEMETHOD_OFFLINE      CouponUsageMethod = "OFFLINE"
	COUPONUSAGEMETHOD_MINI_PROGRAM CouponUsageMethod = "MINI_PROGRAM"
	COUPONUSAGEMETHOD_APP          CouponUsageMethod = "APP"
	COUPONUSAGEMETHOD_PAYMENT_CODE CouponUsageMethod = "PAYMENT_CODE"
)

type CouponCodeDisplayMode string

func (e CouponCodeDisplayMode) Ptr() *CouponCodeDisplayMode { return &e }

const (
	COUPONCODEDISPLAYMODE_INVISIBLE CouponCodeDisplayMode = "INVISIBLE"
	COUPONCODEDISPLAYMODE_BARCODE   CouponCodeDisplayMode = "BARCODE"
	COUPONCODEDISPLAYMODE_QRCODE    CouponCodeDisplayMode = "QRCODE"
)

type WeekEnum string

func (e WeekEnum) Ptr() *WeekEnum { return &e }

const (
	WEEKENUM_MONDAY    WeekEnum = "MONDAY"
	WEEKENUM_TUESDAY   WeekEnum = "TUESDAY"
	WEEKENUM_WEDNESDAY WeekEnum = "WEDNESDAY"
	WEEKENUM_THURSDAY  WeekEnum = "THURSDAY"
	WEEKENUM_FRIDAY    WeekEnum = "FRIDAY"
	WEEKENUM_SATURDAY  WeekEnum = "SATURDAY"
	WEEKENUM_SUNDAY    WeekEnum = "SUNDAY"
)

// ==================== 模型结构体定义 ====================

type ProgressiveBundleUsageInfo struct {
	Count        *int64 `json:"count,omitempty"`
	IntervalDays *int64 `json:"interval_days,omitempty"`
}

type ProductCouponDisplayInfo struct {
	Name               *string        `json:"name,omitempty"`
	ImageUrl           *string        `json:"image_url,omitempty"`
	BackgroundUrl      *string        `json:"background_url,omitempty"`
	DetailImageUrlList []string       `json:"detail_image_url_list,omitempty"`
	OriginalPrice      *int64         `json:"original_price,omitempty"`
	ComboPackageList   []ComboPackage `json:"combo_package_list,omitempty"`
}

type ComboPackage struct {
	Name       *string              `json:"name,omitempty"`
	PickCount  *int64               `json:"pick_count,omitempty"`
	ChoiceList []ComboPackageChoice `json:"choice_list,omitempty"`
}

type ComboPackageChoice struct {
	Name             *string `json:"name,omitempty"`
	Price            *int64  `json:"price,omitempty"`
	Count            *int64  `json:"count,omitempty"`
	ImageUrl         *string `json:"image_url,omitempty"`
	MiniProgramAppid *string `json:"mini_program_appid,omitempty"`
	MiniProgramPath  *string `json:"mini_program_path,omitempty"`
}

type StockForProgressiveBundle struct {
	Remark                     *string                     `json:"remark,omitempty"`
	CouponCodeMode             *CouponCodeMode             `json:"coupon_code_mode,omitempty"`
	StockSendRule              *StockSendRule              `json:"stock_send_rule,omitempty"`
	ProgressiveBundleUsageRule *ProgressiveBundleUsageRule `json:"progressive_bundle_usage_rule,omitempty"`
	UsageRuleDisplayInfo       *UsageRuleDisplayInfo       `json:"usage_rule_display_info,omitempty"`
	CouponDisplayInfo          *CouponDisplayInfo          `json:"coupon_display_info,omitempty"`
	NotifyConfig               *NotifyConfig               `json:"notify_config,omitempty"`
	StoreScope                 *StockStoreScope            `json:"store_scope,omitempty"`
}

type StockSendRule struct {
	MaxCount        *int64 `json:"max_count,omitempty"`
	MaxCountPerDay  *int64 `json:"max_count_per_day,omitempty"`
	MaxCountPerUser *int64 `json:"max_count_per_user,omitempty"`
}

type ProgressiveBundleUsageRule struct {
	CouponAvailablePeriod *CouponAvailablePeriod   `json:"coupon_available_period,omitempty"`
	NormalCoupon          *NormalCouponUsageRule   `json:"normal_coupon,omitempty"`
	DiscountCoupon        *DiscountCouponUsageRule `json:"discount_coupon,omitempty"`
	ExchangeCoupon        *ExchangeCouponUsageRule `json:"exchange_coupon,omitempty"`
}

type CouponAvailablePeriod struct {
	AvailableBeginTime    *string          `json:"available_begin_time,omitempty"`
	AvailableEndTime      *string          `json:"available_end_time,omitempty"`
	AvailableDays         *int64           `json:"available_days,omitempty"`
	WaitDaysAfterReceive  *int64           `json:"wait_days_after_receive,omitempty"`
	WeeklyAvailablePeriod *FixedWeekPeriod `json:"weekly_available_period,omitempty"`
}

type FixedWeekPeriod struct {
	DayList []WeekEnum `json:"day_list,omitempty"`
}

type NormalCouponUsageRule struct {
	Threshold      *int64 `json:"threshold,omitempty"`
	DiscountAmount *int64 `json:"discount_amount,omitempty"`
}

type DiscountCouponUsageRule struct {
	Threshold  *int64 `json:"threshold,omitempty"`
	PercentOff *int64 `json:"percent_off,omitempty"`
}

type ExchangeCouponUsageRule struct {
	Threshold     *int64 `json:"threshold,omitempty"`
	ExchangePrice *int64 `json:"exchange_price,omitempty"`
}

type UsageRuleDisplayInfo struct {
	CouponUsageMethodList    []CouponUsageMethod       `json:"coupon_usage_method_list,omitempty"`
	MiniProgramAppid         *string                   `json:"mini_program_appid,omitempty"`
	MiniProgramPath          *string                   `json:"mini_program_path,omitempty"`
	AppPath                  *string                   `json:"app_path,omitempty"`
	UsageDescription         *string                   `json:"usage_description,omitempty"`
	CouponAvailableStoreInfo *CouponAvailableStoreInfo `json:"coupon_available_store_info,omitempty"`
}

type CouponAvailableStoreInfo struct {
	Description      *string `json:"description,omitempty"`
	MiniProgramAppid *string `json:"mini_program_appid,omitempty"`
	MiniProgramPath  *string `json:"mini_program_path,omitempty"`
}

type CouponDisplayInfo struct {
	CodeDisplayMode         *CouponCodeDisplayMode   `json:"code_display_mode,omitempty"`
	BackgroundColor         *string                  `json:"background_color,omitempty"`
	EntranceMiniProgram     *EntranceMiniProgram     `json:"entrance_mini_program,omitempty"`
	EntranceOfficialAccount *EntranceOfficialAccount `json:"entrance_official_account,omitempty"`
	EntranceFinder          *EntranceFinder          `json:"entrance_finder,omitempty"`
}

type EntranceMiniProgram struct {
	Appid           *string `json:"appid,omitempty"`
	Path            *string `json:"path,omitempty"`
	EntranceWording *string `json:"entrance_wording,omitempty"`
	GuidanceWording *string `json:"guidance_wording,omitempty"`
}

type EntranceOfficialAccount struct {
	Appid *string `json:"appid,omitempty"`
}

type EntranceFinder struct {
	FinderId                 *string `json:"finder_id,omitempty"`
	FinderVideoId            *string `json:"finder_video_id,omitempty"`
	FinderVideoCoverImageUrl *string `json:"finder_video_cover_image_url,omitempty"`
}

type NotifyConfig struct {
	NotifyAppid *string `json:"notify_appid,omitempty"`
}

type StockBundleEntity struct {
	StockBundleId *string              `json:"stock_bundle_id,omitempty"`
	StockList     []StockEntityInBundle `json:"stock_list,omitempty"`
}

type StockEntityInBundle struct {
	ProductCouponId *string `json:"product_coupon_id,omitempty"`
	StockId         *string `json:"stock_id,omitempty"`
	Remark          *string `json:"remark,omitempty"`
}

```