withdraw apply
This commit is contained in:
parent
4c6125177b
commit
537ed90d65
|
@ -56,6 +56,9 @@ var ErrCodeMsgMap = map[ErrCode]string{
|
||||||
ErrCodeVasAlreadyUnlock: "已解锁,重复购买",
|
ErrCodeVasAlreadyUnlock: "已解锁,重复购买",
|
||||||
ErrCodeVasRepeatDeal: "重复处理",
|
ErrCodeVasRepeatDeal: "重复处理",
|
||||||
ErrCodeVasInvalidCalcPrice: "价格计算错误",
|
ErrCodeVasInvalidCalcPrice: "价格计算错误",
|
||||||
|
ErrCodeVasNoEnoughWithdrawDias: "可提现钻石不足",
|
||||||
|
ErrCodeVasInvalidVerifycode: "验证码错误",
|
||||||
|
ErrCodeVasAlipayUniTransferFail: "支付宝提现失败",
|
||||||
|
|
||||||
ErrCodeMomentSrvFail: "动态服务错误",
|
ErrCodeMomentSrvFail: "动态服务错误",
|
||||||
ErrCodeMomentNotExist: "动态不存在",
|
ErrCodeMomentNotExist: "动态不存在",
|
||||||
|
@ -208,6 +211,9 @@ const (
|
||||||
ErrCodeVasRepeatDeal ErrCode = -7016 // 重复处理
|
ErrCodeVasRepeatDeal ErrCode = -7016 // 重复处理
|
||||||
ErrCodeVasInvalidCalcPrice ErrCode = -7017 // 计算价格错误
|
ErrCodeVasInvalidCalcPrice ErrCode = -7017 // 计算价格错误
|
||||||
ErrCodeVasInvalidParam ErrCode = -7018 // 参数错误
|
ErrCodeVasInvalidParam ErrCode = -7018 // 参数错误
|
||||||
|
ErrCodeVasNoEnoughWithdrawDias ErrCode = -7019 // 参数错误
|
||||||
|
ErrCodeVasInvalidVerifycode ErrCode = -7020 // 提现验证码错误
|
||||||
|
ErrCodeVasAlipayUniTransferFail ErrCode = -7021 // 支付宝提现失败
|
||||||
|
|
||||||
// Moment: 8xxx
|
// Moment: 8xxx
|
||||||
ErrCodeMomentSrvOk ErrCode = ErrCodeOk
|
ErrCodeMomentSrvOk ErrCode = ErrCodeOk
|
||||||
|
|
|
@ -38,6 +38,8 @@ var ErrEcMap = map[error]errcode.ErrCode{
|
||||||
ErrVasRepeatDeal: errcode.ErrCodeVasRepeatDeal,
|
ErrVasRepeatDeal: errcode.ErrCodeVasRepeatDeal,
|
||||||
ErrVasInvalidCalcPrice: errcode.ErrCodeVasInvalidCalcPrice,
|
ErrVasInvalidCalcPrice: errcode.ErrCodeVasInvalidCalcPrice,
|
||||||
ErrVasInvalidParam: errcode.ErrCodeVasInvalidParam,
|
ErrVasInvalidParam: errcode.ErrCodeVasInvalidParam,
|
||||||
|
ErrVasNoEnoughWithdrawDias: errcode.ErrCodeVasNoEnoughWithdrawDias,
|
||||||
|
ErrVasAlipayUniTransferFail: errcode.ErrCodeVasAlipayUniTransferFail,
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -56,4 +58,6 @@ var (
|
||||||
ErrVasRepeatDeal = errors.New("repeat deal")
|
ErrVasRepeatDeal = errors.New("repeat deal")
|
||||||
ErrVasInvalidCalcPrice = errors.New("invalid calc price")
|
ErrVasInvalidCalcPrice = errors.New("invalid calc price")
|
||||||
ErrVasInvalidParam = errors.New("invalid param")
|
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
|
package proto
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/go-pay/gopay/alipay"
|
||||||
"service/api/base"
|
"service/api/base"
|
||||||
"service/dbstruct"
|
"service/dbstruct"
|
||||||
)
|
)
|
||||||
|
@ -109,7 +110,9 @@ type WithdrawApplyReq struct {
|
||||||
AuthAlipayId string `json:"auth_alipay_id"` // 加密的支付宝账号
|
AuthAlipayId string `json:"auth_alipay_id"` // 加密的支付宝账号
|
||||||
AuthAlipayName string `json:"auth_alipay_name"` // 加密的真实姓名
|
AuthAlipayName string `json:"auth_alipay_name"` // 加密的真实姓名
|
||||||
VerifyCode string `json:"verify_code"` // 短信验证码
|
VerifyCode string `json:"verify_code"` // 短信验证码
|
||||||
|
Ip string `json:"ip"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type WithdrawApplyData struct {
|
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("h5_get_unlock_wechat_list", middleware.JSONParamValidator(vasproto.GetUnlockWechatListReq{}), GetUnlockWechatList)
|
||||||
vasPayGroup.POST("withdraw_page", middleware.JSONParamValidator(vasproto.WithdrawPageReq{}), WithdrawPage)
|
vasPayGroup.POST("withdraw_page", middleware.JSONParamValidator(vasproto.WithdrawPageReq{}), WithdrawPage)
|
||||||
vasPayGroup.POST("withdraw_send_verifycode", middleware.JSONParamValidator(vasproto.WithdrawSendVerifycodeReq{}), WithdrawSendVerifycode)
|
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 := r.Group("/ext/vas")
|
||||||
extVasPayGroup.POST("alipay_callback", AlipayCallback)
|
extVasPayGroup.POST("alipay_callback", AlipayCallback)
|
||||||
|
|
|
@ -233,3 +233,15 @@ func WithdrawSendVerifycode(ctx *gin.Context) {
|
||||||
}
|
}
|
||||||
ReplyOk(ctx, nil)
|
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) {
|
func TestGen(t *testing.T) {
|
||||||
data, _ := RsaEncrypt([]byte("lwl0608@foxmail.com"))
|
data, _ := RsaEncrypt([]byte("lwl0608@foxmail.com"))
|
||||||
|
fmt.Println(string(data))
|
||||||
fmt.Println(base64.StdEncoding.EncodeToString(data))
|
fmt.Println(base64.StdEncoding.EncodeToString(data))
|
||||||
origData, _ := RsaDecrypt(data)
|
origData, _ := RsaDecrypt(data)
|
||||||
fmt.Println(string(origData))
|
fmt.Println(string(origData))
|
||||||
|
|
|
@ -70,6 +70,7 @@ const (
|
||||||
TableConsumeHistoryIncome = "vas_ch_income" // 收入明细
|
TableConsumeHistoryIncome = "vas_ch_income" // 收入明细
|
||||||
TableConsumeHistoryWithdraw = "vas_ch_withdraw" // 提现明细
|
TableConsumeHistoryWithdraw = "vas_ch_withdraw" // 提现明细
|
||||||
TableVasUserUnlock = "vas_user_unlock" // 用增解锁
|
TableVasUserUnlock = "vas_user_unlock" // 用增解锁
|
||||||
|
TableWithdrawOrder = "vas_withdraw_order" // 提现订单表
|
||||||
)
|
)
|
||||||
|
|
||||||
func (m *Mysql) ChTableName(ch *dbstruct.ConsumeHistory) (string, error) {
|
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
|
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 {
|
func (m *Mysql) CreateCoinOrder(ctx *gin.Context, tx *sqlx.Tx, order *dbstruct.CoinOrder) error {
|
||||||
var err error
|
var err error
|
||||||
|
@ -597,3 +615,46 @@ func (m *Mysql) GetOrderCountGroupByStatus(ctx *gin.Context, tx *sqlx.Tx, orderS
|
||||||
}
|
}
|
||||||
return
|
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
|
package logic
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/rand"
|
||||||
|
"crypto/rsa"
|
||||||
|
"crypto/x509"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
|
"encoding/base64"
|
||||||
|
"encoding/pem"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/go-pay/gopay/alipay"
|
||||||
"service/api/base"
|
"service/api/base"
|
||||||
"service/api/errs"
|
"service/api/errs"
|
||||||
vasproto "service/api/proto/vas/proto"
|
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) {
|
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)
|
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 = "+"
|
changeMark = "+"
|
||||||
}
|
}
|
||||||
switch chDB.GetSType() {
|
switch chDB.GetSType() {
|
||||||
case dbstruct.CHSTypeWithdrawDiamond:
|
case dbstruct.CHSTypeWithdrawDiamondAuto:
|
||||||
item.Desc = "提现"
|
item.Desc = "自动提现"
|
||||||
item.Change = changeMark + fmt.Sprintf("%d钻石", chDB.GetChange())
|
item.Change = changeMark + fmt.Sprintf("%d钻石", chDB.GetChange())
|
||||||
|
if chDB.GetChange() < 0 {
|
||||||
|
item.Change = fmt.Sprintf("%d钻石", chDB.GetChange())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
list = append(list, item)
|
list = append(list, item)
|
||||||
}
|
}
|
||||||
|
@ -396,9 +399,50 @@ func (s *Service) WithdrawSendVerifycode(ctx *gin.Context, req *vasproto.Withdra
|
||||||
RegionCode: util.DerefString(acnt.RegionCode),
|
RegionCode: util.DerefString(acnt.RegionCode),
|
||||||
Trigger: vericodeproto.VerifyCodeTriggerWithdraw,
|
Trigger: vericodeproto.VerifyCodeTriggerWithdraw,
|
||||||
})
|
})
|
||||||
|
ec, err = errs.DealVasErr(err)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("OpSendVeriCode fail, req: %v, err: %v", util.ToJson(req), err)
|
logger.Error("OpSendVeriCode fail, req: %v, err: %v", util.ToJson(req), err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
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 // 收入明细,联系方式
|
CHSTypeIncomeContact = 30001 // 收入明细,联系方式
|
||||||
CHSTypeIncomeInvite = 30002 // 收入明细,邀请分成
|
CHSTypeIncomeInvite = 30002 // 收入明细,邀请分成
|
||||||
|
|
||||||
CHSTypeWithdrawDiamond = 40001 // 提现明细
|
CHSTypeWithdrawDiamondAuto = 40001 // 自动提现明细
|
||||||
)
|
)
|
||||||
|
|
||||||
type ConsumeHistory struct {
|
type ConsumeHistory struct {
|
||||||
|
@ -658,3 +658,126 @@ type VasOrderStatusCount struct {
|
||||||
OrderStatus *int32 `json:"order_status" db:"order_status"`
|
OrderStatus *int32 `json:"order_status" db:"order_status"`
|
||||||
Count *int32 `json:"count" db:"count"`
|
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 文字审核
|
NodeTextAudit // node 文字审核
|
||||||
NodeTextAuditTask // node 文字审核任务
|
NodeTextAuditTask // node 文字审核任务
|
||||||
NodeDailyStatement // node 每日报表表
|
NodeDailyStatement // node 每日报表表
|
||||||
|
NodeWithdrawOrderId // node 提现订单
|
||||||
)
|
)
|
||||||
|
|
||||||
func GenIdInt64(node int64) (int64, error) {
|
func GenIdInt64(node int64) (int64, error) {
|
||||||
|
@ -196,3 +197,9 @@ func GenDailyStatementId() int64 {
|
||||||
id, _ := GenIdInt64(NodeDailyStatement)
|
id, _ := GenIdInt64(NodeDailyStatement)
|
||||||
return id
|
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)
|
logger.Info("alipay TradeWapPay param: %v", alipayWapParamStr)
|
||||||
return
|
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