voucher/internal/biz/warning_budget.go

125 lines
3.6 KiB
Go

package biz
import (
"context"
"fmt"
"github.com/go-kratos/kratos/v2/log"
"github.com/wechatpay-apiv3/wechatpay-go/services/cashcoupons"
"strings"
"time"
"voucher/internal/biz/bo"
"voucher/internal/biz/do"
)
func (v *VoucherBiz) WarningBudget(ctx context.Context) {
start := time.Now()
log.Warnf("预警查询,执行开始: %s", start.Format(time.DateTime))
if err := v.warningBudget(ctx); err != nil {
log.Errorf("预警查询,执行失败: %v", err)
}
end := time.Now()
elapsed := end.Sub(start)
log.Warnf("预警查询,开始执行时间%s,执行结束时间%s,代码块执行耗时: %s", start.Format(time.DateTime), end.Format(time.DateTime), elapsed)
return
}
func (v *VoucherBiz) warningBudget(ctx context.Context) error {
err := v.ProductRepo.FindWarningBudget(ctx, func(ctx context.Context, rows []*bo.ProductBo) error {
for _, row := range rows {
wxResp, err := v.WechatCpnRepo.QueryProduct(ctx, row.MchId, row.BatchNo)
if err != nil {
log.Context(ctx).Errorf("预警查询,查询微信券失败: %v", err)
continue
} else {
if err = v.Calculate(ctx, row, wxResp); err != nil {
log.Context(ctx).Errorf("预警查询,处理失败: %v", err)
}
}
time.Sleep(time.Second * 2)
}
return nil
})
if err != nil {
return err
}
return nil
}
func (v *VoucherBiz) Calculate(ctx context.Context, product *bo.ProductBo, wxResp *cashcoupons.Stock) error {
availableStock := *wxResp.StockUseRule.MaxCoupons - *wxResp.DistributedCoupons
couponAmount := *wxResp.StockUseRule.FixedNormalCoupon.CouponAmount / 100
remainingBudget := availableStock * couponAmount
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,
}
str := formatAsCard(req)
log.Warnf("预警查询,券预算明细,%s", str)
if product.WarningBudget >= remainingBudget {
return v.WarningSend(ctx, str)
}
return nil
}
func (v *VoucherBiz) WarningSend(ctx context.Context, str string) error {
return v.DingMixRepo.SendMarkdownMessage(ctx, "券预算不足", str)
}
func formatAsCard(req *do.WarningBudget) string {
var card strings.Builder
card.WriteString("### 🎫 " + req.StockName + "\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("- **面额**: %d元\n", req.Amount))
card.WriteString(fmt.Sprintf("- **总预算**: %d元\n", req.AllBudget))
card.WriteString(fmt.Sprintf("- **总库存**: %d张\n", req.AllStock))
card.WriteString("\n")
// 使用情况
card.WriteString("#### 📊 使用情况\n")
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("\n")
// 使用率
stockUsageRate := float64(req.UsedStock) / float64(req.AllStock) * 100
card.WriteString("#### 📈 使用率\n")
card.WriteString(fmt.Sprintf("- **使用率**: %.1f%%\n", stockUsageRate))
return card.String()
}