by Robin at 20240624
This commit is contained in:
parent
6fb44a3b01
commit
813636ca8f
|
@ -35,27 +35,28 @@ const (
|
|||
|
||||
// apollo_config
|
||||
const (
|
||||
MaxPswdWrongTimesKey = "max_pswd_wrong_times"
|
||||
MaxVeriCodeValidDurationKey = "max_veri_code_valid_duration"
|
||||
IosKey = "ios"
|
||||
AndroidKey = "android"
|
||||
AccountInitKey = "account_init"
|
||||
TagNumKey = "tag_num"
|
||||
PlatformNumKey = "platform_num"
|
||||
SupportWxIdNumKey = "support_wx_id_num"
|
||||
MaxDailyVeriCodeSendTimesKey = "max_daily_veri_code_send_times"
|
||||
ImageIdForUploadFail = "image_id_for_upload_fail"
|
||||
VideoIdForUploadFail = "video_id_for_upload_fail"
|
||||
RestrictedVisitorKey = "restricted_visitor"
|
||||
MaxDailyMomentCreateTimesKey = "max_daily_moment_create_times"
|
||||
DefaultMomentTextKey = "default_moment_text"
|
||||
MaxDailyZoneMomentCreateTimesKey = "max_daily_zone_moment_create_times"
|
||||
ReferentialZoneMomentKey = "referential_zone_moment"
|
||||
IsMomentImageEncryptEnabledKey = "is_moment_image_encrypt_enabled"
|
||||
RestrictedVisitorMomentKey = "restricted_visitor_moment"
|
||||
AppConfigReflectKey = "app_config_reflect"
|
||||
ZoneVIPConfigKey = "zone_vip_config"
|
||||
StreamerScoreFormulaKey = "streamer_score_formula"
|
||||
MaxPswdWrongTimesKey = "max_pswd_wrong_times"
|
||||
MaxVeriCodeValidDurationKey = "max_veri_code_valid_duration"
|
||||
IosKey = "ios"
|
||||
AndroidKey = "android"
|
||||
AccountInitKey = "account_init"
|
||||
TagNumKey = "tag_num"
|
||||
PlatformNumKey = "platform_num"
|
||||
SupportWxIdNumKey = "support_wx_id_num"
|
||||
MaxDailyVeriCodeSendTimesKey = "max_daily_veri_code_send_times"
|
||||
ImageIdForUploadFail = "image_id_for_upload_fail"
|
||||
VideoIdForUploadFail = "video_id_for_upload_fail"
|
||||
RestrictedVisitorKey = "restricted_visitor"
|
||||
MaxDailyMomentCreateTimesKey = "max_daily_moment_create_times"
|
||||
DefaultMomentTextKey = "default_moment_text"
|
||||
MaxDailyZoneMomentCreateTimesKey = "max_daily_zone_moment_create_times"
|
||||
ReferentialZoneMomentKey = "referential_zone_moment"
|
||||
IsMomentImageEncryptEnabledKey = "is_moment_image_encrypt_enabled"
|
||||
RestrictedVisitorMomentKey = "restricted_visitor_moment"
|
||||
AppConfigReflectKey = "app_config_reflect"
|
||||
ZoneVIPConfigKey = "zone_vip_config"
|
||||
StreamerScoreFormulaKey = "streamer_score_formula"
|
||||
HvyogoSingleDistributeChargePercentageKey = "hvyogo_single_distribute_charge_percentage"
|
||||
)
|
||||
|
||||
// del_flag
|
||||
|
|
|
@ -215,8 +215,9 @@ var ErrCodeMsgMap = map[ErrCode]string{
|
|||
ErrCodeWorkerIdSrvFail: "用户职业者id映射表服务错误",
|
||||
ErrCodeWorkerIdNotExist: "用户职业者id映射表不存在",
|
||||
|
||||
ErrCodeSingleDistributeHisSrvFail: "慧用工下发打款历史表服务错误",
|
||||
ErrCodeSingleDistributeHisNotExist: "慧用工下发打款历史表不存在",
|
||||
ErrCodeSingleDistributeHisSrvFail: "慧用工下发打款历史表服务错误",
|
||||
ErrCodeSingleDistributeHisNotExist: "慧用工下发打款历史表不存在",
|
||||
ErrCodeCurrentSingleDistributeNotTerminated: "当前慧用工下发打款申请尚未结束",
|
||||
|
||||
ErrCodeHvyogoSrvFail: "慧用工接口服务错误",
|
||||
}
|
||||
|
@ -519,9 +520,10 @@ const (
|
|||
ErrCodeWorkerIdNotExist ErrCode = -41002 // 用户职业者id映射表不存在
|
||||
|
||||
// SingleDistributeHis: 42xxx
|
||||
ErrCodeSingleDistributeHisSrvOk ErrCode = ErrCodeOk
|
||||
ErrCodeSingleDistributeHisSrvFail ErrCode = -42001 // 慧用工下发打款历史表服务错误
|
||||
ErrCodeSingleDistributeHisNotExist ErrCode = -42002 // 慧用工下发打款历史表不存在
|
||||
ErrCodeSingleDistributeHisSrvOk ErrCode = ErrCodeOk
|
||||
ErrCodeSingleDistributeHisSrvFail ErrCode = -42001 // 慧用工下发打款历史表服务错误
|
||||
ErrCodeSingleDistributeHisNotExist ErrCode = -42002 // 慧用工下发打款历史表不存在
|
||||
ErrCodeCurrentSingleDistributeNotTerminated ErrCode = -42003 // 当前慧用工下发打款申请尚未结束
|
||||
|
||||
// Media: 60xxx
|
||||
ErrCodeMediaSrvOk ErrCode = ErrCodeOk
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
package proto
|
||||
|
||||
import (
|
||||
"github.com/go-pay/gopay/alipay"
|
||||
"service/api/base"
|
||||
"service/dbstruct"
|
||||
"service/library/payclients/wxpaycli"
|
||||
|
||||
"github.com/go-pay/gopay/alipay"
|
||||
)
|
||||
|
||||
// 待添加微信列表
|
||||
|
@ -120,6 +121,13 @@ type WithdrawApplyData struct {
|
|||
TransferResp *alipay.FundTransUniTransferResponse `json:"transfer_resp"`
|
||||
}
|
||||
|
||||
// 单侧提现申请
|
||||
type UnilaterallyWithdrawApplyReq struct {
|
||||
base.BaseRequest
|
||||
Diamonds int64 `json:"diamonds"` // 本次提现的钻石
|
||||
Ip string `json:"ip"`
|
||||
}
|
||||
|
||||
// 任意额度提现
|
||||
var WithdrawAnyDiasMap = map[int64]bool{
|
||||
74: true,
|
||||
|
|
|
@ -219,8 +219,9 @@ const (
|
|||
DBWorkerId = "worker_id"
|
||||
COLWorkerId = "worker_id"
|
||||
|
||||
DBSingleDistributeHis = "single_distribute_his"
|
||||
COLSingleDistributeHis = "single_distribute_his"
|
||||
DBSingleDistributeHis = "single_distribute_his"
|
||||
COLSingleDistributeHis = "single_distribute_his"
|
||||
COLSingleDistributeLock = "single_distribute_lock"
|
||||
)
|
||||
|
||||
// 商品表
|
||||
|
@ -547,16 +548,21 @@ func (m *Mongo) getColStreamerScore() *qmgo.Collection {
|
|||
return m.clientMix.Database(DBStreamerScore).Collection(COLStreamerScore)
|
||||
}
|
||||
|
||||
// 用户职业者id映射表表
|
||||
// 用户职业者id映射表
|
||||
func (m *Mongo) getColWorkerId() *qmgo.Collection {
|
||||
return m.clientMix.Database(DBWorkerId).Collection(COLWorkerId)
|
||||
}
|
||||
|
||||
// 慧用工下发打款历史表表
|
||||
// 慧用工下发打款历史表
|
||||
func (m *Mongo) getColSingleDistributeHis() *qmgo.Collection {
|
||||
return m.clientMix.Database(DBSingleDistributeHis).Collection(COLSingleDistributeHis)
|
||||
}
|
||||
|
||||
// 慧用工下发打款锁表
|
||||
func (m *Mongo) getColSingleDistributeLock() *qmgo.Collection {
|
||||
return m.clientMix.Database(DBSingleDistributeHis).Collection(COLSingleDistributeLock)
|
||||
}
|
||||
|
||||
// 商品相关
|
||||
func (m *Mongo) CreateProduct(ctx *gin.Context, product *dbstruct.Product) error {
|
||||
col := m.getColProduct()
|
||||
|
@ -5322,3 +5328,43 @@ func (m *Mongo) GetSingleDistributeHisList(ctx *gin.Context, req *single_distrib
|
|||
}
|
||||
return list, err
|
||||
}
|
||||
|
||||
func (m *Mongo) GetAndUpdateSingleDistributeLock(ctx *gin.Context, mid int64) (singleDistributeLock *dbstruct.SingleDistributeLock, err error) {
|
||||
col := m.getColSingleDistributeLock()
|
||||
|
||||
change := qmgo.Change{
|
||||
Update: qmgo.M{"$inc": qmgo.M{"lock": 1}},
|
||||
Upsert: true,
|
||||
ReturnNew: false,
|
||||
}
|
||||
|
||||
singleDistributeLockInstance := dbstruct.SingleDistributeLock{}
|
||||
if err = col.Find(ctx, qmgo.M{"_id": mid}).Apply(change, &singleDistributeLockInstance); err != nil {
|
||||
logger.Error("change error : %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
return &singleDistributeLockInstance, err
|
||||
}
|
||||
|
||||
func (m *Mongo) ClearSingleDistributeLock(ctx *gin.Context, mid int64) (err error) {
|
||||
col := m.getColSingleDistributeLock()
|
||||
|
||||
setClause := qmgo.M{
|
||||
"lock": int64(0),
|
||||
}
|
||||
|
||||
change := qmgo.Change{
|
||||
Update: qmgo.M{"$set": setClause},
|
||||
Upsert: true,
|
||||
ReturnNew: false,
|
||||
}
|
||||
|
||||
singleDistributeLockInstance := dbstruct.SingleDistributeLock{}
|
||||
if err = col.Find(ctx, qmgo.M{"_id": mid}).Apply(change, &singleDistributeLockInstance); err != nil {
|
||||
logger.Error("change error : %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -1027,6 +1027,26 @@ func (m *Mysql) GetWithdrawOrdersByMid(ctx *gin.Context, tx *sqlx.Tx, mid, st, e
|
|||
return
|
||||
}
|
||||
|
||||
// 从订单号获取提现订单
|
||||
func (m *Mysql) GetWithdrawOrderById(ctx *gin.Context, tx *sqlx.Tx, id string) (wOrder *dbstruct.WithdrawOrder, err error) {
|
||||
wOrder = &dbstruct.WithdrawOrder{}
|
||||
sqlStr := fmt.Sprintf("select * from %s where id=?", TableWithdrawOrder)
|
||||
if tx != nil {
|
||||
err = tx.SelectContext(ctx, wOrder, sqlStr, id)
|
||||
} else {
|
||||
db := m.getDBVas()
|
||||
err = db.SelectContext(ctx, wOrder, sqlStr, id)
|
||||
}
|
||||
if err == sql.ErrNoRows {
|
||||
err = nil
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// 获取指定任务中所有已经执行成功的xxl_job任务
|
||||
func (m *Mysql) GetSuccessXxlJobLogs(ctx *gin.Context, tx *sqlx.Tx, jobIdsStr string, errorPrefix string) (list []*dbstruct.XxlJobLog, err error) {
|
||||
list = make([]*dbstruct.XxlJobLog, 0)
|
||||
|
|
|
@ -5,7 +5,9 @@ import (
|
|||
"service/api/base"
|
||||
"service/api/consts"
|
||||
"service/api/errcode"
|
||||
"service/api/errs"
|
||||
"service/api/message/request"
|
||||
"service/api/message/response"
|
||||
accountproto "service/api/proto/account/proto"
|
||||
account_cancellationproto "service/api/proto/account_cancellation/proto"
|
||||
accountrelationproto "service/api/proto/accountrelation/proto"
|
||||
|
@ -42,6 +44,7 @@ import (
|
|||
"service/library/apollo"
|
||||
"service/library/logger"
|
||||
interceptor "service/library/taginterceptor"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"go.mongodb.org/mongo-driver/mongo"
|
||||
|
@ -3342,7 +3345,7 @@ func (s *Service) ApiHvyogoSingleDistribute(ctx *gin.Context, req *hvyogoproto.A
|
|||
|
||||
ec = errcode.ErrCodeHvyogoSrvOk
|
||||
|
||||
// 1.查询workerId
|
||||
// 查询workerId
|
||||
workerId, err := _DefaultWorkerId.OpListByMid(ctx, &workeridproto.OpListByMidReq{
|
||||
BaseRequest: req.BaseRequest,
|
||||
})
|
||||
|
@ -3353,17 +3356,20 @@ func (s *Service) ApiHvyogoSingleDistribute(ctx *gin.Context, req *hvyogoproto.A
|
|||
}
|
||||
if workerId == nil {
|
||||
logger.Error("No worker_id entity was found")
|
||||
ec = errcode.ErrCodeWorkerIdNotExist
|
||||
data = &hvyogoproto.ApiSingleDistributeData{
|
||||
StatusCode: response.StatusCodeFail,
|
||||
StatusText: "用户尚未认证",
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// 2.组装HYG10000002报文,查询详细信息
|
||||
// 组装HYG10000002报文,查询详细信息
|
||||
detailMsg := &request.HYG10000002Req{
|
||||
HYGBaseReq: &request.HYGBaseReq{},
|
||||
WorkerId: workerId.GetWorkerId(),
|
||||
}
|
||||
|
||||
// 3.调用查询接口
|
||||
// 调用查询接口
|
||||
detailResp, err := DefaultHvyogoService.WorkerFindDetail(detailMsg)
|
||||
if err != nil {
|
||||
logger.Error("DefaultHvyogoService WorkerAgreeState fail, err: %v", err)
|
||||
|
@ -3371,7 +3377,21 @@ func (s *Service) ApiHvyogoSingleDistribute(ctx *gin.Context, req *hvyogoproto.A
|
|||
return
|
||||
}
|
||||
|
||||
// 4.组装HYG10010001报文,准备下发打款
|
||||
// 扣除手续费
|
||||
distributeAmount, err := strconv.Atoi(req.DistributeAmount)
|
||||
if err != nil || distributeAmount <= 0 {
|
||||
err = fmt.Errorf("下发金额必须为大于0的整数!")
|
||||
return
|
||||
}
|
||||
chargePercentage, err := apollo.GetFloat64Value(consts.HvyogoSingleDistributeChargePercentageKey, apollo.ApolloOpts().SetNamespace("application"))
|
||||
if err != nil {
|
||||
logger.Error("Apollo read failed : %v", err)
|
||||
ec, err = errcode.ErrCodeApolloReadFail, nil
|
||||
return
|
||||
}
|
||||
finalDistributeAmount := int(float64(distributeAmount) * (1 - chargePercentage))
|
||||
|
||||
// 组装HYG10010001报文,准备下发打款
|
||||
msg := &request.HYG10010001Req{
|
||||
HYGBaseReq: &request.HYGBaseReq{},
|
||||
WorkerName: detailResp.WorkerName,
|
||||
|
@ -3380,54 +3400,80 @@ func (s *Service) ApiHvyogoSingleDistribute(ctx *gin.Context, req *hvyogoproto.A
|
|||
WorkerType: detailResp.CertificateType,
|
||||
IdNumber: detailResp.IdentNo,
|
||||
WorkerMobile: detailResp.WorkerMobile,
|
||||
DistributeAmount: req.DistributeAmount,
|
||||
DistributeAmount: fmt.Sprint(finalDistributeAmount),
|
||||
}
|
||||
|
||||
// 5.若上送了别的渠道,则设置参数
|
||||
// 若上送了别的渠道,则设置参数
|
||||
if req.ReceiptChannel != 0 {
|
||||
msg.ReceiptChannel = int(req.ReceiptChannel)
|
||||
msg.WorkerAccount = req.WorkerAccount
|
||||
}
|
||||
|
||||
// 6.写入下发历史表,将历史表id作为requestNo
|
||||
singleDistributeHis := &single_distribute_his_proto.OpCreateReq{
|
||||
SingleDistributeHis: &dbstruct.SingleDistributeHis{
|
||||
Mid: goproto.Int64(req.BaseRequest.Mid),
|
||||
},
|
||||
}
|
||||
err = _DefaultSingleDistributeHis.OpCreate(ctx, singleDistributeHis)
|
||||
// 锁操作,当前提前申请结束之前,禁止再发起提现申请
|
||||
lock, err := _DefaultSingleDistributeHis.GetAndUpdateLock(ctx, req.BaseRequest.Mid)
|
||||
if err != nil {
|
||||
logger.Error("_DefaultSingleDistributeHis OpCreate fail, err: %v", err)
|
||||
ec = errcode.ErrCodeSingleDistributeHisSrvFail
|
||||
logger.Error("_DefaultSingleDistributeHis GetAndUpdateLock failed : %v", err)
|
||||
ec, err = errcode.ErrCodeSingleDistributeHisSrvFail, nil
|
||||
return
|
||||
}
|
||||
msg.RequestNo = singleDistributeHis.GetId()
|
||||
|
||||
// 7.调用下发打款接口
|
||||
resp, err := DefaultHvyogoService.SingleDistribute(msg)
|
||||
if err != nil {
|
||||
logger.Error("DefaultHvyogoService SingleDistribute fail, err: %v", err)
|
||||
ec = errcode.ErrCodeHvyogoSrvFail
|
||||
if lock.IsLocked() {
|
||||
logger.Error("Unhandled single distribution request is found")
|
||||
ec = errcode.ErrCodeCurrentSingleDistributeNotTerminated
|
||||
return
|
||||
}
|
||||
|
||||
// 8.更新至历史表
|
||||
err = _DefaultSingleDistributeHis.OpUpdate(ctx, &single_distribute_his_proto.OpUpdateReq{
|
||||
SingleDistributeHis: &dbstruct.SingleDistributeHis{
|
||||
Id: singleDistributeHis.Id,
|
||||
StatusCode: goproto.String(resp.StatusCode),
|
||||
StatusText: goproto.String(resp.StatusText),
|
||||
DistributeId: goproto.String(resp.DistributeId),
|
||||
DistributeAmount: goproto.String(resp.DistributeAmount),
|
||||
},
|
||||
})
|
||||
// 外部提现申请函数
|
||||
extWithdrawFunc := func(orderId string) (*hvyogoproto.SingleDistributeVO, error) {
|
||||
// 写入下发历史表,将历史表id作为requestNo
|
||||
singleDistributeHis := &single_distribute_his_proto.OpCreateReq{
|
||||
SingleDistributeHis: &dbstruct.SingleDistributeHis{
|
||||
Mid: goproto.Int64(req.BaseRequest.Mid),
|
||||
OrderId: goproto.String(orderId),
|
||||
},
|
||||
}
|
||||
err = _DefaultSingleDistributeHis.OpCreate(ctx, singleDistributeHis)
|
||||
if err != nil {
|
||||
logger.Error("_DefaultSingleDistributeHis OpCreate fail, err: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
msg.RequestNo = singleDistributeHis.GetId()
|
||||
|
||||
// 调用下发打款接口
|
||||
resp, err := DefaultHvyogoService.SingleDistribute(msg)
|
||||
if err != nil {
|
||||
logger.Error("DefaultHvyogoService SingleDistribute fail, err: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 更新至历史表
|
||||
err = _DefaultSingleDistributeHis.OpUpdate(ctx, &single_distribute_his_proto.OpUpdateReq{
|
||||
SingleDistributeHis: &dbstruct.SingleDistributeHis{
|
||||
Id: singleDistributeHis.Id,
|
||||
StatusCode: goproto.String(resp.StatusCode),
|
||||
StatusText: goproto.String(resp.StatusText),
|
||||
DistributeId: goproto.String(resp.DistributeId),
|
||||
DistributeAmount: goproto.String(resp.DistributeAmount),
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
logger.Error("_DefaultSingleDistributeHis OpUpdate fail, err: %v", err)
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// 发起单侧提现申请
|
||||
resp, err := _DefaultVas.UnilaterallyHvyogoWithdrawApply(ctx, &vasproto.UnilaterallyWithdrawApplyReq{
|
||||
BaseRequest: req.BaseRequest,
|
||||
Diamonds: int64(distributeAmount),
|
||||
}, extWithdrawFunc)
|
||||
ec, err = errs.DealVasErr(err)
|
||||
if err != nil {
|
||||
logger.Error("_DefaultSingleDistributeHis OpUpdate fail, err: %v", err)
|
||||
ec = errcode.ErrCodeSingleDistributeHisSrvFail
|
||||
logger.Error("WithdrawApply fail, req: %v, err: %v", util.ToJson(req), err)
|
||||
return
|
||||
}
|
||||
|
||||
// 9.组装返回结果
|
||||
// 组装返回结果
|
||||
data = &hvyogoproto.ApiSingleDistributeData{}
|
||||
deepcopier.Copy(resp).To(data)
|
||||
|
||||
|
|
|
@ -63,3 +63,21 @@ func (p *SingleDistributeHis) OpList(ctx *gin.Context, req *single_distribute_hi
|
|||
}
|
||||
return list, nil
|
||||
}
|
||||
|
||||
func (p *SingleDistributeHis) GetAndUpdateLock(ctx *gin.Context, mid int64) (*dbstruct.SingleDistributeLock, error) {
|
||||
lock, err := p.store.GetAndUpdateSingleDistributeLock(ctx, mid)
|
||||
if err != nil {
|
||||
logger.Error("GetAndUpdateSingleDistributeLock fail, err: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
return lock, nil
|
||||
}
|
||||
|
||||
func (p *SingleDistributeHis) ClearLock(ctx *gin.Context, mid int64) error {
|
||||
err := p.store.ClearSingleDistributeLock(ctx, mid)
|
||||
if err != nil {
|
||||
logger.Error("ClearSingleDistributeLock fail, err: %v", err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ import (
|
|||
"service/api/base"
|
||||
"service/api/errs"
|
||||
accountproto "service/api/proto/account/proto"
|
||||
hvyogoproto "service/api/proto/hvyogo/proto"
|
||||
vasproto "service/api/proto/vas/proto"
|
||||
"service/app/mix/dao"
|
||||
"service/bizcommon/common"
|
||||
|
@ -3591,3 +3592,210 @@ func (v *Vas) GetIncomeByTimeSpanGroupByMid(ctx *gin.Context, tx *sqlx.Tx, st, e
|
|||
func (v *Vas) GetRefundRateGroupByMid(ctx *gin.Context, tx *sqlx.Tx) ([]*dbstruct.RefundRate, error) {
|
||||
return v.store.GetRefundRateGroupByMid(ctx, tx)
|
||||
}
|
||||
|
||||
// 单侧提现申请
|
||||
func (v *Vas) UnilaterallyHvyogoWithdrawApply(ctx *gin.Context, req *vasproto.UnilaterallyWithdrawApplyReq, extWithdrawFunc func(orderId string) (*hvyogoproto.SingleDistributeVO, error)) (resp *hvyogoproto.SingleDistributeVO, err error) {
|
||||
var (
|
||||
mid = req.Mid
|
||||
diamonds = req.Diamonds
|
||||
money = req.Diamonds * 10
|
||||
)
|
||||
|
||||
// 今日提现次数
|
||||
st := util.GetTodayZeroTime().Unix()
|
||||
et := st + 86400
|
||||
list, _ := v.store.GetWithdrawOrdersByMid(ctx, nil, mid, st, et)
|
||||
if len(list) > 0 {
|
||||
err = errs.ErrVasOverTodayWithdrawCnt
|
||||
return
|
||||
}
|
||||
|
||||
// todo 分布式锁
|
||||
|
||||
// 检查余额
|
||||
wallet, _ := v.CheckWalletExist(ctx, nil, mid)
|
||||
if wallet == nil {
|
||||
err = errs.ErrVasWalletNotExist
|
||||
return
|
||||
}
|
||||
if wallet.GetWithdrawDiamonds() < diamonds {
|
||||
err = errs.ErrVasNoEnoughWithdrawDias
|
||||
return
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
// 扣钻石
|
||||
err = v.store.DecDiamonds(ctx, tx, mid, diamonds)
|
||||
if err != nil {
|
||||
logger.Error("DecDiamonds 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()),
|
||||
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
|
||||
}
|
||||
|
||||
// 更改状态
|
||||
err = v.store.UpdateWithdrawOrderStatus(ctx, tx, orderId, dbstruct.VasWithdrawOrderStatusInit, dbstruct.VasWithdrawOrderStatusWaitHvyogoDeal)
|
||||
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.CHSTypeWithdrawDiamondHvyogo),
|
||||
TypeId: goproto.String("hvyogo_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
|
||||
}
|
||||
|
||||
// 外部提现申请函数执行
|
||||
resp, err = extWithdrawFunc(orderId)
|
||||
if err != nil {
|
||||
logger.Error("extWithdrawFunc fail, err: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// 单侧提现冲正
|
||||
func (v *Vas) UnilaterallyWithdrawReverse(ctx *gin.Context, orderId string) (err error) {
|
||||
|
||||
// 从订单号查询提现订单
|
||||
wOrder, err := v.store.GetWithdrawOrderById(ctx, nil, orderId)
|
||||
if err != nil {
|
||||
logger.Error("GetWithdrawOrderById fail, orderId : %v, err: %v", orderId, err)
|
||||
return
|
||||
}
|
||||
|
||||
// 开启事务
|
||||
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, err: %v", err)
|
||||
}
|
||||
errTx := v.store.DealTxCR(tx, err)
|
||||
if errTx != nil {
|
||||
logger.Error("DealTxCR fail, err: %v", errTx)
|
||||
return
|
||||
}
|
||||
}()
|
||||
|
||||
mid := wOrder.GetMid()
|
||||
diamonds := wOrder.GetWithdrawDias()
|
||||
|
||||
// 锁定钱包
|
||||
walletLock, err := v.store.GetWalletForUpdate(ctx, tx, mid)
|
||||
if err != nil {
|
||||
logger.Error("GetWalletForUpdate fail, mid: %v, err: %v", mid, err)
|
||||
return
|
||||
}
|
||||
|
||||
// 恢复提现钻石
|
||||
err = v.store.IncWithdrawDiamonds(ctx, tx, mid, diamonds)
|
||||
if err != nil {
|
||||
logger.Error("DecWithdrawDiamonds fail, mid: %, err: %v", mid, err)
|
||||
return
|
||||
}
|
||||
|
||||
// 恢复钻石
|
||||
err = v.store.IncDiamonds(ctx, tx, mid, diamonds)
|
||||
if err != nil {
|
||||
logger.Error("DecDiamonds fail, mid: %, err: %v", mid, err)
|
||||
return
|
||||
}
|
||||
|
||||
// 更改提现订单状态
|
||||
err = v.store.UpdateWithdrawOrderStatus(ctx, tx, orderId, dbstruct.VasWithdrawOrderStatusWaitHvyogoDeal, dbstruct.VasWithdrawOrderStatusReversed)
|
||||
if err != nil {
|
||||
logger.Error("UpdateWithdrawOrderStatus fail, order: %v, err: %v", wOrder.ToString(), err)
|
||||
return
|
||||
}
|
||||
|
||||
// 添加提现记录
|
||||
chWithdraw := &dbstruct.ConsumeHistory{
|
||||
Mid: goproto.Int64(mid),
|
||||
Type: goproto.Int32(dbstruct.CHTypeWithdraw),
|
||||
SType: goproto.Int32(dbstruct.CHSTypeWithdrawDiamondReversal),
|
||||
TypeId: goproto.String("withdraw_diamonds_reversal"),
|
||||
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
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ type SingleDistributeHis struct {
|
|||
Timestamp *string `json:"timestamp" bson:"timestamp"` // 下单时间
|
||||
Remark *string `json:"remark" bson:"remark"` // 银行返回打款备注
|
||||
ReasonCode *string `json:"reason_code" bson:"reason_code"` // 余额不足时会返回E00001
|
||||
OrderId *string `json:"order_id" bson:""order_id` // 订单号
|
||||
Ct *int64 `json:"ct" bson:"ct"` // 创建时间
|
||||
Ut *int64 `json:"ut" bson:"ut"` // 更新时间
|
||||
DelFlag *int64 `json:"del_flag" bson:"del_flag"` // 删除标记
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
package dbstruct
|
||||
|
||||
type SingleDistributeLock struct {
|
||||
Id int64 `json:"id" bson:"_id"` //id,主播的mid
|
||||
Lock int64 `json:"lock" bson:"lock"` //发帖次数
|
||||
}
|
||||
|
||||
func (p *SingleDistributeLock) IsLocked() bool {
|
||||
if p == nil {
|
||||
return false
|
||||
}
|
||||
return p.Lock > 0
|
||||
}
|
|
@ -550,7 +550,9 @@ const (
|
|||
CHSTypeIncomeRefundCollaborator = 30011 // 收入明细,协作者
|
||||
CHSTypeIncomeRefundZoneStreamer = 30012 // 收入明细,主播空间收益
|
||||
|
||||
CHSTypeWithdrawDiamondAuto = 40001 // 自动提现明细
|
||||
CHSTypeWithdrawDiamondAuto = 40001 // 自动提现明细
|
||||
CHSTypeWithdrawDiamondHvyogo = 40002 // 慧用工提现明细
|
||||
CHSTypeWithdrawDiamondReversal = 40002 // 提现冲正明细
|
||||
)
|
||||
|
||||
type ConsumeHistory struct {
|
||||
|
@ -723,21 +725,25 @@ type VasOrderStatusCount struct {
|
|||
|
||||
// 钱包
|
||||
const (
|
||||
VasWithdrawOrderStatusFail = -2 // 失败
|
||||
VasWithdrawOrderStatusNone = -1 // 零状态
|
||||
VasWithdrawOrderStatusInit = 0 // 初始化
|
||||
VasWithdrawOrderStatusWaitDeal = 1 // 等待运营处理
|
||||
VasWithdrawOrderStatusAuto = 2 // 小额自动提现
|
||||
VasWithdrawOrderStatusDeal = 3 // 已处理
|
||||
VasWithdrawOrderStatusFail = -2 // 失败
|
||||
VasWithdrawOrderStatusNone = -1 // 零状态
|
||||
VasWithdrawOrderStatusInit = 0 // 初始化
|
||||
VasWithdrawOrderStatusWaitDeal = 1 // 等待运营处理
|
||||
VasWithdrawOrderStatusAuto = 2 // 小额自动提现
|
||||
VasWithdrawOrderStatusDeal = 3 // 已处理
|
||||
VasWithdrawOrderStatusWaitHvyogoDeal = 4 // 等待慧用工处理
|
||||
VasWithdrawOrderStatusReversed = 5 // 已冲正
|
||||
)
|
||||
|
||||
var WithdrawOrderStatusDescMap = map[int32]string{
|
||||
VasWithdrawOrderStatusFail: "提现失败",
|
||||
VasWithdrawOrderStatusNone: "零状态",
|
||||
VasWithdrawOrderStatusInit: "初始化",
|
||||
VasWithdrawOrderStatusWaitDeal: "等待运营处理",
|
||||
VasWithdrawOrderStatusAuto: "小额自动提醒",
|
||||
VasWithdrawOrderStatusDeal: "已处理",
|
||||
VasWithdrawOrderStatusFail: "提现失败",
|
||||
VasWithdrawOrderStatusNone: "零状态",
|
||||
VasWithdrawOrderStatusInit: "初始化",
|
||||
VasWithdrawOrderStatusWaitDeal: "等待运营处理",
|
||||
VasWithdrawOrderStatusAuto: "小额自动提醒",
|
||||
VasWithdrawOrderStatusDeal: "已处理",
|
||||
VasWithdrawOrderStatusWaitHvyogoDeal: "等待慧用工处理",
|
||||
VasWithdrawOrderStatusReversed: "已冲正",
|
||||
}
|
||||
|
||||
type WithdrawOrder struct {
|
||||
|
|
|
@ -34,9 +34,10 @@ func Init(cfg *configcenter.ApolloConfig) (err error) {
|
|||
}
|
||||
|
||||
type ApolloOptions struct {
|
||||
Namespace *string
|
||||
DefaultValue *string
|
||||
DefaultIntValue *int
|
||||
Namespace *string
|
||||
DefaultValue *string
|
||||
DefaultIntValue *int
|
||||
DefaultFloat64Value *float64
|
||||
}
|
||||
|
||||
func mergeApolloOptions(opts ...*ApolloOptions) *ApolloOptions {
|
||||
|
@ -54,6 +55,9 @@ func mergeApolloOptions(opts ...*ApolloOptions) *ApolloOptions {
|
|||
if opt.DefaultIntValue != nil {
|
||||
ao.DefaultIntValue = opt.DefaultIntValue
|
||||
}
|
||||
if opt.DefaultFloat64Value != nil {
|
||||
ao.DefaultFloat64Value = opt.DefaultFloat64Value
|
||||
}
|
||||
}
|
||||
return ao
|
||||
}
|
||||
|
@ -93,6 +97,13 @@ func (ao *ApolloOptions) GetDefaultIntValue() int {
|
|||
return 0
|
||||
}
|
||||
|
||||
func (ao *ApolloOptions) GetDefaultFloat64Value() float64 {
|
||||
if ao != nil && ao.DefaultFloat64Value != nil {
|
||||
return *ao.DefaultFloat64Value
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func GetJson(key string, v interface{}, opts ...*ApolloOptions) (err error) {
|
||||
opt := mergeApolloOptions(opts...)
|
||||
var value string
|
||||
|
@ -126,3 +137,13 @@ func GetIntValue(key string, opts ...*ApolloOptions) (value int, err error) {
|
|||
}
|
||||
return
|
||||
}
|
||||
|
||||
func GetFloat64Value(key string, opts ...*ApolloOptions) (value float64, err error) {
|
||||
opt := mergeApolloOptions(opts...)
|
||||
if opt.GetNamespace() != "" {
|
||||
value = defaultApolloClient.GetConfig(opt.GetNamespace()).GetFloatValue(key, opt.GetDefaultFloat64Value())
|
||||
} else {
|
||||
value = defaultApolloClient.GetFloatValue(key, opt.GetDefaultFloat64Value())
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue