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