1、零售优惠券发放相关接口优化;

2、增加微信订阅通知发送逻辑;
3、增加定时刷新刷新access_token逻辑;
This commit is contained in:
chenlin 2024-11-29 18:47:58 +08:00
parent 0d1f3c3aa8
commit 40227538f9
8 changed files with 436 additions and 102 deletions

View File

@ -58,7 +58,7 @@ func ErpMarketingCouponCreate(c *gin.Context) {
err := tools.Validate(req) //必填参数校验 err := tools.Validate(req) //必填参数校验
if err != nil { if err != nil {
app.Error(c, http.StatusBadRequest, err, "参数错误:缺少必填参数") app.Error(c, http.StatusBadRequest, err, err.Error())
return return
} }
@ -96,7 +96,7 @@ func ErpMarketingCouponEdit(c *gin.Context) {
err := tools.Validate(req) //必填参数校验 err := tools.Validate(req) //必填参数校验
if err != nil { if err != nil {
app.Error(c, http.StatusBadRequest, err, "参数错误:缺少必填参数") app.Error(c, http.StatusBadRequest, err, err.Error())
return return
} }
@ -129,7 +129,7 @@ func ErpMarketingCouponDelete(c *gin.Context) {
err := tools.Validate(req) //必填参数校验 err := tools.Validate(req) //必填参数校验
if err != nil { if err != nil {
app.Error(c, http.StatusBadRequest, err, "参数错误优惠券id为空") app.Error(c, http.StatusBadRequest, err, err.Error())
return return
} }
@ -162,7 +162,7 @@ func ErpMarketingCouponStart(c *gin.Context) {
err := tools.Validate(req) //必填参数校验 err := tools.Validate(req) //必填参数校验
if err != nil { if err != nil {
app.Error(c, http.StatusBadRequest, err, "参数错误优惠券id为空") app.Error(c, http.StatusBadRequest, err, err.Error())
return return
} }
@ -174,18 +174,21 @@ func ErpMarketingCouponStart(c *gin.Context) {
} }
var waitSendTaskList []model.CouponIssuanceTask var waitSendTaskList []model.CouponIssuanceTask
for _, task := range taskList {
switch task.Status { if len(taskList) != 0 {
case model.TaskInProgress: // 执行中 for _, task := range taskList {
app.Error(c, http.StatusInternalServerError, errors.New(fmt.Sprintf("[%s]已在执行中,请勿重复启动", task.ErpCouponName)), switch task.Status {
fmt.Sprintf("[%s]已在执行中,请勿重复启动", task.ErpCouponName)) case model.TaskInProgress: // 执行中
return app.Error(c, http.StatusInternalServerError, errors.New(fmt.Sprintf("[%s]已在执行中,请勿重复启动", task.ErpCouponName)),
case model.TaskCompleted: // 已完成 fmt.Sprintf("[%s]已在执行中,请勿重复启动", task.ErpCouponName))
app.Error(c, http.StatusInternalServerError, errors.New(fmt.Sprintf("[%s]已执行完成", task.ErpCouponName)), return
fmt.Sprintf("[%s]已执行完成", task.ErpCouponName)) case model.TaskCompleted: // 已完成
return app.Error(c, http.StatusInternalServerError, errors.New(fmt.Sprintf("[%s]已执行完成", task.ErpCouponName)),
default: fmt.Sprintf("[%s]已执行完成", task.ErpCouponName))
waitSendTaskList = append(waitSendTaskList, task) return
default:
waitSendTaskList = append(waitSendTaskList, task)
}
} }
} }
@ -195,9 +198,11 @@ func ErpMarketingCouponStart(c *gin.Context) {
} }
// 更新短信和备注 // 更新短信和备注
err = orm.Eloquent.Table("erp_coupon").Where("erp_coupon_id in ?", req.ErpCouponId). err = orm.Eloquent.Table("erp_coupon").Where("id in ?", req.ErpCouponId).
Updates(map[string]interface{}{ Updates(map[string]interface{}{
"remark": req.Remark, "remark": req.Remark,
"state": model.ErpCouponSending,
"start_time": time.Now(),
"sms_content": req.SmsContent, "sms_content": req.SmsContent,
"updated_at": time.Now(), "updated_at": time.Now(),
}).Error }).Error

View File

@ -5,7 +5,6 @@ import (
"crypto/md5" "crypto/md5"
"encoding/hex" "encoding/hex"
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"go-admin/logger" "go-admin/logger"
"io" "io"
@ -51,9 +50,9 @@ type GtSendMessageResp struct {
} }
func GtSendMessage(phoneList []string, content string) error { func GtSendMessage(phoneList []string, content string) error {
if len(phoneList) > GetSmsNumberRemaining() { // 待发送短信超出剩余可用数量 //if len(phoneList) > GetSmsNumberRemaining() { // 待发送短信超出剩余可用数量
return errors.New("短信剩余数量不足") // return errors.New("短信剩余数量不足")
} //}
params := make(map[string]interface{}, 0) params := make(map[string]interface{}, 0)
nowTime := time.Now() nowTime := time.Now()
@ -70,12 +69,12 @@ func GtSendMessage(phoneList []string, content string) error {
} }
fmt.Println("resp:", resp) fmt.Println("resp:", resp)
// 更新已使用的短信数量 //// 更新已使用的短信数量
err = UpdateSmsUsedCount(len(phoneList)) //err = UpdateSmsUsedCount(len(phoneList))
if err != nil { //if err != nil {
logger.Error("UpdateSmsUsedCount err", logger.Field("sms count", len(phoneList)), logger.Field("err", err)) // logger.Error("UpdateSmsUsedCount err", logger.Field("sms count", len(phoneList)), logger.Field("err", err))
return err // return err
} //}
return nil return nil
} }

View File

@ -1,12 +1,17 @@
package models package models
import ( import (
"bytes"
"encoding/json"
"errors" "errors"
"fmt" "fmt"
utils "go-admin/app/admin/models/tools" utils "go-admin/app/admin/models/tools"
orm "go-admin/common/global" orm "go-admin/common/global"
"go-admin/logger" "go-admin/logger"
"io/ioutil"
"log" "log"
"net/http"
"net/url"
"time" "time"
) )
@ -20,8 +25,24 @@ const (
TaskInProgress = "in_progress" // 执行中 TaskInProgress = "in_progress" // 执行中
TaskCompleted = "completed" // 已完成 TaskCompleted = "completed" // 已完成
TaskFailed = "failed" // 发送失败 TaskFailed = "failed" // 发送失败
AccessTokenUrl = "https://api.weixin.qq.com/cgi-bin/token"
WXAppID = "wx806c079463b5b56c"
WXSecret = "cb125688bf4e482f66e8c46062d568fc"
WxSubscribeMessage = "https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token="
TemplateId = "aP3c503T3wn-tJtpDccvxtNi7b1qjrwavFFfo-k2SAQ"
WxJumpUrl = "/pages/voucher/voucher" // 跳转微信小程序的页面路径
) )
// WxAccessToken 微信access_token
type WxAccessToken struct {
Model
Appid string `json:"appid"` // 小程序appid
AccessToken string `json:"access_token"` // 获取到的凭证
ExpiresTime time.Time `json:"expires_time"` // 凭证有效时间
}
// CouponIssuanceTask 优惠券发放任务表 // CouponIssuanceTask 优惠券发放任务表
type CouponIssuanceTask struct { type CouponIssuanceTask struct {
Model Model
@ -35,21 +56,22 @@ type CouponIssuanceTask struct {
// ErpCoupon 营销管理-优惠券 // ErpCoupon 营销管理-优惠券
type ErpCoupon struct { type ErpCoupon struct {
Model Model
Name string `json:"name" gorm:"index"` // 优惠券名称 Name string `json:"name" gorm:"index"` // 优惠券名称
Remark string `json:"remark"` // 名称备注 Remark string `json:"remark"` // 备注
Describe string `json:"describe" gorm:"type:text"` // 优惠券简介 Describe string `json:"describe" gorm:"type:text"` // 优惠券简介
Rule string `json:"rule" gorm:"type:text"` // 优惠券使用规则 Rule string `json:"rule" gorm:"type:text"` // 优惠券使用规则
CategoryNumber string `json:"category_number"` // 可以使用该优惠券的商品分类,如果为空则表示没限制 CategoryNumber string `json:"category_number"` // 可以使用该优惠券的商品分类,如果为空则表示没限制
ActiveDate uint32 `json:"active_date"` // 有效期(天) ActiveDate uint32 `json:"active_date"` // 有效期(天)
Amount uint32 `json:"amount"` // 金额(元) Amount uint32 `json:"amount"` // 金额(元)
UserType uint32 `json:"user_type"` // 领取人限制1-所有人 2-未付费用户 3-已付费用户 4-尊享会员 UserType uint32 `json:"user_type"` // 领取人限制1-所有人 2-未付费用户 3-已付费用户 4-尊享会员
Limit uint32 `json:"limit"` // 优惠券叠加限制 0-不限制1-仅限原价购买时使用 Limit uint32 `json:"limit"` // 优惠券叠加限制 0-不限制1-仅限原价购买时使用
State uint32 `json:"state" gorm:"index"` // 当前状态 1-未开始2-发放中3-进行中4-已结束5-发放失败 StartTime *time.Time `json:"start_time"` // 启动时间
SendCount uint32 `json:"send_count"` // 已发放 State uint32 `json:"state" gorm:"index"` // 当前状态 1-未开始2-发放中3-进行中4-已结束5-发放失败
UsedCount uint32 `json:"used_count"` // 已使用 SendCount uint32 `json:"send_count"` // 已发放
TotalPayAmount float64 `json:"total_pay_amount"` // 支付金额(元) UsedCount uint32 `json:"used_count"` // 已使用
PerCustomerAmount float64 `json:"per_customer_amount"` // 客单价(元) TotalPayAmount float64 `json:"total_pay_amount"` // 支付金额(元)
SmsContent string `json:"sms_content" gorm:"type:text"` // 短信提示内容 PerCustomerAmount float64 `json:"per_customer_amount"` // 客单价(元)
SmsContent string `json:"sms_content" gorm:"type:text"` // 短信提示内容
} }
// ErpMarketingCouponListReq 优惠券列表入参 // ErpMarketingCouponListReq 优惠券列表入参
@ -75,7 +97,7 @@ type ErpMarketingCouponListResp struct {
// ErpMarketingCouponCreateReq 新增优惠券入参 // ErpMarketingCouponCreateReq 新增优惠券入参
type ErpMarketingCouponCreateReq struct { type ErpMarketingCouponCreateReq struct {
Name string `json:"name" validate:"required"` // 优惠券名称 Name string `json:"name" validate:"required"` // 优惠券名称
Remark string `json:"remark"` // 名称备注 Remark string `json:"remark"` // 备注
Describe string `json:"describe" gorm:"type:text"` // 优惠券简介 Describe string `json:"describe" gorm:"type:text"` // 优惠券简介
Rule string `json:"rule" gorm:"type:text"` // 优惠券使用规则 Rule string `json:"rule" gorm:"type:text"` // 优惠券使用规则
CategoryNumber string `json:"category_number" validate:"required"` // 可以使用该优惠券的商品分类编号,如果为空则表示没限制 CategoryNumber string `json:"category_number" validate:"required"` // 可以使用该优惠券的商品分类编号,如果为空则表示没限制
@ -187,7 +209,7 @@ func CreateErpMarketingCoupon(req *ErpMarketingCouponCreateReq) error {
Rule: req.Rule, Rule: req.Rule,
CategoryNumber: req.CategoryNumber, CategoryNumber: req.CategoryNumber,
ActiveDate: req.ActiveDate, ActiveDate: req.ActiveDate,
Amount: req.Amount, Amount: req.Amount * 100,
UserType: req.UserType, UserType: req.UserType,
Limit: req.Limit, Limit: req.Limit,
State: ErpCouponUnStarted, State: ErpCouponUnStarted,
@ -204,9 +226,10 @@ func CreateErpMarketingCoupon(req *ErpMarketingCouponCreateReq) error {
Describe: req.Describe, Describe: req.Describe,
Rule: req.Rule, Rule: req.Rule,
CouponType: "deduction", CouponType: "deduction",
Value: req.Amount, Value: req.Amount * 100,
CategoryNumber: req.CategoryNumber, CategoryNumber: req.CategoryNumber,
ErpCouponId: erpCoupon.ID, ErpCouponId: erpCoupon.ID,
ActiveEnd: Now().AddDate(0, 0, int(req.ActiveDate)),
} }
err = orm.Eloquent.Create(coupon).Error err = orm.Eloquent.Create(coupon).Error
@ -385,10 +408,11 @@ func StartCouponIssuanceTask(req *ErpMarketingCouponStartReq, taskList []CouponI
} }
} }
var nTotalCount int
// 处理任务从上次中断的用户ID开始 // 处理任务从上次中断的用户ID开始
for { for {
// 查询用户ID大于 lastUserID 的用户 // 查询用户ID大于 lastUserID 的用户
users, err := getUsersAfterID(lastUserID) users, err := getUsersAfterID(lastUserID, erpCouponList[0].UserType)
if err != nil || len(users) == 0 { if err != nil || len(users) == 0 {
log.Println("没有更多用户,任务结束") log.Println("没有更多用户,任务结束")
break break
@ -403,6 +427,7 @@ func StartCouponIssuanceTask(req *ErpMarketingCouponStartReq, taskList []CouponI
// 更新任务进度记录处理到的最后一个用户ID // 更新任务进度记录处理到的最后一个用户ID
lastUserID = users[len(users)-1].ID lastUserID = users[len(users)-1].ID
nTotalCount += len(users)
//err = updateTaskProgress(req.ErpCouponId, lastUserID, err.Error()) //err = updateTaskProgress(req.ErpCouponId, lastUserID, err.Error())
//if err != nil { //if err != nil {
// log.Printf("更新任务进度失败: %v", err) // log.Printf("更新任务进度失败: %v", err)
@ -411,7 +436,7 @@ func StartCouponIssuanceTask(req *ErpMarketingCouponStartReq, taskList []CouponI
} }
// 任务完成,更新状态 // 任务完成,更新状态
err = markTaskAsCompleted(req.ErpCouponId) err = markTaskAsCompleted(req.ErpCouponId, nTotalCount)
if err != nil { if err != nil {
return nil return nil
} }
@ -447,17 +472,33 @@ func GetTaskProgress(erpCouponId []uint32) ([]CouponIssuanceTask, error) {
var task []CouponIssuanceTask var task []CouponIssuanceTask
err := orm.Eloquent.Table("coupon_issuance_task").Where("erp_coupon_id in ?", erpCouponId). err := orm.Eloquent.Table("coupon_issuance_task").Where("erp_coupon_id in ?", erpCouponId).
Order("updated_at desc").First(&task).Error Order("updated_at desc").First(&task).Error
if err != nil { if err != nil && err.Error() != "record not found" {
return nil, err return nil, err
} }
return task, nil return task, nil
} }
func getUsersAfterID(lastUserID uint32) ([]UserInfo, error) { func getUsersAfterID(lastUserID, userType uint32) ([]UserInfo, error) {
var err error
var users []UserInfo var users []UserInfo
err := orm.Eloquent.Model(&UserInfo{}).Where("id > ? ", lastUserID).
Order("id asc").Limit(100).Find(&users).Error switch userType {
case 2: // 2-未付费用户MemberLevel 不能是 (2, 3, 4, 5)
err = orm.Eloquent.Model(&UserInfo{}).Where("id > ? and member_level not in ?", lastUserID, []uint32{
MemberLevelGold, MemberLevelPeriod, MemberLevelPlatinum, MemberLevelBlackGold}).
Order("id asc").Limit(100).Find(&users).Error
case 3:
// 3-已付费用户MemberLevel 必须是 (2, 3, 4, 5)
err = orm.Eloquent.Model(&UserInfo{}).Where("id > ? and member_level in ?", lastUserID, []uint32{
MemberLevelGold, MemberLevelPeriod, MemberLevelPlatinum, MemberLevelBlackGold}).
Order("id asc").Limit(100).Find(&users).Error
case 1: // 1-所有人:不限制会员等级,所有人均可领取
default:
err = orm.Eloquent.Model(&UserInfo{}).Where("id > ?", lastUserID).
Order("id asc").Limit(100).Find(&users).Error
}
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -477,7 +518,7 @@ func updateTaskProgress(erpCouponId []uint32, lastUserID uint32, errMsg string)
return nil return nil
} }
func markTaskAsCompleted(erpCouponId []uint32) error { func markTaskAsCompleted(erpCouponId []uint32, nTotalCount int) error {
err := orm.Eloquent.Table("coupon_issuance_task").Where("erp_coupon_id in ?", erpCouponId). err := orm.Eloquent.Table("coupon_issuance_task").Where("erp_coupon_id in ?", erpCouponId).
Updates(map[string]interface{}{ Updates(map[string]interface{}{
"Status": TaskCompleted, "Status": TaskCompleted,
@ -488,6 +529,17 @@ func markTaskAsCompleted(erpCouponId []uint32) error {
return err return err
} }
err = orm.Eloquent.Table("erp_coupon").Where("id in ?", erpCouponId).
Updates(map[string]interface{}{
"state": ErpCouponInProgress,
"send_count": nTotalCount,
"updated_at": time.Now(),
}).Error
if err != nil {
log.Printf("更新任务完成状态失败: %v", err)
return err
}
log.Println("任务完成") log.Println("任务完成")
return nil return nil
} }
@ -550,7 +602,7 @@ func issueCouponsToUsers(users []UserInfo, erpCouponId []uint32) error {
Value: coupon.Value, Value: coupon.Value,
State: 1, State: 1,
ActiveStart: time.Now(), ActiveStart: time.Now(),
ActiveEnd: time.Now().AddDate(0, 0, 7), ActiveEnd: coupon.ActiveEnd,
RedeemCode: "", RedeemCode: "",
CategoryNumber: coupon.CategoryNumber, CategoryNumber: coupon.CategoryNumber,
Code: couponCode, Code: couponCode,
@ -567,12 +619,192 @@ func issueCouponsToUsers(users []UserInfo, erpCouponId []uint32) error {
} }
} }
// 发送短信或者消息订阅通知 // 发送订阅通知
err = GtSendMessage([]string{user.Tel}, erpCoupon[0].SmsContent) var wxToken WxAccessToken
err = orm.Eloquent.Table("wx_access_token").Where("appid = ?", WXAppID).First(&wxToken).Error
if err != nil { if err != nil {
logger.Error(err.Error()) logger.Error("query wx_access_token err:", logger.Field("err", err))
}
if wxToken.ID == 0 || wxToken.ExpiresTime.Before(time.Now()) {
CheckAccessToken()
err = orm.Eloquent.Table("wx_access_token").Where("appid = ?", WXAppID).First(&wxToken).Error
if err != nil {
logger.Error("query wx_access_token err:", logger.Field("err", err))
}
}
toUserOpenid := user.WxOpenID
templateId := TemplateId
data := map[string]interface{}{
"thing1": map[string]interface{}{"value": coupons[0].Name},
"thing5": map[string]interface{}{"value": coupons[0].Describe},
"date3": map[string]interface{}{"value": coupons[0].ActiveEnd.Format("2006年01月02日")},
"thing4": map[string]interface{}{"value": coupons[0].Rule},
}
//developer为开发版trial为体验版formal为正式版默认为正式版
_, err = SendMessage(wxToken.AccessToken, toUserOpenid, templateId, data, WxJumpUrl, "trial")
if err != nil {
// 如果订阅通知发送失败,则发送短信
err = GtSendMessage([]string{user.Tel}, erpCoupon[0].SmsContent)
if err != nil {
logger.Error(err.Error())
}
} }
} }
} }
return nil return nil
} }
// Response 请求微信返回基础数据
type Response struct {
Errcode int `json:"errcode"`
Errmsg string `json:"errmsg"`
}
// AccessTokenResponse 返回给用户的数据
type AccessTokenResponse struct {
AccessToken string `json:"access_token"` // 获取到的凭证
ExpiresIn int64 `json:"expires_in"` // 凭证有效时间单位秒。目前是7200秒之内的值。
}
type accessTokenResponse struct {
Response
AccessTokenResponse
}
// CheckAccessToken 定期更新access_token
func CheckAccessToken() {
accessToken, err := GetWxAccessToken()
if err != nil {
logger.Error("query wx_access_token err:", logger.Field("err", err))
} else {
now := time.Now()
twoHoursLater := now.Add(2 * time.Hour)
// 查询access_token
var wxToken WxAccessToken
err = orm.Eloquent.Table("wx_access_token").Where("appid = ?", WXAppID).First(&wxToken).Error
if err != nil {
logger.Error("query wx_access_token err:", logger.Field("err", err))
}
if wxToken.ID != 0 { // 更新
// 更新access_token
err = orm.Eloquent.Table("wx_access_token").Where("appid = ?", WXAppID).
Updates(map[string]interface{}{
"access_token": accessToken,
"expires_time": twoHoursLater,
}).Error
if err != nil {
logger.Errorf("更新wx_access_token失败: %v", err)
}
} else { // 插入
tempToken := &WxAccessToken{
Appid: WXAppID,
AccessToken: accessToken.AccessToken,
ExpiresTime: twoHoursLater,
}
err = orm.Eloquent.Create(tempToken).Error
if err != nil {
logger.Error("create wx_access_token err:", logger.Field("err", err))
}
}
}
}
// GetWxAccessToken 获取小程序的access_token
func GetWxAccessToken() (lures AccessTokenResponse, err error) {
api, err := code2url(WXAppID, WXSecret)
if err != nil {
return
}
res, err := http.Get(api)
if err != nil {
return
}
defer res.Body.Close()
if res.StatusCode != 200 {
err = errors.New("微信服务器发生错误")
return
}
var data accessTokenResponse
err = json.NewDecoder(res.Body).Decode(&data)
if err != nil {
return
}
if data.Errcode != 0 {
err = errors.New(data.Errmsg)
return
}
lures = data.AccessTokenResponse
return
}
// 拼接 获取 session_key 的 URL
func code2url(appID, secret string) (string, error) {
url, err := url.Parse(AccessTokenUrl)
if err != nil {
return "", err
}
query := url.Query()
query.Set("appid", appID)
query.Set("secret", secret)
query.Set("grant_type", "client_credential")
url.RawQuery = query.Encode()
return url.String(), nil
}
// SendMessage 发送订阅消息
func SendMessage(accessToken, toUserOpenid, templateId string, data interface{}, page, miniprogramState string) (
[]byte, error) {
url := fmt.Sprintf("%s%s", WxSubscribeMessage, accessToken)
body := map[string]interface{}{
"touser": toUserOpenid,
"template_id": templateId,
"data": data,
"page": page,
"miniprogramState": miniprogramState,
"lang": "zh_CN",
}
rsp, err := HttpRequest(http.MethodPost, url, body)
return rsp, err
}
func HttpRequest(method, url string, reqBody interface{}) ([]byte, error) {
client := http.Client{}
reqBodyBytes, err := json.Marshal(reqBody)
if err != nil {
return nil, err
}
reqBodyReader := bytes.NewReader(reqBodyBytes)
req, err := http.NewRequest(method, url, reqBodyReader)
if err != nil {
return nil, err
}
rsp, err := client.Do(req)
if err != nil {
return nil, err
}
defer rsp.Body.Close()
if rsp.StatusCode != 200 {
return nil, errors.New(fmt.Sprintf("response Status err:%d", rsp.StatusCode))
}
rspBody, err := ioutil.ReadAll(rsp.Body)
if err != nil {
return nil, err
}
return rspBody, nil
}

View File

@ -181,6 +181,13 @@ func run() error {
if err != nil { if err != nil {
fmt.Println("err:", err) fmt.Println("err:", err)
} }
// 刷新access_token
err = s.Every(1).Hour().Do(models.CheckAccessToken)
if err != nil {
fmt.Println("err:", err)
}
<-s.Start() <-s.Start()
}() }()

