Files
sim-server/app/main/api/internal/logic/agent/createwithdrawlogic.go
2026-02-08 16:19:37 +08:00

140 lines
4.4 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package agent
import (
"context"
"database/sql"
"sim-server/app/main/api/internal/svc"
"sim-server/app/main/api/internal/types"
"sim-server/app/main/model"
"sim-server/common/ctxdata"
"sim-server/common/xerr"
"sim-server/pkg/lzkit/crypto"
"github.com/google/uuid"
"github.com/pkg/errors"
"github.com/zeromicro/go-zero/core/logx"
"github.com/zeromicro/go-zero/core/stores/sqlx"
)
type CreateWithdrawLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewCreateWithdrawLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CreateWithdrawLogic {
return &CreateWithdrawLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *CreateWithdrawLogic) CreateWithdraw(req *types.CreateWithdrawReq) (resp *types.CreateWithdrawResp, err error) {
// 1. 获取当前用户ID代理ID
userId, err := ctxdata.GetUidFromCtx(l.ctx)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取用户信息失败: %v", err)
}
// 2. 查询代理信息
agent, err := l.svcCtx.AgentModel.FindOneByUserId(l.ctx, userId)
if err != nil {
if errors.Is(err, model.ErrNotFound) {
return nil, errors.Wrap(xerr.NewErrCode(xerr.CUSTOM_ERROR), "您还不是代理,无法申请提现")
}
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询代理信息失败: %v", err)
}
// 3. 查询钱包信息
wallet, err := l.svcCtx.AgentWalletModel.FindOneByAgentId(l.ctx, agent.Id)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询钱包信息失败: %v", err)
}
// 4. 验证提现金额
if req.WithdrawAmount <= 0 {
return nil, errors.Wrap(xerr.NewErrCode(xerr.REUQEST_PARAM_ERROR), "提现金额必须大于0")
}
minWithdraw := 100.00 // 最低提现金额100元
if req.WithdrawAmount < minWithdraw {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.REUQEST_PARAM_ERROR), "最低提现金额为%.2f元", minWithdraw)
}
if wallet.Balance < req.WithdrawAmount {
return nil, errors.Wrap(xerr.NewErrCode(xerr.CUSTOM_ERROR), "可用余额不足")
}
// 5. 加密银行卡号
encryptedCardNumber, err := crypto.AesEncrypt([]byte(req.BankCardNumber), []byte(l.svcCtx.Config.Encrypt.SecretKey))
if err != nil {
logx.Errorf("加密银行卡号失败: %v", err)
return nil, errors.Wrap(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "加密银行卡号失败")
}
// 6. 生成提现记录ID
withdrawId := uuid.NewString()
// 7. 解密代理手机号(用于冗余存储)
agentMobile, err := crypto.DecryptMobile(agent.Mobile, l.svcCtx.Config.Encrypt.SecretKey)
if err != nil {
logx.Errorf("解密代理手机号失败: %v", err)
agentMobile = ""
}
// 8. 开启事务处理
err = l.svcCtx.AgentWalletModel.Trans(l.ctx, func(ctx context.Context, session sqlx.Session) error {
// 8.1 冻结提现金额
wallet.Balance -= req.WithdrawAmount
wallet.FrozenAmount += req.WithdrawAmount
// 使用版本号乐观锁更新
err := l.svcCtx.AgentWalletModel.UpdateWithVersion(ctx, session, wallet)
if err != nil {
return errors.Wrapf(err, "冻结金额失败")
}
// 8.2 创建提现记录
withdrawRecord := &model.AgentWithdraw{
Id: withdrawId,
AgentId: agent.Id,
WithdrawAmount: req.WithdrawAmount,
TaxAmount: 0.00,
ActualAmount: 0.00,
FrozenAmount: req.WithdrawAmount,
AccountName: req.AccountName,
BankCardNumber: req.BankCardNumber,
BankCardNumberEncrypted: sql.NullString{String: string(encryptedCardNumber), Valid: true},
BankBranch: sql.NullString{String: req.BankBranch, Valid: req.BankBranch != ""},
Status: 0,
}
// 冗余存储代理手机号和编码
if agentMobile != "" {
withdrawRecord.AgentMobile = sql.NullString{String: agentMobile, Valid: true}
}
if agent.AgentCode > 0 {
withdrawRecord.AgentCode = sql.NullInt64{Int64: agent.AgentCode, Valid: true}
}
_, err = l.svcCtx.AgentWithdrawModel.Insert(ctx, session, withdrawRecord)
if err != nil {
return errors.Wrapf(err, "创建提现记录失败")
}
return nil
})
if err != nil {
return nil, errors.Wrap(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), err.Error())
}
logx.Infof("代理 %s 申请提现成功,提现金额: %.2f", agent.Id, req.WithdrawAmount)
return &types.CreateWithdrawResp{
WithdrawId: withdrawId,
}, nil
}