You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
482 lines
13 KiB
482 lines
13 KiB
package model |
|
|
|
import ( |
|
"fmt" |
|
"go-common/library/ecode" |
|
"time" |
|
) |
|
|
|
/* |
|
const STREAM_OP_RESULT_SUCCESS = 0 //交易成功 |
|
const STREAM_OP_RESULT_IN_PROGRESS = 1 //交易进行中 |
|
const STREAM_OP_RESULT_FAILED = 2 //交易失败 |
|
const STREAM_OP_RESULT_ROLLBACK_SUCC = 2 //回滚成功 |
|
const STREAM_OP_RESULT_ROLLBACK_IN_PROGRESS = 2 //交易回滚中 |
|
const STREAM_OP_RESULT_ROLLBACK_FAILED = 2 //回滚成功 |
|
|
|
*/ |
|
|
|
const STREAM_OP_RESULT_SUB_SUCC = 1 //扣款成功 |
|
const STREAM_OP_RESULT_ADD_SUCC = 2 //加款成功 |
|
const STREAM_OP_RESULT_SUB_FAILED = -1 //扣款失败 |
|
const STREAM_OP_RESULT_ADD_FAILED = -2 //加款失败 |
|
|
|
const STREAM_OP_REASON_EXECUTE_UNKNOWN = -6 //系统内部逻辑错误: 结果未知,当作失败 |
|
const STREAM_OP_REASON_POST_QUERY_FAILED = -5 //系统内部错误,后置查询失败 |
|
const STREAM_OP_REASON_QUERY_FAILED = -4 //系统内部错误,查询失败 |
|
const STREAM_OP_REASON_LOCK_ERROR = -3 //系统内部错误,获取锁异常 |
|
const STREAM_OP_REASON_EXECUTE_FAILED = -2 //系统内部逻辑错误: 执行失败,连接异常 OR SQL错误 OR 修改要求的条件不满足(有别的进程越过用户锁,对货币数进行了变更) |
|
const STREAM_OP_REASON_PRE_QUERY_FAILED = -1 //前置查询失败 |
|
const STREAM_OP_REASON_NOT_ENOUGH_COIN = 1 |
|
const STREAM_OP_REASON_LOCK_FAILED = 2 |
|
|
|
const ( |
|
LIVE_PLATFORM_IOS = "ios" |
|
LIVE_PLATFORM_PC = "pc" |
|
LIVE_PLATFORM_ANDROID = "android" |
|
LIVE_PLATFORM_H5 = "h5" |
|
COIN_TYPE_IOS_GOLD = "iap_gold" |
|
COIN_TYPE_GOLD = "gold" |
|
COIN_TYPE_SILVER = "silver" |
|
COIN_TYPE_METAL = "metal" //主站硬币(主站提供硬币数查询、硬币扣除接口供调用) |
|
) |
|
|
|
type RechargeOrPayForm struct { |
|
Uid int64 `form:"uid" validate:"required"` |
|
CoinType string `form:"coin_type" validate:"required"` |
|
CoinNum int64 `form:"coin_num" validate:"required"` |
|
ExtendTid string `form:"extend_tid" validate:"required"` |
|
Timestamp int64 `form:"timestamp" validate:"required"` |
|
TransactionId string `form:"transaction_id" validate:"required"` |
|
} |
|
|
|
type ExchangeForm struct { |
|
Uid int64 `form:"uid" validate:"required"` |
|
ExtendTid string `form:"extend_tid" validate:"required"` |
|
Timestamp int64 `form:"timestamp" validate:"required"` |
|
TransactionId string `form:"transaction_id" validate:"required"` |
|
SrcCoinType string `form:"src_coin_type" validate:"required"` |
|
SrcCoinNum int64 `form:"src_coin_num" validate:"required"` |
|
DestCoinType string `form:"dest_coin_type" validate:"required"` |
|
DestCoinNum int64 `form:"dest_coin_num" validate:"required"` |
|
} |
|
|
|
type RecordCoinStreamForm struct { |
|
Uid int64 `form:"uid" validate:"required"` |
|
Data string `form:"data" validate:"required"` |
|
} |
|
|
|
type ServiceType int32 |
|
|
|
const ( |
|
PAYTYPE ServiceType = 0 |
|
RECHARGETYPE ServiceType = 1 |
|
EXCHANGETYPE ServiceType = 2 |
|
ROLLBACKTYPE ServiceType = 3 |
|
SysCoinTypeIosGold int32 = 2 |
|
SysCoinTypeGold int32 = 1 |
|
SysCoinTypeSilver int32 = 0 |
|
SysCoinTypeMetal int32 = 3 |
|
) |
|
|
|
func IsValidServiceType(serviceType int32) bool { |
|
st := ServiceType(serviceType) |
|
return st == PAYTYPE || |
|
st == RECHARGETYPE || |
|
st == EXCHANGETYPE || |
|
st == ROLLBACKTYPE |
|
} |
|
|
|
var ( |
|
validPlatformMap = map[string]string{LIVE_PLATFORM_ANDROID: LIVE_PLATFORM_ANDROID, LIVE_PLATFORM_H5: LIVE_PLATFORM_H5, LIVE_PLATFORM_PC: LIVE_PLATFORM_PC, LIVE_PLATFORM_IOS: LIVE_PLATFORM_IOS} |
|
validCoinTypeMap = map[string]int32{COIN_TYPE_IOS_GOLD: SysCoinTypeIosGold, COIN_TYPE_GOLD: SysCoinTypeGold, COIN_TYPE_SILVER: SysCoinTypeSilver, COIN_TYPE_METAL: SysCoinTypeMetal} |
|
validPlatformNoMap = map[string]int32{LIVE_PLATFORM_PC: 1, LIVE_PLATFORM_ANDROID: 2, LIVE_PLATFORM_IOS: 3, LIVE_PLATFORM_H5: 4} |
|
) |
|
|
|
func IsValidCoinType(coinType string) bool { |
|
_, ok := validCoinTypeMap[coinType] |
|
return ok |
|
} |
|
|
|
func GetCoinTypeNumber(coinType string) int32 { |
|
n := validCoinTypeMap[coinType] |
|
return n |
|
} |
|
|
|
func IsValidPlatform(platform string) bool { |
|
_, ok := validPlatformMap[platform] |
|
return ok |
|
} |
|
|
|
func IsPlatformIOS(platform string) bool { |
|
return platform == LIVE_PLATFORM_IOS |
|
} |
|
|
|
func IsLocalCoin(coinTypeNo int32) bool { |
|
return coinTypeNo != SysCoinTypeMetal |
|
} |
|
func GetSysCoinType(coinType string, platform string) string { |
|
if IsPlatformIOS(platform) && coinType == COIN_TYPE_GOLD { |
|
coinType = COIN_TYPE_IOS_GOLD |
|
} |
|
return coinType |
|
} |
|
|
|
func GetSysCoinTypeByNo(coinTypeNo int32) string { |
|
switch coinTypeNo { |
|
case SysCoinTypeGold: |
|
return COIN_TYPE_GOLD |
|
case SysCoinTypeIosGold: |
|
return COIN_TYPE_IOS_GOLD |
|
case SysCoinTypeSilver: |
|
return COIN_TYPE_SILVER |
|
case SysCoinTypeMetal: |
|
return COIN_TYPE_METAL |
|
default: |
|
return "not_define" |
|
} |
|
} |
|
|
|
func GetRechargeCnt(coinTypeNo int32) string { |
|
var rechargeCntField string |
|
if coinTypeNo == SysCoinTypeSilver { |
|
rechargeCntField = "" |
|
} else if coinTypeNo == SysCoinTypeIosGold { |
|
rechargeCntField = "gold_recharge_cnt" |
|
} else if coinTypeNo == SysCoinTypeGold { |
|
rechargeCntField = "gold_recharge_cnt" |
|
} |
|
return rechargeCntField |
|
} |
|
|
|
func GetPayCnt(coinTypeNo int32) string { |
|
var cntField string |
|
if coinTypeNo == SysCoinTypeSilver { |
|
cntField = "silver_pay_cnt" |
|
} else if coinTypeNo == SysCoinTypeIosGold { |
|
cntField = "gold_pay_cnt" |
|
} else if coinTypeNo == SysCoinTypeGold { |
|
cntField = "gold_pay_cnt" |
|
} |
|
return cntField |
|
} |
|
|
|
func GetWalletFormatTime(opTime int64) string { |
|
tm := time.Unix(opTime, 0) |
|
date := tm.Format("2006-01-02 15:04:05") |
|
return date |
|
} |
|
|
|
func NewCoinStream(uid int64, tid string, extendTid string, coinType int32, coinNum int64, opType int32, opTime int64, bizCode string, area int64, source string, bizSource string, metadata string) *CoinStreamRecord { |
|
return &CoinStreamRecord{ |
|
Uid: uid, |
|
TransactionId: tid, |
|
ExtendTid: extendTid, |
|
CoinType: coinType, |
|
DeltaCoinNum: coinNum, |
|
OpType: opType, |
|
OpTime: opTime, |
|
BizCode: bizCode, |
|
Area: area, |
|
Source: source, |
|
BizSource: bizSource, |
|
MetaData: metadata, |
|
} |
|
} |
|
|
|
func NewExchangeSteam(uid int64, tid string, srcCoinType int32, srcCoinNum int32, destCoinType int32, destCoinNum int32, opTime int64, status int32) *CoinExchangeRecord { |
|
return &CoinExchangeRecord{ |
|
Uid: uid, |
|
TransactionId: tid, |
|
SrcType: srcCoinType, |
|
SrcNum: srcCoinNum, |
|
DestType: destCoinType, |
|
DestNum: destCoinNum, |
|
ExchangeTime: opTime, |
|
Status: status, |
|
} |
|
} |
|
|
|
func (m *CoinStreamRecord) SetOpReason(r int32) { |
|
m.OpReason = r |
|
} |
|
|
|
func GetMelonseedResp(platform string, melonseed *Melonseed) *MelonseedResp { |
|
gold := getPlatformGold(melonseed.Gold, melonseed.IapGold, platform) |
|
return &MelonseedResp{ |
|
Silver: fmt.Sprintf("%d", melonseed.Silver), |
|
Gold: fmt.Sprintf("%d", gold), |
|
} |
|
} |
|
|
|
func GetMelonseedWithMetalResp(platform string, melonseed *Melonseed, metal float64) *MelonseedWithMetalResp { |
|
gold := getPlatformGold(melonseed.Gold, melonseed.IapGold, platform) |
|
return &MelonseedWithMetalResp{ |
|
Silver: fmt.Sprintf("%d", melonseed.Silver), |
|
Gold: fmt.Sprintf("%d", gold), |
|
Metal: fmt.Sprintf("%.2f", metal), |
|
} |
|
} |
|
|
|
func GetDetailResp(platform string, detail *Detail) *DetailResp { |
|
gold := getPlatformGold(detail.Gold, detail.IapGold, platform) |
|
return &DetailResp{ |
|
Silver: fmt.Sprintf("%d", detail.Silver), |
|
Gold: fmt.Sprintf("%d", gold), |
|
GoldPayCnt: fmt.Sprintf("%d", detail.GoldPayCnt), |
|
GoldRechargeCnt: fmt.Sprintf("%d", detail.GoldRechargeCnt), |
|
SilverPayCnt: fmt.Sprintf("%d", detail.SilverPayCnt), |
|
CostBase: detail.CostBase, |
|
} |
|
} |
|
|
|
func GetDetailWithMetalResp(platform string, detail *Detail, metal float64) *DetailWithMetalResp { |
|
gold := getPlatformGold(detail.Gold, detail.IapGold, platform) |
|
return &DetailWithMetalResp{ |
|
Silver: fmt.Sprintf("%d", detail.Silver), |
|
Gold: fmt.Sprintf("%d", gold), |
|
GoldPayCnt: fmt.Sprintf("%d", detail.GoldPayCnt), |
|
GoldRechargeCnt: fmt.Sprintf("%d", detail.GoldRechargeCnt), |
|
SilverPayCnt: fmt.Sprintf("%d", detail.SilverPayCnt), |
|
Metal: fmt.Sprintf("%.2f", metal), |
|
CostBase: detail.CostBase, |
|
} |
|
} |
|
|
|
func GetTidResp(tid string) *TidResp { |
|
return &TidResp{TransactionId: tid} |
|
} |
|
|
|
func getPlatformGold(normalGold int64, iapGold int64, platform string) int64 { |
|
gold := normalGold |
|
if IsPlatformIOS(platform) { |
|
gold = iapGold |
|
} |
|
return gold |
|
} |
|
|
|
func IncrMelonseedCoin(userCoins *Melonseed, num int64, coinTypeNo int32) { |
|
switch coinTypeNo { |
|
case SysCoinTypeIosGold: |
|
userCoins.IapGold += num |
|
case SysCoinTypeGold: |
|
userCoins.Gold += num |
|
case SysCoinTypeSilver: |
|
userCoins.Silver += num |
|
default: |
|
} |
|
} |
|
|
|
func GetCoinByMelonseed(coinTypeNo int32, userCoin *Melonseed) int64 { |
|
switch coinTypeNo { |
|
case SysCoinTypeIosGold: |
|
return userCoin.IapGold |
|
case SysCoinTypeGold: |
|
return userCoin.Gold |
|
case SysCoinTypeSilver: |
|
return userCoin.Silver |
|
default: |
|
return 0 |
|
} |
|
} |
|
|
|
func GetCoinByDetailWithSnapShot(coinTypeNo int32, userCoin *DetailWithSnapShot) int64 { |
|
switch coinTypeNo { |
|
case SysCoinTypeIosGold: |
|
return userCoin.IapGold |
|
case SysCoinTypeGold: |
|
return userCoin.Gold |
|
case SysCoinTypeSilver: |
|
return userCoin.Silver |
|
default: |
|
return 0 |
|
} |
|
} |
|
|
|
func CompareCoin(origin interface{}, num int64) bool { |
|
switch origin.(type) { |
|
case int64: |
|
return origin.(int64) >= num |
|
case float64: |
|
return int64(origin.(float64)) >= num |
|
default: |
|
return false |
|
} |
|
} |
|
|
|
// 得到数据库适配的货币数据,由于数据库的org_coin_num delta_coin_num都是整型,但是硬币的类型是浮点数,所以做一下适配 |
|
func GetDbFitCoin(v interface{}) int64 { |
|
switch v.(type) { |
|
case int64: |
|
return v.(int64) |
|
case float64: |
|
return int64(v.(float64)) |
|
default: |
|
return 0 |
|
} |
|
} |
|
|
|
func SubCoin(v1 interface{}, v2 interface{}) int64 { |
|
switch v1.(type) { |
|
case int64: |
|
return v1.(int64) - v2.(int64) |
|
case float64: |
|
return int64(v1.(float64) - v2.(float64)) |
|
default: |
|
return 0 |
|
} |
|
} |
|
|
|
func AddMoreParam2CoinStream(stream *CoinStreamRecord, bp *BasicParam, platform string) { |
|
platformNo := GetPlatformNo(platform) |
|
stream.Platform = platformNo |
|
stream.Reserved1 = bp.Reason |
|
stream.Version = bp.Version |
|
} |
|
|
|
type CoinStreamFieldInject interface { |
|
GetExtendTid() string |
|
GetTimestamp() int64 |
|
GetTransactionId() string |
|
GetBizCode() string |
|
GetArea() int64 |
|
GetBizSource() string |
|
GetSource() string |
|
GetReason() int64 |
|
GetVersion() int64 |
|
GetMetaData() string |
|
GetPlatform() string |
|
GetUid() int64 |
|
} |
|
|
|
func InjectFieldToCoinStream(stream *CoinStreamRecord, inject CoinStreamFieldInject) { |
|
stream.ExtendTid = inject.GetExtendTid() |
|
stream.TransactionId = inject.GetTransactionId() |
|
stream.OpTime = inject.GetTimestamp() |
|
|
|
stream.BizCode = inject.GetBizCode() |
|
stream.Area = inject.GetArea() |
|
stream.BizSource = inject.GetBizSource() |
|
stream.MetaData = inject.GetMetaData() |
|
stream.Source = inject.GetSource() |
|
|
|
stream.Reserved1 = inject.GetReason() |
|
stream.Version = inject.GetVersion() |
|
platformNo := GetPlatformNo(inject.GetPlatform()) |
|
stream.Platform = platformNo |
|
|
|
stream.Uid = inject.GetUid() |
|
} |
|
|
|
func GetPlatformNo(platform string) int32 { |
|
platformNo, ok := validPlatformNoMap[platform] |
|
if !ok { |
|
platformNo = 0 |
|
} |
|
return platformNo |
|
} |
|
|
|
var ( |
|
validRecordCoinStreamItemType = map[string]bool{"recharge": true, "pay": true} |
|
) |
|
|
|
func (m *RecordCoinStreamItem) IsValidType() bool { |
|
_, ok := validRecordCoinStreamItemType[m.Type] |
|
return ok |
|
} |
|
|
|
func (m *RecordCoinStreamItem) IsPayType() bool { |
|
return m.Type == "pay" |
|
} |
|
|
|
func (m *RecordCoinStreamItem) IsRechargeType() bool { |
|
return m.Type == "recharge" |
|
} |
|
|
|
func (m *RecordCoinStreamItem) GetOpType() int32 { |
|
if m.IsPayType() { |
|
return int32(PAYTYPE) |
|
} else { |
|
return int32(RECHARGETYPE) |
|
} |
|
} |
|
|
|
func (m *RecordCoinStreamItem) GetOpResult() int32 { |
|
if m.IsPayType() { |
|
return STREAM_OP_RESULT_SUB_SUCC |
|
} else { |
|
return STREAM_OP_RESULT_ADD_SUCC |
|
} |
|
} |
|
|
|
func (m *RecordCoinStreamItem) IsValid() (valid bool) { |
|
valid = false |
|
if m.OrgCoinNum < 0 { |
|
return |
|
} |
|
|
|
if !m.IsValidType() { |
|
return |
|
} |
|
|
|
if !IsValidCoinType(m.CoinType) { |
|
return |
|
} |
|
if m.IsPayType() && m.CoinNum >= 0 { |
|
return |
|
} |
|
|
|
if m.IsRechargeType() && m.CoinNum <= 0 { |
|
return |
|
} |
|
|
|
valid = true |
|
return |
|
} |
|
|
|
func GetMelonByDetailWithSnapShot(wallet *DetailWithSnapShot, platform string) (melon *MelonseedResp) { |
|
gold := wallet.Gold |
|
if platform == LIVE_PLATFORM_IOS { |
|
gold = wallet.IapGold |
|
} |
|
return &MelonseedResp{ |
|
Silver: fmt.Sprintf("%d", wallet.Silver), |
|
Gold: fmt.Sprintf("%d", gold), |
|
} |
|
} |
|
|
|
func ModifyCoinInDetailWithSnapShot(wallet *DetailWithSnapShot, sysCoinTypeNo int32, coinNum int64) { |
|
switch sysCoinTypeNo { |
|
case SysCoinTypeGold: |
|
wallet.Gold += coinNum |
|
case SysCoinTypeIosGold: |
|
wallet.IapGold += coinNum |
|
case SysCoinTypeSilver: |
|
wallet.Silver += coinNum |
|
} |
|
} |
|
|
|
// 根据锁的错误设置数据库的reason |
|
func SetReasonByLockErr(lockErr error, coinStream *CoinStreamRecord) { |
|
if lockErr == ecode.TargetBlocked { |
|
coinStream.OpReason = STREAM_OP_REASON_LOCK_FAILED |
|
} else { |
|
coinStream.OpReason = STREAM_OP_REASON_LOCK_ERROR |
|
} |
|
} |
|
|
|
func NeedSnapshot(wallet *DetailWithSnapShot, now time.Time) bool { |
|
lastTime, _ := time.Parse("2006-01-02 15:04:05", wallet.SnapShotTime) |
|
return now.After(lastTime) |
|
} |
|
|
|
func GetTodayTime(now time.Time) time.Time { |
|
timeStr := now.Format("2006-01-02") + " 00:00:00" |
|
today, _ := time.Parse("2006-01-02 15:04:05", timeStr) |
|
return today |
|
} |
|
|
|
func TodayNeedSnapShot(wallet *DetailWithSnapShot) bool { |
|
now := GetTodayTime(time.Now()) |
|
return NeedSnapshot(wallet, now) |
|
}
|
|
|