拆分提现 Repository 文件职责
This commit is contained in:
@@ -0,0 +1,195 @@
|
||||
package withdrawal
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"hfb_sys/backend/internal/model"
|
||||
"hfb_sys/backend/internal/modules/wallet"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// 用户创建提现申请
|
||||
func (r *Repository) Create(ctx context.Context, userID uint64, req CreateWithdrawalRequest) (*WithdrawalDTO, error) {
|
||||
db := r.db.WithContext(ctx)
|
||||
// 验证收款账号
|
||||
var paymentAccount model.UserPaymentAccount
|
||||
if err := db.Where("id = ? AND user_id = ? AND status = ?", req.PaymentAccountID, userID, "active").
|
||||
First(&paymentAccount).Error; err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, errors.New("payment account not found")
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 计算手续费和实际到账金额(分)
|
||||
feeCent := int64(float64(req.AmountCent) * WithdrawalFeeRate)
|
||||
actualAmountCent := req.AmountCent - feeCent
|
||||
|
||||
// 生成提现单号
|
||||
withdrawNo, err := generateWithdrawNo()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 解密账号(用于存储快照)
|
||||
decryptedNo, err := r.decryptAccountNo(paymentAccount.AccountNo)
|
||||
if err != nil {
|
||||
decryptedNo = paymentAccount.AccountNo
|
||||
}
|
||||
|
||||
withdrawal := model.WithdrawalRequest{
|
||||
WithdrawNo: withdrawNo,
|
||||
UserID: userID,
|
||||
AmountCent: req.AmountCent,
|
||||
FeeCent: feeCent,
|
||||
ActualAmountCent: actualAmountCent,
|
||||
PaymentAccountID: &req.PaymentAccountID,
|
||||
AccountType: paymentAccount.AccountType,
|
||||
AccountName: paymentAccount.AccountName,
|
||||
AccountNo: maskAccountNo(decryptedNo, paymentAccount.AccountType),
|
||||
BankName: paymentAccount.BankName,
|
||||
BankBranch: paymentAccount.BankBranch,
|
||||
Status: "pending",
|
||||
}
|
||||
|
||||
// 事务处理
|
||||
err = db.Transaction(func(tx *gorm.DB) error {
|
||||
// 创建提现申请
|
||||
if err := tx.Create(&withdrawal).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 冻结用户余额
|
||||
if err := wallet.AppendEntries(tx, wallet.Entry{
|
||||
UserID: userID,
|
||||
Direction: "out",
|
||||
AmountCent: req.AmountCent,
|
||||
BalanceType: "available",
|
||||
BizType: "withdraw_freeze",
|
||||
BizNo: withdrawNo,
|
||||
Remark: "提现冻结",
|
||||
}, wallet.Entry{
|
||||
UserID: userID,
|
||||
Direction: "in",
|
||||
AmountCent: req.AmountCent,
|
||||
BalanceType: "frozen",
|
||||
BizType: "withdraw_freeze",
|
||||
BizNo: withdrawNo,
|
||||
Remark: "提现冻结",
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return r.FindByID(ctx, userID, withdrawal.ID)
|
||||
}
|
||||
|
||||
// 用户查询提现列表
|
||||
|
||||
// 用户查询提现列表
|
||||
func (r *Repository) List(ctx context.Context, userID uint64, page, pageSize int) (*PaginatedResult, error) {
|
||||
db := r.db.WithContext(ctx)
|
||||
var total int64
|
||||
if err := db.Model(&model.WithdrawalRequest{}).
|
||||
Where("user_id = ?", userID).
|
||||
Count(&total).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
offset := (page - 1) * pageSize
|
||||
var withdrawals []model.WithdrawalRequest
|
||||
if err := db.Where("user_id = ?", userID).
|
||||
Order("created_at DESC").
|
||||
Offset(offset).Limit(pageSize).
|
||||
Find(&withdrawals).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
items := make([]WithdrawalDTO, 0, len(withdrawals))
|
||||
for _, w := range withdrawals {
|
||||
items = append(items, toDTO(w))
|
||||
}
|
||||
|
||||
return &PaginatedResult{
|
||||
Items: items,
|
||||
Total: total,
|
||||
Page: page,
|
||||
PageSize: pageSize,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 用户查询提现详情
|
||||
|
||||
// 用户查询提现详情
|
||||
func (r *Repository) FindByID(ctx context.Context, userID, id uint64) (*WithdrawalDTO, error) {
|
||||
var withdrawal model.WithdrawalRequest
|
||||
if err := r.db.WithContext(ctx).Where("id = ? AND user_id = ?", id, userID).
|
||||
First(&withdrawal).Error; err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, ErrWithdrawalNotFound
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
dto := toDTO(withdrawal)
|
||||
return &dto, nil
|
||||
}
|
||||
|
||||
// 用户取消提现
|
||||
|
||||
// 用户取消提现
|
||||
func (r *Repository) Cancel(ctx context.Context, userID, id uint64) error {
|
||||
db := r.db.WithContext(ctx)
|
||||
var withdrawal model.WithdrawalRequest
|
||||
if err := db.Where("id = ? AND user_id = ?", id, userID).
|
||||
First(&withdrawal).Error; err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return ErrWithdrawalNotFound
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// 只有待审核状态可以取消
|
||||
if withdrawal.Status != "pending" {
|
||||
return ErrWithdrawalLocked
|
||||
}
|
||||
|
||||
return db.Transaction(func(tx *gorm.DB) error {
|
||||
// 更新状态
|
||||
if err := tx.Model(&withdrawal).Update("status", "cancelled").Error; err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 解冻余额
|
||||
if err := wallet.AppendEntries(tx, wallet.Entry{
|
||||
UserID: userID,
|
||||
Direction: "out",
|
||||
AmountCent: withdrawal.AmountCent,
|
||||
BalanceType: "frozen",
|
||||
BizType: "withdraw_cancel",
|
||||
BizNo: withdrawal.WithdrawNo,
|
||||
Remark: "用户取消提现",
|
||||
}, wallet.Entry{
|
||||
UserID: userID,
|
||||
Direction: "in",
|
||||
AmountCent: withdrawal.AmountCent,
|
||||
BalanceType: "available",
|
||||
BizType: "withdraw_cancel",
|
||||
BizNo: withdrawal.WithdrawNo,
|
||||
Remark: "用户取消提现",
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// 管理员查询提现列表
|
||||
Reference in New Issue
Block a user