withdraw apply
This commit is contained in:
parent
4c6125177b
commit
537ed90d65
|
@ -56,6 +56,9 @@ var ErrCodeMsgMap = map[ErrCode]string{
|
|||
ErrCodeVasAlreadyUnlock: "已解锁,重复购买",
|
||||
ErrCodeVasRepeatDeal: "重复处理",
|
||||
ErrCodeVasInvalidCalcPrice: "价格计算错误",
|
||||
ErrCodeVasNoEnoughWithdrawDias: "可提现钻石不足",
|
||||
ErrCodeVasInvalidVerifycode: "验证码错误",
|
||||
ErrCodeVasAlipayUniTransferFail: "支付宝提现失败",
|
||||
|
||||
ErrCodeMomentSrvFail: "动态服务错误",
|
||||
ErrCodeMomentNotExist: "动态不存在",
|
||||
|
@ -208,6 +211,9 @@ const (
|
|||
ErrCodeVasRepeatDeal ErrCode = -7016 // 重复处理
|
||||
ErrCodeVasInvalidCalcPrice ErrCode = -7017 // 计算价格错误
|
||||
ErrCodeVasInvalidParam ErrCode = -7018 // 参数错误
|
||||
ErrCodeVasNoEnoughWithdrawDias ErrCode = -7019 // 参数错误
|
||||
ErrCodeVasInvalidVerifycode ErrCode = -7020 // 提现验证码错误
|
||||
ErrCodeVasAlipayUniTransferFail ErrCode = -7021 // 支付宝提现失败
|
||||
|
||||
// Moment: 8xxx
|
||||
ErrCodeMomentSrvOk ErrCode = ErrCodeOk
|
||||
|
|
|
@ -38,6 +38,8 @@ var ErrEcMap = map[error]errcode.ErrCode{
|
|||
ErrVasRepeatDeal: errcode.ErrCodeVasRepeatDeal,
|
||||
ErrVasInvalidCalcPrice: errcode.ErrCodeVasInvalidCalcPrice,
|
||||
ErrVasInvalidParam: errcode.ErrCodeVasInvalidParam,
|
||||
ErrVasNoEnoughWithdrawDias: errcode.ErrCodeVasNoEnoughWithdrawDias,
|
||||
ErrVasAlipayUniTransferFail: errcode.ErrCodeVasAlipayUniTransferFail,
|
||||
}
|
||||
|
||||
var (
|
||||
|
@ -56,4 +58,6 @@ var (
|
|||
ErrVasRepeatDeal = errors.New("repeat deal")
|
||||
ErrVasInvalidCalcPrice = errors.New("invalid calc price")
|
||||
ErrVasInvalidParam = errors.New("invalid param")
|
||||
ErrVasNoEnoughWithdrawDias = errors.New("no enough withdraw dias")
|
||||
ErrVasAlipayUniTransferFail = errors.New("alipay uni transfer fail")
|
||||
)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package proto
|
||||
|
||||
import (
|
||||
"github.com/go-pay/gopay/alipay"
|
||||
"service/api/base"
|
||||
"service/dbstruct"
|
||||
)
|
||||
|
@ -109,7 +110,9 @@ type WithdrawApplyReq struct {
|
|||
AuthAlipayId string `json:"auth_alipay_id"` // 加密的支付宝账号
|
||||
AuthAlipayName string `json:"auth_alipay_name"` // 加密的真实姓名
|
||||
VerifyCode string `json:"verify_code"` // 短信验证码
|
||||
Ip string `json:"ip"`
|
||||
}
|
||||
|
||||
type WithdrawApplyData struct {
|
||||
TransferResp *alipay.FundTransUniTransferResponse `json:"transfer_resp"`
|
||||
}
|
||||
|
|
|
@ -191,6 +191,7 @@ func Init(r *gin.Engine) {
|
|||
vasPayGroup.POST("h5_get_unlock_wechat_list", middleware.JSONParamValidator(vasproto.GetUnlockWechatListReq{}), GetUnlockWechatList)
|
||||
vasPayGroup.POST("withdraw_page", middleware.JSONParamValidator(vasproto.WithdrawPageReq{}), WithdrawPage)
|
||||
vasPayGroup.POST("withdraw_send_verifycode", middleware.JSONParamValidator(vasproto.WithdrawSendVerifycodeReq{}), WithdrawSendVerifycode)
|
||||
vasPayGroup.POST("withdraw_apply", middleware.JSONParamValidator(vasproto.WithdrawApplyReq{}), WithdrawApply)
|
||||
|
||||
extVasPayGroup := r.Group("/ext/vas")
|
||||
extVasPayGroup.POST("alipay_callback", AlipayCallback)
|
||||
|
|
|
@ -233,3 +233,15 @@ func WithdrawSendVerifycode(ctx *gin.Context) {
|
|||
}
|
||||
ReplyOk(ctx, nil)
|
||||
}
|
||||
|
||||
// 提现申请
|
||||
func WithdrawApply(ctx *gin.Context) {
|
||||
req := ctx.MustGet("client_req").(*vasproto.WithdrawApplyReq)
|
||||
data, ec := service.DefaultService.WithdrawApply(ctx, req)
|
||||
if ec != errcode.ErrCodeVasSrvOk {
|
||||
logger.Error("WithdrawApply fail, req: %v, data: %v, ec: %v", util.ToJson(req), data, ec)
|
||||
ReplyErrCodeMsg(ctx, ec)
|
||||
return
|
||||
}
|
||||
ReplyOk(ctx, nil)
|
||||
}
|
||||
|
|
|
@ -78,6 +78,7 @@ func RsaDecrypt(ciphertext []byte) ([]byte, error) {
|
|||
|
||||
func TestGen(t *testing.T) {
|
||||
data, _ := RsaEncrypt([]byte("lwl0608@foxmail.com"))
|
||||
fmt.Println(string(data))
|
||||
fmt.Println(base64.StdEncoding.EncodeToString(data))
|
||||
origData, _ := RsaDecrypt(data)
|
||||
fmt.Println(string(origData))
|
||||
|
|
|
@ -70,6 +70,7 @@ const (
|
|||
TableConsumeHistoryIncome = "vas_ch_income" // 收入明细
|
||||
TableConsumeHistoryWithdraw = "vas_ch_withdraw" // 提现明细
|
||||
TableVasUserUnlock = "vas_user_unlock" // 用增解锁
|
||||
TableWithdrawOrder = "vas_withdraw_order" // 提现订单表
|
||||
)
|
||||
|
||||
func (m *Mysql) ChTableName(ch *dbstruct.ConsumeHistory) (string, error) {
|
||||
|
@ -325,6 +326,23 @@ func (m *Mysql) IncDiamonds(ctx *gin.Context, tx *sqlx.Tx, mid, dias int64) erro
|
|||
return err
|
||||
}
|
||||
|
||||
// 扣提现钻石
|
||||
func (m *Mysql) DecWithdrawDiamonds(ctx *gin.Context, tx *sqlx.Tx, mid, dias int64) error {
|
||||
var err error
|
||||
sqlStr := "update " + TableWallet + " set withdraw_diamonds=withdraw_diamonds-? where id=?"
|
||||
if tx != nil {
|
||||
_, err = tx.ExecContext(ctx, sqlStr, dias, mid)
|
||||
} else {
|
||||
db := m.getDBVas()
|
||||
_, err = db.ExecContext(ctx, sqlStr, dias, mid)
|
||||
}
|
||||
if err != nil {
|
||||
logger.Error("DecWithdrawDiamonds fail, mid: %v, dias: %v, err: %v", mid, dias, err)
|
||||
return err
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// 创建金币订单
|
||||
func (m *Mysql) CreateCoinOrder(ctx *gin.Context, tx *sqlx.Tx, order *dbstruct.CoinOrder) error {
|
||||
var err error
|
||||
|
@ -597,3 +615,46 @@ func (m *Mysql) GetOrderCountGroupByStatus(ctx *gin.Context, tx *sqlx.Tx, orderS
|
|||
}
|
||||
return
|
||||
}
|
||||
|
||||
// 创建提现订单
|
||||
func (m *Mysql) CreateWithdrawOrder(ctx *gin.Context, tx *sqlx.Tx, wOrder *dbstruct.WithdrawOrder) error {
|
||||
var err error
|
||||
sqlStr := "insert into " + TableOrder +
|
||||
" (id, mid, did, apply_time, alipay_id, alipay_name, " +
|
||||
" withdraw_dias, withdraw_money, ip, order_status, operator, op_time) " +
|
||||
" values (?,?,?,?,?,?,?,?,?,?,?,?) "
|
||||
if tx != nil {
|
||||
_, err = tx.ExecContext(ctx, sqlStr,
|
||||
wOrder.GetID(), wOrder.GetMid(), wOrder.GetDid(), wOrder.GetAlipayId(), wOrder.GetAlipayName(),
|
||||
wOrder.GetWithdrawDias(), wOrder.GetWithdrawMoney(), wOrder.GetIp(), wOrder.GetOrderStatus(), wOrder.GetOperator(), wOrder.GetOpTime(),
|
||||
)
|
||||
} else {
|
||||
db := m.getDBVas()
|
||||
_, err = db.ExecContext(ctx, sqlStr,
|
||||
wOrder.GetID(), wOrder.GetMid(), wOrder.GetDid(), wOrder.GetAlipayId(), wOrder.GetAlipayName(),
|
||||
wOrder.GetWithdrawDias(), wOrder.GetWithdrawMoney(), wOrder.GetIp(), wOrder.GetOrderStatus(), wOrder.GetOperator(), wOrder.GetOpTime(),
|
||||
)
|
||||
}
|
||||
if err != nil {
|
||||
logger.Error("CreateOrder fail, wOrder: %v, err: %v", wOrder.ToString(), err)
|
||||
return err
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// 更新提现订单状态
|
||||
func (m *Mysql) UpdateWithdrawOrderStatus(ctx *gin.Context, tx *sqlx.Tx, orderId string, preStatus, aftStatus int32) error {
|
||||
var err error
|
||||
sqlStr := "update " + TableWithdrawOrder + " set order_status=? where id=? and order_status=?"
|
||||
if tx != nil {
|
||||
_, err = tx.ExecContext(ctx, sqlStr, aftStatus, orderId, preStatus)
|
||||
} else {
|
||||
db := m.getDBVas()
|
||||
_, err = db.ExecContext(ctx, sqlStr, aftStatus, orderId, preStatus)
|
||||
}
|
||||
if err != nil {
|
||||
logger.Error("UpdateWithdrawOrderStatus fail, orderId: %v, preStatus: %v, aftStatus: %v, err: %v", orderId, preStatus, aftStatus, err)
|
||||
return err
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
package dao
|
|
@ -1,9 +1,15 @@
|
|||
package logic
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"database/sql"
|
||||
"encoding/base64"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/go-pay/gopay/alipay"
|
||||
"service/api/base"
|
||||
"service/api/errs"
|
||||
vasproto "service/api/proto/vas/proto"
|
||||
|
@ -1676,3 +1682,232 @@ func (v *Vas) GetCoinOrderById(ctx *gin.Context, id string) (*dbstruct.CoinOrder
|
|||
func (v *Vas) GetOrderCountGroupByStatus(ctx *gin.Context, req *vasproto.GetOrderByStatusReq) ([]*dbstruct.VasOrderStatusCount, error) {
|
||||
return v.store.GetOrderCountGroupByStatus(ctx, nil, req.OrderStatuses, req.CtStart, req.CtEnd)
|
||||
}
|
||||
|
||||
var privateKey = []byte(`
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIICXgIBAAKBgQDlQ1WoxfQUmNHKFQiRLSq7Bu+vUHV4UIpEf6qgJ1m9ExIAsTGT
|
||||
BVu5v4U1A8Z1uprov2vb+a6XA1I61liZ0Z7aaYDr8IhY/wuktmNLxqIkzE3Vhvk/
|
||||
TGJIkLC8RUYxnzyIgGK4UuzfOj1S/o2ymjZo44+sBXEhAF+PWgpqFVtewwIDAQAB
|
||||
AoGBAOS11qdmy0cc6PSDJSfG+kDX+5ZWWsnq9vS8s5fPicuAUc5U9pKnnsjf0eCA
|
||||
YqShwtX72Hr7S3ulOYwutvbEUoXHMC7dVLmAaoby86A7lJYaDABbKN13PFMwIvGi
|
||||
lcQCqxTzz0Uvd5Jx3QettIBjNOi/rfa2ZNLcCn2uPU5cEdM5AkEA/UxTgFOdIWPN
|
||||
WdMeBDw1aXjSGgpVRFhLbBmVfpdi63l6CZbANu14D9ljaF2/XViM4ynOb+n0rca0
|
||||
toJLdm0+bwJBAOe1YF1NjUDtsdYSH0RNyOSXfUqClPfFOIuPKxvPnTn8R/AnLAwc
|
||||
51iQx4vldXYFnW1vBc7WyOTBI5+PsqtZju0CQQDMCgfZf4E7vGFW0jGDx9xesezM
|
||||
/TXicB2RXqqF5vzQInKj9sOve2sTmVHyaFIWp5YWBz8794IZ2c8IlbykESwRAkEA
|
||||
38gl1Jb0yHOIoMaJ2g8B6fyBLjglpZKdhPP133tJT1pfJArBGMXFjZzujCdFpYHQ
|
||||
xINIaba4+W2reQxws9rgFQJAPOB0/ymfTRDNgKZBB/MFHQcRA4z3L591lwEFN9Bl
|
||||
qE6UU5JMf5egQk1A9kyz1RIXaEC+L2LTi9TiWoy+XxGrAg==
|
||||
-----END RSA PRIVATE KEY-----
|
||||
`)
|
||||
|
||||
// 公钥: 根据私钥生成
|
||||
// openssl rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem
|
||||
var publicKey = []byte(`
|
||||
-----BEGIN PUBLIC KEY-----
|
||||
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDlQ1WoxfQUmNHKFQiRLSq7Bu+v
|
||||
UHV4UIpEf6qgJ1m9ExIAsTGTBVu5v4U1A8Z1uprov2vb+a6XA1I61liZ0Z7aaYDr
|
||||
8IhY/wuktmNLxqIkzE3Vhvk/TGJIkLC8RUYxnzyIgGK4UuzfOj1S/o2ymjZo44+s
|
||||
BXEhAF+PWgpqFVtewwIDAQAB
|
||||
-----END PUBLIC KEY-----
|
||||
`)
|
||||
|
||||
// 加密
|
||||
func RsaEncrypt(origData []byte) ([]byte, error) {
|
||||
//解密pem格式的公钥
|
||||
block, _ := pem.Decode(publicKey)
|
||||
if block == nil {
|
||||
return nil, errors.New("public key error")
|
||||
}
|
||||
// 解析公钥
|
||||
pubInterface, err := x509.ParsePKIXPublicKey(block.Bytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// 类型断言
|
||||
pub := pubInterface.(*rsa.PublicKey)
|
||||
//加密
|
||||
return rsa.EncryptPKCS1v15(rand.Reader, pub, origData)
|
||||
}
|
||||
|
||||
// 解密
|
||||
func RsaDecrypt(ciphertext []byte) ([]byte, error) {
|
||||
//解密
|
||||
block, _ := pem.Decode(privateKey)
|
||||
if block == nil {
|
||||
return nil, errors.New("private key error!")
|
||||
}
|
||||
//解析PKCS1格式的私钥
|
||||
priv, err := x509.ParsePKCS1PrivateKey(block.Bytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// 解密
|
||||
return rsa.DecryptPKCS1v15(rand.Reader, priv, ciphertext)
|
||||
}
|
||||
|
||||
// 提现申请
|
||||
func (v *Vas) WithdrawApply(ctx *gin.Context, req *vasproto.WithdrawApplyReq) (transferResp *alipay.FundTransUniTransferResponse, err error) {
|
||||
var (
|
||||
mid = req.Mid
|
||||
diamonds = req.Diamonds
|
||||
money = req.Diamonds * 10
|
||||
authAlipayId = req.AuthAlipayId
|
||||
authAlipayName = req.AuthAlipayName
|
||||
)
|
||||
|
||||
// todo 分布式锁
|
||||
|
||||
// 检查余额
|
||||
wallet, _ := v.CheckWalletExist(ctx, mid)
|
||||
if wallet == nil {
|
||||
err = errs.ErrVasWalletNotExist
|
||||
return
|
||||
}
|
||||
if wallet.GetWithdrawDiamonds() < diamonds {
|
||||
err = errs.ErrVasNoEnoughWithdrawDias
|
||||
return
|
||||
}
|
||||
|
||||
// 支付宝账号解密
|
||||
alipayIdDecodeBytes, err := base64.StdEncoding.DecodeString(authAlipayId)
|
||||
if err != nil {
|
||||
logger.Error("DecodeString authAlipayId fail, req: %v, err: %v", util.ToJson(req), err)
|
||||
return
|
||||
}
|
||||
alipayIdBytes, err := RsaDecrypt(alipayIdDecodeBytes)
|
||||
if err != nil {
|
||||
logger.Error("RsaDecrypt authAlipayId fail, req: %v, err: %v", util.ToJson(req), err)
|
||||
return
|
||||
}
|
||||
alipayId := string(alipayIdBytes)
|
||||
|
||||
// 支付宝姓名
|
||||
alipayNameDecodeBytes, err := base64.StdEncoding.DecodeString(authAlipayName)
|
||||
if err != nil {
|
||||
logger.Error("DecodeString authAlipayName fail, req: %v, err: %v", util.ToJson(req), err)
|
||||
return
|
||||
}
|
||||
alipayNameBytes, err := RsaDecrypt(alipayNameDecodeBytes)
|
||||
if err != nil {
|
||||
logger.Error("RsaDecrypt authAlipayName fail, req: %v, err: %v", util.ToJson(req), err)
|
||||
return
|
||||
}
|
||||
alipayName := string(alipayNameBytes)
|
||||
|
||||
var (
|
||||
wOrder *dbstruct.WithdrawOrder
|
||||
orderId = idgenerator.GenWithdrawOrderId()
|
||||
)
|
||||
|
||||
// 开启事务
|
||||
tx, err := v.store.VasBegin(ctx)
|
||||
if err != nil {
|
||||
logger.Error("vas begin fail, err: %v", err)
|
||||
return
|
||||
}
|
||||
defer func() {
|
||||
if err != nil {
|
||||
logger.Error("global err, req: %v, err: %v", util.ToJson(req), err)
|
||||
}
|
||||
errTx := v.store.DealTxCR(tx, err)
|
||||
if errTx != nil {
|
||||
logger.Error("DealTxCR fail, err: %v", errTx)
|
||||
return
|
||||
}
|
||||
}()
|
||||
|
||||
// 锁定钱包
|
||||
walletLock, err := v.store.GetWalletForUpdate(ctx, tx, mid)
|
||||
if err != nil {
|
||||
logger.Error("GetWalletForUpdate fail, mid: %, err: %v", mid, err)
|
||||
return
|
||||
}
|
||||
|
||||
// 扣提现钻石
|
||||
err = v.store.DecWithdrawDiamonds(ctx, tx, mid, diamonds)
|
||||
if err != nil {
|
||||
logger.Error("DecWithdrawDiamonds fail, mid: %, err: %v", mid, err)
|
||||
return
|
||||
}
|
||||
|
||||
// 添加提现订单
|
||||
wOrder = &dbstruct.WithdrawOrder{
|
||||
ID: goproto.String(orderId),
|
||||
Mid: goproto.Int64(mid),
|
||||
Did: goproto.String(req.Did),
|
||||
ApplyTime: goproto.Int64(time.Now().Unix()),
|
||||
AlipayId: goproto.String(alipayId),
|
||||
AlipayName: goproto.String(alipayName),
|
||||
WithdrawDias: goproto.Int64(diamonds),
|
||||
WithdrawMoney: goproto.Int64(money),
|
||||
Ip: goproto.String(req.Ip),
|
||||
OrderStatus: goproto.Int32(dbstruct.VasWithdrawOrderStatusInit),
|
||||
Operator: goproto.String(""),
|
||||
OpTime: goproto.Int64(0),
|
||||
}
|
||||
err = v.store.CreateWithdrawOrder(ctx, tx, wOrder)
|
||||
if err != nil {
|
||||
logger.Error("CreateWithdrawOrder fail, req: %v, order: %v, err: %v", req, wOrder.ToString(), err)
|
||||
return
|
||||
}
|
||||
|
||||
// 2000元以下直接操作
|
||||
if money <= 200000 {
|
||||
// 更改状态
|
||||
err = v.store.UpdateWithdrawOrderStatus(ctx, tx, orderId, dbstruct.VasWithdrawOrderStatusInit, dbstruct.VasWithdrawOrderStatusAuto)
|
||||
if err != nil {
|
||||
logger.Error("UpdateWithdrawOrderStatus fail, order: %v, err: %v", wOrder.ToString(), err)
|
||||
return
|
||||
}
|
||||
|
||||
// 添加提现记录
|
||||
chWithdraw := &dbstruct.ConsumeHistory{
|
||||
Mid: goproto.Int64(mid),
|
||||
Did: goproto.String(req.Did),
|
||||
Type: goproto.Int32(dbstruct.CHTypeWithdraw),
|
||||
SType: goproto.Int32(dbstruct.CHSTypeWithdrawDiamondAuto),
|
||||
TypeId: goproto.String("auto_withdraw_diamonds"),
|
||||
OrderId: goproto.String(orderId),
|
||||
Change: goproto.Int64(-diamonds),
|
||||
Before: goproto.Int64(walletLock.GetWithdrawDiamonds()),
|
||||
After: goproto.Int64(walletLock.GetWithdrawDiamonds() - diamonds),
|
||||
Ct: goproto.Int64(time.Now().Unix()),
|
||||
}
|
||||
err = v.store.CreateConsumeHistory(ctx, tx, chWithdraw)
|
||||
if err != nil {
|
||||
logger.Error("CreateConsumeHistory fail, ch: %v, err: %v", util.ToJson(chWithdraw), err)
|
||||
return
|
||||
}
|
||||
|
||||
// 支付宝转账
|
||||
transferParam := &alipaycli.UniTransferParam{
|
||||
OutBizNo: orderId,
|
||||
Amount: money,
|
||||
Title: fmt.Sprintf("%d钻石提现", diamonds),
|
||||
AlipayLoginId: alipayId,
|
||||
AlipayName: alipayName,
|
||||
}
|
||||
transferResp, err = alipaycli.GetDefaultAlipayClient().UniTransfer(ctx, transferParam)
|
||||
if err != nil {
|
||||
logger.Error("UniTransfer fail, param: %v, err: %v", util.ToJson(transferParam), err)
|
||||
return
|
||||
}
|
||||
if transferResp == nil {
|
||||
err = errors.New("invalid transfer resp")
|
||||
logger.Error("Invalid transfer resp, param: %v, err: %v", util.ToJson(transferParam), err)
|
||||
return
|
||||
}
|
||||
if transferResp.Response == nil {
|
||||
err = errors.New("invalid transfer resp")
|
||||
logger.Error("Invalid transfer resp response, param: %v, resp: %v, err: %v", util.ToJson(transferParam), util.ToJson(transferResp), err)
|
||||
return
|
||||
}
|
||||
if transferResp.Response.Status != "SUCCESS" {
|
||||
err = errs.ErrVasAlipayUniTransferFail
|
||||
logger.Error("UniTransfer fail, param: %v, resp: %v, err: %v", util.ToJson(transferParam), util.ToJson(transferResp), err)
|
||||
return
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
|
@ -317,9 +317,12 @@ func (s *Service) chListWithdraw(ctx *gin.Context, chList []*dbstruct.ConsumeHis
|
|||
changeMark = "+"
|
||||
}
|
||||
switch chDB.GetSType() {
|
||||
case dbstruct.CHSTypeWithdrawDiamond:
|
||||
item.Desc = "提现"
|
||||
case dbstruct.CHSTypeWithdrawDiamondAuto:
|
||||
item.Desc = "自动提现"
|
||||
item.Change = changeMark + fmt.Sprintf("%d钻石", chDB.GetChange())
|
||||
if chDB.GetChange() < 0 {
|
||||
item.Change = fmt.Sprintf("%d钻石", chDB.GetChange())
|
||||
}
|
||||
}
|
||||
list = append(list, item)
|
||||
}
|
||||
|
@ -396,9 +399,50 @@ func (s *Service) WithdrawSendVerifycode(ctx *gin.Context, req *vasproto.Withdra
|
|||
RegionCode: util.DerefString(acnt.RegionCode),
|
||||
Trigger: vericodeproto.VerifyCodeTriggerWithdraw,
|
||||
})
|
||||
ec, err = errs.DealVasErr(err)
|
||||
if err != nil {
|
||||
logger.Error("OpSendVeriCode fail, req: %v, err: %v", util.ToJson(req), err)
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// 提现申请
|
||||
func (s *Service) WithdrawApply(ctx *gin.Context, req *vasproto.WithdrawApplyReq) (data *vasproto.WithdrawApplyData, ec errcode.ErrCode) {
|
||||
// 获取用户
|
||||
acntMap, _ := _DefaultAccount.GetAccountMapByMids(ctx, []int64{req.Mid})
|
||||
acnt, has := acntMap[req.Mid]
|
||||
if !has {
|
||||
ec = errcode.ErrCodeVasSrvFail
|
||||
return
|
||||
}
|
||||
|
||||
// 校验验证码
|
||||
vCode, _ := _DefaultVeriCode.OpListByPhoneHash(ctx, &vericodeproto.OpListByPhoneHashReq{
|
||||
BaseRequest: req.BaseRequest,
|
||||
PhoneHash: util.DerefString(acnt.PhoneHash),
|
||||
RegionCode: util.DerefString(acnt.RegionCode),
|
||||
})
|
||||
if vCode == nil || vCode.VeriCode != req.VerifyCode {
|
||||
ec = errcode.ErrCodeVasInvalidVerifycode
|
||||
return
|
||||
}
|
||||
|
||||
// 检验完删除
|
||||
err := _DefaultVeriCode.OpDelete(ctx, vCode.Id)
|
||||
if err != nil {
|
||||
logger.Error("_DefaultVeriCode.OpDelete fail, req: %v, code: %v, err: %v", util.ToJson(req), util.ToJson(vCode), err)
|
||||
ec = errcode.ErrCodeVasInvalidVerifycode
|
||||
return
|
||||
}
|
||||
|
||||
// 提现
|
||||
data = new(vasproto.WithdrawApplyData)
|
||||
data.TransferResp, err = _DefaultVas.WithdrawApply(ctx, req)
|
||||
ec, err = errs.DealVasErr(err)
|
||||
if err != nil {
|
||||
logger.Error("WithdrawApply fail, req: %v, resp: %v, err: %v", util.ToJson(req), util.ToJson(data.TransferResp), err)
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
|
@ -500,7 +500,7 @@ const (
|
|||
CHSTypeIncomeContact = 30001 // 收入明细,联系方式
|
||||
CHSTypeIncomeInvite = 30002 // 收入明细,邀请分成
|
||||
|
||||
CHSTypeWithdrawDiamond = 40001 // 提现明细
|
||||
CHSTypeWithdrawDiamondAuto = 40001 // 自动提现明细
|
||||
)
|
||||
|
||||
type ConsumeHistory struct {
|
||||
|
@ -658,3 +658,126 @@ type VasOrderStatusCount struct {
|
|||
OrderStatus *int32 `json:"order_status" db:"order_status"`
|
||||
Count *int32 `json:"count" db:"count"`
|
||||
}
|
||||
|
||||
// 钱包
|
||||
const (
|
||||
VasWithdrawOrderStatusFail = -2 // 失败
|
||||
VasWithdrawOrderStatusNone = -1 // 零状态
|
||||
VasWithdrawOrderStatusInit = 0 // 初始化
|
||||
VasWithdrawOrderStatusWaitDeal = 1 // 等待运营处理
|
||||
VasWithdrawOrderStatusAuto = 2 // 小额自动提现
|
||||
VasWithdrawOrderStatusDeal = 3 // 已处理
|
||||
)
|
||||
|
||||
var WithdrawOrderStatusDescMap = map[int32]string{
|
||||
VasWithdrawOrderStatusFail: "提现失败",
|
||||
VasWithdrawOrderStatusNone: "零状态",
|
||||
VasWithdrawOrderStatusInit: "初始化",
|
||||
VasWithdrawOrderStatusWaitDeal: "等待运营处理",
|
||||
VasWithdrawOrderStatusAuto: "小额自动提醒",
|
||||
VasWithdrawOrderStatusDeal: "已处理",
|
||||
}
|
||||
|
||||
type WithdrawOrder struct {
|
||||
ID *string `json:"id" db:"id"`
|
||||
Mid *int64 `json:"mid" db:"mid"` // mid
|
||||
Did *string `json:"did" db:"did"` // 设备id
|
||||
ApplyTime *int64 `json:"apply_time" db:"apply_time"` // 申请时间
|
||||
AlipayId *string `json:"alipay_id" db:"alipay_id"` // 支付宝账号
|
||||
AlipayName *string `json:"alipay_name" db:"alipay_name"` // 支付宝姓名
|
||||
WithdrawDias *int64 `json:"withdraw_dias" db:"withdraw_dias"` // 提现钻石数
|
||||
WithdrawMoney *int64 `json:"withdraw_money" db:"withdraw_money"` // 提现金额
|
||||
Ip *string `json:"ip" db:"ip"` // ip
|
||||
OrderStatus *int32 `json:"order_status" db:"order_status"` // 订单状态
|
||||
Operator *string `json:"operator" db:"operator"` // 操作的运营同学
|
||||
OpTime *int64 `json:"op_time" db:"op_time"` // op操作时间
|
||||
}
|
||||
|
||||
func (p *WithdrawOrder) ToString() string {
|
||||
bs, _ := json.Marshal(p)
|
||||
return string(bs)
|
||||
}
|
||||
|
||||
func (p *WithdrawOrder) GetID() string {
|
||||
if p != nil && p.ID != nil {
|
||||
return *p.ID
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (p *WithdrawOrder) GetMid() int64 {
|
||||
if p != nil && p.Mid != nil {
|
||||
return *p.Mid
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (p *WithdrawOrder) GetDid() string {
|
||||
if p != nil && p.Did != nil {
|
||||
return *p.Did
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (p *WithdrawOrder) GetApplyTime() int64 {
|
||||
if p != nil && p.ApplyTime != nil {
|
||||
return *p.ApplyTime
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (p *WithdrawOrder) GetAlipayId() string {
|
||||
if p != nil && p.AlipayId != nil {
|
||||
return *p.AlipayId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (p *WithdrawOrder) GetAlipayName() string {
|
||||
if p != nil && p.AlipayName != nil {
|
||||
return *p.AlipayName
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (p *WithdrawOrder) GetWithdrawDias() int64 {
|
||||
if p != nil && p.WithdrawDias != nil {
|
||||
return *p.WithdrawDias
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (p *WithdrawOrder) GetWithdrawMoney() int64 {
|
||||
if p != nil && p.WithdrawMoney != nil {
|
||||
return *p.WithdrawMoney
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (p *WithdrawOrder) GetIp() string {
|
||||
if p != nil && p.Ip != nil {
|
||||
return *p.Ip
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (p *WithdrawOrder) GetOrderStatus() int32 {
|
||||
if p != nil && p.OrderStatus != nil {
|
||||
return *p.OrderStatus
|
||||
}
|
||||
return VasWithdrawOrderStatusNone
|
||||
}
|
||||
|
||||
func (p *WithdrawOrder) GetOperator() string {
|
||||
if p != nil && p.Operator != nil {
|
||||
return *p.Operator
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (p *WithdrawOrder) GetOpTime() int64 {
|
||||
if p != nil && p.OpTime != nil {
|
||||
return *p.OpTime
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
|
|
@ -45,6 +45,7 @@ const (
|
|||
NodeTextAudit // node 文字审核
|
||||
NodeTextAuditTask // node 文字审核任务
|
||||
NodeDailyStatement // node 每日报表表
|
||||
NodeWithdrawOrderId // node 提现订单
|
||||
)
|
||||
|
||||
func GenIdInt64(node int64) (int64, error) {
|
||||
|
@ -196,3 +197,9 @@ func GenDailyStatementId() int64 {
|
|||
id, _ := GenIdInt64(NodeDailyStatement)
|
||||
return id
|
||||
}
|
||||
|
||||
// withdraw_order
|
||||
func GenWithdrawOrderId() string {
|
||||
id, _ := GenIdString(NodeWithdrawOrderId)
|
||||
return id
|
||||
}
|
||||
|
|
|
@ -120,3 +120,33 @@ func (c *AlipayClient) WapPay(ctx context.Context, param *WapPayParam) (alipayWa
|
|||
logger.Info("alipay TradeWapPay param: %v", alipayWapParamStr)
|
||||
return
|
||||
}
|
||||
|
||||
// 支付宝单笔转账
|
||||
type UniTransferParam struct {
|
||||
OutBizNo string // 商家订单id,我们自己的订单id
|
||||
Amount int64 // 金额,单位:分
|
||||
Title string // 转账业务的标题,用于在支付宝用户的账单里显示。
|
||||
AlipayLoginId string // 支付宝登录账号
|
||||
AlipayName string // 支付宝真实姓名
|
||||
}
|
||||
|
||||
func (c *AlipayClient) UniTransfer(ctx context.Context, param *UniTransferParam) (resp *alipay.FundTransUniTransferResponse, err error) {
|
||||
bm := gopay.BodyMap{
|
||||
"out_biz_no": param.OutBizNo,
|
||||
"trans_amount": fmt.Sprintf("%.2f", float64(param.Amount)/100.0),
|
||||
"biz_scene": "DIRECT_TRANSFER",
|
||||
"product_code": "TRANS_ACCOUNT_NO_PWD",
|
||||
"order_title": param.Title,
|
||||
"payee_info": map[string]interface{}{
|
||||
"identity": param.AlipayLoginId,
|
||||
"identity_type": "ALIPAY_LOGON_ID",
|
||||
"name": param.AlipayName,
|
||||
},
|
||||
}
|
||||
resp, err = c.FundTransUniTransfer(ctx, bm)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
logger.Info("alipay UniTransfer param: %v, resp: %v", bm.JsonBody(), util.ToJson(resp))
|
||||
return
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue