diff --git a/app/admin/apis/member_withdrawal_log.go b/app/admin/apis/member_withdrawal_log.go index 9ded828..4af3187 100644 --- a/app/admin/apis/member_withdrawal_log.go +++ b/app/admin/apis/member_withdrawal_log.go @@ -1,7 +1,7 @@ package apis import ( - "fmt" + "fmt" "github.com/gin-gonic/gin" "github.com/go-admin-team/go-admin-core/sdk/api" @@ -30,18 +30,18 @@ type MemberWithdrawalLog struct { // @Router /api/v1/member-withdrawal-log [get] // @Security Bearer func (e MemberWithdrawalLog) GetPage(c *gin.Context) { - req := dto.MemberWithdrawalLogGetPageReq{} - s := service.MemberWithdrawalLog{} - 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 - } + req := dto.MemberWithdrawalLogGetPageReq{} + s := service.MemberWithdrawalLog{} + 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 + } p := actions.GetPermissionFromContext(c) list := make([]models.MemberWithdrawalLog, 0) @@ -50,7 +50,7 @@ func (e MemberWithdrawalLog) GetPage(c *gin.Context) { err = s.GetPage(&req, p, &list, &count) if err != nil { e.Error(500, err, fmt.Sprintf("获取用户提现记录失败,\r\n失败信息 %s", err.Error())) - return + return } e.PageOK(list, int(count), req.GetPageIndex(), req.GetPageSize(), "查询成功") @@ -67,7 +67,7 @@ func (e MemberWithdrawalLog) GetPage(c *gin.Context) { func (e MemberWithdrawalLog) Get(c *gin.Context) { req := dto.MemberWithdrawalLogGetReq{} s := service.MemberWithdrawalLog{} - err := e.MakeContext(c). + err := e.MakeContext(c). MakeOrm(). Bind(&req). MakeService(&s.Service). @@ -83,10 +83,10 @@ func (e MemberWithdrawalLog) Get(c *gin.Context) { err = s.Get(&req, p, &object) if err != nil { e.Error(500, err, fmt.Sprintf("获取用户提现记录失败,\r\n失败信息 %s", err.Error())) - return + return } - e.OK( object, "查询成功") + e.OK(object, "查询成功") } // Insert 创建用户提现记录 @@ -100,25 +100,25 @@ func (e MemberWithdrawalLog) Get(c *gin.Context) { // @Router /api/v1/member-withdrawal-log [post] // @Security Bearer func (e MemberWithdrawalLog) Insert(c *gin.Context) { - req := dto.MemberWithdrawalLogInsertReq{} - s := service.MemberWithdrawalLog{} - 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 - } + req := dto.MemberWithdrawalLogInsertReq{} + s := service.MemberWithdrawalLog{} + 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 + } // 设置创建人 req.SetCreateBy(user.GetUserId(c)) err = s.Insert(&req) if err != nil { e.Error(500, err, fmt.Sprintf("创建用户提现记录失败,\r\n失败信息 %s", err.Error())) - return + return } e.OK(req.GetId(), "创建成功") @@ -136,27 +136,27 @@ func (e MemberWithdrawalLog) Insert(c *gin.Context) { // @Router /api/v1/member-withdrawal-log/{id} [put] // @Security Bearer func (e MemberWithdrawalLog) Update(c *gin.Context) { - req := dto.MemberWithdrawalLogUpdateReq{} - s := service.MemberWithdrawalLog{} - 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 - } + req := dto.MemberWithdrawalLogUpdateReq{} + s := service.MemberWithdrawalLog{} + 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 + } req.SetUpdateBy(user.GetUserId(c)) p := actions.GetPermissionFromContext(c) err = s.Update(&req, p) if err != nil { e.Error(500, err, fmt.Sprintf("修改用户提现记录失败,\r\n失败信息 %s", err.Error())) - return + return } - e.OK( req.GetId(), "修改成功") + e.OK(req.GetId(), "修改成功") } // Delete 删除用户提现记录 @@ -168,18 +168,18 @@ func (e MemberWithdrawalLog) Update(c *gin.Context) { // @Router /api/v1/member-withdrawal-log [delete] // @Security Bearer func (e MemberWithdrawalLog) Delete(c *gin.Context) { - s := service.MemberWithdrawalLog{} - req := dto.MemberWithdrawalLogDeleteReq{} - 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 - } + s := service.MemberWithdrawalLog{} + req := dto.MemberWithdrawalLogDeleteReq{} + 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 + } // req.SetUpdateBy(user.GetUserId(c)) p := actions.GetPermissionFromContext(c) @@ -187,7 +187,55 @@ func (e MemberWithdrawalLog) Delete(c *gin.Context) { err = s.Remove(&req, p) if err != nil { e.Error(500, err, fmt.Sprintf("删除用户提现记录失败,\r\n失败信息 %s", err.Error())) - return + return } - e.OK( req.GetId(), "删除成功") + 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, "确认提现成功") } diff --git a/app/admin/fronted/line_user.go b/app/admin/fronted/line_user.go index e15e0c3..0811155 100644 --- a/app/admin/fronted/line_user.go +++ b/app/admin/fronted/line_user.go @@ -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") } diff --git a/app/admin/fronted/member_withdrawal_log.go b/app/admin/fronted/member_withdrawal_log.go index 3542270..7315452 100644 --- a/app/admin/fronted/member_withdrawal_log.go +++ b/app/admin/fronted/member_withdrawal_log.go @@ -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 { diff --git a/app/admin/router/line_user.go b/app/admin/router/line_user.go index bd02ff3..61eee00 100644 --- a/app/admin/router/line_user.go +++ b/app/admin/router/line_user.go @@ -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) //充值 通过充值币种选择主网络 diff --git a/app/admin/service/dto/line_user.go b/app/admin/service/dto/line_user.go index 6422b22..f38c46a 100644 --- a/app/admin/service/dto/line_user.go +++ b/app/admin/service/dto/line_user.go @@ -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可用余额 +} diff --git a/app/admin/service/dto/member_withdrawal_log.go b/app/admin/service/dto/member_withdrawal_log.go index ad4bac4..be30a4b 100644 --- a/app/admin/service/dto/member_withdrawal_log.go +++ b/app/admin/service/dto/member_withdrawal_log.go @@ -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"` } diff --git a/app/admin/service/line_user.go b/app/admin/service/line_user.go index 363b4bc..d2ef21a 100644 --- a/app/admin/service/line_user.go +++ b/app/admin/service/line_user.go @@ -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 +} diff --git a/app/admin/service/member_withdrawal_log.go b/app/admin/service/member_withdrawal_log.go index 03c191b..32f0cf9 100644 --- a/app/admin/service/member_withdrawal_log.go +++ b/app/admin/service/member_withdrawal_log.go @@ -2,13 +2,15 @@ package service import ( "errors" + "time" - "github.com/go-admin-team/go-admin-core/sdk/service" + "github.com/go-admin-team/go-admin-core/sdk/service" "gorm.io/gorm" "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" ) @@ -59,9 +61,9 @@ func (e *MemberWithdrawalLog) Get(d *dto.MemberWithdrawalLogGetReq, p *actions.D // Insert 创建MemberWithdrawalLog对象 func (e *MemberWithdrawalLog) Insert(c *dto.MemberWithdrawalLogInsertReq) error { - var err error - var data models.MemberWithdrawalLog - c.Generate(&data) + var err error + var data models.MemberWithdrawalLog + c.Generate(&data) err = e.Orm.Create(&data).Error if err != nil { e.Log.Errorf("MemberWithdrawalLogService Insert error:%s \r\n", err) @@ -72,22 +74,22 @@ func (e *MemberWithdrawalLog) Insert(c *dto.MemberWithdrawalLogInsertReq) error // Update 修改MemberWithdrawalLog对象 func (e *MemberWithdrawalLog) Update(c *dto.MemberWithdrawalLogUpdateReq, p *actions.DataPermission) error { - var err error - var data = models.MemberWithdrawalLog{} - e.Orm.Scopes( - actions.Permission(data.TableName(), p), - ).First(&data, c.GetId()) - c.Generate(&data) + var err error + var data = models.MemberWithdrawalLog{} + e.Orm.Scopes( + actions.Permission(data.TableName(), p), + ).First(&data, c.GetId()) + c.Generate(&data) - db := e.Orm.Save(&data) - if err = db.Error; err != nil { - e.Log.Errorf("MemberWithdrawalLogService Save error:%s \r\n", err) - return err - } - if db.RowsAffected == 0 { - return errors.New("无权更新该数据") - } - return nil + db := e.Orm.Save(&data) + if err = db.Error; err != nil { + e.Log.Errorf("MemberWithdrawalLogService Save error:%s \r\n", err) + return err + } + if db.RowsAffected == 0 { + return errors.New("无权更新该数据") + } + return nil } // Remove 删除MemberWithdrawalLog @@ -99,11 +101,69 @@ func (e *MemberWithdrawalLog) Remove(d *dto.MemberWithdrawalLogDeleteReq, p *act actions.Permission(data.TableName(), p), ).Delete(&data, d.GetId()) if err := db.Error; err != nil { - e.Log.Errorf("Service RemoveMemberWithdrawalLog error:%s \r\n", err) - return err - } - if db.RowsAffected == 0 { - return errors.New("无权删除该数据") - } + e.Log.Errorf("Service RemoveMemberWithdrawalLog error:%s \r\n", err) + return err + } + if db.RowsAffected == 0 { + return errors.New("无权删除该数据") + } 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 +} diff --git a/common/status_code/code_11-12.go b/common/status_code/code_11-12.go index 8efe450..30bc3dd 100644 --- a/common/status_code/code_11-12.go +++ b/common/status_code/code_11-12.go @@ -8,4 +8,5 @@ const ( NetworkUnAvailable // 网络不可用 CanNotCancel // 无法取消 RenwalConfigDisabled // 续费配置不可用 + UserApiUserNotBind // 用户未授权 ) diff --git a/models/binancedto/binance.go b/models/binancedto/binance.go index fdb64ce..72195bf 100644 --- a/models/binancedto/binance.go +++ b/models/binancedto/binance.go @@ -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"` // 更新时间(时间戳) +} diff --git a/services/binanceservice/binancerest.go b/services/binanceservice/binancerest.go index c08d49f..40096ee 100644 --- a/services/binanceservice/binancerest.go +++ b/services/binanceservice/binancerest.go @@ -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 +} diff --git a/services/binanceservice/futuresbinancerest.go b/services/binanceservice/futuresbinancerest.go index 5130133..70bfa53 100644 --- a/services/binanceservice/futuresbinancerest.go +++ b/services/binanceservice/futuresbinancerest.go @@ -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 +}