1547 lines
42 KiB
Go
1547 lines
42 KiB
Go
package biz
|
||
|
||
import (
|
||
"context"
|
||
"encoding/json"
|
||
"fmt"
|
||
"strconv"
|
||
"strings"
|
||
"time"
|
||
|
||
"sandc/app/eonline/internal/conf"
|
||
"sandc/app/eonline/internal/config"
|
||
"sandc/pkg/geo"
|
||
"sandc/pkg/middleware/xhttp"
|
||
"sandc/pkg/utils"
|
||
|
||
"github.com/go-kratos/kratos/v2/log"
|
||
"github.com/hibiken/asynq"
|
||
"github.com/tx7do/kratos-transport/broker"
|
||
)
|
||
|
||
type Eonline struct {
|
||
Hello string
|
||
}
|
||
|
||
type EonlineRepo interface {
|
||
CreateEonline(context.Context, *Eonline) error
|
||
UpdateEonline(context.Context, *Eonline) error
|
||
|
||
GetUserByUuid(ctx context.Context, uuid string) (*PayoutUser, error)
|
||
CreatePayoutUser(ctx context.Context, item *PayoutUser) (*PayoutUser, error)
|
||
SearchPayoutRecord(ctx context.Context, opts *SearchPayoutRecordReq) (*ListPayoutRecord, error)
|
||
GetPayoutLeftum(ctx context.Context, uuid string) (int, error)
|
||
GetPayoutRecordCountByAccount(ctx context.Context, account string) (int, error)
|
||
CreatePayoutRecord(ctx context.Context, item *PayoutRecord) (*PayoutRecord, error)
|
||
UpdatePayoutRecordNotify(ctx context.Context, recordNo string, payoutId string, status uint8, fail string) error
|
||
GetPayoutRecordListByUuid(ctx context.Context, uuid string) ([]*PayoutRecord, error)
|
||
// GetPayoutRecordByRecordNo 获取提现记录
|
||
GetPayoutRecordByRecordNo(ctx context.Context, recordNo string) (*PayoutRecord, error)
|
||
// 根据account、status 获取提现记录
|
||
GetPayoutRecordByAccountStatus(ctx context.Context, account string, status, pageIndex, pageSize int) ([]*PayoutRecord, error)
|
||
// UpdatePayoutUserLoginDays 更新用户登录天数
|
||
UpdatePayoutUserLoginDays(ctx context.Context, uuid string, loginDays uint) error
|
||
// 更新 客户端上传的、需要保持的数据
|
||
UpdatePayoutUserClientData(ctx context.Context, uuid string, clientData string) error
|
||
|
||
CreateBonusRecord(ctx context.Context, item *BonusRecord) (*BonusRecord, error)
|
||
UpdateBonusCur(ctx context.Context, id uint32, bonusCur uint32) error
|
||
}
|
||
|
||
type EonlineUsecase struct {
|
||
repo EonlineRepo
|
||
conf *conf.Bootstrap
|
||
log *log.Helper
|
||
tx Transaction
|
||
pscli *PagsmileClient
|
||
cache Cache
|
||
geocli *geo.GeoClient
|
||
}
|
||
|
||
func NewEonlineUsecase(repo EonlineRepo, conf *conf.Bootstrap, tx Transaction, logger log.Logger, cache Cache) *EonlineUsecase {
|
||
return &EonlineUsecase{
|
||
repo: repo,
|
||
tx: tx,
|
||
log: log.NewHelper(logger),
|
||
pscli: NewPagsmileClient(&PayoutClient{
|
||
AppId: conf.Pagsmile.Payout.AppId,
|
||
AppKey: conf.Pagsmile.Payout.AppKey,
|
||
ApiUrl: conf.Pagsmile.Payout.ApiUrl,
|
||
NotifyUrl: conf.Pagsmile.Payout.NotifyUrl,
|
||
}, logger),
|
||
conf: conf,
|
||
cache: cache,
|
||
geocli: geo.NewGeoClient(conf.Server.GeoFile),
|
||
}
|
||
}
|
||
|
||
func (uc *EonlineUsecase) Create(ctx context.Context, g *Eonline) error {
|
||
return uc.repo.CreateEonline(ctx, g)
|
||
}
|
||
|
||
func (uc *EonlineUsecase) Update(ctx context.Context, g *Eonline) error {
|
||
return uc.repo.UpdateEonline(ctx, g)
|
||
}
|
||
|
||
func (uc *EonlineUsecase) KakfaExampleConsumer(_ context.Context, topic string, headers broker.Headers, msg *ExampleStruct) error {
|
||
log.Infof("Topic %s, Headers: %+v, Payload: %+v\n", topic, headers, msg)
|
||
return nil
|
||
}
|
||
|
||
const EonlineTaskName = "eonline:task"
|
||
|
||
// AsynqEonlineTaskHandler Asynq handler task
|
||
func (uc *EonlineUsecase) AsynqEonlineTaskHandler(ctx context.Context, t *asynq.Task) error {
|
||
// do something
|
||
// do some else logging
|
||
log.Info("AsynqEonlineTaskHandle: ", string(t.Payload()))
|
||
return nil
|
||
}
|
||
|
||
// PayInitReq 支付初始化请求
|
||
type PayInitReq struct {
|
||
DeviceId string
|
||
}
|
||
|
||
// PayInitReply 支付初始化响应
|
||
type PayInitReply struct {
|
||
UUID string
|
||
ClientData string
|
||
Days uint32 // 登录天数
|
||
Items []*PayoutItem
|
||
}
|
||
|
||
// PayoutItem 支付项目
|
||
type PayoutItem struct {
|
||
Id uint
|
||
Amount float64
|
||
Status uint8
|
||
}
|
||
|
||
// PayInit
|
||
func (uc *EonlineUsecase) PayInit(ctx context.Context, req *PayoutAddtionalReq) (*PayInitReply, error) {
|
||
// 生成唯一用户ID
|
||
uuid := GenPayoutUuid(req.DeviceId)
|
||
err := uc.initUserLoginDays(ctx, uuid, req)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("init user login days error: %v", err)
|
||
}
|
||
|
||
// 判断是否提现
|
||
payoutValidRes, err, _ := uc.checkPayoutValid(ctx, uuid, req)
|
||
if err != nil {
|
||
// 如果不允许提现,状态全部更改为不可提现
|
||
payoutValidRes.LeftNum[uint(PayoutItemId1)] = -1
|
||
payoutValidRes.LeftNum[uint(PayoutItemId2)] = -1
|
||
payoutValidRes.LeftNum[uint(PayoutItemId3)] = -1
|
||
payoutValidRes.LeftNum[uint(PayoutItemId4)] = -1
|
||
}
|
||
|
||
items := make([]*PayoutItem, 0)
|
||
for k, v := range PayoutItemIdAmountes {
|
||
if k == 0 {
|
||
continue
|
||
}
|
||
// 生成对应的payoutItem
|
||
payoutItem := &PayoutItem{
|
||
Id: uint(k),
|
||
Amount: v,
|
||
Status: uint8(uc.getPayoutItemStatus(ctx, uuid, req.Ts, uint(k), payoutValidRes)),
|
||
}
|
||
|
||
items = append(items, payoutItem)
|
||
}
|
||
|
||
reply := &PayInitReply{
|
||
UUID: uuid,
|
||
ClientData: payoutValidRes.ClientData,
|
||
Days: payoutValidRes.Days,
|
||
Items: items,
|
||
}
|
||
|
||
return reply, nil
|
||
}
|
||
|
||
// initUserLoginDays 初始化用户登录天数
|
||
func (uc *EonlineUsecase) initUserLoginDays(ctx context.Context, uuid string, req *PayoutAddtionalReq) error {
|
||
// 插入用户登录信息
|
||
// 判断当前用户是否存在
|
||
user, err := uc.repo.GetUserByUuid(ctx, uuid)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
|
||
// 定义用户登录redis key
|
||
keyDay := ""
|
||
if uc.conf.Server.Env == "qa" {
|
||
ts, _ := strconv.ParseInt(req.Ts, 10, 64)
|
||
keyDay = time.Unix(ts, 0).Format("20060102")
|
||
}
|
||
userLoginRedisKey := GetUserLoginRedisKey(uuid, keyDay)
|
||
|
||
// 创建用户
|
||
if user.Id == 0 {
|
||
// 记录登录用户
|
||
_, err = uc.repo.CreatePayoutUser(ctx, &PayoutUser{
|
||
Uuid: uuid,
|
||
DeviceId: req.DeviceId,
|
||
Platform: req.Platform,
|
||
Version: req.Version,
|
||
Country: req.Country,
|
||
Ip: req.Ip,
|
||
LoginDays: 1,
|
||
})
|
||
if err != nil {
|
||
return err
|
||
}
|
||
|
||
// 是否已记录当前登录行为
|
||
err = uc.cache.WriteValue(ctx, userLoginRedisKey, "1", 24*3600)
|
||
if err != nil {
|
||
return fmt.Errorf("write redis error: %v", err)
|
||
}
|
||
} else {
|
||
// 更新登录天数
|
||
currentValue, err := uc.cache.GetValue(ctx, userLoginRedisKey)
|
||
if err != nil {
|
||
return fmt.Errorf("get redis value error: %v", err)
|
||
}
|
||
|
||
if currentValue == "" {
|
||
// 更新登录天数
|
||
loginDays := user.LoginDays + 1
|
||
err = uc.repo.UpdatePayoutUserLoginDays(ctx, uuid, loginDays)
|
||
if err != nil {
|
||
return fmt.Errorf("update payout user login days error: %v", err)
|
||
}
|
||
|
||
// 记录当前登录行为
|
||
err = uc.cache.WriteValue(ctx, userLoginRedisKey, "1", 24*3600)
|
||
if err != nil {
|
||
return fmt.Errorf("write redis error: %v", err)
|
||
}
|
||
}
|
||
}
|
||
|
||
return nil
|
||
}
|
||
|
||
func (uc *EonlineUsecase) updateUserClientData(ctx context.Context, uuid string, clientData string) error {
|
||
err := uc.repo.UpdatePayoutUserClientData(ctx, uuid, clientData)
|
||
if err != nil {
|
||
return fmt.Errorf("update payout user clientData error: %v", err)
|
||
}
|
||
|
||
return nil
|
||
}
|
||
|
||
// getPayoutItemStatus 获取提现项目状态
|
||
func (uc *EonlineUsecase) getPayoutItemStatus(ctx context.Context, uuid, ts string, itemId uint, payoutValidRes *PayoutValidRes) PayoutItemStatus {
|
||
leftNum, ok := payoutValidRes.LeftNum[itemId]
|
||
if !ok || leftNum <= 0 {
|
||
return PayoutItemStatusForbidden
|
||
}
|
||
|
||
if _, ok = payoutValidRes.RecordStatusMap[itemId]; ok {
|
||
switch payoutValidRes.RecordStatusMap[itemId] {
|
||
// 提现成功的状态,返回已提现
|
||
case uint8(PayoutStatusPayouted):
|
||
return PayoutItemStatusPayouted
|
||
// 提现失败的状态,返回可提现
|
||
case uint8(PayoutStatusPayoutFailed):
|
||
return PayoutItemStatusAvailable
|
||
// 提现中的状态,返回提现中
|
||
case uint8(PayoutStatusPayouting):
|
||
return PayoutItemStatusPayouting
|
||
default:
|
||
return PayoutItemStatusForbidden
|
||
}
|
||
}
|
||
|
||
// 如果没有提现记录,返回可提现
|
||
if itemId == 1 {
|
||
return PayoutItemStatusAvailable
|
||
}
|
||
|
||
// 如果没有提现记录,返回可提现
|
||
// 根据uuid查询用户是否满足第二天的提现条件
|
||
// user, err := uc.repo.GetUserByUuid(ctx, uuid)
|
||
// if err != nil {
|
||
// return PayoutItemStatusForbidden
|
||
// }
|
||
//
|
||
// if user.LoginDays >= 3 && payoutValidRes.LeftNum[itemId] == 1 {
|
||
// return PayoutItemStatusAvailable
|
||
// } else {
|
||
// return PayoutItemStatusUnfinished
|
||
// }
|
||
|
||
keyDay := ""
|
||
if uc.conf.Server.Env == "qa" {
|
||
ts, _ := strconv.ParseInt(ts, 10, 64)
|
||
keyDay = time.Unix(ts, 0).Format("20060102")
|
||
}
|
||
|
||
uuidRedisKey := GetUuidPayoutRedisKey(uuid, keyDay, uint32(itemId))
|
||
v, err := uc.cache.GetValue(ctx, uuidRedisKey)
|
||
if err != nil {
|
||
// uc.log.WithContext(ctx).Errorf("get redis value error: %v", err)
|
||
log.Infof("get redis value error: %v", err)
|
||
return PayoutItemStatusUnfinished
|
||
}
|
||
if v == "" && leftNum > 0 {
|
||
return PayoutItemStatusAvailable
|
||
} else {
|
||
return PayoutItemStatusUnfinished
|
||
}
|
||
}
|
||
|
||
// PayoutValidRes 提现是否有效响应
|
||
type PayoutValidRes struct {
|
||
Days uint32
|
||
LeftNum map[uint]int
|
||
RecordStatusMap map[uint]uint8
|
||
ClientData string
|
||
}
|
||
|
||
// true表示可以提现的国家
|
||
func canPayoutCountry(country string) bool {
|
||
if country == "US" || country == "CA" || country == "IN" || country == "PH" || country == "ID" || country == "VN" || country == "TH" || country == "BR" {
|
||
return true
|
||
}
|
||
return false
|
||
}
|
||
|
||
// 转换国家代码
|
||
func convertCountry(country string) string {
|
||
if country == "US" { // 美国
|
||
return "USA"
|
||
} else if country == "CA" { // 加拿大
|
||
return "CAN"
|
||
} else if country == "IN" { // 印度
|
||
return "IND"
|
||
} else if country == "PH" { // 菲律宾
|
||
return "PHL"
|
||
} else if country == "ID" { // 印度尼西亚
|
||
return "IDN"
|
||
} else if country == "VN" { // 越南
|
||
return "VNM"
|
||
} else if country == "TH" { // 泰国
|
||
return "THA"
|
||
} else if country == "BR" { // 巴西
|
||
return "BRA"
|
||
}
|
||
|
||
log.Infof("convertCountry error: country[%s]", country)
|
||
return country
|
||
}
|
||
|
||
// checkPayoutValid 检查提现是否有效,1+2位数
|
||
func (uc *EonlineUsecase) checkPayoutValid(ctx context.Context, uuid string, opts *PayoutAddtionalReq) (*PayoutValidRes, error, int32) {
|
||
payoutValidRes := &PayoutValidRes{
|
||
Days: 0,
|
||
LeftNum: make(map[uint]int),
|
||
RecordStatusMap: make(map[uint]uint8),
|
||
}
|
||
|
||
// 判断是否可以提现,国家判断
|
||
// if opts.Country != "US" && opts.Country != "CA" && opts.Country != "IN" && opts.Country != "PH" {
|
||
// if !canPayoutCountry(opts.Country) {
|
||
// return payoutValidRes, fmt.Errorf("country [%s] not support", opts.Country), 101
|
||
// }
|
||
|
||
if opts.ItemId > 0 {
|
||
if opts.ItemId <= uint32(len(PayoutItemIdAmountes)) {
|
||
// 判断金额是否一致
|
||
if int32(opts.Amount*100) != int32(PayoutItemIdAmountes[int(opts.ItemId)]*100) {
|
||
return payoutValidRes, fmt.Errorf("amount error"), 102
|
||
}
|
||
} else {
|
||
return payoutValidRes, fmt.Errorf("ItemId error"), 103
|
||
}
|
||
}
|
||
|
||
user, err := uc.repo.GetUserByUuid(ctx, uuid)
|
||
if err != nil {
|
||
return payoutValidRes, err, 1
|
||
}
|
||
|
||
payoutValidRes.Days = uint32(user.LoginDays)
|
||
payoutValidRes.ClientData = user.ClientData
|
||
|
||
records, err := uc.repo.GetPayoutRecordListByUuid(ctx, uuid)
|
||
if err != nil {
|
||
return payoutValidRes, err, 1
|
||
}
|
||
|
||
var num1, num2, num3, num4 int
|
||
var lastest1, lastest2, lastest3, lastest4 *PayoutRecord
|
||
var leftAmount float64
|
||
for _, record := range records {
|
||
if record.ItemId == uint(PayoutItemId4) {
|
||
continue
|
||
}
|
||
|
||
switch record.ItemId {
|
||
case uint(PayoutItemId1):
|
||
if record.Status == uint8(PayoutStatusPayouted) || record.Status == uint8(PayoutStatusPayouting) {
|
||
num1++
|
||
leftAmount += record.Amount
|
||
}
|
||
if lastest1 != nil {
|
||
if lastest1.CreatedAt.Compare(record.CreatedAt) < 0 {
|
||
lastest1 = record
|
||
}
|
||
} else {
|
||
lastest1 = record
|
||
}
|
||
case uint(PayoutItemId2):
|
||
if record.Status == uint8(PayoutStatusPayouted) || record.Status == uint8(PayoutStatusPayouting) {
|
||
num2++
|
||
leftAmount += record.Amount
|
||
}
|
||
if lastest2 != nil {
|
||
if lastest2.CreatedAt.Compare(record.CreatedAt) < 0 {
|
||
lastest2 = record
|
||
}
|
||
} else {
|
||
lastest2 = record
|
||
}
|
||
case uint(PayoutItemId3):
|
||
if record.Status == uint8(PayoutStatusPayouted) || record.Status == uint8(PayoutStatusPayouting) {
|
||
num3++
|
||
leftAmount += record.Amount
|
||
}
|
||
if lastest3 != nil {
|
||
if lastest3.CreatedAt.Compare(record.CreatedAt) < 0 {
|
||
lastest3 = record
|
||
}
|
||
} else {
|
||
lastest3 = record
|
||
}
|
||
case uint(PayoutItemId4):
|
||
if record.Status == uint8(PayoutStatusPayouted) || record.Status == uint8(PayoutStatusPayouting) {
|
||
num4++
|
||
}
|
||
if lastest4 != nil {
|
||
if lastest4.CreatedAt.Compare(record.CreatedAt) < 0 {
|
||
lastest4 = record
|
||
}
|
||
} else {
|
||
lastest4 = record
|
||
}
|
||
default:
|
||
log.Infof("checkPayoutValid error: uuid[%s] record.ItemId[%d] not dispatch No.1", uuid, record.ItemId)
|
||
}
|
||
}
|
||
|
||
ts, _ := strconv.ParseInt(opts.Ts, 10, 64)
|
||
|
||
keyDay := ""
|
||
if uc.conf.Server.Env == "qa" {
|
||
keyDay = time.Unix(ts, 0).Format("20060102")
|
||
}
|
||
|
||
var now time.Time
|
||
now = time.Unix(ts, 0)
|
||
recordStatusMap := make(map[uint]uint8)
|
||
if lastest1 != nil {
|
||
if isSameDay(now, lastest1.CreatedAt) {
|
||
recordStatusMap[lastest1.ItemId] = lastest1.Status
|
||
}
|
||
}
|
||
|
||
if lastest2 != nil {
|
||
if isSameDay(now, lastest2.CreatedAt) {
|
||
recordStatusMap[lastest2.ItemId] = lastest2.Status
|
||
}
|
||
}
|
||
|
||
if lastest3 != nil {
|
||
if isSameDay(now, lastest3.CreatedAt) {
|
||
recordStatusMap[lastest3.ItemId] = lastest3.Status
|
||
}
|
||
}
|
||
|
||
if lastest4 != nil {
|
||
if isSameDay(now, lastest4.CreatedAt) {
|
||
recordStatusMap[lastest4.ItemId] = lastest4.Status
|
||
}
|
||
}
|
||
|
||
// true表示今天已提现过
|
||
// callCheckTodayPayoutStatus := func(itemId PayoutItemId) bool {
|
||
// uuidRedisKey := GetUuidPayoutRedisKey(uuid, keyDay, uint32(itemId))
|
||
// value, err := uc.cache.GetValue(ctx, uuidRedisKey)
|
||
// if err == nil {
|
||
// if value != "" {
|
||
// return true
|
||
// }
|
||
// }
|
||
// return false
|
||
// }
|
||
|
||
// 检查已提现次数
|
||
if num1 < PayoutRecordLimit1 {
|
||
payoutValidRes.LeftNum[uint(PayoutItemId1)] = PayoutRecordLimit1 - num1
|
||
} else {
|
||
payoutValidRes.LeftNum[uint(PayoutItemId1)] = -1
|
||
}
|
||
|
||
if num2 < PayoutRecordLimit2 {
|
||
payoutValidRes.LeftNum[uint(PayoutItemId2)] = PayoutRecordLimit2 - num2
|
||
} else {
|
||
payoutValidRes.LeftNum[uint(PayoutItemId2)] = -1
|
||
}
|
||
|
||
if num3 < PayoutRecordLimit3 {
|
||
payoutValidRes.LeftNum[uint(PayoutItemId3)] = PayoutRecordLimit3 - num3
|
||
} else {
|
||
payoutValidRes.LeftNum[uint(PayoutItemId3)] = -1
|
||
}
|
||
|
||
if num4 < PayoutRecordLimit4 {
|
||
payoutValidRes.LeftNum[uint(PayoutItemId4)] = PayoutRecordLimit4 - num4
|
||
} else {
|
||
payoutValidRes.LeftNum[uint(PayoutItemId4)] = -1
|
||
}
|
||
|
||
payoutValidRes.RecordStatusMap = recordStatusMap
|
||
// 判断金额
|
||
leftAmount += opts.Amount
|
||
if leftAmount > PayoutAmountLimit {
|
||
return payoutValidRes, fmt.Errorf("amount limit"), 104
|
||
}
|
||
|
||
if opts.ItemId > 0 {
|
||
// 首次提现必须是0.1
|
||
if num1+num2+num3+num4 <= 0 {
|
||
if opts.ItemId != uint32(PayoutItemId1) {
|
||
return payoutValidRes, fmt.Errorf("ItemId error"), 108
|
||
}
|
||
}
|
||
|
||
switch opts.ItemId {
|
||
case 1:
|
||
if num1 >= PayoutRecordLimit1 {
|
||
return payoutValidRes, fmt.Errorf("no payout chance"), 105
|
||
}
|
||
case 2:
|
||
if num2 >= PayoutRecordLimit2 {
|
||
return payoutValidRes, fmt.Errorf("no payout chance"), 105
|
||
}
|
||
case 3:
|
||
if num3 >= PayoutRecordLimit3 {
|
||
return payoutValidRes, fmt.Errorf("no payout chance"), 105
|
||
}
|
||
case 4:
|
||
if num4 >= PayoutRecordLimit4 {
|
||
return payoutValidRes, fmt.Errorf("no payout chance"), 105
|
||
}
|
||
default:
|
||
log.Infof("checkPayoutValid error: uuid[%s] record.ItemId[%d] not dispatch No.2", uuid, opts.ItemId)
|
||
return payoutValidRes, fmt.Errorf("no payout chance"), 105
|
||
}
|
||
} else {
|
||
|
||
}
|
||
// if leftNum1 <= 0 {
|
||
// return payoutValidRes, fmt.Errorf("no payout chance"), 105
|
||
// }
|
||
|
||
if opts.ItemId > 0 {
|
||
uuidRedisKey := GetUuidPayoutRedisKey(uuid, keyDay, opts.ItemId)
|
||
value, err := uc.cache.GetValue(ctx, uuidRedisKey)
|
||
if err != nil {
|
||
return payoutValidRes, err, 1
|
||
}
|
||
// 次日才能进行第二次提现(逻辑保留)
|
||
if value != "" {
|
||
return payoutValidRes, fmt.Errorf("no payout chance, please try tomorrow"), 106
|
||
}
|
||
}
|
||
|
||
// 登录第三日才能体现第二次
|
||
// if leftNum1 == 1 && user.LoginDays < 3 && opts.ItemId > 0 {
|
||
// return payoutValidRes, fmt.Errorf("no payout chance, please try tomorrow")
|
||
// }
|
||
|
||
if len(opts.Account) > 0 {
|
||
// 如果是qa环境,test账号不限制提现次数
|
||
// if uc.conf.Server.Env == "qa" && opts.Account == "pagsmile_test_success@pagsmile.com" {
|
||
if uc.conf.Server.Env == "qa" && strings.Contains(opts.Account, "@pagsmile.com") {
|
||
return payoutValidRes, nil, 0
|
||
}
|
||
|
||
// 一个账号只能提现2次
|
||
count, err := uc.repo.GetPayoutRecordCountByAccount(ctx, opts.Account)
|
||
if err != nil {
|
||
return payoutValidRes, err, 1
|
||
}
|
||
|
||
if count >= PayoutRecordLimit1+PayoutRecordLimit2+PayoutRecordLimit3+PayoutRecordLimit4 {
|
||
return payoutValidRes, fmt.Errorf("account payouted limit"), 107
|
||
}
|
||
}
|
||
|
||
return payoutValidRes, nil, 0
|
||
}
|
||
|
||
// 1+2位数
|
||
func (uc *EonlineUsecase) checkPayoutValidNew(ctx context.Context, uuid string, opts *PayoutAddtionalReq) (*PayoutValidRes, error, int32) {
|
||
x, err := uc.CheckInfo(ctx, &CheckInfoReq{
|
||
Uuid: uuid,
|
||
Ts: opts.Ts,
|
||
})
|
||
if err != nil {
|
||
return nil, fmt.Errorf("error: %w", err), 1
|
||
}
|
||
|
||
if x.CanCheckPayOut == 1 {
|
||
return nil, fmt.Errorf("can't payout"), 150
|
||
}
|
||
|
||
payoutValidRes := &PayoutValidRes{
|
||
LeftNum: make(map[uint]int),
|
||
RecordStatusMap: make(map[uint]uint8),
|
||
}
|
||
// 判断是否可以提现,国家判断
|
||
// if opts.Country != "US" && opts.Country != "CA" && opts.Country != "IN" && opts.Country != "PH" {
|
||
// if !canPayoutCountry(opts.Country) {
|
||
// return payoutValidRes, fmt.Errorf("country [%s] not support", opts.Country), 101
|
||
// }
|
||
|
||
// 判断金额是否一致
|
||
if int32(opts.Amount*100) != config.PublicCheckCoin {
|
||
return payoutValidRes, fmt.Errorf("amount error"), 102
|
||
}
|
||
|
||
records, err := uc.repo.GetPayoutRecordListByUuid(ctx, uuid)
|
||
if err != nil {
|
||
return payoutValidRes, err, 1
|
||
}
|
||
|
||
recordStatusMap := make(map[uint]uint8)
|
||
for _, record := range records {
|
||
if _, ok := recordStatusMap[record.ItemId]; !ok {
|
||
recordStatusMap[record.ItemId] = record.Status
|
||
}
|
||
}
|
||
payoutValidRes.RecordStatusMap = recordStatusMap
|
||
|
||
status, ok := recordStatusMap[uint(PayoutItemId4)]
|
||
if ok {
|
||
if status == uint8(PayoutStatusPayouted) || status == uint8(PayoutStatusPayouting) {
|
||
return payoutValidRes, fmt.Errorf("no payout chance"), 105
|
||
}
|
||
}
|
||
|
||
// keyDay := ""
|
||
// if uc.conf.Server.Env == "qa" {
|
||
// ts, _ := strconv.ParseInt(opts.Ts, 10, 64)
|
||
// keyDay = time.Unix(ts, 0).Format("20060102")
|
||
// }
|
||
//
|
||
// uuidRedisKey := GetUuidPayoutRedisKey(uuid, keyDay)
|
||
// value, err := uc.cache.GetValue(ctx, uuidRedisKey)
|
||
// if err != nil {
|
||
// return payoutValidRes, err
|
||
// }
|
||
//
|
||
// // 次日才能进行第二次体现(逻辑保留)
|
||
// if value != "" && opts.ItemId > 0 {
|
||
// return payoutValidRes, fmt.Errorf("no payout chance, please try tomorrow")
|
||
// }
|
||
|
||
return payoutValidRes, nil, 0
|
||
}
|
||
|
||
// PayoutAddtionalReq 支付附加请求
|
||
type PayoutAddtionalReq struct {
|
||
Platform string
|
||
DeviceId string
|
||
Version string
|
||
EcpmLvl uint32
|
||
ItemId uint32
|
||
Ip string
|
||
Amount float64
|
||
Country string
|
||
Account string
|
||
Ts string
|
||
Email string
|
||
}
|
||
|
||
// Payout 支付请求
|
||
func (uc *EonlineUsecase) Payout(ctx context.Context, uuid string, opts *PayoutAddtionalReq, req *PayoutReq) (*PayoutReplyData, error, int32) {
|
||
// 定义一个uuid的redis key
|
||
keyDay := ""
|
||
if uc.conf.Server.Env == "qa" {
|
||
ts, _ := strconv.ParseInt(opts.Ts, 10, 64)
|
||
keyDay = time.Unix(ts, 0).Format("20060102")
|
||
}
|
||
uuidRedisKey := GetUuidPayoutRedisKey(uuid, keyDay, opts.ItemId)
|
||
// 定义一个uuid的redis lock key, 用于锁定, 防止并发
|
||
uuidRedisLockKey := GetUuidLockRedisKey(uuid, keyDay)
|
||
lock, _ := uc.cache.RedisLock(ctx, uuidRedisLockKey, 1, 20)
|
||
if !lock {
|
||
return nil, fmt.Errorf("lock error"), 1
|
||
}
|
||
defer func() {
|
||
uc.cache.RedisUnLock(ctx, uuidRedisLockKey)
|
||
}()
|
||
|
||
country, currentIp := uc.GetCountryCodeByIp(ctx, opts.Ip)
|
||
opts.Country = country
|
||
opts.Ip = currentIp
|
||
|
||
// 验证提现是否有效
|
||
var err error
|
||
var errCode int32
|
||
if opts.ItemId == uint32(PayoutItemId4) {
|
||
_, err, errCode = uc.checkPayoutValidNew(ctx, uuid, opts)
|
||
} else {
|
||
_, err, errCode = uc.checkPayoutValid(ctx, uuid, opts)
|
||
}
|
||
if err != nil {
|
||
switch errCode {
|
||
case 101:
|
||
errCode = 5
|
||
case 102:
|
||
errCode = 6
|
||
case 103:
|
||
errCode = 7
|
||
case 104:
|
||
errCode = 8
|
||
case 105:
|
||
errCode = 9
|
||
case 106:
|
||
errCode = 10
|
||
case 107:
|
||
errCode = 11
|
||
case 150:
|
||
errCode = 12
|
||
default:
|
||
log.Infof("checkPayoutValid error: errCode[%d]", errCode)
|
||
errCode = 1
|
||
}
|
||
return nil, err, errCode
|
||
}
|
||
|
||
// 判断当前用户是否存在
|
||
user, err := uc.repo.GetUserByUuid(ctx, uuid)
|
||
if err != nil {
|
||
return nil, err, 1
|
||
}
|
||
|
||
// 支付的时候需要替换掉country code
|
||
// if country == "US" { // 美国
|
||
// req.Country = "USA"
|
||
// } else if country == "CA" { // 加拿大
|
||
// req.Country = "CAN"
|
||
// } else if country == "IN" { // 印度
|
||
// req.Country = "IND"
|
||
// } else if country == "PH" { // 菲律宾
|
||
// req.Country = "PHL"
|
||
// }
|
||
req.Country = convertCountry(country)
|
||
|
||
// 创建提现用户
|
||
if user.Id == 0 {
|
||
// 记录提现的用户
|
||
_, err = uc.repo.CreatePayoutUser(ctx, &PayoutUser{
|
||
Uuid: uuid,
|
||
DeviceId: opts.DeviceId,
|
||
Platform: opts.Platform,
|
||
Version: opts.Version,
|
||
Country: country,
|
||
Ip: opts.Ip,
|
||
LoginDays: 1,
|
||
})
|
||
if err != nil {
|
||
return nil, err, 1
|
||
}
|
||
}
|
||
|
||
// 记录提现及操作
|
||
var payoutReplyData PayoutReplyData
|
||
var payoutStatus uint8 // 记录提现状态
|
||
err = uc.tx.InTx(ctx, func(ctx context.Context) error {
|
||
// 创建提现记录
|
||
|
||
// 以下参数固定
|
||
req.AccountType = "EMAIL"
|
||
req.Method = "WALLET"
|
||
req.Channel = "PayPal"
|
||
req.FeeBear = "merchant" // beneficiary , merchant
|
||
// 如果金额大于等于0.3, 收款方承担手续费
|
||
if opts.Amount > 0.3 {
|
||
req.FeeBear = "beneficiary"
|
||
}
|
||
req.SourceCurrency = "USD"
|
||
req.ArrivalCurrency = "USD"
|
||
reqMd5 := utils.MD5Any(req)
|
||
customCode := fmt.Sprintf("PGS_%s", utils.MD5Any(fmt.Sprintf("%s-%d", reqMd5, time.Now().Unix())))
|
||
// 类似唯一订单号
|
||
req.CustomCode = customCode
|
||
|
||
record, err := uc.repo.CreatePayoutRecord(ctx, &PayoutRecord{
|
||
Uuid: uuid,
|
||
Channel: req.Channel,
|
||
ItemId: uint(opts.ItemId),
|
||
Amount: opts.Amount,
|
||
Account: req.Account,
|
||
Currency: req.SourceCurrency,
|
||
Status: uint8(PayoutStatusPayouting),
|
||
RecordNo: req.CustomCode,
|
||
Version: opts.Version,
|
||
Email: opts.Email,
|
||
})
|
||
if err != nil {
|
||
return fmt.Errorf("create payout record error: %v", err)
|
||
}
|
||
// 第三方提现
|
||
x, err := uc.pscli.out.Payout(ctx, req)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
|
||
payoutReplyData = *x
|
||
payoutStatus = uint8(PayoutStatusPayouting)
|
||
// 等待回调更新状态
|
||
err = uc.repo.UpdatePayoutRecordNotify(ctx, payoutReplyData.CustomCode, payoutReplyData.Id, payoutStatus, "")
|
||
if err != nil {
|
||
return fmt.Errorf("update payout record_%d status error: %v", record.Id, err)
|
||
}
|
||
|
||
return nil
|
||
})
|
||
|
||
if err != nil {
|
||
return nil, err, 1
|
||
}
|
||
|
||
// 记录此次提现,用于判断是否可以继续提现
|
||
uc.cache.WriteValue(ctx, uuidRedisKey, "1", 24*3600)
|
||
return &payoutReplyData, nil, 0
|
||
}
|
||
|
||
// PayoutBrazil 支付请求
|
||
func (uc *EonlineUsecase) PayoutBrazil(ctx context.Context, uuid string, opts *PayoutAddtionalReq, req *PayoutReq) (*PayoutReplyData, error, int32) {
|
||
// 定义一个uuid的redis key
|
||
keyDay := ""
|
||
if uc.conf.Server.Env == "qa" {
|
||
ts, _ := strconv.ParseInt(opts.Ts, 10, 64)
|
||
keyDay = time.Unix(ts, 0).Format("20060102")
|
||
}
|
||
uuidRedisKey := GetUuidPayoutRedisKey(uuid, keyDay, opts.ItemId)
|
||
// 定义一个uuid的redis lock key, 用于锁定, 防止并发
|
||
uuidRedisLockKey := GetUuidLockRedisKey(uuid, keyDay)
|
||
lock, _ := uc.cache.RedisLock(ctx, uuidRedisLockKey, 1, 20)
|
||
if !lock {
|
||
return nil, fmt.Errorf("lock error"), 1
|
||
}
|
||
defer func() {
|
||
uc.cache.RedisUnLock(ctx, uuidRedisLockKey)
|
||
}()
|
||
|
||
country, currentIp := uc.GetCountryCodeByIp(ctx, opts.Ip)
|
||
if country != "BR" {
|
||
// return nil, fmt.Errorf("Not Brazil")
|
||
country = "BR"
|
||
}
|
||
|
||
opts.Country = country
|
||
opts.Ip = currentIp
|
||
|
||
// 验证提现是否有效
|
||
var err error
|
||
var errCode int32
|
||
if opts.ItemId == uint32(PayoutItemId4) {
|
||
_, err, errCode = uc.checkPayoutValidNew(ctx, uuid, opts)
|
||
} else {
|
||
_, err, errCode = uc.checkPayoutValid(ctx, uuid, opts)
|
||
}
|
||
if err != nil {
|
||
switch errCode {
|
||
case 101:
|
||
errCode = 5
|
||
case 102:
|
||
errCode = 6
|
||
case 103:
|
||
errCode = 7
|
||
case 104:
|
||
errCode = 8
|
||
case 105:
|
||
errCode = 9
|
||
case 106:
|
||
errCode = 10
|
||
case 107:
|
||
errCode = 11
|
||
case 108:
|
||
errCode = 25
|
||
case 150:
|
||
errCode = 12
|
||
default:
|
||
log.Infof("checkPayoutValid error: errCode[%d]", errCode)
|
||
errCode = 1
|
||
}
|
||
return nil, err, errCode
|
||
}
|
||
|
||
// 判断当前用户是否存在
|
||
user, err := uc.repo.GetUserByUuid(ctx, uuid)
|
||
if err != nil {
|
||
return nil, err, 1
|
||
}
|
||
|
||
// 支付的时候需要替换掉country code
|
||
req.Country = convertCountry(country)
|
||
|
||
// 创建提现用户
|
||
if user.Id == 0 {
|
||
// 记录提现的用户
|
||
_, err = uc.repo.CreatePayoutUser(ctx, &PayoutUser{
|
||
Uuid: uuid,
|
||
DeviceId: opts.DeviceId,
|
||
Platform: opts.Platform,
|
||
Version: opts.Version,
|
||
Country: country,
|
||
Ip: opts.Ip,
|
||
LoginDays: 1,
|
||
})
|
||
if err != nil {
|
||
return nil, err, 1
|
||
}
|
||
}
|
||
|
||
if len(req.ClientData) > 0 {
|
||
uc.updateUserClientData(ctx, uuid, req.ClientData)
|
||
}
|
||
|
||
// 记录提现及操作
|
||
var payoutReplyData PayoutReplyData
|
||
var payoutStatus uint8 // 记录提现状态
|
||
err = uc.tx.InTx(ctx, func(ctx context.Context) error {
|
||
// 创建提现记录
|
||
|
||
// 以下参数固定
|
||
req.Method = "PIX"
|
||
// req.Channel = "PayPal"
|
||
req.FeeBear = "merchant" // beneficiary , merchant
|
||
// 如果金额大于等于0.3, 收款方承担手续费
|
||
if opts.Amount > 0.3 {
|
||
req.FeeBear = "beneficiary"
|
||
}
|
||
req.SourceCurrency = "USD"
|
||
req.ArrivalCurrency = "BRL"
|
||
reqMd5 := utils.MD5Any(req)
|
||
customCode := fmt.Sprintf("PGS_%s", utils.MD5Any(fmt.Sprintf("%s-%d", reqMd5, time.Now().Unix())))
|
||
// 类似唯一订单号
|
||
req.CustomCode = customCode
|
||
|
||
record, err := uc.repo.CreatePayoutRecord(ctx, &PayoutRecord{
|
||
Uuid: uuid,
|
||
Channel: req.Channel,
|
||
ItemId: uint(opts.ItemId),
|
||
Amount: opts.Amount,
|
||
Account: req.Account,
|
||
Currency: req.SourceCurrency,
|
||
Status: uint8(PayoutStatusPayouting),
|
||
RecordNo: req.CustomCode,
|
||
Version: opts.Version,
|
||
})
|
||
if err != nil {
|
||
return fmt.Errorf("create payout record error: %v", err)
|
||
}
|
||
|
||
// 第三方提现
|
||
x, err := uc.pscli.out.Payout(ctx, req)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
|
||
payoutReplyData = *x
|
||
payoutStatus = uint8(PayoutStatusPayouting)
|
||
// 等待回调更新状态
|
||
err = uc.repo.UpdatePayoutRecordNotify(ctx, payoutReplyData.CustomCode, payoutReplyData.Id, payoutStatus, "")
|
||
if err != nil {
|
||
return fmt.Errorf("update payout record_%d status error: %v", record.Id, err)
|
||
}
|
||
|
||
return nil
|
||
})
|
||
|
||
if err != nil {
|
||
return nil, err, 1
|
||
}
|
||
|
||
// 记录此次提现,用于判断是否可以继续提现
|
||
uc.cache.WriteValue(ctx, uuidRedisKey, "1", 24*3600)
|
||
|
||
orderId := GetPayoutOrderIdRedisKey(payoutReplyData.Id)
|
||
uc.cache.WriteValue(ctx, orderId, uuidRedisKey, 15*3600)
|
||
|
||
return &payoutReplyData, nil, 0
|
||
}
|
||
|
||
// PayoutNotify 支付回调
|
||
func (uc *EonlineUsecase) PayoutNotify(ctx context.Context, req *PayoutNotifyReq) error {
|
||
value, _ := json.Marshal(req)
|
||
fmt.Printf("[%s] payout notify: %s \n", time.Now().Format("2006-01-02 15:04:05"), string(value))
|
||
log.Infof("[%s] payout notify: %s \n", time.Now().Format("2006-01-02 15:04:05"), string(value))
|
||
err := uc.pscli.out.PayoutNotify(ctx, req)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
|
||
// 测试用代码
|
||
// callTest := func() {
|
||
// uuidRedisKey := "pt_6b59480226f21f10a8939807dded2679_20250518_1"
|
||
// orderTs := "TS202505080744025sxBs5nA47qPB"
|
||
// err = uc.cache.WriteValue(ctx, uuidRedisKey, "1", 24*3600)
|
||
// if err != nil {
|
||
// err = nil
|
||
// }
|
||
// orderId := GetPayoutOrderIdRedisKey(orderTs)
|
||
// err = uc.cache.WriteValue(ctx, orderId, uuidRedisKey, 15*3600)
|
||
// if err != nil {
|
||
// err = nil
|
||
// }
|
||
//
|
||
// // 查找删除
|
||
// ctx2 := ctx
|
||
// orderId = GetPayoutOrderIdRedisKey(orderTs)
|
||
// value2, err2 := uc.cache.GetValue(ctx2, orderId)
|
||
// if err2 == nil {
|
||
// if value2 != "" {
|
||
// err2 = uc.cache.DelValue(ctx2, value2)
|
||
// if err2 == nil {
|
||
// log.Infof("del GetUuidPayoutRedisKey: %s", value2)
|
||
//
|
||
// err2 = uc.cache.DelValue(ctx2, orderId)
|
||
// if err2 == nil {
|
||
// log.Infof("del redis key orderId: %s", orderId)
|
||
// } else {
|
||
// log.Infof("del redis key orderId: %s err[%v]", orderId, err2)
|
||
// }
|
||
// } else {
|
||
// log.Infof("del GetUuidPayoutRedisKey error: %s err[%v]", value2, err2)
|
||
// }
|
||
// } else {
|
||
// log.Infof("GetPayoutOrderIdRedisKey error: key[%s] value2 is null", orderId)
|
||
// }
|
||
// } else {
|
||
// log.Infof("GetPayoutOrderIdRedisKey error: key[%s] err[%v]", orderId, err2)
|
||
// }
|
||
// }
|
||
|
||
// 判断回调是否有效
|
||
_, err = uc.repo.GetPayoutRecordByRecordNo(ctx, req.CustomCode)
|
||
if err != nil {
|
||
return fmt.Errorf("get payout record error: %v", err)
|
||
}
|
||
|
||
// callTest()
|
||
|
||
reportData := GetReportData(req.PayoutId)
|
||
|
||
// 更新提现记录状态
|
||
var payoutStatus uint8
|
||
switch req.Status {
|
||
case "PAID":
|
||
payoutStatus = uint8(PayoutStatusPayouted)
|
||
|
||
if reportData != nil && reportData.Adjust != nil && reportData.ShuShu != nil {
|
||
adjust := GetAdjustData2(reportData.Adjust, "")
|
||
shuShu := GetShuShuData2(reportData.ShuShu, "")
|
||
SendReport(ctx, adjust, shuShu)
|
||
}
|
||
case "REJECTED":
|
||
payoutStatus = uint8(PayoutStatusPayoutFailed)
|
||
|
||
ctx2 := ctx
|
||
// ctx2 := context.Background()
|
||
orderId := GetPayoutOrderIdRedisKey(req.PayoutId)
|
||
value2, err2 := uc.cache.GetValue(ctx2, orderId)
|
||
if err2 == nil {
|
||
if value2 != "" {
|
||
err2 = uc.cache.DelValue(ctx2, value2)
|
||
if err2 == nil {
|
||
log.Infof("del GetUuidPayoutRedisKey: %s", value2)
|
||
|
||
// err2 = uc.cache.DelValue(ctx2, orderId)
|
||
// if err2 == nil {
|
||
// log.Infof("del redis key orderId: %s", orderId)
|
||
// } else {
|
||
// log.Infof("del redis key orderId: %s err[%v]", orderId, err2)
|
||
// }
|
||
} else {
|
||
log.Infof("del GetUuidPayoutRedisKey error: %s err[%v]", value2, err2)
|
||
}
|
||
} else {
|
||
log.Infof("GetPayoutOrderIdRedisKey error: key[%s] value2 is null", orderId)
|
||
}
|
||
} else {
|
||
log.Infof("GetPayoutOrderIdRedisKey error: key[%s] err[%v]", orderId, err2)
|
||
}
|
||
|
||
if reportData != nil && reportData.Adjust != nil && reportData.ShuShu != nil {
|
||
adjust := GetAdjustData2(reportData.Adjust, req.Msg)
|
||
shuShu := GetShuShuData2(reportData.ShuShu, req.Msg)
|
||
SendReport(ctx, adjust, shuShu)
|
||
}
|
||
default:
|
||
payoutStatus = uint8(PayoutStatusPayouting)
|
||
}
|
||
|
||
err = uc.repo.UpdatePayoutRecordNotify(ctx, req.CustomCode, req.PayoutId, payoutStatus, req.Msg)
|
||
if err != nil {
|
||
return fmt.Errorf("update payout record status error: %v", err)
|
||
}
|
||
|
||
// //存入redis给请求提现的用户
|
||
// payoutNotifyRedisKey := GetPayoutNotifyRedisKey(req.PayoutId)
|
||
|
||
// err = uc.cache.WriteValue(ctx, payoutNotifyRedisKey, string(value), 24*3600)
|
||
// if err != nil {
|
||
// return fmt.Errorf("write redis error: %v", err)
|
||
// }
|
||
|
||
return nil
|
||
}
|
||
|
||
// PayoutNotify 支付回调
|
||
func (uc *EonlineUsecase) PayoutNotify2(ctx context.Context, req *PayoutNotifyReq) error {
|
||
value, _ := json.Marshal(req)
|
||
fmt.Printf("[%s] payout notify: %s \n", time.Now().Format("2006-01-02 15:04:05"), string(value))
|
||
log.Infof("[%s] payout notify: %s \n", time.Now().Format("2006-01-02 15:04:05"), string(value))
|
||
// err := uc.pscli.out.PayoutNotify(ctx, req)
|
||
// if err != nil {
|
||
// return err
|
||
// }
|
||
|
||
// 判断回调是否有效
|
||
_, err := uc.repo.GetPayoutRecordByRecordNo(ctx, req.CustomCode)
|
||
if err != nil {
|
||
return fmt.Errorf("get payout record error: %v", err)
|
||
}
|
||
|
||
// callTest()
|
||
|
||
reportData := GetReportData(req.PayoutId)
|
||
|
||
// 更新提现记录状态
|
||
var payoutStatus uint8
|
||
switch req.Status {
|
||
case "PAID":
|
||
payoutStatus = uint8(PayoutStatusPayouted)
|
||
|
||
if reportData != nil && reportData.Adjust != nil && reportData.ShuShu != nil {
|
||
adjust := GetAdjustData2(reportData.Adjust, "")
|
||
shuShu := GetShuShuData2(reportData.ShuShu, "")
|
||
SendReport(ctx, adjust, shuShu)
|
||
}
|
||
case "REJECTED":
|
||
payoutStatus = uint8(PayoutStatusPayoutFailed)
|
||
|
||
ctx2 := ctx
|
||
// ctx2 := context.Background()
|
||
orderId := GetPayoutOrderIdRedisKey(req.PayoutId)
|
||
value2, err2 := uc.cache.GetValue(ctx2, orderId)
|
||
if err2 == nil {
|
||
if value2 != "" {
|
||
err2 = uc.cache.DelValue(ctx2, value2)
|
||
if err2 == nil {
|
||
log.Infof("del GetUuidPayoutRedisKey: %s", value2)
|
||
|
||
// err2 = uc.cache.DelValue(ctx2, orderId)
|
||
// if err2 == nil {
|
||
// log.Infof("del redis key orderId: %s", orderId)
|
||
// } else {
|
||
// log.Infof("del redis key orderId: %s err[%v]", orderId, err2)
|
||
// }
|
||
} else {
|
||
log.Infof("del GetUuidPayoutRedisKey error: %s err[%v]", value2, err2)
|
||
}
|
||
} else {
|
||
log.Infof("GetPayoutOrderIdRedisKey error: key[%s] value2 is null", orderId)
|
||
}
|
||
} else {
|
||
log.Infof("GetPayoutOrderIdRedisKey error: key[%s] err[%v]", orderId, err2)
|
||
}
|
||
|
||
if reportData != nil && reportData.Adjust != nil && reportData.ShuShu != nil {
|
||
adjust := GetAdjustData2(reportData.Adjust, req.Msg)
|
||
shuShu := GetShuShuData2(reportData.ShuShu, req.Msg)
|
||
SendReport(ctx, adjust, shuShu)
|
||
}
|
||
default:
|
||
payoutStatus = uint8(PayoutStatusPayouting)
|
||
}
|
||
|
||
err = uc.repo.UpdatePayoutRecordNotify(ctx, req.CustomCode, req.PayoutId, payoutStatus, req.Msg)
|
||
if err != nil {
|
||
return fmt.Errorf("update payout record status error: %v", err)
|
||
}
|
||
|
||
return nil
|
||
}
|
||
|
||
// ParseIp 解析IP
|
||
func (uc *EonlineUsecase) ParseIp(ctx context.Context, ip string) (*geo.GeoInfo, error) {
|
||
return uc.geocli.Parse(ip)
|
||
}
|
||
|
||
// 通过IP获取对应country code 和 country ip, 如果IP为空,从服务端获取
|
||
func (uc *EonlineUsecase) GetCountryCodeByIp(ctx context.Context, ip string) (string, string) {
|
||
var country string
|
||
var currentIp string
|
||
currentIp = ip
|
||
// 获取国家
|
||
// 强制通过服务端获取IP,不支持客户端传递, QA环境仍然支持客户端传递
|
||
if ip == "" || uc.conf.Server.Env != "qa" {
|
||
httpCtx := xhttp.RequestFromContext(ctx)
|
||
if httpCtx != nil {
|
||
// 获取当前的IP地址
|
||
currentIp = utils.GetClientPublicIP(httpCtx.Request())
|
||
} else {
|
||
uc.log.WithContext(ctx).Errorf("get http context error")
|
||
return "", ""
|
||
}
|
||
}
|
||
|
||
// 解析IP地址
|
||
geonInfo, err := uc.geocli.Parse(currentIp)
|
||
if err != nil {
|
||
uc.log.WithContext(ctx).Errorf("parse ip(%s) error: %v", currentIp, err)
|
||
return currentIp, ""
|
||
}
|
||
country = geonInfo.Country.ISOCode
|
||
fmt.Println("parse ip success: ", currentIp, country)
|
||
return country, currentIp
|
||
}
|
||
|
||
// PayoutCheck 检查提现状态
|
||
func (uc *EonlineUsecase) PayoutCheck(ctx context.Context, recordNo string) (uint8, error) {
|
||
record, err := uc.repo.GetPayoutRecordByRecordNo(ctx, recordNo)
|
||
if err != nil {
|
||
return 0, err
|
||
}
|
||
|
||
return record.Status, nil
|
||
}
|
||
|
||
// PayoutCheck 检查提现状态
|
||
func (uc *EonlineUsecase) GetPayoutRecordByAccount(ctx context.Context, account string, status, pageIndex, pageSize int) ([]*PayoutRecord, error) {
|
||
record, err := uc.repo.GetPayoutRecordByAccountStatus(ctx, account, int(status), int(pageIndex), int(pageSize))
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
return record, nil
|
||
}
|
||
|
||
type SubmitCheckReq struct {
|
||
Account string
|
||
Uuid string
|
||
}
|
||
|
||
type SubmitCheckReply struct {
|
||
Result int32 // 0成功,1失败,2以前提交过,还没审核结果,3以前提交过,并审核通过(以前提交过,但审核失败的,可以继续提交),
|
||
}
|
||
|
||
const (
|
||
StringNull = "" // 审核无结果
|
||
CheckResultFail = "0" // 审核没通过
|
||
CheckResultSuccess = "1" // 审核通过
|
||
)
|
||
|
||
// 提交审核,0成功,1失败,2以前提交过,还没审核结果,3以前提交过,并审核通过(以前提交过,但审核失败的,可以继续提交),
|
||
func (uc *EonlineUsecase) SubmitCheck(ctx context.Context, req *SubmitCheckReq) (*SubmitCheckReply, error) {
|
||
reply := &SubmitCheckReply{}
|
||
|
||
// 查询是否已经提交过
|
||
v, err := uc.getCheckSubmit(ctx, req.Account)
|
||
if err != nil {
|
||
reply.Result = 1
|
||
return reply, err
|
||
}
|
||
|
||
if v == 1 {
|
||
// 提交过,检查审核结果
|
||
v2, err := uc.getCheckResult(ctx, req.Account)
|
||
if err != nil {
|
||
reply.Result = 1
|
||
return reply, err
|
||
}
|
||
// 还没审核结果
|
||
if v2 == 0 {
|
||
reply.Result = 2
|
||
return reply, nil
|
||
}
|
||
// 审核通过的
|
||
if v2 == 2 {
|
||
reply.Result = 3
|
||
return reply, nil
|
||
}
|
||
}
|
||
|
||
// 检查提交人数
|
||
// v3, err := uc.getCheckSubmitNum(ctx)
|
||
// _ = v3
|
||
|
||
// 提交计数
|
||
err = uc.increaseCheckSubmitNum(ctx)
|
||
if err != nil {
|
||
reply.Result = 1
|
||
return reply, err
|
||
}
|
||
|
||
// 建立[uuid, paypal]
|
||
err = uc.setUuid2Paypal(ctx, req.Account, req.Uuid)
|
||
if err != nil {
|
||
reply.Result = 1
|
||
return reply, err
|
||
}
|
||
|
||
// 不加redis锁,并发写入提交记录,也没什么影响
|
||
// 存入redis
|
||
key := GetCheckSubmitRedisKey(req.Account)
|
||
uc.cache.WriteValue(ctx, key, req.Uuid, 0)
|
||
|
||
return reply, nil
|
||
}
|
||
|
||
type CheckInfoReq struct {
|
||
Uuid string
|
||
Ts string
|
||
}
|
||
|
||
type CheckInfoReply struct {
|
||
CanCheckSubmit uint32
|
||
CheckSubmit int32
|
||
CheckResult int32
|
||
CheckPayout int32
|
||
CanCheckPayOut int32
|
||
CheckResultFailedDesc string
|
||
}
|
||
|
||
func (uc *EonlineUsecase) CheckInfo(ctx context.Context, req *CheckInfoReq) (*CheckInfoReply, error) {
|
||
reply := &CheckInfoReply{}
|
||
|
||
acc, err := uc.getUuid2Paypal(ctx, req.Uuid)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
if acc == StringNull {
|
||
reply.CheckSubmit = 0
|
||
reply.CheckResult = 0
|
||
reply.CheckPayout = 0
|
||
} else {
|
||
// 提交身份文件验证情况
|
||
v, err := uc.getCheckSubmit(ctx, acc)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
if v == 0 {
|
||
reply.CheckSubmit = 0
|
||
} else {
|
||
reply.CheckSubmit = 1
|
||
}
|
||
// 身份文件审核有反馈的情况
|
||
v2, err := uc.getCheckResult(ctx, acc)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
if v2 != 0 {
|
||
if v2 == 2 {
|
||
reply.CheckResult = 2
|
||
} else {
|
||
reply.CheckResult = 1
|
||
|
||
reply.CheckResultFailedDesc, err = uc.getCheckResultFailedDesc(ctx, acc)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
}
|
||
}
|
||
// 提交身份文件奖励5美元领取的情况,0没有提现记录,1提现中,2提现成功,3提现失败
|
||
records, err := uc.repo.GetPayoutRecordListByUuid(ctx, req.Uuid)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
for _, record := range records {
|
||
if record.ItemId == uint(PayoutItemId4) {
|
||
switch record.Status {
|
||
case uint8(PayoutStatusPayouting):
|
||
reply.CheckPayout = 1
|
||
case uint8(PayoutStatusPayouted):
|
||
reply.CheckPayout = 2
|
||
case uint8(PayoutStatusPayoutFailed):
|
||
reply.CheckPayout = 3
|
||
}
|
||
break
|
||
}
|
||
}
|
||
}
|
||
|
||
// 获得当前提交审核计数
|
||
v3, err := uc.getCheckSubmitNum(ctx)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
reply.CanCheckSubmit = v3
|
||
log.Infof("CheckInfo: getCheckSubmitNum[%d]", v3)
|
||
|
||
if reply.CanCheckSubmit < config.PublicCheckNum {
|
||
reply.CanCheckSubmit = 1
|
||
} else {
|
||
reply.CanCheckSubmit = 0
|
||
}
|
||
|
||
var resultTixian int
|
||
reply.CanCheckPayOut = 1 // 身份文件审核过的提现奖励5美元 能否 提现,0能提现,1条件不满足,不能提现,2当天已经提现过,不能再次提现
|
||
if reply.CheckSubmit == 1 && reply.CheckResult == 2 && reply.CheckPayout == 0 {
|
||
resultTixian, err = uc.GetCashStatus(ctx, req.Uuid, req.Ts, uint32(PayoutItemId4))
|
||
if err != nil {
|
||
return nil, fmt.Errorf("error: %w", err)
|
||
}
|
||
if resultTixian == 1 {
|
||
reply.CanCheckPayOut = 2
|
||
} else {
|
||
reply.CanCheckPayOut = 0
|
||
}
|
||
}
|
||
|
||
return reply, nil
|
||
}
|
||
|
||
// 获取已经提交身份审核计数
|
||
func (uc *EonlineUsecase) getCheckSubmitNum(ctx context.Context) (uint32, error) {
|
||
key := GetCheckSubmitNumRedisKey()
|
||
v, err := uc.cache.GetValue(ctx, key)
|
||
if err != nil {
|
||
return 0, err
|
||
}
|
||
if v == StringNull {
|
||
return 0, nil
|
||
} else {
|
||
x, err := strconv.Atoi(v)
|
||
if err != nil {
|
||
return 0, err
|
||
}
|
||
return uint32(x), nil
|
||
}
|
||
}
|
||
|
||
// 提交身份审核计数 自增
|
||
func (uc *EonlineUsecase) increaseCheckSubmitNum(ctx context.Context) error {
|
||
key := GetCheckSubmitNumRedisKey()
|
||
v, err := uc.cache.GetValue(ctx, key)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
|
||
var x int
|
||
if v != StringNull {
|
||
x, err = strconv.Atoi(v)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
}
|
||
|
||
err = uc.cache.WriteValue(ctx, key, x+1, 0)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
return nil
|
||
}
|
||
|
||
// 提交身份文件验证情况,0没有提交,1提交过
|
||
func (uc *EonlineUsecase) getCheckSubmit(ctx context.Context, account string) (int32, error) {
|
||
key := GetCheckSubmitRedisKey(account)
|
||
v, err := uc.cache.GetValue(ctx, key)
|
||
if err != nil {
|
||
return 0, err
|
||
}
|
||
if v == StringNull {
|
||
return 0, nil
|
||
} else {
|
||
return 1, nil
|
||
}
|
||
}
|
||
|
||
// 身份文件审核有反馈的情况,0没有记录,1审核没通过,2审核通过
|
||
func (uc *EonlineUsecase) getCheckResult(ctx context.Context, account string) (int32, error) {
|
||
key := GetCheckResultRedisKey(account)
|
||
v, err := uc.cache.GetValue(ctx, key)
|
||
if err != nil {
|
||
return 0, err
|
||
}
|
||
if v == StringNull {
|
||
return 0, nil
|
||
}
|
||
|
||
if v == CheckResultSuccess {
|
||
return 2, nil
|
||
} else {
|
||
return 1, nil
|
||
}
|
||
}
|
||
|
||
// 提交身份文件奖励5美元领取的情况,0没有领取记录,1有领取记录
|
||
func (uc *EonlineUsecase) getCheckPayout(ctx context.Context, account string) (int32, error) {
|
||
return 0, nil
|
||
}
|
||
|
||
// 存储[uuid, paypal]
|
||
func (uc *EonlineUsecase) setUuid2Paypal(ctx context.Context, account, uuid string) error {
|
||
key := GetUuid2PaypalRedisKey(uuid)
|
||
err := uc.cache.WriteValue(ctx, key, account, 0)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
return nil
|
||
}
|
||
|
||
// 根据uuid获取paypal
|
||
func (uc *EonlineUsecase) getUuid2Paypal(ctx context.Context, uuid string) (string, error) {
|
||
key := GetUuid2PaypalRedisKey(uuid)
|
||
v, err := uc.cache.GetValue(ctx, key)
|
||
if err != nil {
|
||
return StringNull, err
|
||
}
|
||
return v, nil
|
||
}
|
||
|
||
// 查询当天是否有提现记录,0没有,1有
|
||
func (uc *EonlineUsecase) GetCashStatus(ctx context.Context, uuid, ts string, itemId uint32) (int, error) {
|
||
keyDay := ""
|
||
if uc.conf.Server.Env == "qa" {
|
||
ts, _ := strconv.ParseInt(ts, 10, 64)
|
||
keyDay = time.Unix(ts, 0).Format("20060102")
|
||
}
|
||
|
||
uuidRedisKey := GetUuidPayoutRedisKey(uuid, keyDay, itemId)
|
||
value, err := uc.cache.GetValue(ctx, uuidRedisKey)
|
||
if err != nil {
|
||
return 0, err
|
||
}
|
||
|
||
if value != "" {
|
||
return 1, nil
|
||
}
|
||
return 0, nil
|
||
}
|
||
|
||
// 获取审核没通过的原因描述信息
|
||
func (uc *EonlineUsecase) getCheckResultFailedDesc(ctx context.Context, account string) (string, error) {
|
||
key := GetCheckResultFailRedisKey(account)
|
||
v, err := uc.cache.GetValue(ctx, key)
|
||
if err != nil {
|
||
return "", err
|
||
}
|
||
return v, nil
|
||
}
|