活动批次查询确认

This commit is contained in:
李子铭 2025-03-17 19:48:10 +08:00
parent 95dbc27dcc
commit 8ec8f2a980
9 changed files with 156 additions and 55 deletions

View File

@ -124,8 +124,10 @@ message CmbQueryProductReply {
string detail = 18 [json_name = "detail"];
// yyyy-mm-dd hh:mm:ss.sss
//
string saleStartTime = 19 [json_name = "saleStartTime"];
// yyyy-mm-dd hh:mm:ss.sss
//
string saleEndTime = 20 [json_name = "saleEndTime"];
//

View File

@ -7,13 +7,15 @@ import (
// ProductBo 领域实体Bo结构字段和模型字段保持一致
type ProductBo struct {
ID int32
Name string
ProductNo string
BatchName string
BatchNo string
MchId string
Channel vo.Channel
CreateTime *time.Time
UpdateTime *time.Time
ID int32
Name string
ProductNo string
BatchName string
BatchNo string
MchId string
Channel vo.Channel
AvailableType vo.AvailableType
AvailableDays uint32
CreateTime *time.Time
UpdateTime *time.Time
}

View File

@ -112,22 +112,6 @@ func (v *VoucherBiz) CmbProductQuery(ctx context.Context, productNo string) (rep
return err
}
inputFormat := time.RFC3339
beginTime := ""
if wechatResp.AvailableBeginTime != nil {
// 解析开始时间
availableBeginTime, _ := time.Parse(inputFormat, *wechatResp.AvailableBeginTime)
beginTime = availableBeginTime.Format(time.DateTime)
}
endTime := ""
if wechatResp.AvailableEndTime != nil {
// 解析结束时间
availableEndTime, _ := time.Parse(inputFormat, *wechatResp.AvailableEndTime)
endTime = availableEndTime.Format(time.DateTime)
}
reps = &v1.CmbQueryProductReply{
RespCode: vo.CmbResponseStatusSuccess.GetValue(),
RespMsg: "成功",
@ -137,28 +121,49 @@ func (v *VoucherBiz) CmbProductQuery(ctx context.Context, productNo string) (rep
MinAmount: "",
AvailableType: "",
AvailableDays: "", // 动态有效期天数
StartTime: beginTime,
EndTime: endTime,
StartTime: "",
EndTime: "",
AvailableStock: "",
Detail: *wechatResp.Description,
}
inputFormat := time.RFC3339
if wechatResp.AvailableBeginTime != nil {
// 解析开始时间
availableBeginTime, _ := time.Parse(inputFormat, *wechatResp.AvailableBeginTime)
reps.StartTime = availableBeginTime.Format(time.DateTime)
}
if wechatResp.AvailableEndTime != nil {
// 解析结束时间
availableEndTime, _ := time.Parse(inputFormat, *wechatResp.AvailableEndTime)
reps.EndTime = availableEndTime.Format(time.DateTime)
}
if wechatResp.StartTime != nil {
s, _ := time.Parse(inputFormat, *wechatResp.StartTime)
reps.SaleStartTime = s.Format(time.DateTime)
}
if wechatResp.StopTime != nil {
e, _ := time.Parse(inputFormat, *wechatResp.StopTime)
reps.SaleEndTime = e.Format(time.DateTime)
}
reps.Amount = fmt.Sprintf("%d", *wechatResp.StockUseRule.FixedNormalCoupon.CouponAmount)
reps.MinAmount = fmt.Sprintf("%d", *wechatResp.StockUseRule.FixedNormalCoupon.TransactionMinimum)
availableStock := *wechatResp.StockUseRule.MaxCoupons - *wechatResp.DistributedCoupons
reps.AvailableStock = fmt.Sprintf("%d", availableStock)
if wechatResp.StartTime != nil {
s, _ := time.Parse(inputFormat, *wechatResp.StartTime)
reps.SaleStartTime = s.Format(time.DateTime)
}
if wechatResp.StopTime != nil {
e, _ := time.Parse(inputFormat, *wechatResp.StopTime)
reps.SaleEndTime = e.Format(time.DateTime)
availableType, err := product.AvailableType.GetCmbAvailableType()
if err != nil {
return err
}
reps.AvailableType = vo.CmbAvailableTypeFixed.GetValue()
reps.AvailableType = availableType.GetValue()
reps.AvailableDays = fmt.Sprintf("%d", product.AvailableDays)
return nil
})

View File

@ -2,11 +2,10 @@ package biz
import (
"context"
"errors"
"fmt"
"github.com/go-kratos/kratos/v2/log"
"github.com/redis/go-redis/v9"
"gorm.io/gorm"
err2 "voucher/api/err"
"voucher/internal/biz/bo"
"voucher/internal/biz/vo"
"voucher/internal/pkg/lock"
@ -34,8 +33,8 @@ func (v *VoucherBiz) order(ctx context.Context, req *bo.OrderCreateReqBo, produc
// 真实发放
voucherNo, err = v.WechatCpnRepo.Order(ctx, order)
if err != nil {
if err2 := v.fail(ctx, order, err.Error()); err2 != nil {
return nil, err2
if err3 := v.fail(ctx, order, err.Error()); err3 != nil {
return nil, err3
}
return nil, err
}
@ -118,7 +117,7 @@ func (v *VoucherBiz) registerNotifyTag(ctx context.Context, stockCreatorMchID, s
}
wechatNotifyTag, err := v.WechatNotifyRegisterTagRepo.GetByStockIdAndMchId(ctx, stockCreatorMchID, stockID)
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
if err != nil && !err2.IsDbNotFound(err) {
return err
}

View File

@ -0,0 +1,46 @@
package vo
import "errors"
type AvailableType uint8
const (
AvailableTypeFixed AvailableType = iota + 1
AvailableTypeDynamic
)
var AvailableTypeMap = map[AvailableType]string{
AvailableTypeFixed: "固定有效期",
AvailableTypeDynamic: "动态有效期",
}
func (s AvailableType) GetText() string {
if t, ok := AvailableTypeMap[s]; ok {
return t
}
return "未知券领取类型"
}
func (s AvailableType) GetValue() uint8 {
return uint8(s)
}
func (s AvailableType) IsFixed() bool {
return s == AvailableTypeFixed
}
func (s AvailableType) IsDynamic() bool {
return s == AvailableTypeDynamic
}
var AvailableCmbTypeMap = map[AvailableType]CmbAvailableType{
AvailableTypeFixed: CmbAvailableTypeFixed,
AvailableTypeDynamic: CmbAvailableTypeDynamic,
}
func (s AvailableType) GetCmbAvailableType() (CmbAvailableType, error) {
if t, ok := AvailableCmbTypeMap[s]; ok {
return t, nil
}
return "", errors.New("未知券领取类型")
}

View File

@ -16,8 +16,8 @@ func (s CmbFuncName) GetValue() string {
type CmbStatus string
const (
CmbStatusSuccess CmbStatus = "0"
CmbStatusUse CmbStatus = "1"
CmbStatusSuccess CmbStatus = "0" // 券可用
CmbStatusUse CmbStatus = "1" // 券使用
CmbStatusExpired CmbStatus = "2" // 券过期-待确认是否通知
)
@ -29,8 +29,8 @@ func (s CmbStatus) GetValue() string {
type CmbResponseStatus string
const (
CmbResponseStatusSuccess CmbResponseStatus = "1000"
CmbResponseStatusFail CmbResponseStatus = "1001"
CmbResponseStatusSuccess CmbResponseStatus = "1000" // 响应成功
CmbResponseStatusFail CmbResponseStatus = "1001" // 响应失败
)
func (s CmbResponseStatus) GetValue() string {
@ -41,8 +41,8 @@ func (s CmbResponseStatus) GetValue() string {
type CmbAvailableType string
const (
CmbAvailableTypeFixed CmbAvailableType = "0"
CmbAvailableTypeDynamic CmbAvailableType = "1"
CmbAvailableTypeFixed CmbAvailableType = "0" // 固定有效期
CmbAvailableTypeDynamic CmbAvailableType = "1" // 动态有效期
)
func (s CmbAvailableType) GetValue() string {

View File

@ -12,15 +12,17 @@ const TableNameProduct = "product"
// Product mapped from table <product>
type Product struct {
ID int32 `gorm:"column:id;primaryKey;autoIncrement:true" json:"id"`
Name string `gorm:"column:name;not null;comment:商品名称" json:"name"` // 商品名称
ProductNo string `gorm:"column:product_no;not null;comment:商品编号" json:"product_no"` // 商品编号
BatchName string `gorm:"column:batch_name;not null;comment:批次名称" json:"batch_name"` // 批次名称
BatchNo string `gorm:"column:batch_no;not null;comment:立减金批次号" json:"batch_no"` // 立减金批次号
MchId string `gorm:"column:mch_id;not null;comment:商户号,创建批次的商户号" json:"mch_id"` // 商户号,创建批次的商户号
Channel uint8 `gorm:"column:channel;not null;comment:1:微信 2:支付宝" json:"channel"` // 1:微信 2:支付宝
CreateTime *time.Time `gorm:"column:create_time;not null" json:"create_time"`
UpdateTime *time.Time `gorm:"column:update_time" json:"update_time"`
ID int32 `gorm:"column:id;primaryKey;autoIncrement:true" json:"id"`
Name string `gorm:"column:name;not null;comment:商品名称" json:"name"` // 商品名称
ProductNo string `gorm:"column:product_no;not null;comment:商品编号" json:"product_no"` // 商品编号
BatchName string `gorm:"column:batch_name;not null;comment:批次名称" json:"batch_name"` // 批次名称
BatchNo string `gorm:"column:batch_no;not null;comment:立减金批次号" json:"batch_no"` // 立减金批次号
MchId string `gorm:"column:mch_id;not null;comment:商户号,创建批次的商户号" json:"mch_id"` // 商户号,创建批次的商户号
Channel uint8 `gorm:"column:channel;not null;comment:1:微信 2:支付宝" json:"channel"` // 1:微信 2:支付宝
AvailableType uint8 `gorm:"column:available_type;not null;comment:1:固定有效期 2:动态有效期" json:"available_type"`
AvailableDays uint32 `gorm:"column:available_days;not null;comment:领取后多少天内" json:"available_days"`
CreateTime *time.Time `gorm:"column:create_time;not null" json:"create_time"`
UpdateTime *time.Time `gorm:"column:update_time" json:"update_time"`
}
// TableName Product's table name

View File

@ -257,3 +257,17 @@ func IsInSameNaturalMonth(startTime, endTime time.Time) bool {
expectedEndTime.Minute() == endTime.Minute() &&
expectedEndTime.Second() == endTime.Second()
}
func DaysBetween(start, end time.Time) (int, error) {
// 2. 统一到同一天的 0 点(避免时分秒干扰)
startDay := start.Truncate(24 * time.Hour)
endDay := end.Truncate(24 * time.Hour)
// 3. 计算天数(含结束日)
days := int(endDay.Sub(startDay).Hours() / 24)
if end.After(endDay) { // 结束时间非 0 点,加 1 天
days++
}
return days, nil
}

View File

@ -101,3 +101,34 @@ func TestRFC3339(t *testing.T) {
fmt.Printf("格式化后的开始时间: %s\n", formattedBeginTime)
fmt.Printf("格式化后的结束时间: %s\n", formattedEndTime)
}
func TestDaysBetween(t *testing.T) {
// 输入的时间字符串
availableBeginTimeStr := "2025-03-07T00:00:00+08:00"
availableEndTimeStr := "2025-06-05T23:59:59+08:00"
// 定义输入时间字符串的格式
inputFormat := time.RFC3339
// 解析开始时间
availableBeginTime, err := time.Parse(inputFormat, availableBeginTimeStr)
if err != nil {
fmt.Printf("解析开始时间出错: %v\n", err)
return
}
// 解析结束时间
availableEndTime, err := time.Parse(inputFormat, availableEndTimeStr)
if err != nil {
fmt.Printf("解析结束时间出错: %v\n", err)
return
}
days, err := DaysBetween(availableBeginTime, availableEndTime)
if err != nil {
fmt.Printf("解析结束时间出错: %v\n", err)
return
}
t.Log(days)
}