@@ -0,0 +1,471 @@
|
||||
package withdrawser
|
||||
|
||||
import (
|
||||
"91porn-server/app/service/messageser"
|
||||
"91porn-server/common/stderr"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"91porn-server/app/appg"
|
||||
"91porn-server/common"
|
||||
"91porn-server/common/constant/redisconst"
|
||||
"91porn-server/common/db"
|
||||
"91porn-server/common/log"
|
||||
"91porn-server/common/rchgutil"
|
||||
"91porn-server/common/redis"
|
||||
"91porn-server/models/v/txnactmod"
|
||||
"91porn-server/models/v/txnmod"
|
||||
"91porn-server/models/v/walletmod"
|
||||
"91porn-server/models/v/wdchannmod"
|
||||
"91porn-server/models/v/wdordmod"
|
||||
"91porn-server/models/v/wdtaxmod"
|
||||
"91porn-server/skd/skdg"
|
||||
"91porn-server/web/webg"
|
||||
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||
"go.mongodb.org/mongo-driver/mongo/options"
|
||||
)
|
||||
|
||||
// ExchangeAllow 提现通过
|
||||
func ExchangeAllow(id string, usdtRate float64, operator string) (err error) {
|
||||
// 查询订单信息
|
||||
withdrawOrder, ec := wdordmod.FindWithdrawOrderByID(id)
|
||||
if ec != nil {
|
||||
return ec
|
||||
}
|
||||
now := time.Now()
|
||||
set := wdordmod.EditSelector{
|
||||
CheckedAt: &now,
|
||||
ProgressAt: &now,
|
||||
Status: wdordmod.PROCESSING,
|
||||
StatusDesc: wdordmod.PROCESSINGError,
|
||||
Operator: &operator,
|
||||
}
|
||||
content := "提现审核已通过,预计1个工作日内到账。"
|
||||
// 特殊处理usdt提现审核
|
||||
if usdtRate > 0 {
|
||||
if withdrawOrder.PayType != wdordmod.TypeUsdt || withdrawOrder.Status != wdordmod.DEFAULT {
|
||||
return fmt.Errorf("订单异常")
|
||||
}
|
||||
// 更新订单状态
|
||||
if ec = wdordmod.UpdateOne(nil, bson.M{"_id": withdrawOrder.ID}, bson.M{
|
||||
"checkedAt": now,
|
||||
"progressAt": now,
|
||||
"successAt": now,
|
||||
"updatedAt": now,
|
||||
"receivedAt": now,
|
||||
"status": wdordmod.SUCCESS,
|
||||
"statusDesc": wdordmod.SUCCESSStatus,
|
||||
"usdtRate": usdtRate,
|
||||
"operator": operator,
|
||||
}); ec != nil {
|
||||
return ec
|
||||
}
|
||||
go func() {
|
||||
content = "USDT" + content
|
||||
// 处理消息
|
||||
log.Info(fmt.Sprintf("HandleOfficialMsg pass withdraw start content:%v,uid:%v", content, withdrawOrder.UID))
|
||||
code := messageser.HandleOfficialMsg(withdrawOrder.UID, content, 2)
|
||||
if code != stderr.Success {
|
||||
log.Error(fmt.Sprintf("HandleOfficialMsg pass withdraw error:%+v:", err), log.Any("uid", withdrawOrder.UID))
|
||||
}
|
||||
}()
|
||||
return nil
|
||||
}
|
||||
//获取银行卡编码
|
||||
if withdrawOrder.PayType == wdordmod.TypeBankCard && withdrawOrder.BankCode == "" {
|
||||
withdrawOrder.BankCode = GetBankInfo(withdrawOrder.Act)
|
||||
if withdrawOrder.BankCode == "" {
|
||||
log.Warn("GetBankInfo BankCode == ''", log.Any("uid", withdrawOrder.UID), log.Any("bankAct", withdrawOrder.Act))
|
||||
return errors.New("获取银行编码异常,请重试")
|
||||
}
|
||||
}
|
||||
w, err := wdordmod.FindOneAndUpate(id, wdordmod.DEFAULT, set)
|
||||
if err != nil {
|
||||
if w.ID.IsZero() || w.ActName == "" {
|
||||
return err
|
||||
}
|
||||
return err
|
||||
}
|
||||
var msg rchgutil.ExchgMsg
|
||||
var tradeNo string
|
||||
if w.ProductType == 0 {
|
||||
tradeNo = rchgutil.EChgIDAssemble(w.ID.Hex())
|
||||
}
|
||||
if w.ProductType == 1 {
|
||||
tradeNo = rchgutil.EChgWLIDAssemble(w.ID.Hex())
|
||||
}
|
||||
if w.PayType == wdordmod.TypeBankCard && w.BankCode == "" {
|
||||
typeAct := txnactmod.Bank
|
||||
act, err := txnactmod.FindOne(txnactmod.Query{
|
||||
Act: &(w.Act),
|
||||
AType: &typeAct,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
w.BankCode = act.BankCode
|
||||
}
|
||||
req := &rchgutil.Exchg{
|
||||
TransNo: tradeNo,
|
||||
UID: strconv.FormatUint(w.UID, 10),
|
||||
Name: w.Name,
|
||||
PayMoney: w.PayMoney,
|
||||
PayType: w.PayType,
|
||||
ActName: w.ActName,
|
||||
Act: w.Act,
|
||||
UserIP: w.UserIP,
|
||||
DeviceType: w.DeviceType,
|
||||
DevID: w.DevID,
|
||||
CheckedAt: now,
|
||||
ProductType: w.ProductType,
|
||||
BankCode: w.BankCode,
|
||||
}
|
||||
if w.ProductType == 1 {
|
||||
req.Rate = 3
|
||||
}
|
||||
msg = req.ToPay()
|
||||
set.OID = &(msg.OID)
|
||||
if msg.Code != 200 {
|
||||
if msg.Code == rchgutil.UNKNOWError {
|
||||
set.Status = wdordmod.UNKNOWN
|
||||
set.StatusDesc = wdordmod.UNKNOWNError
|
||||
set.FailureAt = &now
|
||||
if err = wdordmod.Update(nil, id, set); err != nil {
|
||||
return err
|
||||
}
|
||||
return errors.New(set.StatusDesc)
|
||||
}
|
||||
//发生错误,执行退款程序
|
||||
set.FailureAt = &now
|
||||
set.Status = wdordmod.FAILURE
|
||||
set.StatusDesc = wdordmod.ServerError + "[第三方返回: " + msg.Err + "]"
|
||||
if err = refusedWirhdraw(w, set, "服务器请求平台失败"); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
common.Go(func() {
|
||||
if err := CacheProcessingOrder(w.UID); err != nil {
|
||||
log.Error("CacheProcessingUser", log.Any("order id", id), log.E(err))
|
||||
}
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
// ExchangeRefuseByHand 手动对特定状态的提现订单进行退款
|
||||
func ExchangeRefuseByHand(id string, status int, desc string) error {
|
||||
w, err := wdordmod.FindWithdrawOrderByIDAndStatus(id, status) //防重入
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
//发生错误,执行退款程序
|
||||
now := time.Now()
|
||||
set := wdordmod.EditSelector{
|
||||
Status: wdordmod.REFUSE,
|
||||
StatusDesc: desc,
|
||||
CheckedAt: &now,
|
||||
}
|
||||
if err = refusedWirhdraw(w, set, desc); err != nil {
|
||||
return err
|
||||
}
|
||||
//棋牌usdt兑换拒绝增加usdt可提现额度
|
||||
if w.ProductType == 1 && w.PayType == wdordmod.TypeUsdt {
|
||||
if _, err = walletmod.IncUsdtAmount(w.UID, w.Money); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ExchangeRefuse 提现拒绝
|
||||
func ExchangeRefuse(id string, statusDesc, operator string) error {
|
||||
w, err := wdordmod.FindWithdrawOrderByIDAndStatus(id, wdordmod.DEFAULT) //防重入
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
//发生错误,执行退款程序
|
||||
now := time.Now()
|
||||
set := wdordmod.EditSelector{
|
||||
Status: wdordmod.REFUSE,
|
||||
StatusDesc: statusDesc,
|
||||
Operator: &operator,
|
||||
CheckedAt: &now,
|
||||
}
|
||||
if err = refusedWirhdraw(w, set, statusDesc); err != nil {
|
||||
return err
|
||||
}
|
||||
//棋牌usdt兑换拒绝增加usdt可提现额度
|
||||
if w.ProductType == 1 && w.PayType == wdordmod.TypeUsdt {
|
||||
if _, err = walletmod.IncUsdtAmount(w.UID, w.Money); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
go func() {
|
||||
content := "提现审核未通过," + statusDesc + "。"
|
||||
if w.PayType == wdordmod.TypeUsdt {
|
||||
content = "USDT" + content
|
||||
}
|
||||
if w.PayType == wdordmod.TypeAlipay {
|
||||
content = "支付宝" + content
|
||||
}
|
||||
if w.PayType == wdordmod.TypeBankCard {
|
||||
content = "银行卡" + content
|
||||
}
|
||||
// 处理消息
|
||||
log.Info(fmt.Sprintf("HandleOfficialMsg refused withdraw start content:%v,uid:%v", content, w.UID))
|
||||
code := messageser.HandleOfficialMsg(w.UID, content, 2)
|
||||
if code != stderr.Success {
|
||||
log.Error(fmt.Sprintf("HandleOfficialMsg refused withdraw error:%+v:", err), log.Any("uid", w.UID))
|
||||
}
|
||||
}()
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetAllOrders 分页获取订单,
|
||||
func GetAllOrders(cond primitive.M, opt *options.FindOptions) (total int64,
|
||||
data []*wdordmod.WithdrawOrder, err error) {
|
||||
if _, ok := cond["uid"]; !ok {
|
||||
if b, ok := cond["filterChecked"].(bool); ok && b {
|
||||
uids, err := GetAllProcessingOrders()
|
||||
if err != nil {
|
||||
log.Error("GetAllProcessingUser", log.E(err))
|
||||
}
|
||||
if len(uids) > 0 {
|
||||
cond["uid"] = bson.M{"$nin": uids}
|
||||
}
|
||||
}
|
||||
}
|
||||
delete(cond, "filterChecked")
|
||||
return wdordmod.FindOrders(cond, opt)
|
||||
}
|
||||
|
||||
// GetAllProcessingOrders 获取过去15分钟内缓存的所有审核过的订单
|
||||
func GetAllProcessingOrders() (uids []uint64, err error) {
|
||||
redisc := getRedis()
|
||||
if redisc != nil {
|
||||
now := time.Now()
|
||||
start := fmt.Sprintf("%d", now.Add(-redisconst.WithdrawOrderDuration).Unix())
|
||||
end := fmt.Sprintf("%d", now.Unix())
|
||||
uidStrs, err := redisc.ZRangeByScore(redisconst.WithdrawOrderKey, start, end)
|
||||
if err != nil {
|
||||
return uids, err
|
||||
}
|
||||
uids = make([]uint64, 0, len(uidStrs))
|
||||
for _, str := range uidStrs {
|
||||
uid, err := strconv.ParseUint(str, 0, 64)
|
||||
if err != nil {
|
||||
log.Error("strconv.ParseUint", log.Any("str", str), log.E(err))
|
||||
continue
|
||||
}
|
||||
uids = append(uids, uid)
|
||||
}
|
||||
common.Go(func() {
|
||||
DelCacheProcessingOrders()
|
||||
})
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DelCacheProcessingOrders 删除过期数据(超过配置时间窗口的数据:-inf~前15分钟)
|
||||
func DelCacheProcessingOrders() {
|
||||
now := time.Now()
|
||||
start := "-inf"
|
||||
end := fmt.Sprintf("(%d", now.Add(-redisconst.WithdrawOrderDuration).Unix())
|
||||
removed, err := getRedis().ZRemRangeByScore(redisconst.WithdrawOrderKey, start, end)
|
||||
if err != nil {
|
||||
log.Error("redisc.ZRemRangeByScore", log.Any("start", start), log.Any("end", end), log.E(err))
|
||||
}
|
||||
log.Info("redisc.ZRemRangeByScore removed success", log.Any("start", start), log.Any("end", end),
|
||||
log.Any("number", removed))
|
||||
}
|
||||
|
||||
// CacheProcessingOrder 缓存正在审核中的订单
|
||||
func CacheProcessingOrder(uid uint64) error {
|
||||
redisc := getRedis()
|
||||
if redisc != nil {
|
||||
_, err := redisc.ZAdd(redisconst.WithdrawOrderKey, redis.Member{Score: float64(time.Now().Unix()), Member: uid})
|
||||
return err
|
||||
}
|
||||
return errors.New("nil redis client")
|
||||
}
|
||||
|
||||
func getRedis() *redis.Client {
|
||||
if appg.Redis != nil {
|
||||
return appg.Redis
|
||||
}
|
||||
if webg.Redis != nil {
|
||||
return webg.Redis
|
||||
}
|
||||
if skdg.Redis != nil {
|
||||
return skdg.Redis
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ExchgCallBack 提现回调
|
||||
func ExchgCallBack(tradeNo string, oid string, money int64, status string, mark string) (err error) {
|
||||
w, err := wdordmod.FindWithdrawOrderByID(tradeNo)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if w.Status == wdordmod.SUCCESS || w.Status == wdordmod.FAILURE {
|
||||
return
|
||||
}
|
||||
if w.Status != wdordmod.PROCESSING && w.Status != wdordmod.UNKNOWN {
|
||||
err = errors.New("Wtihdraw status error")
|
||||
log.Error(fmt.Sprintf("Wtihdraw status error ,order:%+v:", w))
|
||||
return
|
||||
}
|
||||
now := time.Now()
|
||||
set := wdordmod.EditSelector{
|
||||
ReceivedAt: &now,
|
||||
OID: &oid,
|
||||
}
|
||||
switch status {
|
||||
case "paid": //已经打款
|
||||
//修改订单状态
|
||||
set.PayMoney = &money
|
||||
set.SuccessAt = &now
|
||||
set.Status = wdordmod.SUCCESS
|
||||
set.StatusDesc = wdordmod.SUCCESSStatus
|
||||
set.SuccessAt = &now
|
||||
if err = wdordmod.Update(nil, tradeNo, set); err != nil {
|
||||
return
|
||||
}
|
||||
case "refused": //拒绝
|
||||
set.Status = wdordmod.FAILURE
|
||||
set.StatusDesc = mark
|
||||
set.FailureAt = &now
|
||||
if err = refusedWirhdraw(w, set, "提现被平台拒绝"); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func refusedWirhdraw(w wdordmod.WithdrawOrder, set wdordmod.EditSelector, mark string) error {
|
||||
if w.ID.IsZero() {
|
||||
return errors.New("id is invalid")
|
||||
}
|
||||
if w.ProductType == 1 {
|
||||
return errors.New("瓦力游戏已下架")
|
||||
}
|
||||
return webg.VideoDB.Trans(func(t *db.MongoTool) error {
|
||||
switch w.WithdrawType {
|
||||
case wdordmod.GoldWithdraw:
|
||||
wallet, err := walletmod.CreditIncome(t, w.Amount, w.UID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
//插入收支流水
|
||||
tk := txnmod.TransactionLog{
|
||||
TransNo: w.ID,
|
||||
UID: w.UID,
|
||||
Amount: w.Amount,
|
||||
TranType: txnmod.WithdrawRefund.Key(),
|
||||
TranTypeInt: int64(txnmod.WithdrawRefund),
|
||||
ChannelType: w.PayType,
|
||||
Desc: "用户提现失败,退款" + strconv.FormatInt(w.Amount, 10),
|
||||
DiscDoc: w.DiscDoc,
|
||||
SysType: w.DeviceType,
|
||||
ActualAmount: float64(w.Amount),
|
||||
RealAmount: walletmod.GetRealAmount(wallet),
|
||||
}
|
||||
//插入一条支出流水
|
||||
if err = txnmod.InsertTransactionLog(t, &tk); err != nil {
|
||||
return err
|
||||
}
|
||||
case wdordmod.AgentWithdraw:
|
||||
if err := walletmod.CreditMoney(t, w.Money, w.UID); err != nil {
|
||||
return err
|
||||
}
|
||||
case wdordmod.DiscWithdraw:
|
||||
// err = discWirhdrawRefund(t, w, mark)
|
||||
// if err != nil {
|
||||
// log.Error("discWirhdrawRefund failed", log.E(err), log.Any("witOrd", w))
|
||||
// return err
|
||||
// }
|
||||
default:
|
||||
return errors.New("invalid type")
|
||||
}
|
||||
return wdordmod.Update(t, w.ID.Hex(), set)
|
||||
})
|
||||
}
|
||||
|
||||
// WithdrawType 获取提现方式
|
||||
func WithdrawType() (res []*wdchannmod.WithdrawChannelRes, err error) {
|
||||
wt, err := wdtaxmod.GetWithDrawTariff()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
wcs, err := wdchannmod.GetWithdrawChannels()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
res = make([]*wdchannmod.WithdrawChannelRes, len(wcs))
|
||||
for i, v := range wcs {
|
||||
res[i] = &wdchannmod.WithdrawChannelRes{
|
||||
WithdrawChannel: *v,
|
||||
WithdrawTariff: wt,
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
type WithdrawMethod struct {
|
||||
ChannelName string //提现渠道名字
|
||||
CID string //渠道id
|
||||
PayType string //支付方式
|
||||
MinMoney int //支持最小支付金额
|
||||
QpMinMoney int //支持棋牌最小支付金额
|
||||
MaxMoney int //支持最大支付金额
|
||||
Weight int //权重
|
||||
Active bool //是否激活
|
||||
CashTax int //代理提现比率
|
||||
CoinTax int //金币提现比率
|
||||
DiscCashTax int //商区提现比率
|
||||
}
|
||||
|
||||
func (w WithdrawMethod) IsValid() bool {
|
||||
return w.ChannelName != "" && w.CID != ""
|
||||
}
|
||||
|
||||
// GetWithdrawMethod 获取提现方法
|
||||
func GetWithdrawMethod(paymentMethod string) (WithdrawMethod, error) {
|
||||
active := true
|
||||
mats := []wdchannmod.Matcher{
|
||||
(&wdchannmod.ActiveMatch{Active: &active}).New(),
|
||||
(&wdchannmod.PayTypeMatch{PayType: &paymentMethod}).New(),
|
||||
}
|
||||
wcList, err := wdchannmod.List(nil, nil, nil, mats...)
|
||||
if err != nil {
|
||||
log.Error("GetWithdrawChannel failed", log.E(err))
|
||||
return WithdrawMethod{}, err
|
||||
}
|
||||
wc := wcList.WeightedRandom()
|
||||
if wc.ID.IsZero() {
|
||||
return WithdrawMethod{}, nil
|
||||
}
|
||||
var method WithdrawMethod
|
||||
method.ChannelName = wc.ChannelName
|
||||
method.CID = wc.CID
|
||||
method.PayType = wc.PayType
|
||||
method.MinMoney = wc.MinMoney
|
||||
method.QpMinMoney = wc.QpMinMoney
|
||||
method.MaxMoney = wc.MaxMoney
|
||||
method.Weight = wc.Weight
|
||||
method.Active = wc.Active
|
||||
wt, err := wdtaxmod.GetWithDrawTariff()
|
||||
if err != nil {
|
||||
log.Error("GetWithDrawTariff failed", log.E(err))
|
||||
return WithdrawMethod{}, err
|
||||
}
|
||||
method.CashTax = wt.CashTax
|
||||
method.CoinTax = wt.CoinTax
|
||||
method.DiscCashTax = wt.DiscCashTax
|
||||
return method, nil
|
||||
}
|
||||
Reference in New Issue
Block a user