withdraw apply

This commit is contained in:
lwl0608 2024-01-08 11:49:16 +08:00
parent 4c6125177b
commit 537ed90d65
13 changed files with 539 additions and 11 deletions

View File

@ -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

View File

@ -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")
)

View File

@ -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"`
}

View File

@ -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)

View File

@ -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)
}

View File

@ -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))

View File

@ -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
}

1
app/mix/dao/redis.go Normal file
View File

@ -0,0 +1 @@
package dao

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}