1、确认提现

This commit is contained in:
2025-02-25 18:34:20 +08:00
parent 32ba6262cc
commit 3f85158eed
12 changed files with 364 additions and 83 deletions

View File

@ -191,3 +191,51 @@ func (e MemberWithdrawalLog) Delete(c *gin.Context) {
}
e.OK(req.GetId(), "删除成功")
}
// 审核提现
func (e MemberWithdrawalLog) Process(c *gin.Context) {
s := service.MemberWithdrawalLog{}
req := dto.MemberWithdrawalLogApprovedReq{}
err := e.MakeContext(c).
MakeOrm().
Bind(&req).
MakeService(&s.Service).
Errors
if err != nil {
e.Logger.Error(err)
e.Error(500, err, err.Error())
return
}
err = s.Process(&req)
if err != nil {
e.Error(500, err, fmt.Sprintf("审核提现失败,\r\n失败信息 %s", err.Error()))
return
}
e.OK(nil, "确认提现成功")
}
// 确认提现
func (e MemberWithdrawalLog) Confirm(c *gin.Context) {
s := service.MemberWithdrawalLog{}
req := dto.MemberWithdrawalLogConfirmReq{}
err := e.MakeContext(c).
MakeOrm().
Bind(&req).
MakeService(&s.Service).
Errors
if err != nil {
e.Logger.Error(err)
e.Error(500, err, err.Error())
return
}
err = s.Confirm(&req)
if err != nil {
e.Error(500, err, fmt.Sprintf("确认到账失败,\r\n失败信息 %s", err.Error()))
return
}
e.OK(nil, "确认提现成功")
}

View File