View File

@ -8982,20 +8982,20 @@ const docTemplate = `{
}, },
"amount": { "amount": {
"description": "金额(元)", "description": "金额(元)",
"type": "number" "type": "integer"
}, },
"category_number": { "category_number": {
"description": "可以使用该优惠券的商品分类,如果为空则表示没限制", "description": "可以使用该优惠券的商品分类,如果为空则表示没限制",
"type": "string" "type": "string"
}, },
"content": {
"description": "优惠内容",
"type": "string"
},
"createdAt": { "createdAt": {
"description": "创建时间", "description": "创建时间",
"type": "string" "type": "string"
}, },
"describe": {
"description": "优惠券简介",
"type": "string"
},
"id": { "id": {
"description": "数据库记录编号", "description": "数据库记录编号",
"type": "integer" "type": "integer"
@ -9013,15 +9013,27 @@ const docTemplate = `{
"type": "number" "type": "number"
}, },
"remark": { "remark": {
"description": "名称备注", "description": "备注",
"type": "string"
},
"rule": {
"description": "优惠券使用规则",
"type": "string" "type": "string"
}, },
"send_count": { "send_count": {
"description": "已发放", "description": "已发放",
"type": "integer" "type": "integer"
}, },
"sms_content": {
"description": "短信提示内容",
"type": "string"
},
"start_time": {
"description": "启动时间",
"type": "string"
},
"state": { "state": {
"description": "当前状态 1-未开始2-发放中3-进行中4-已结束", "description": "当前状态 1-未开始2-发放中3-进行中4-已结束5-发放失败",
"type": "integer" "type": "integer"
}, },
"total_pay_amount": { "total_pay_amount": {
@ -9595,14 +9607,14 @@ const docTemplate = `{
}, },
"amount": { "amount": {
"description": "金额(元)", "description": "金额(元)",
"type": "number" "type": "integer"
}, },
"category_number": { "category_number": {
"description": "可以使用该优惠券的商品分类编号,如果为空则表示没限制", "description": "可以使用该优惠券的商品分类编号,如果为空则表示没限制",
"type": "string" "type": "string"
}, },
"content": { "describe": {
"description": "优惠内容/使用说明", "description": "优惠券简介",
"type": "string" "type": "string"
}, },
"limit": { "limit": {
@ -9614,7 +9626,11 @@ const docTemplate = `{
"type": "string" "type": "string"
}, },
"remark": { "remark": {
"description": "名称备注", "description": "备注",
"type": "string"
},
"rule": {
"description": "优惠券使用规则",
"type": "string" "type": "string"
}, },
"user_type": { "user_type": {
@ -9667,14 +9683,14 @@ const docTemplate = `{
}, },
"amount": { "amount": {
"description": "金额(元)", "description": "金额(元)",
"type": "number" "type": "integer"
}, },
"category_number": { "category_number": {
"description": "可以使用该优惠券的商品分类,如果为空则表示没限制", "description": "可以使用该优惠券的商品分类,如果为空则表示没限制",
"type": "string" "type": "string"
}, },
"content": { "describe": {
"description": "优惠内容/使用说明", "description": "优惠券简介",
"type": "string" "type": "string"
}, },
"erp_coupon_id": { "erp_coupon_id": {
@ -9693,6 +9709,10 @@ const docTemplate = `{
"description": "名称备注", "description": "名称备注",
"type": "string" "type": "string"
}, },
"rule": {
"description": "优惠券使用规则",
"type": "string"
},
"user_type": { "user_type": {
"description": "领取人限制1-所有人 2-未付费用户 3-已付费用户 4-尊享会员", "description": "领取人限制1-所有人 2-未付费用户 3-已付费用户 4-尊享会员",
"type": "integer" "type": "integer"
@ -9762,12 +9782,25 @@ const docTemplate = `{
"models.ErpMarketingCouponStartReq": { "models.ErpMarketingCouponStartReq": {
"type": "object", "type": "object",
"required": [ "required": [
"erp_coupon_id" "erp_coupon_id",
"remark",
"sms_content"
], ],
"properties": { "properties": {
"erp_coupon_id": { "erp_coupon_id": {
"description": "优惠券id", "description": "优惠券id",
"type": "integer" "type": "array",
"items": {
"type": "integer"
}
},
"remark": {
"description": "活动名称备注",
"type": "string"
},
"sms_content": {
"description": "短信提示内容",
"type": "string"
} }
} }
}, },

View File

@ -8971,20 +8971,20 @@
}, },
"amount": { "amount": {
"description": "金额(元)", "description": "金额(元)",
"type": "number" "type": "integer"
}, },
"category_number": { "category_number": {
"description": "可以使用该优惠券的商品分类,如果为空则表示没限制", "description": "可以使用该优惠券的商品分类,如果为空则表示没限制",
"type": "string" "type": "string"
}, },
"content": {
"description": "优惠内容",
"type": "string"
},
"createdAt": { "createdAt": {
"description": "创建时间", "description": "创建时间",
"type": "string" "type": "string"
}, },
"describe": {
"description": "优惠券简介",
"type": "string"
},
"id": { "id": {
"description": "数据库记录编号", "description": "数据库记录编号",
"type": "integer" "type": "integer"
@ -9002,15 +9002,27 @@
"type": "number" "type": "number"
}, },
"remark": { "remark": {
"description": "名称备注", "description": "备注",
"type": "string"
},
"rule": {
"description": "优惠券使用规则",
"type": "string" "type": "string"
}, },
"send_count": { "send_count": {
"description": "已发放", "description": "已发放",
"type": "integer" "type": "integer"
}, },
"sms_content": {
"description": "短信提示内容",
"type": "string"
},
"start_time": {
"description": "启动时间",
"type": "string"
},
"state": { "state": {
"description": "当前状态 1-未开始2-发放中3-进行中4-已结束", "description": "当前状态 1-未开始2-发放中3-进行中4-已结束5-发放失败",
"type": "integer" "type": "integer"
}, },
"total_pay_amount": { "total_pay_amount": {
@ -9584,14 +9596,14 @@
}, },
"amount": { "amount": {
"description": "金额(元)", "description": "金额(元)",
"type": "number" "type": "integer"
}, },
"category_number": { "category_number": {
"description": "可以使用该优惠券的商品分类编号,如果为空则表示没限制", "description": "可以使用该优惠券的商品分类编号,如果为空则表示没限制",
"type": "string" "type": "string"
}, },
"content": { "describe": {
"description": "优惠内容/使用说明", "description": "优惠券简介",
"type": "string" "type": "string"
}, },
"limit": { "limit": {
@ -9603,7 +9615,11 @@
"type": "string" "type": "string"
}, },
"remark": { "remark": {
"description": "名称备注", "description": "备注",
"type": "string"
},
"rule": {
"description": "优惠券使用规则",
"type": "string" "type": "string"
}, },
"user_type": { "user_type": {
@ -9656,14 +9672,14 @@
}, },
"amount": { "amount": {
"description": "金额(元)", "description": "金额(元)",
"type": "number" "type": "integer"
}, },
"category_number": { "category_number": {
"description": "可以使用该优惠券的商品分类,如果为空则表示没限制", "description": "可以使用该优惠券的商品分类,如果为空则表示没限制",
"type": "string" "type": "string"
}, },
"content": { "describe": {
"description": "优惠内容/使用说明", "description": "优惠券简介",
"type": "string" "type": "string"
}, },
"erp_coupon_id": { "erp_coupon_id": {
@ -9682,6 +9698,10 @@
"description": "名称备注", "description": "名称备注",
"type": "string" "type": "string"
}, },
"rule": {
"description": "优惠券使用规则",
"type": "string"
},
"user_type": { "user_type": {
"description": "领取人限制1-所有人 2-未付费用户 3-已付费用户 4-尊享会员", "description": "领取人限制1-所有人 2-未付费用户 3-已付费用户 4-尊享会员",
"type": "integer" "type": "integer"
@ -9751,12 +9771,25 @@
"models.ErpMarketingCouponStartReq": { "models.ErpMarketingCouponStartReq": {
"type": "object", "type": "object",
"required": [ "required": [
"erp_coupon_id" "erp_coupon_id",
"remark",
"sms_content"
], ],
"properties": { "properties": {
"erp_coupon_id": { "erp_coupon_id": {
"description": "优惠券id", "description": "优惠券id",
"type": "integer" "type": "array",
"items": {
"type": "integer"
}
},
"remark": {
"description": "活动名称备注",
"type": "string"
},
"sms_content": {
"description": "短信提示内容",
"type": "string"
} }
} }
}, },

View File

@ -1728,16 +1728,16 @@ definitions:
type: integer type: integer
amount: amount:
description: 金额(元) description: 金额(元)
type: number type: integer
category_number: category_number:
description: 可以使用该优惠券的商品分类,如果为空则表示没限制 description: 可以使用该优惠券的商品分类,如果为空则表示没限制
type: string type: string
content:
description: 优惠内容
type: string
createdAt: createdAt:
description: 创建时间 description: 创建时间
type: string type: string
describe:
description: 优惠券简介
type: string
id: id:
description: 数据库记录编号 description: 数据库记录编号
type: integer type: integer
@ -1751,13 +1751,22 @@ definitions:
description: 客单价(元) description: 客单价(元)
type: number type: number
remark: remark:
description: 名称备注 description: 备注
type: string
rule:
description: 优惠券使用规则
type: string type: string
send_count: send_count:
description: 已发放 description: 已发放
type: integer type: integer
sms_content:
description: 短信提示内容
type: string
start_time:
description: 启动时间
type: string
state: state:
description: 当前状态 1-未开始2-发放中3-进行中4-已结束 description: 当前状态 1-未开始2-发放中3-进行中4-已结束5-发放失败
type: integer type: integer
total_pay_amount: total_pay_amount:
description: 支付金额(元) description: 支付金额(元)
@ -2172,12 +2181,12 @@ definitions:
type: integer type: integer
amount: amount:
description: 金额(元) description: 金额(元)
type: number type: integer
category_number: category_number:
description: 可以使用该优惠券的商品分类编号,如果为空则表示没限制 description: 可以使用该优惠券的商品分类编号,如果为空则表示没限制
type: string type: string
content: describe:
description: 优惠内容/使用说明 description: 优惠券简介
type: string type: string
limit: limit:
description: 优惠券叠加限制 0-不限制1-仅限原价购买时使用 description: 优惠券叠加限制 0-不限制1-仅限原价购买时使用
@ -2186,7 +2195,10 @@ definitions:
description: 优惠券名称 description: 优惠券名称
type: string type: string
remark: remark:
description: 名称备注 description: 备注
type: string
rule:
description: 优惠券使用规则
type: string type: string
user_type: user_type:
description: 领取人限制1-所有人 2-未付费用户 3-已付费用户 4-尊享会员 description: 领取人限制1-所有人 2-未付费用户 3-已付费用户 4-尊享会员
@ -2223,12 +2235,12 @@ definitions:
type: integer type: integer
amount: amount:
description: 金额(元) description: 金额(元)
type: number type: integer
category_number: category_number:
description: 可以使用该优惠券的商品分类,如果为空则表示没限制 description: 可以使用该优惠券的商品分类,如果为空则表示没限制
type: string type: string
content: describe:
description: 优惠内容/使用说明 description: 优惠券简介
type: string type: string
erp_coupon_id: erp_coupon_id:
description: 优惠券id description: 优惠券id
@ -2242,6 +2254,9 @@ definitions:
remark: remark:
description: 名称备注 description: 名称备注
type: string type: string
rule:
description: 优惠券使用规则
type: string
user_type: user_type:
description: 领取人限制1-所有人 2-未付费用户 3-已付费用户 4-尊享会员 description: 领取人限制1-所有人 2-未付费用户 3-已付费用户 4-尊享会员
type: integer type: integer
@ -2300,9 +2315,19 @@ definitions:
properties: properties:
erp_coupon_id: erp_coupon_id:
description: 优惠券id description: 优惠券id
type: integer items:
type: integer
type: array
remark:
description: 活动名称备注
type: string
sms_content:
description: 短信提示内容
type: string
required: required:
- erp_coupon_id - erp_coupon_id
- remark
- sms_content
type: object type: object
models.ErpOrder: models.ErpOrder:
properties: properties:

BIN
static/导零售.xlsx Normal file

Binary file not shown.