helper.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482
  1. package model
  2. import (
  3. "fmt"
  4. "go-common/library/ecode"
  5. "time"
  6. )
  7. /*
  8. const STREAM_OP_RESULT_SUCCESS = 0 //交易成功
  9. const STREAM_OP_RESULT_IN_PROGRESS = 1 //交易进行中
  10. const STREAM_OP_RESULT_FAILED = 2 //交易失败
  11. const STREAM_OP_RESULT_ROLLBACK_SUCC = 2 //回滚成功
  12. const STREAM_OP_RESULT_ROLLBACK_IN_PROGRESS = 2 //交易回滚中
  13. const STREAM_OP_RESULT_ROLLBACK_FAILED = 2 //回滚成功
  14. */
  15. const STREAM_OP_RESULT_SUB_SUCC = 1 //扣款成功
  16. const STREAM_OP_RESULT_ADD_SUCC = 2 //加款成功
  17. const STREAM_OP_RESULT_SUB_FAILED = -1 //扣款失败
  18. const STREAM_OP_RESULT_ADD_FAILED = -2 //加款失败
  19. const STREAM_OP_REASON_EXECUTE_UNKNOWN = -6 //系统内部逻辑错误: 结果未知,当作失败
  20. const STREAM_OP_REASON_POST_QUERY_FAILED = -5 //系统内部错误,后置查询失败
  21. const STREAM_OP_REASON_QUERY_FAILED = -4 //系统内部错误,查询失败
  22. const STREAM_OP_REASON_LOCK_ERROR = -3 //系统内部错误,获取锁异常
  23. const STREAM_OP_REASON_EXECUTE_FAILED = -2 //系统内部逻辑错误: 执行失败,连接异常 OR SQL错误 OR 修改要求的条件不满足(有别的进程越过用户锁,对货币数进行了变更)
  24. const STREAM_OP_REASON_PRE_QUERY_FAILED = -1 //前置查询失败
  25. const STREAM_OP_REASON_NOT_ENOUGH_COIN = 1
  26. const STREAM_OP_REASON_LOCK_FAILED = 2
  27. const (
  28. LIVE_PLATFORM_IOS = "ios"
  29. LIVE_PLATFORM_PC = "pc"
  30. LIVE_PLATFORM_ANDROID = "android"
  31. LIVE_PLATFORM_H5 = "h5"
  32. COIN_TYPE_IOS_GOLD = "iap_gold"
  33. COIN_TYPE_GOLD = "gold"
  34. COIN_TYPE_SILVER = "silver"
  35. COIN_TYPE_METAL = "metal" //主站硬币(主站提供硬币数查询、硬币扣除接口供调用)
  36. )
  37. type RechargeOrPayForm struct {
  38. Uid int64 `form:"uid" validate:"required"`
  39. CoinType string `form:"coin_type" validate:"required"`
  40. CoinNum int64 `form:"coin_num" validate:"required"`
  41. ExtendTid string `form:"extend_tid" validate:"required"`
  42. Timestamp int64 `form:"timestamp" validate:"required"`
  43. TransactionId string `form:"transaction_id" validate:"required"`
  44. }
  45. type ExchangeForm struct {
  46. Uid int64 `form:"uid" validate:"required"`
  47. ExtendTid string `form:"extend_tid" validate:"required"`
  48. Timestamp int64 `form:"timestamp" validate:"required"`
  49. TransactionId string `form:"transaction_id" validate:"required"`
  50. SrcCoinType string `form:"src_coin_type" validate:"required"`
  51. SrcCoinNum int64 `form:"src_coin_num" validate:"required"`
  52. DestCoinType string `form:"dest_coin_type" validate:"required"`
  53. DestCoinNum int64 `form:"dest_coin_num" validate:"required"`
  54. }
  55. type RecordCoinStreamForm struct {
  56. Uid int64 `form:"uid" validate:"required"`
  57. Data string `form:"data" validate:"required"`
  58. }
  59. type ServiceType int32
  60. const (
  61. PAYTYPE ServiceType = 0
  62. RECHARGETYPE ServiceType = 1
  63. EXCHANGETYPE ServiceType = 2
  64. ROLLBACKTYPE ServiceType = 3
  65. SysCoinTypeIosGold int32 = 2
  66. SysCoinTypeGold int32 = 1
  67. SysCoinTypeSilver int32 = 0
  68. SysCoinTypeMetal int32 = 3
  69. )
  70. func IsValidServiceType(serviceType int32) bool {
  71. st := ServiceType(serviceType)
  72. return st == PAYTYPE ||
  73. st == RECHARGETYPE ||
  74. st == EXCHANGETYPE ||
  75. st == ROLLBACKTYPE
  76. }
  77. var (
  78. 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}
  79. validCoinTypeMap = map[string]int32{COIN_TYPE_IOS_GOLD: SysCoinTypeIosGold, COIN_TYPE_GOLD: SysCoinTypeGold, COIN_TYPE_SILVER: SysCoinTypeSilver, COIN_TYPE_METAL: SysCoinTypeMetal}
  80. validPlatformNoMap = map[string]int32{LIVE_PLATFORM_PC: 1, LIVE_PLATFORM_ANDROID: 2, LIVE_PLATFORM_IOS: 3, LIVE_PLATFORM_H5: 4}
  81. )
  82. func IsValidCoinType(coinType string) bool {
  83. _, ok := validCoinTypeMap[coinType]
  84. return ok
  85. }
  86. func GetCoinTypeNumber(coinType string) int32 {
  87. n := validCoinTypeMap[coinType]
  88. return n
  89. }
  90. func IsValidPlatform(platform string) bool {
  91. _, ok := validPlatformMap[platform]
  92. return ok
  93. }
  94. func IsPlatformIOS(platform string) bool {
  95. return platform == LIVE_PLATFORM_IOS
  96. }
  97. func IsLocalCoin(coinTypeNo int32) bool {
  98. return coinTypeNo != SysCoinTypeMetal
  99. }
  100. func GetSysCoinType(coinType string, platform string) string {
  101. if IsPlatformIOS(platform) && coinType == COIN_TYPE_GOLD {
  102. coinType = COIN_TYPE_IOS_GOLD
  103. }
  104. return coinType
  105. }
  106. func GetSysCoinTypeByNo(coinTypeNo int32) string {
  107. switch coinTypeNo {
  108. case SysCoinTypeGold:
  109. return COIN_TYPE_GOLD
  110. case SysCoinTypeIosGold:
  111. return COIN_TYPE_IOS_GOLD
  112. case SysCoinTypeSilver:
  113. return COIN_TYPE_SILVER
  114. case SysCoinTypeMetal:
  115. return COIN_TYPE_METAL
  116. default:
  117. return "not_define"
  118. }
  119. }
  120. func GetRechargeCnt(coinTypeNo int32) string {
  121. var rechargeCntField string
  122. if coinTypeNo == SysCoinTypeSilver {
  123. rechargeCntField = ""
  124. } else if coinTypeNo == SysCoinTypeIosGold {
  125. rechargeCntField = "gold_recharge_cnt"
  126. } else if coinTypeNo == SysCoinTypeGold {
  127. rechargeCntField = "gold_recharge_cnt"
  128. }
  129. return rechargeCntField
  130. }
  131. func GetPayCnt(coinTypeNo int32) string {
  132. var cntField string
  133. if coinTypeNo == SysCoinTypeSilver {
  134. cntField = "silver_pay_cnt"
  135. } else if coinTypeNo == SysCoinTypeIosGold {
  136. cntField = "gold_pay_cnt"
  137. } else if coinTypeNo == SysCoinTypeGold {
  138. cntField = "gold_pay_cnt"
  139. }
  140. return cntField
  141. }
  142. func GetWalletFormatTime(opTime int64) string {
  143. tm := time.Unix(opTime, 0)
  144. date := tm.Format("2006-01-02 15:04:05")
  145. return date
  146. }
  147. 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 {
  148. return &CoinStreamRecord{
  149. Uid: uid,
  150. TransactionId: tid,
  151. ExtendTid: extendTid,
  152. CoinType: coinType,
  153. DeltaCoinNum: coinNum,
  154. OpType: opType,
  155. OpTime: opTime,
  156. BizCode: bizCode,
  157. Area: area,
  158. Source: source,
  159. BizSource: bizSource,
  160. MetaData: metadata,
  161. }
  162. }
  163. func NewExchangeSteam(uid int64, tid string, srcCoinType int32, srcCoinNum int32, destCoinType int32, destCoinNum int32, opTime int64, status int32) *CoinExchangeRecord {
  164. return &CoinExchangeRecord{
  165. Uid: uid,
  166. TransactionId: tid,
  167. SrcType: srcCoinType,
  168. SrcNum: srcCoinNum,
  169. DestType: destCoinType,
  170. DestNum: destCoinNum,
  171. ExchangeTime: opTime,
  172. Status: status,
  173. }
  174. }
  175. func (m *CoinStreamRecord) SetOpReason(r int32) {
  176. m.OpReason = r
  177. }
  178. func GetMelonseedResp(platform string, melonseed *Melonseed) *MelonseedResp {
  179. gold := getPlatformGold(melonseed.Gold, melonseed.IapGold, platform)
  180. return &MelonseedResp{
  181. Silver: fmt.Sprintf("%d", melonseed.Silver),
  182. Gold: fmt.Sprintf("%d", gold),
  183. }
  184. }
  185. func GetMelonseedWithMetalResp(platform string, melonseed *Melonseed, metal float64) *MelonseedWithMetalResp {
  186. gold := getPlatformGold(melonseed.Gold, melonseed.IapGold, platform)
  187. return &MelonseedWithMetalResp{
  188. Silver: fmt.Sprintf("%d", melonseed.Silver),
  189. Gold: fmt.Sprintf("%d", gold),
  190. Metal: fmt.Sprintf("%.2f", metal),
  191. }
  192. }
  193. func GetDetailResp(platform string, detail *Detail) *DetailResp {
  194. gold := getPlatformGold(detail.Gold, detail.IapGold, platform)
  195. return &DetailResp{
  196. Silver: fmt.Sprintf("%d", detail.Silver),
  197. Gold: fmt.Sprintf("%d", gold),
  198. GoldPayCnt: fmt.Sprintf("%d", detail.GoldPayCnt),
  199. GoldRechargeCnt: fmt.Sprintf("%d", detail.GoldRechargeCnt),
  200. SilverPayCnt: fmt.Sprintf("%d", detail.SilverPayCnt),
  201. CostBase: detail.CostBase,
  202. }
  203. }
  204. func GetDetailWithMetalResp(platform string, detail *Detail, metal float64) *DetailWithMetalResp {
  205. gold := getPlatformGold(detail.Gold, detail.IapGold, platform)
  206. return &DetailWithMetalResp{
  207. Silver: fmt.Sprintf("%d", detail.Silver),
  208. Gold: fmt.Sprintf("%d", gold),
  209. GoldPayCnt: fmt.Sprintf("%d", detail.GoldPayCnt),
  210. GoldRechargeCnt: fmt.Sprintf("%d", detail.GoldRechargeCnt),
  211. SilverPayCnt: fmt.Sprintf("%d", detail.SilverPayCnt),
  212. Metal: fmt.Sprintf("%.2f", metal),
  213. CostBase: detail.CostBase,
  214. }
  215. }
  216. func GetTidResp(tid string) *TidResp {
  217. return &TidResp{TransactionId: tid}
  218. }
  219. func getPlatformGold(normalGold int64, iapGold int64, platform string) int64 {
  220. gold := normalGold
  221. if IsPlatformIOS(platform) {
  222. gold = iapGold
  223. }
  224. return gold
  225. }
  226. func IncrMelonseedCoin(userCoins *Melonseed, num int64, coinTypeNo int32) {
  227. switch coinTypeNo {
  228. case SysCoinTypeIosGold:
  229. userCoins.IapGold += num
  230. case SysCoinTypeGold:
  231. userCoins.Gold += num
  232. case SysCoinTypeSilver:
  233. userCoins.Silver += num
  234. default:
  235. }
  236. }
  237. func GetCoinByMelonseed(coinTypeNo int32, userCoin *Melonseed) int64 {
  238. switch coinTypeNo {
  239. case SysCoinTypeIosGold:
  240. return userCoin.IapGold
  241. case SysCoinTypeGold:
  242. return userCoin.Gold
  243. case SysCoinTypeSilver:
  244. return userCoin.Silver
  245. default:
  246. return 0
  247. }
  248. }
  249. func GetCoinByDetailWithSnapShot(coinTypeNo int32, userCoin *DetailWithSnapShot) int64 {
  250. switch coinTypeNo {
  251. case SysCoinTypeIosGold:
  252. return userCoin.IapGold
  253. case SysCoinTypeGold:
  254. return userCoin.Gold
  255. case SysCoinTypeSilver:
  256. return userCoin.Silver
  257. default:
  258. return 0
  259. }
  260. }
  261. func CompareCoin(origin interface{}, num int64) bool {
  262. switch origin.(type) {
  263. case int64:
  264. return origin.(int64) >= num
  265. case float64:
  266. return int64(origin.(float64)) >= num
  267. default:
  268. return false
  269. }
  270. }
  271. // 得到数据库适配的货币数据,由于数据库的org_coin_num delta_coin_num都是整型,但是硬币的类型是浮点数,所以做一下适配
  272. func GetDbFitCoin(v interface{}) int64 {
  273. switch v.(type) {
  274. case int64:
  275. return v.(int64)
  276. case float64:
  277. return int64(v.(float64))
  278. default:
  279. return 0
  280. }
  281. }
  282. func SubCoin(v1 interface{}, v2 interface{}) int64 {
  283. switch v1.(type) {
  284. case int64:
  285. return v1.(int64) - v2.(int64)
  286. case float64:
  287. return int64(v1.(float64) - v2.(float64))
  288. default:
  289. return 0
  290. }
  291. }
  292. func AddMoreParam2CoinStream(stream *CoinStreamRecord, bp *BasicParam, platform string) {
  293. platformNo := GetPlatformNo(platform)
  294. stream.Platform = platformNo
  295. stream.Reserved1 = bp.Reason
  296. stream.Version = bp.Version
  297. }
  298. type CoinStreamFieldInject interface {
  299. GetExtendTid() string
  300. GetTimestamp() int64
  301. GetTransactionId() string
  302. GetBizCode() string
  303. GetArea() int64
  304. GetBizSource() string
  305. GetSource() string
  306. GetReason() int64
  307. GetVersion() int64
  308. GetMetaData() string
  309. GetPlatform() string
  310. GetUid() int64
  311. }
  312. func InjectFieldToCoinStream(stream *CoinStreamRecord, inject CoinStreamFieldInject) {
  313. stream.ExtendTid = inject.GetExtendTid()
  314. stream.TransactionId = inject.GetTransactionId()
  315. stream.OpTime = inject.GetTimestamp()
  316. stream.BizCode = inject.GetBizCode()
  317. stream.Area = inject.GetArea()
  318. stream.BizSource = inject.GetBizSource()
  319. stream.MetaData = inject.GetMetaData()
  320. stream.Source = inject.GetSource()
  321. stream.Reserved1 = inject.GetReason()
  322. stream.Version = inject.GetVersion()
  323. platformNo := GetPlatformNo(inject.GetPlatform())
  324. stream.Platform = platformNo
  325. stream.Uid = inject.GetUid()
  326. }
  327. func GetPlatformNo(platform string) int32 {
  328. platformNo, ok := validPlatformNoMap[platform]
  329. if !ok {
  330. platformNo = 0
  331. }
  332. return platformNo
  333. }
  334. var (
  335. validRecordCoinStreamItemType = map[string]bool{"recharge": true, "pay": true}
  336. )
  337. func (m *RecordCoinStreamItem) IsValidType() bool {
  338. _, ok := validRecordCoinStreamItemType[m.Type]
  339. return ok
  340. }
  341. func (m *RecordCoinStreamItem) IsPayType() bool {
  342. return m.Type == "pay"
  343. }
  344. func (m *RecordCoinStreamItem) IsRechargeType() bool {
  345. return m.Type == "recharge"
  346. }
  347. func (m *RecordCoinStreamItem) GetOpType() int32 {
  348. if m.IsPayType() {
  349. return int32(PAYTYPE)
  350. } else {
  351. return int32(RECHARGETYPE)
  352. }
  353. }
  354. func (m *RecordCoinStreamItem) GetOpResult() int32 {
  355. if m.IsPayType() {
  356. return STREAM_OP_RESULT_SUB_SUCC
  357. } else {
  358. return STREAM_OP_RESULT_ADD_SUCC
  359. }
  360. }
  361. func (m *RecordCoinStreamItem) IsValid() (valid bool) {
  362. valid = false
  363. if m.OrgCoinNum < 0 {
  364. return
  365. }
  366. if !m.IsValidType() {
  367. return
  368. }
  369. if !IsValidCoinType(m.CoinType) {
  370. return
  371. }
  372. if m.IsPayType() && m.CoinNum >= 0 {
  373. return
  374. }
  375. if m.IsRechargeType() && m.CoinNum <= 0 {
  376. return
  377. }
  378. valid = true
  379. return
  380. }
  381. func GetMelonByDetailWithSnapShot(wallet *DetailWithSnapShot, platform string) (melon *MelonseedResp) {
  382. gold := wallet.Gold
  383. if platform == LIVE_PLATFORM_IOS {
  384. gold = wallet.IapGold
  385. }
  386. return &MelonseedResp{
  387. Silver: fmt.Sprintf("%d", wallet.Silver),
  388. Gold: fmt.Sprintf("%d", gold),
  389. }
  390. }
  391. func ModifyCoinInDetailWithSnapShot(wallet *DetailWithSnapShot, sysCoinTypeNo int32, coinNum int64) {
  392. switch sysCoinTypeNo {
  393. case SysCoinTypeGold:
  394. wallet.Gold += coinNum
  395. case SysCoinTypeIosGold:
  396. wallet.IapGold += coinNum
  397. case SysCoinTypeSilver:
  398. wallet.Silver += coinNum
  399. }
  400. }
  401. // 根据锁的错误设置数据库的reason
  402. func SetReasonByLockErr(lockErr error, coinStream *CoinStreamRecord) {
  403. if lockErr == ecode.TargetBlocked {
  404. coinStream.OpReason = STREAM_OP_REASON_LOCK_FAILED
  405. } else {
  406. coinStream.OpReason = STREAM_OP_REASON_LOCK_ERROR
  407. }
  408. }
  409. func NeedSnapshot(wallet *DetailWithSnapShot, now time.Time) bool {
  410. lastTime, _ := time.Parse("2006-01-02 15:04:05", wallet.SnapShotTime)
  411. return now.After(lastTime)
  412. }
  413. func GetTodayTime(now time.Time) time.Time {
  414. timeStr := now.Format("2006-01-02") + " 00:00:00"
  415. today, _ := time.Parse("2006-01-02 15:04:05", timeStr)
  416. return today
  417. }
  418. func TodayNeedSnapShot(wallet *DetailWithSnapShot) bool {
  419. now := GetTodayTime(time.Now())
  420. return NeedSnapshot(wallet, now)
  421. }