@ -614,11 +614,23 @@ func (e LineUserApi) Logout(c *gin.Context) {
// 查询个人资产
func (e LineUserApi) GetProperty(c *gin.Context) {
s := service.LineUser{}
err := e.MakeContext(c).
MakeOrm().
MakeService(&s.Service).
Errors
if err != nil {
e.Logger.Error(err)
e.Error(statuscode.ServerError, nil, sysstatuscode.GetStatusCodeDescription(c, statuscode.ServerError))
}
var data dto.LineUserPropertyResp
userId := common.GetUserId(c)
code := s.GetProperty(userId, &data)
if code != statuscode.OK {
// e.Logger.Error(err)
e.Error(code, nil, sysstatuscode.GetStatusCodeDescription(c, code))
}
e.OK(data, "success")
}

View File

@ -34,6 +34,7 @@ func (e MemberWithdrawalLog) GetPage(c *gin.Context) {
var count int64
var list []dto.MemberWithdrawalLogResp
req.UserId = common.GetUserId(c)
code := s.GetPage(&req, &list, &count)
if code != statuscode.OK {

View File

@ -48,6 +48,8 @@ func frontedRegisterLinUserRouter(v1 *gin.RouterGroup) {
r.POST("/opStatus", middleware.FrontedAuth, api.OpenStatus) //开启或者关闭状态
r.DELETE("/logout", middleware.FrontedAuth, api.Logout) //退出登录
r.GET("/exchange-balance", middleware.FrontedAuth, api.GetProperty) //合约用户交易所u资产
//充值
r.POST("/notify", api.Notify) //uDun回调
r.POST("/rechargeNetworkList", middleware.FrontedAuth, api.RechargeNetworkList) //充值 通过充值币种选择主网络

View File

@ -344,3 +344,10 @@ type InviteLogResp struct {
NickName string `json:"nickName"`
Childs []InviteLogResp `json:"childs"`
}
type LineUserPropertyResp struct {
SpotTotalAmount decimal.Decimal `json:"spotTotalAmount"` //现货U总资产
SpotFreeAmount decimal.Decimal `json:"spotFreeAmount"` //现货U可用余额
FuturesTotalAmount decimal.Decimal `json:"futuresTotalAmount"` //合约U总资产
FuturesFreeAmount decimal.Decimal `json:"futuresFreeAmount"` //合约U可用余额
}

View File

@ -180,4 +180,17 @@ type MemberWithdrawalLogResp struct {
Status string `json:"status"`
CreateTimeUnix int64 `json:"createTime"`
ConfirmTimeUnix int64 `json:"confirmTime"`
Remark string `json:"remark"`
}
type MemberWithdrawalLogApprovedReq struct {
Id int `json:"id"`
Approval int `json:"approval"` // 1:通过 2:拒绝
Remark string `json:"remark" comment:"备注" `
}
type MemberWithdrawalLogConfirmReq struct {
Id int `json:"id"`
ConfirmVal int `json:"confirmVal"` // 1:成功 2:失败
Remark string `json:"remark"`
}

View File

@ -21,6 +21,7 @@ import (
"time"
"github.com/bytedance/sonic"
"github.com/go-admin-team/go-admin-core/logger"
"github.com/go-admin-team/go-admin-core/sdk/service"
"github.com/shopspring/decimal"
"go.uber.org/zap"
@ -491,6 +492,7 @@ func (e *LineUser) PreOrder(userId int, req *dto.VtsRechargePreOrderReq, resp *d
return nil
}
// 模拟支付回调
func (e *LineUser) CallBack(req *coingatedto.OrderCallBackResponse) error {
token, err := aeshelper.PswEncrypt(fmt.Sprintf("%s:%s:%s", req.OrderID, utility.StringAsDecimal(req.PriceAmount), req.PriceCurrency))
@ -562,3 +564,21 @@ func (e *LineUser) CallBack(req *coingatedto.OrderCallBackResponse) error {
return err
}
// 获取用户资产
func (e *LineUser) GetProperty(userId int, data *dto.LineUserPropertyResp) int {
lineApiUser := models.LineApiUser{}
if err := e.Orm.Model(&lineApiUser).Where("user_id=?", userId).First(&lineApiUser).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return statuscode.UserApiUserNotBind
}
logger.Errorf("用户id %v 获取api用户失败:%v", userId, err)
return statuscode.ServerError
}
binanceservice.GetSpotUProperty(lineApiUser, data)
binanceservice.GetFuturesUProperty(lineApiUser, data)
return statuscode.OK
}

View File

@ -2,6 +2,7 @@ package service
import (
"errors"
"time"
"github.com/go-admin-team/go-admin-core/sdk/service"
"gorm.io/gorm"
@ -9,6 +10,7 @@ import (
"go-admin/app/admin/models"
"go-admin/app/admin/service/dto"
"go-admin/common/actions"
memberwithdrawallogstatus "go-admin/common/const/dicts/member_withdrawal_log_status"
cDto "go-admin/common/dto"
)
@ -107,3 +109,61 @@ func (e *MemberWithdrawalLog) Remove(d *dto.MemberWithdrawalLogDeleteReq, p *act
}
return nil
}
// 审核
func (e *MemberWithdrawalLog) Process(req *dto.MemberWithdrawalLogApprovedReq) error {
data := models.MemberWithdrawalLog{}
if err := e.Orm.Model(&data).Where("id =?", req.Id).First(&data).Error; err != nil {
return err
}
if data.Status != memberwithdrawallogstatus.PENDING {
return errors.New("已审核请勿重复审核")
}
if req.Approval == 1 {
data.Status = memberwithdrawallogstatus.APPROVED
} else {
data.Status = memberwithdrawallogstatus.REJECTED
}
if err := e.Orm.Model(&data).
Where("status =?", memberwithdrawallogstatus.PENDING).
Updates(map[string]interface{}{"status": data.Status}).Error; err != nil {
return err
}
return nil
}
// 确认到账
func (e *MemberWithdrawalLog) Confirm(req *dto.MemberWithdrawalLogConfirmReq) error {
data := models.MemberWithdrawalLog{}
if err := e.Orm.Model(&data).Where("id =?", req.Id).First(&data).Error; err != nil {
return err
}
if data.Status != memberwithdrawallogstatus.APPROVED {
return errors.New("未审核请勿确认到账")
}
err := e.Orm.Transaction(func(tx *gorm.DB) error {
if err := e.Orm.Model(&data).
Where("status =?", memberwithdrawallogstatus.APPROVED).
Updates(map[string]interface{}{"status": data.Status, "confirm_time": time.Now()}).Error; err != nil {
return err
}
totalAmount := data.Amount.Add(data.Fee)
if err := tx.Exec("UPDATE member_balance set total_amount=total_amount-?,frozen_amount=frozen_amount-? where user_id=? and total_amount>=? and frozen_amount>=?", totalAmount, totalAmount, data.UserId, totalAmount, totalAmount).Error; err != nil {
return err
}
return nil
})
return err
}

View File

@ -8,4 +8,5 @@ const (
NetworkUnAvailable // 网络不可用
CanNotCancel // 无法取消
RenwalConfigDisabled // 续费配置不可用
UserApiUserNotBind // 用户未授权
)

View File

@ -74,3 +74,25 @@ type BinanceFutureOrder struct {
SelfTradePreventionMode string `json:"selfTradePreventionMode"` // 订单自成交保护模式
GoodTillDate int64 `json:"goodTillDate"` // 订单TIF为GTD时的自动取消时间
}
type BinanceSpotAccount struct {
Balances []BinanceSpotBalance `json:"balances"`
}
type BinanceSpotBalance struct {
Asset string `json:"asset"`
Free string `json:"free"`
Locked string `json:"locked"`
}
type BinanceFutureBalance struct {
AccountAlias string `json:"accountAlias"` // 账户唯一识别码
Asset string `json:"asset"` // 资产
Balance string `json:"balance"` // 总余额
CrossWalletBalance string `json:"crossWalletBalance"` // 全仓余额
CrossUnPnl string `json:"crossUnPnl"` // 全仓持仓未实现盈亏
AvailableBalance string `json:"availableBalance"` // 下单可用余额
MaxWithdrawAmount string `json:"maxWithdrawAmount"` // 最大可转出余额
MarginAvailable bool `json:"marginAvailable"` // 是否可用作联合保证金
UpdateTime int64 `json:"updateTime"` // 更新时间(时间戳)
}

View File

@ -4,6 +4,7 @@ import (
"errors"
"fmt"
DbModels "go-admin/app/admin/models"
"go-admin/app/admin/service/dto"
"go-admin/common/const/rediskey"
commondto "go-admin/common/dto"
"go-admin/common/global"
@ -588,3 +589,51 @@ func (e SpotRestApi) GetOrderByOrderSnLoop(symbol, ordersn string, apiUserInfo D
return result, err
}
// 获取现货U资产
func GetSpotUProperty(apiUserInfo DbModels.LineApiUser, data *dto.LineUserPropertyResp) error {
endpoint := "/api/v3/account"
params := map[string]string{
"omitZeroBalances": "true",
}
balanceResp := binancedto.BinanceSpotAccount{}
client := GetClient(&apiUserInfo)
body, code, err := client.SendSpotAuth(endpoint, "GET", params)
if err != nil || code != 200 {
log.Error("查询现货资产 参数:", params)
log.Error("查询现货资产 code:", code)
log.Error("查询现货资产 err:", err)
dataMap := make(map[string]interface{})
if err.Error() != "" {
if err := sonic.Unmarshal([]byte(err.Error()), &dataMap); err != nil {
return fmt.Errorf("api_id:%d 查询资产失败:%+v", apiUserInfo.Id, err.Error())
}
}
code, ok := dataMap["code"]
if ok {
return fmt.Errorf("api_id:%d 查询资产失败:%s", apiUserInfo.Id, ErrorMaps[code.(float64)])
}
if strings.Contains(err.Error(), "Unknown order sent.") {
return fmt.Errorf("api_id:%d 查询资产失败:%+v", apiUserInfo.Id, ErrorMaps[-2011])
}
return fmt.Errorf("api_id:%d 查询资产失败:%+v", apiUserInfo.Id, err.Error())
}
sonic.Unmarshal(body, &balanceResp)
if len(balanceResp.Balances) > 0 {
for _, item := range balanceResp.Balances {
if strings.ToUpper(item.Asset) == "USDT" {
free := utility.StrToDecimal(item.Free)
lock := utility.StrToDecimal(item.Locked)
data.SpotFreeAmount = utility.StrToDecimal(item.Free)
data.SpotTotalAmount = free.Add(lock)
}
}
}
return nil
}

View File

@ -1000,3 +1000,49 @@ func (e FutRestApi) GetOrderByOrderSnLoop(symbol, ordersn string, apiUserInfo Db
return result, err
}
// 获取合约U资产
func GetFuturesUProperty(apiUserInfo DbModels.LineApiUser, data *dto.LineUserPropertyResp) error {
endpoint := "/fapi/v3/balance"
params := map[string]string{
"recvWindow": "5000",
}
balanceResp := make([]binancedto.BinanceFutureBalance, 0)
client := GetClient(&apiUserInfo)
body, code, err := client.SendFuturesAuth(endpoint, "GET", params)
if err != nil || code != 200 {
log.Error("查询合约资产 参数:", params)
log.Error("查询合约资产 code:", code)
log.Error("查询合约资产 err:", err)
dataMap := make(map[string]interface{})
if err.Error() != "" {
if err := sonic.Unmarshal([]byte(err.Error()), &dataMap); err != nil {
return fmt.Errorf("api_id:%d 查询资产失败:%+v", apiUserInfo.Id, err.Error())
}
}
code, ok := dataMap["code"]
if ok {
return fmt.Errorf("api_id:%d 查询资产失败:%s", apiUserInfo.Id, ErrorMaps[code.(float64)])
}
if strings.Contains(err.Error(), "Unknown order sent.") {
return fmt.Errorf("api_id:%d 查询资产失败:%+v", apiUserInfo.Id, ErrorMaps[-2011])
}
return fmt.Errorf("api_id:%d 查询资产失败:%+v", apiUserInfo.Id, err.Error())
}
sonic.Unmarshal(body, &balanceResp)
for _, v := range balanceResp {
if v.Asset == "USDT" {
free := utility.StrToDecimal(v.AvailableBalance)
data.FuturesFreeAmount = free
data.FuturesTotalAmount = utility.StrToDecimal(v.Balance)
}
}
return nil
}