diff --git a/internal/biz/bo/product_bo.go b/internal/biz/bo/product_bo.go index 31f412e..c778fcb 100644 --- a/internal/biz/bo/product_bo.go +++ b/internal/biz/bo/product_bo.go @@ -7,19 +7,21 @@ import ( // ProductBo 领域实体Bo结构,字段和模型字段保持一致 type ProductBo struct { - ID int32 - Name string - ProductNo string - BatchName string - BatchNo string - MchId string - Channel vo.Channel - AvailableType vo.AvailableType - AvailableDays uint32 - Amount int64 - WarningBudget int64 - StartTime *time.Time - EndTime *time.Time - 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 + Amount int64 + AllBudget int64 + AvailableBudget int64 + WarningBudget int64 + StartTime *time.Time + EndTime *time.Time + CreateTime *time.Time + UpdateTime *time.Time } diff --git a/internal/biz/do/product.go b/internal/biz/do/product.go index d228d57..168c919 100644 --- a/internal/biz/do/product.go +++ b/internal/biz/do/product.go @@ -3,13 +3,14 @@ package do import "time" type WxResp struct { - Amount int64 // 券面额 - AllBudget int64 // 总预算 - AllStock int64 // 总库存 - UsedStock int64 // 已使用库存 - UsedBudget int64 // 已使用预算 - AvailableStock int64 // 可用库存 - RemainingBudget int64 // 剩余预算 + Amount int64 // 券面额 + AllBudget int64 // 总预算 + AllStock int64 // 总库存 + UsedStock int64 // 已使用库存 + UsedBudget int64 // 已使用预算 + AvailableStock int64 // 可用库存 + AvailableBudget int64 // 可用预算 + StockUsageRate float64 // 券使用率 StartTime *time.Time EndTime *time.Time } diff --git a/internal/biz/product.go b/internal/biz/product.go index 7a220a1..2c13490 100644 --- a/internal/biz/product.go +++ b/internal/biz/product.go @@ -88,6 +88,8 @@ func (v *VoucherBiz) WxResp(wxResp *cashcoupons.Stock) (reps *do.WxResp) { remainingBudget := availableStock * couponAmount + stockUsageRate := float64(*wxResp.DistributedCoupons) / float64(*wxResp.StockUseRule.MaxCoupons) * 100 + req := &do.WxResp{ Amount: couponAmount, AllBudget: *wxResp.StockUseRule.MaxAmount / 100, @@ -95,7 +97,8 @@ func (v *VoucherBiz) WxResp(wxResp *cashcoupons.Stock) (reps *do.WxResp) { UsedStock: *wxResp.DistributedCoupons, UsedBudget: *wxResp.DistributedCoupons * couponAmount, AvailableStock: availableStock, - RemainingBudget: remainingBudget, + AvailableBudget: remainingBudget, + StockUsageRate: stockUsageRate, } inputFormat := time.RFC3339 diff --git a/internal/biz/warning_budget.go b/internal/biz/warning_budget.go index 1df45a6..c3f8d49 100644 --- a/internal/biz/warning_budget.go +++ b/internal/biz/warning_budget.go @@ -138,53 +138,24 @@ func (v *VoucherBiz) warningBudget(ctx context.Context) error { return nil } -func (v *VoucherBiz) GetWarningBudget(product *bo.ProductBo, wxResp *cashcoupons.Stock) (*do.WarningBudget, error) { - - availableStock := *wxResp.StockUseRule.MaxCoupons - *wxResp.DistributedCoupons - couponAmount := *wxResp.StockUseRule.FixedNormalCoupon.CouponAmount / 100 - - remainingBudget := availableStock * couponAmount - - stockUsageRate := float64(*wxResp.DistributedCoupons) / float64(*wxResp.StockUseRule.MaxCoupons) * 100 - - req := &do.WarningBudget{ - StockName: product.Name, - StockId: product.BatchNo, - StockNo: product.ProductNo, - Amount: couponAmount, - AllBudget: *wxResp.StockUseRule.MaxAmount / 100, - AllStock: *wxResp.StockUseRule.MaxCoupons, - UsedStock: *wxResp.DistributedCoupons, - UsedBudget: *wxResp.DistributedCoupons * couponAmount, - AvailableStock: availableStock, - RemainingBudget: remainingBudget, - StockUsageRate: stockUsageRate, - } - - return req, nil -} - func (v *VoucherBiz) Calculate(ctx context.Context, product *bo.ProductBo, wxResp *cashcoupons.Stock) error { - req, err := v.GetWarningBudget(product, wxResp) + w := v.WxResp(wxResp) + + err := v.ProductRepo.UpdateWarningBudget(ctx, product.ID, w) if err != nil { return err } - err = v.ProductRepo.UpdateWarningBudget(ctx, product.ID, v.WxResp(wxResp)) - if err != nil { - return err - } + if product.WarningBudget >= w.AvailableBudget { - if product.WarningBudget >= req.RemainingBudget { - - count, err2 := v.WarningBudgetIncr(ctx, req.StockId) + count, err2 := v.WarningBudgetIncr(ctx, product.BatchNo) if err2 != nil { return err2 } if count == 1 { - return v.WarningSend(ctx, formatAsCard(req)) + return v.WarningSend(ctx, formatAsCard(product, w)) } else { log.Warnf("预警查询,当前达到预警第[%d]次,暂不做通知", count) } @@ -198,15 +169,15 @@ func (v *VoucherBiz) WarningSend(ctx context.Context, str string) error { return v.DingMixRepo.SendMarkdownMessage(ctx, "券预算不足", str) } -func formatAsCard(req *do.WarningBudget) string { +func formatAsCard(product *bo.ProductBo, req *do.WxResp) string { var card strings.Builder - card.WriteString("### " + req.StockName + "\n\n") + card.WriteString("### " + product.BatchName + "\n\n") // 基本信息 card.WriteString("#### 🎫 基本信息\n") - card.WriteString(fmt.Sprintf("- **批次号**: %s\n", req.StockId)) - card.WriteString(fmt.Sprintf("- **活动号**: %s\n", req.StockNo)) + card.WriteString(fmt.Sprintf("- **批次号**: %s\n", product.BatchNo)) + card.WriteString(fmt.Sprintf("- **活动号**: %s\n", product.ProductNo)) card.WriteString(fmt.Sprintf("- **面额**: %d元\n", req.Amount)) card.WriteString(fmt.Sprintf("- **总预算**: %d元\n", req.AllBudget)) card.WriteString(fmt.Sprintf("- **总库存**: %d张\n", req.AllStock)) @@ -217,7 +188,7 @@ func formatAsCard(req *do.WarningBudget) string { card.WriteString(fmt.Sprintf("- **已发券数**: %d张\n", req.UsedStock)) card.WriteString(fmt.Sprintf("- **已发券金额**: %d元\n", req.UsedBudget)) card.WriteString(fmt.Sprintf("- **剩余库存**: %d张\n", req.AvailableStock)) - card.WriteString(fmt.Sprintf("- **剩余预算**: %d元\n", req.RemainingBudget)) + card.WriteString(fmt.Sprintf("- **剩余预算**: %d元\n", req.AvailableBudget)) card.WriteString("\n") card.WriteString("#### 📈 使用率\n") diff --git a/internal/data/model/product.gen.go b/internal/data/model/product.gen.go index 8cdd9dc..ac3dd3f 100644 --- a/internal/data/model/product.gen.go +++ b/internal/data/model/product.gen.go @@ -23,7 +23,7 @@ type Product struct { AvailableDays uint32 `gorm:"column:available_days;not null;comment:领取后多少天内" json:"available_days"` Amount int64 `gorm:"column:amount;not null;default:0" json:"amount"` AllBudget int64 `gorm:"column:all_budget;not null;default:0" json:"all_budget"` - RemainingBudget int64 `gorm:"column:remaining_budget;not null;default:0" json:"remaining_budget"` + AvailableBudget int64 `gorm:"column:available_budget;not null;default:0" json:"available_budget"` WarningBudget int64 `gorm:"column:warning_budget;not null;default:0" json:"warning_budget"` // 预警预算=0不做预警 WarningPerson string `gorm:"column:warning_person" json:"warning_person"` StartTime *time.Time `gorm:"column:start_time;not null" json:"start_time"` diff --git a/internal/data/repoimpl/product.go b/internal/data/repoimpl/product.go index 7b2461d..5f758a2 100644 --- a/internal/data/repoimpl/product.go +++ b/internal/data/repoimpl/product.go @@ -59,7 +59,7 @@ func (r *ProductRepoImpl) UpdateWarningBudget(ctx context.Context, id int32, req u := model.Product{ AllBudget: req.AllBudget, - RemainingBudget: req.RemainingBudget, + AvailableBudget: req.AvailableBudget, UpdateTime: &now, } diff --git a/internal/pkg/sms/sms_test.go b/internal/pkg/sms/sms_test.go index 17847fb..69cb6a2 100644 --- a/internal/pkg/sms/sms_test.go +++ b/internal/pkg/sms/sms_test.go @@ -68,7 +68,7 @@ func TestWarningSend(t *testing.T) { return } - err = smsService.SendSMS(context.Background(), []string{"18666173766"}, "", params) + err = smsService.SendSMS(context.Background(), []string{"18666173766"}, "SMS_489705720", params) if err != nil { t.Errorf("发送短信失败: %v", err) return @@ -84,8 +84,8 @@ func buildTemplateParams(req *do.WarningBudget) map[string]string { "all_stock": strconv.Itoa(int(req.AllStock)), "used_stock": strconv.Itoa(int(req.UsedStock)), "used_budget": strconv.Itoa(int(req.UsedBudget)), - "remaining_budget": strconv.Itoa(int(req.RemainingBudget)), - "remaining_stock": strconv.Itoa(int(req.AvailableStock)), + "available_budget": strconv.Itoa(int(req.RemainingBudget)), + "available_stock": strconv.Itoa(int(req.AvailableStock)), "budget_usage_rate": fmt.Sprintf("%.1f", req.StockUsageRate), } }