140 lines
4.4 KiB
Go
140 lines
4.4 KiB
Go
|
|
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
|
|||
|
|
}
|