2025-12-06 09:10:24 +08:00
|
|
|
|
package service
|
|
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
|
"context"
|
|
|
|
|
|
"time"
|
|
|
|
|
|
|
|
|
|
|
|
"github.com/gogf/gf/v2/errors/gerror"
|
|
|
|
|
|
"github.com/gogf/gf/v2/util/gconv"
|
|
|
|
|
|
|
2025-12-09 16:10:45 +08:00
|
|
|
|
"cid/dao"
|
|
|
|
|
|
"cid/model/dto"
|
|
|
|
|
|
"cid/model/entity"
|
2025-12-06 09:10:24 +08:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
var Advertiser = new(advertiser)
|
|
|
|
|
|
|
|
|
|
|
|
type advertiser struct{}
|
|
|
|
|
|
|
|
|
|
|
|
// Add 添加广告主
|
|
|
|
|
|
func (s *advertiser) Add(ctx context.Context, req *dto.AddAdvertiserReq) (res *dto.AddAdvertiserRes, err error) {
|
|
|
|
|
|
advertiser := &entity.Advertiser{}
|
|
|
|
|
|
if err = gconv.Struct(req, advertiser); err != nil {
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 设置基础字段
|
|
|
|
|
|
now := time.Now()
|
|
|
|
|
|
advertiser.CreatedAt = now
|
|
|
|
|
|
advertiser.UpdatedAt = now
|
|
|
|
|
|
advertiser.IsDeleted = false
|
|
|
|
|
|
|
|
|
|
|
|
// 设置初始状态
|
|
|
|
|
|
advertiser.Status = "待审核"
|
|
|
|
|
|
|
|
|
|
|
|
if err = dao.Advertiser.Insert(ctx, advertiser); err != nil {
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
res = &dto.AddAdvertiserRes{Id: advertiser.Id.Hex()}
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Update 更新广告主
|
|
|
|
|
|
func (s *advertiser) Update(ctx context.Context, req *dto.UpdateAdvertiserReq) (err error) {
|
|
|
|
|
|
// 更新修改时间(不需要设置,DAO层会处理)
|
|
|
|
|
|
return dao.Advertiser.Update(ctx, req)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// UpdateStatus 更新广告主状态
|
|
|
|
|
|
func (s *advertiser) UpdateStatus(ctx context.Context, req *dto.UpdateAdvertiserStatusReq) (err error) {
|
|
|
|
|
|
return dao.Advertiser.UpdateStatus(ctx, req.Id, req.Status)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Audit 审核广告主
|
|
|
|
|
|
func (s *advertiser) Audit(ctx context.Context, req *dto.AuditAdvertiserReq) (err error) {
|
|
|
|
|
|
return dao.Advertiser.Audit(ctx, req.Id, req.AuditStatus, req.AuditReason)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Recharge 充值
|
|
|
|
|
|
func (s *advertiser) Recharge(ctx context.Context, req *dto.RechargeAdvertiserReq) (err error) {
|
|
|
|
|
|
// 验证金额
|
|
|
|
|
|
if req.Amount <= 0 {
|
|
|
|
|
|
return gerror.New("充值金额必须大于0")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 执行充值
|
|
|
|
|
|
err = dao.Advertiser.Recharge(ctx, req.Id, req.Amount, req.Remark)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 记录充值流水(实际项目中可能需要创建充值记录表)
|
|
|
|
|
|
// 这里简化处理
|
|
|
|
|
|
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// UpdateCreditLimit 更新授信额度
|
|
|
|
|
|
func (s *advertiser) UpdateCreditLimit(ctx context.Context, req *dto.UpdateCreditLimitReq) (err error) {
|
|
|
|
|
|
// 验证授信额度
|
|
|
|
|
|
if req.CreditLimit < 0 {
|
|
|
|
|
|
return gerror.New("授信额度不能为负数")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 更新授信额度
|
|
|
|
|
|
err = dao.Advertiser.UpdateCreditLimit(ctx, req.Id, req.CreditLimit)
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// GetOne 获取广告主详情
|
|
|
|
|
|
func (s *advertiser) GetOne(ctx context.Context, req *dto.GetAdvertiserReq) (res *dto.GetAdvertiserRes, err error) {
|
|
|
|
|
|
advertiser, err := dao.Advertiser.GetOne(ctx, req.Id)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
res = &dto.GetAdvertiserRes{
|
|
|
|
|
|
Advertiser: advertiser,
|
|
|
|
|
|
}
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// List 获取广告主列表
|
|
|
|
|
|
func (s *advertiser) List(ctx context.Context, req *dto.ListAdvertiserReq) (res *dto.ListAdvertiserRes, err error) {
|
|
|
|
|
|
list, total, err := dao.Advertiser.List(ctx, req)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
res = &dto.ListAdvertiserRes{
|
|
|
|
|
|
List: list,
|
|
|
|
|
|
Total: int(total),
|
|
|
|
|
|
}
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// GetBalance 获取广告主余额
|
|
|
|
|
|
func (s *advertiser) GetBalance(ctx context.Context, id string) (balance, creditLimit int64, err error) {
|
|
|
|
|
|
advertiser, err := dao.Advertiser.GetOne(ctx, id)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
balance = advertiser.AccountBalance
|
|
|
|
|
|
creditLimit = advertiser.CreditLimit
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// CheckBudget 检查广告主预算
|
|
|
|
|
|
func (s *advertiser) CheckBudget(ctx context.Context, id string, cost int64) (hasEnoughBudget bool, err error) {
|
|
|
|
|
|
advertiser, err := dao.Advertiser.GetOne(ctx, id)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 可用金额 = 账户余额 + 授信额度 - 已消耗
|
|
|
|
|
|
availableAmount := advertiser.AccountBalance + advertiser.CreditLimit
|
|
|
|
|
|
|
|
|
|
|
|
// 检查预算是否充足
|
|
|
|
|
|
hasEnoughBudget = availableAmount >= cost
|
|
|
|
|
|
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// DeductBudget 扣除预算
|
|
|
|
|
|
func (s *advertiser) DeductBudget(ctx context.Context, id string, cost int64) (err error) {
|
|
|
|
|
|
// 检查预算是否充足
|
|
|
|
|
|
hasEnoughBudget, err := s.CheckBudget(ctx, id, cost)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if !hasEnoughBudget {
|
|
|
|
|
|
return gerror.New("预算不足")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取广告主信息
|
|
|
|
|
|
advertiser, err := dao.Advertiser.GetOne(ctx, id)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 计算新余额
|
|
|
|
|
|
newBalance := advertiser.AccountBalance - cost
|
|
|
|
|
|
|
|
|
|
|
|
// 如果账户余额为负,从授信额度中扣除
|
|
|
|
|
|
if newBalance < 0 {
|
|
|
|
|
|
newCreditLimit := advertiser.CreditLimit + newBalance
|
|
|
|
|
|
newBalance = 0
|
|
|
|
|
|
|
|
|
|
|
|
// 更新授信额度
|
|
|
|
|
|
err = dao.Advertiser.UpdateCreditLimit(ctx, id, newCreditLimit)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 更新账户余额
|
|
|
|
|
|
err = dao.Advertiser.Update(ctx, &dto.UpdateAdvertiserReq{
|
|
|
|
|
|
Id: id,
|
|
|
|
|
|
AccountBalance: &newBalance,
|
|
|
|
|
|
})
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|