新功能(#41): 提现优化 — 收款方式选择 + 取消提现 + 收款码上传
Build docker and publish / build (20.15.1) (push) Failing after 8m37s
Build docker and publish / build (20.15.1) (push) Failing after 8m37s
Co-authored-by: multica-agent <github@multica.ai>
This commit is contained in:
@@ -235,6 +235,7 @@ type (
|
|||||||
Size int `form:"size"`
|
Size int `form:"size"`
|
||||||
UserId *int64 `form:"user_id,omitempty"`
|
UserId *int64 `form:"user_id,omitempty"`
|
||||||
Status *uint8 `form:"status,omitempty"`
|
Status *uint8 `form:"status,omitempty"`
|
||||||
|
Method *uint8 `form:"method,omitempty"`
|
||||||
}
|
}
|
||||||
GetWithdrawalListResponse {
|
GetWithdrawalListResponse {
|
||||||
List []WithdrawalLog `json:"list"`
|
List []WithdrawalLog `json:"list"`
|
||||||
|
|||||||
+15
-2
@@ -109,8 +109,11 @@ type (
|
|||||||
Rules []string `json:"rules" validate:"required"`
|
Rules []string `json:"rules" validate:"required"`
|
||||||
}
|
}
|
||||||
CommissionWithdrawRequest {
|
CommissionWithdrawRequest {
|
||||||
Amount int64 `json:"amount"`
|
Amount int64 `json:"amount"`
|
||||||
Content string `json:"content"`
|
Content string `json:"content"`
|
||||||
|
Method uint8 `json:"method" validate:"oneof=0 1 2 3"`
|
||||||
|
Account string `json:"account,omitempty"`
|
||||||
|
QrCodeUrl string `json:"qr_code_url,omitempty"`
|
||||||
}
|
}
|
||||||
WithdrawalLog {
|
WithdrawalLog {
|
||||||
Id int64 `json:"id"`
|
Id int64 `json:"id"`
|
||||||
@@ -119,9 +122,15 @@ type (
|
|||||||
Content string `json:"content"`
|
Content string `json:"content"`
|
||||||
Status uint8 `json:"status"`
|
Status uint8 `json:"status"`
|
||||||
Reason string `json:"reason,omitempty"`
|
Reason string `json:"reason,omitempty"`
|
||||||
|
Method uint8 `json:"method"`
|
||||||
|
Account string `json:"account"`
|
||||||
|
QrCodeUrl string `json:"qr_code_url"`
|
||||||
CreatedAt int64 `json:"created_at"`
|
CreatedAt int64 `json:"created_at"`
|
||||||
UpdatedAt int64 `json:"updated_at"`
|
UpdatedAt int64 `json:"updated_at"`
|
||||||
}
|
}
|
||||||
|
CancelWithdrawalRequest {
|
||||||
|
WithdrawalId int64 `json:"withdrawal_id" validate:"required,gt=0"`
|
||||||
|
}
|
||||||
QueryWithdrawalLogListRequest {
|
QueryWithdrawalLogListRequest {
|
||||||
Page int `form:"page"`
|
Page int `form:"page"`
|
||||||
Size int `form:"size"`
|
Size int `form:"size"`
|
||||||
@@ -352,6 +361,10 @@ service ppanel {
|
|||||||
@handler CommissionWithdraw
|
@handler CommissionWithdraw
|
||||||
post /commission_withdraw (CommissionWithdrawRequest) returns (WithdrawalLog)
|
post /commission_withdraw (CommissionWithdrawRequest) returns (WithdrawalLog)
|
||||||
|
|
||||||
|
@doc "Cancel pending withdrawal"
|
||||||
|
@handler CancelWithdrawal
|
||||||
|
post /withdrawal_cancel (CancelWithdrawalRequest) returns (WithdrawalLog)
|
||||||
|
|
||||||
@doc "Query Withdrawal Log"
|
@doc "Query Withdrawal Log"
|
||||||
@handler QueryWithdrawalLog
|
@handler QueryWithdrawalLog
|
||||||
get /withdrawal_log (QueryWithdrawalLogListRequest) returns (QueryWithdrawalLogListResponse)
|
get /withdrawal_log (QueryWithdrawalLogListRequest) returns (QueryWithdrawalLogListResponse)
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
ALTER TABLE `withdrawals`
|
||||||
|
DROP COLUMN `qr_code_url`,
|
||||||
|
DROP COLUMN `account`,
|
||||||
|
DROP COLUMN `method`;
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
ALTER TABLE `withdrawals`
|
||||||
|
ADD COLUMN `method` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '收款方式 0:其他 1:支付宝 2:微信 3:银行卡' AFTER `content`,
|
||||||
|
ADD COLUMN `account` VARCHAR(255) NOT NULL DEFAULT '' COMMENT '收款账号' AFTER `method`,
|
||||||
|
ADD COLUMN `qr_code_url` VARCHAR(500) NOT NULL DEFAULT '' COMMENT '收款码图片URL' AFTER `account`;
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package user
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/perfect-panel/server/internal/logic/public/user"
|
||||||
|
"github.com/perfect-panel/server/internal/svc"
|
||||||
|
"github.com/perfect-panel/server/internal/types"
|
||||||
|
"github.com/perfect-panel/server/pkg/result"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Cancel Withdrawal
|
||||||
|
func CancelWithdrawalHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) {
|
||||||
|
return func(c *gin.Context) {
|
||||||
|
var req types.CancelWithdrawalRequest
|
||||||
|
_ = c.ShouldBind(&req)
|
||||||
|
validateErr := svcCtx.Validate(&req)
|
||||||
|
if validateErr != nil {
|
||||||
|
result.ParamErrorResult(c, validateErr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
l := user.NewCancelWithdrawalLogic(c.Request.Context(), svcCtx)
|
||||||
|
resp, err := l.CancelWithdrawal(&req)
|
||||||
|
result.HttpResult(c, resp, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1059,6 +1059,9 @@ func RegisterHandlers(router *gin.Engine, serverCtx *svc.ServiceContext) {
|
|||||||
// Commission Withdraw
|
// Commission Withdraw
|
||||||
publicUserGroupRouter.POST("/commission_withdraw", publicUser.CommissionWithdrawHandler(serverCtx))
|
publicUserGroupRouter.POST("/commission_withdraw", publicUser.CommissionWithdrawHandler(serverCtx))
|
||||||
|
|
||||||
|
// Cancel Withdrawal
|
||||||
|
publicUserGroupRouter.POST("/withdrawal_cancel", publicUser.CancelWithdrawalHandler(serverCtx))
|
||||||
|
|
||||||
// Delete Current User Account
|
// Delete Current User Account
|
||||||
publicUserGroupRouter.DELETE("/current_user_account", publicUser.DeleteCurrentUserAccountHandler(serverCtx))
|
publicUserGroupRouter.DELETE("/current_user_account", publicUser.DeleteCurrentUserAccountHandler(serverCtx))
|
||||||
|
|
||||||
|
|||||||
@@ -42,6 +42,9 @@ func (l *GetWithdrawalListLogic) GetWithdrawalList(req *types.GetWithdrawalListR
|
|||||||
if req.Status != nil {
|
if req.Status != nil {
|
||||||
query = query.Where("status = ?", *req.Status)
|
query = query.Where("status = ?", *req.Status)
|
||||||
}
|
}
|
||||||
|
if req.Method != nil {
|
||||||
|
query = query.Where("method = ?", *req.Method)
|
||||||
|
}
|
||||||
|
|
||||||
var total int64
|
var total int64
|
||||||
if err := query.Count(&total).Error; err != nil {
|
if err := query.Count(&total).Error; err != nil {
|
||||||
@@ -62,6 +65,9 @@ func (l *GetWithdrawalListLogic) GetWithdrawalList(req *types.GetWithdrawalListR
|
|||||||
Content: row.Content,
|
Content: row.Content,
|
||||||
Status: row.Status,
|
Status: row.Status,
|
||||||
Reason: row.Reason,
|
Reason: row.Reason,
|
||||||
|
Method: row.Method,
|
||||||
|
Account: row.Account,
|
||||||
|
QrCodeUrl: row.QrCodeUrl,
|
||||||
CreatedAt: row.CreatedAt.UnixMilli(),
|
CreatedAt: row.CreatedAt.UnixMilli(),
|
||||||
UpdatedAt: row.UpdatedAt.UnixMilli(),
|
UpdatedAt: row.UpdatedAt.UnixMilli(),
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -37,9 +37,9 @@ func approveWithdrawal(ctx context.Context, svcCtx *svc.ServiceContext, withdraw
|
|||||||
}
|
}
|
||||||
|
|
||||||
if err := tx.Model(&usermodel.Withdrawal{}).
|
if err := tx.Model(&usermodel.Withdrawal{}).
|
||||||
Where("id = ? AND status = 0", withdrawalID).
|
Where("id = ? AND status = ?", withdrawalID, usermodel.WithdrawalStatusPending).
|
||||||
Updates(map[string]interface{}{
|
Updates(map[string]interface{}{
|
||||||
"status": 1,
|
"status": usermodel.WithdrawalStatusApproved,
|
||||||
"reason": "",
|
"reason": "",
|
||||||
}).Error; err != nil {
|
}).Error; err != nil {
|
||||||
return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseUpdateError), "approve withdrawal failed: %v", err)
|
return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseUpdateError), "approve withdrawal failed: %v", err)
|
||||||
@@ -80,9 +80,9 @@ func rejectWithdrawal(ctx context.Context, svcCtx *svc.ServiceContext, withdrawa
|
|||||||
// Commission was NOT deducted at application time under the new logic,
|
// Commission was NOT deducted at application time under the new logic,
|
||||||
// so rejection requires no refund — only a status update.
|
// so rejection requires no refund — only a status update.
|
||||||
return tx.Model(&usermodel.Withdrawal{}).
|
return tx.Model(&usermodel.Withdrawal{}).
|
||||||
Where("id = ? AND status = 0", withdrawalID).
|
Where("id = ? AND status = ?", withdrawalID, usermodel.WithdrawalStatusPending).
|
||||||
Updates(map[string]interface{}{
|
Updates(map[string]interface{}{
|
||||||
"status": 2,
|
"status": usermodel.WithdrawalStatusRejected,
|
||||||
"reason": reason,
|
"reason": reason,
|
||||||
}).Error
|
}).Error
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ func LoadPendingWithdrawalForUpdate(ctx context.Context, tx *gorm.DB, withdrawal
|
|||||||
First(&withdrawal).Error; err != nil {
|
First(&withdrawal).Error; err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if withdrawal.Status != 0 {
|
if withdrawal.Status != usermodel.WithdrawalStatusPending {
|
||||||
return nil, errors.New("withdrawal status invalid")
|
return nil, errors.New("withdrawal status invalid")
|
||||||
}
|
}
|
||||||
return &withdrawal, nil
|
return &withdrawal, nil
|
||||||
|
|||||||
@@ -0,0 +1,89 @@
|
|||||||
|
package user
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
logicCommon "github.com/perfect-panel/server/internal/logic/common"
|
||||||
|
"github.com/perfect-panel/server/internal/model/log"
|
||||||
|
"github.com/perfect-panel/server/internal/model/user"
|
||||||
|
"github.com/perfect-panel/server/internal/svc"
|
||||||
|
"github.com/perfect-panel/server/internal/types"
|
||||||
|
"github.com/perfect-panel/server/pkg/constant"
|
||||||
|
"github.com/perfect-panel/server/pkg/logger"
|
||||||
|
"github.com/perfect-panel/server/pkg/xerr"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CancelWithdrawalLogic struct {
|
||||||
|
logger.Logger
|
||||||
|
ctx context.Context
|
||||||
|
svcCtx *svc.ServiceContext
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewCancelWithdrawalLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CancelWithdrawalLogic {
|
||||||
|
return &CancelWithdrawalLogic{
|
||||||
|
Logger: logger.WithContext(ctx),
|
||||||
|
ctx: ctx,
|
||||||
|
svcCtx: svcCtx,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *CancelWithdrawalLogic) CancelWithdrawal(req *types.CancelWithdrawalRequest) (resp *types.WithdrawalLog, err error) {
|
||||||
|
u, ok := l.ctx.Value(constant.CtxKeyUser).(*user.User)
|
||||||
|
if !ok {
|
||||||
|
l.Error("current user is not found in context")
|
||||||
|
return nil, errors.Wrapf(xerr.NewErrCode(xerr.InvalidAccess), "Invalid Access")
|
||||||
|
}
|
||||||
|
|
||||||
|
var withdrawal *user.Withdrawal
|
||||||
|
err = l.svcCtx.DB.WithContext(l.ctx).Transaction(func(tx *gorm.DB) error {
|
||||||
|
var txErr error
|
||||||
|
withdrawal, txErr = logicCommon.LoadPendingWithdrawalForUpdate(l.ctx, tx, req.WithdrawalId)
|
||||||
|
if txErr != nil {
|
||||||
|
if txErr.Error() == "withdrawal status invalid" {
|
||||||
|
return errors.Wrapf(xerr.NewErrCode(xerr.WithdrawalStatusInvalid), "withdrawal %d is not in pending state", req.WithdrawalId)
|
||||||
|
}
|
||||||
|
return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "load withdrawal failed: %v", txErr)
|
||||||
|
}
|
||||||
|
|
||||||
|
if withdrawal.UserId != u.Id {
|
||||||
|
return errors.Wrapf(xerr.NewErrCode(xerr.PermissionDenied), "user %d cannot cancel withdrawal belonging to user %d", u.Id, withdrawal.UserId)
|
||||||
|
}
|
||||||
|
|
||||||
|
if txErr = tx.Model(&user.Withdrawal{}).
|
||||||
|
Where("id = ? AND status = ?", req.WithdrawalId, user.WithdrawalStatusPending).
|
||||||
|
Update("status", user.WithdrawalStatusCancelled).Error; txErr != nil {
|
||||||
|
return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseUpdateError), "cancel withdrawal failed: %v", txErr)
|
||||||
|
}
|
||||||
|
|
||||||
|
if txErr = l.svcCtx.UserModel.UpdateCommission(l.ctx, withdrawal.UserId, withdrawal.Amount, tx); txErr != nil {
|
||||||
|
return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseUpdateError), "refund commission failed: %v", txErr)
|
||||||
|
}
|
||||||
|
|
||||||
|
if txErr = logicCommon.WriteCommissionLog(tx, withdrawal.UserId, log.CommissionTypeWithdrawCancel, withdrawal.Amount, ""); txErr != nil {
|
||||||
|
return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseInsertError), "write commission log failed: %v", txErr)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
_ = l.svcCtx.UserModel.ClearUserCache(l.ctx, u)
|
||||||
|
|
||||||
|
return &types.WithdrawalLog{
|
||||||
|
Id: withdrawal.Id,
|
||||||
|
UserId: withdrawal.UserId,
|
||||||
|
Amount: withdrawal.Amount,
|
||||||
|
Content: withdrawal.Content,
|
||||||
|
Status: user.WithdrawalStatusCancelled,
|
||||||
|
Reason: "",
|
||||||
|
Method: withdrawal.Method,
|
||||||
|
Account: withdrawal.Account,
|
||||||
|
QrCodeUrl: withdrawal.QrCodeUrl,
|
||||||
|
CreatedAt: withdrawal.CreatedAt.UnixMilli(),
|
||||||
|
UpdatedAt: withdrawal.UpdatedAt.UnixMilli(),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
@@ -35,12 +35,28 @@ func (l *CommissionWithdrawLogic) CommissionWithdraw(req *types.CommissionWithdr
|
|||||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.InvalidAccess), "Invalid Access")
|
return nil, errors.Wrapf(xerr.NewErrCode(xerr.InvalidAccess), "Invalid Access")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Validate payment method fields
|
||||||
|
switch req.Method {
|
||||||
|
case user.WithdrawalMethodAlipay, user.WithdrawalMethodWechat:
|
||||||
|
if req.QrCodeUrl == "" {
|
||||||
|
return nil, errors.Wrapf(xerr.NewErrCode(xerr.InvalidParams), "qr_code_url is required for method %d", req.Method)
|
||||||
|
}
|
||||||
|
case user.WithdrawalMethodBank:
|
||||||
|
if req.Account == "" {
|
||||||
|
return nil, errors.Wrapf(xerr.NewErrCode(xerr.InvalidParams), "account is required for bank transfer")
|
||||||
|
}
|
||||||
|
default: // WithdrawalMethodOther
|
||||||
|
if req.Account == "" && req.Content == "" {
|
||||||
|
return nil, errors.Wrapf(xerr.NewErrCode(xerr.InvalidParams), "account or content is required for other methods")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Sum all pending (status=0) withdrawals to compute available balance.
|
// Sum all pending (status=0) withdrawals to compute available balance.
|
||||||
// Available = commission - pendingTotal; commission is only deducted on approval.
|
// Available = commission - pendingTotal; commission is only deducted on approval.
|
||||||
var pendingTotal int64
|
var pendingTotal int64
|
||||||
if err = l.svcCtx.DB.WithContext(l.ctx).
|
if err = l.svcCtx.DB.WithContext(l.ctx).
|
||||||
Model(&user.Withdrawal{}).
|
Model(&user.Withdrawal{}).
|
||||||
Where("user_id = ? AND status = 0", u.Id).
|
Where("user_id = ? AND status = ?", u.Id, user.WithdrawalStatusPending).
|
||||||
Select("COALESCE(SUM(amount), 0)").
|
Select("COALESCE(SUM(amount), 0)").
|
||||||
Scan(&pendingTotal).Error; err != nil {
|
Scan(&pendingTotal).Error; err != nil {
|
||||||
l.Errorf("Failed to query pending withdrawals for user %d: %v", u.Id, err)
|
l.Errorf("Failed to query pending withdrawals for user %d: %v", u.Id, err)
|
||||||
@@ -56,11 +72,14 @@ func (l *CommissionWithdrawLogic) CommissionWithdraw(req *types.CommissionWithdr
|
|||||||
var w user.Withdrawal
|
var w user.Withdrawal
|
||||||
err = l.svcCtx.DB.WithContext(l.ctx).Transaction(func(tx *gorm.DB) error {
|
err = l.svcCtx.DB.WithContext(l.ctx).Transaction(func(tx *gorm.DB) error {
|
||||||
w = user.Withdrawal{
|
w = user.Withdrawal{
|
||||||
UserId: u.Id,
|
UserId: u.Id,
|
||||||
Amount: req.Amount,
|
Amount: req.Amount,
|
||||||
Content: req.Content,
|
Content: req.Content,
|
||||||
Status: 0,
|
Status: user.WithdrawalStatusPending,
|
||||||
Reason: "",
|
Reason: "",
|
||||||
|
Method: req.Method,
|
||||||
|
Account: req.Account,
|
||||||
|
QrCodeUrl: req.QrCodeUrl,
|
||||||
}
|
}
|
||||||
return tx.Create(&w).Error
|
return tx.Create(&w).Error
|
||||||
})
|
})
|
||||||
@@ -70,11 +89,15 @@ func (l *CommissionWithdrawLogic) CommissionWithdraw(req *types.CommissionWithdr
|
|||||||
}
|
}
|
||||||
|
|
||||||
return &types.WithdrawalLog{
|
return &types.WithdrawalLog{
|
||||||
|
Id: w.Id,
|
||||||
UserId: u.Id,
|
UserId: u.Id,
|
||||||
Amount: req.Amount,
|
Amount: req.Amount,
|
||||||
Content: req.Content,
|
Content: req.Content,
|
||||||
Status: 0,
|
Status: user.WithdrawalStatusPending,
|
||||||
Reason: "",
|
Reason: "",
|
||||||
|
Method: req.Method,
|
||||||
|
Account: req.Account,
|
||||||
|
QrCodeUrl: req.QrCodeUrl,
|
||||||
CreatedAt: w.CreatedAt.UnixMilli(),
|
CreatedAt: w.CreatedAt.UnixMilli(),
|
||||||
UpdatedAt: w.UpdatedAt.UnixMilli(),
|
UpdatedAt: w.UpdatedAt.UnixMilli(),
|
||||||
}, nil
|
}, nil
|
||||||
|
|||||||
@@ -64,6 +64,9 @@ func (l *QueryWithdrawalLogLogic) QueryWithdrawalLog(req *types.QueryWithdrawalL
|
|||||||
Content: row.Content,
|
Content: row.Content,
|
||||||
Status: row.Status,
|
Status: row.Status,
|
||||||
Reason: row.Reason,
|
Reason: row.Reason,
|
||||||
|
Method: row.Method,
|
||||||
|
Account: row.Account,
|
||||||
|
QrCodeUrl: row.QrCodeUrl,
|
||||||
CreatedAt: row.CreatedAt.UnixMilli(),
|
CreatedAt: row.CreatedAt.UnixMilli(),
|
||||||
UpdatedAt: row.UpdatedAt.UnixMilli(),
|
UpdatedAt: row.UpdatedAt.UnixMilli(),
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ const (
|
|||||||
CommissionTypeAdjust uint16 = 335 // Admin Adjust
|
CommissionTypeAdjust uint16 = 335 // Admin Adjust
|
||||||
CommissionTypeConvertBalance uint16 = 336 // Convert to Balance
|
CommissionTypeConvertBalance uint16 = 336 // Convert to Balance
|
||||||
CommissionTypeWithdrawReject uint16 = 337 // Withdraw rejected refund
|
CommissionTypeWithdrawReject uint16 = 337 // Withdraw rejected refund
|
||||||
|
CommissionTypeWithdrawCancel uint16 = 338 // 用户取消提现退佣金
|
||||||
GiftTypeIncrease uint16 = 341 // Increase
|
GiftTypeIncrease uint16 = 341 // Increase
|
||||||
GiftTypeReduce uint16 = 342 // Reduce
|
GiftTypeReduce uint16 = 342 // Reduce
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -167,8 +167,11 @@ type Withdrawal struct {
|
|||||||
UserId int64 `gorm:"index:idx_user_id;not null;comment:User ID"`
|
UserId int64 `gorm:"index:idx_user_id;not null;comment:User ID"`
|
||||||
Amount int64 `gorm:"not null;comment:Withdrawal Amount"`
|
Amount int64 `gorm:"not null;comment:Withdrawal Amount"`
|
||||||
Content string `gorm:"type:text;comment:Withdrawal Content"`
|
Content string `gorm:"type:text;comment:Withdrawal Content"`
|
||||||
Status uint8 `gorm:"type:tinyint(1);default:0;comment:Withdrawal Status: 0: Pending 1: Approved 2: Rejected"`
|
Status uint8 `gorm:"type:tinyint(1);default:0;comment:Withdrawal Status: 0: Pending 1: Approved 2: Rejected 3: Cancelled"`
|
||||||
Reason string `gorm:"type:varchar(500);default:'';comment:Rejection Reason"`
|
Reason string `gorm:"type:varchar(500);default:'';comment:Rejection Reason"`
|
||||||
|
Method uint8 `gorm:"type:tinyint(1);default:0;comment:收款方式 0:其他 1:支付宝 2:微信 3:银行卡"`
|
||||||
|
Account string `gorm:"type:varchar(255);default:'';comment:收款账号"`
|
||||||
|
QrCodeUrl string `gorm:"type:varchar(500);default:'';comment:收款码图片URL"`
|
||||||
CreatedAt time.Time `gorm:"<-:create;comment:Creation Time"`
|
CreatedAt time.Time `gorm:"<-:create;comment:Creation Time"`
|
||||||
UpdatedAt time.Time `gorm:"comment:Update Time"`
|
UpdatedAt time.Time `gorm:"comment:Update Time"`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package user
|
||||||
|
|
||||||
|
const (
|
||||||
|
WithdrawalStatusPending uint8 = 0 // 待审核
|
||||||
|
WithdrawalStatusApproved uint8 = 1 // 已通过
|
||||||
|
WithdrawalStatusRejected uint8 = 2 // 已拒绝
|
||||||
|
WithdrawalStatusCancelled uint8 = 3 // 已取消(用户自行撤回)
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
WithdrawalMethodOther uint8 = 0 // 其他
|
||||||
|
WithdrawalMethodAlipay uint8 = 1 // 支付宝
|
||||||
|
WithdrawalMethodWechat uint8 = 2 // 微信
|
||||||
|
WithdrawalMethodBank uint8 = 3 // 银行卡
|
||||||
|
)
|
||||||
+13
-2
@@ -296,8 +296,11 @@ type CommissionLog struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type CommissionWithdrawRequest struct {
|
type CommissionWithdrawRequest struct {
|
||||||
Amount int64 `json:"amount"`
|
Amount int64 `json:"amount"`
|
||||||
Content string `json:"content"`
|
Content string `json:"content"`
|
||||||
|
Method uint8 `json:"method" validate:"oneof=0 1 2 3"`
|
||||||
|
Account string `json:"account,omitempty"`
|
||||||
|
QrCodeUrl string `json:"qr_code_url,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ConnectionRecords struct {
|
type ConnectionRecords struct {
|
||||||
@@ -2315,6 +2318,10 @@ type QueryUserSubscribeNodeListResponse struct {
|
|||||||
List []UserSubscribeInfo `json:"list"`
|
List []UserSubscribeInfo `json:"list"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type CancelWithdrawalRequest struct {
|
||||||
|
WithdrawalId int64 `json:"withdrawal_id" validate:"required,gt=0"`
|
||||||
|
}
|
||||||
|
|
||||||
type QueryWithdrawalLogListRequest struct {
|
type QueryWithdrawalLogListRequest struct {
|
||||||
Page int `form:"page"`
|
Page int `form:"page"`
|
||||||
Size int `form:"size"`
|
Size int `form:"size"`
|
||||||
@@ -2330,6 +2337,7 @@ type GetWithdrawalListRequest struct {
|
|||||||
Size int `form:"size"`
|
Size int `form:"size"`
|
||||||
UserId *int64 `form:"user_id,omitempty"`
|
UserId *int64 `form:"user_id,omitempty"`
|
||||||
Status *uint8 `form:"status,omitempty"`
|
Status *uint8 `form:"status,omitempty"`
|
||||||
|
Method *uint8 `form:"method,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type GetWithdrawalListResponse struct {
|
type GetWithdrawalListResponse struct {
|
||||||
@@ -3648,6 +3656,9 @@ type WithdrawalLog struct {
|
|||||||
Content string `json:"content"`
|
Content string `json:"content"`
|
||||||
Status uint8 `json:"status"`
|
Status uint8 `json:"status"`
|
||||||
Reason string `json:"reason,omitempty"`
|
Reason string `json:"reason,omitempty"`
|
||||||
|
Method uint8 `json:"method"`
|
||||||
|
Account string `json:"account"`
|
||||||
|
QrCodeUrl string `json:"qr_code_url"`
|
||||||
CreatedAt int64 `json:"created_at"`
|
CreatedAt int64 `json:"created_at"`
|
||||||
UpdatedAt int64 `json:"updated_at"`
|
UpdatedAt int64 `json:"updated_at"`
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user