Create & Init Project...

This commit is contained in:
2019-04-22 18:49:16 +08:00
commit fc4fa37393
25440 changed files with 4054998 additions and 0 deletions

21
app/job/main/vip/BUILD Normal file
View File

@ -0,0 +1,21 @@
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//app/job/main/vip/cmd:all-srcs",
"//app/job/main/vip/conf:all-srcs",
"//app/job/main/vip/dao:all-srcs",
"//app/job/main/vip/http:all-srcs",
"//app/job/main/vip/model:all-srcs",
"//app/job/main/vip/service:all-srcs",
],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@ -0,0 +1,236 @@
#### Version 2.15.1
>1. fix sync.WaitGroup issue #417
#### Version 2.15.0
>1. 权益发放补偿job
#### Version 2.14.0
>1. 自动续费v2
#### Version 2.13.1
>1. refined log
#### Version 2.13.0
>1. 增加vipinfo缓存清理
#### Version 2.12.3
>1. fix redis conn
#### Version 2.12.2
>1. frozen java refined
#### Version 2.12.1
>1. frozen java
#### Version 2.12.0
>1. add frozen time
#### Version 2.11.1
1. time after coupon
#### Version 2.11.0
1. create order v2
#### Version 2.10.2
>1. refined sync recentTime logic
#### Version 2.10.0
>1. delete unuse code
#### Version 2.9.11
>1. sync all user info
#### Version 2.9.10
>1. vip type fix
#### Version 2.9.9
>1. update cache key
#### Version 2.9.8
>1. supple code data
#### Version 2.9.7
>1. fix code data
#### Version 2.9.6
>1. fix code data
#### Version 2.9.5
>1. fix sync pay order time
#### Version 2.9.4
>1. sync pay order time
#### Version 2.9.3
>1. update cache key
#### Version 2.9.2
>1. add vip cache to account notify
#### Version 2.9.1
>1. limit short vip
#### Version 2.9.0
>1. vip coupon feature
#### Version 2.8.8
>1. fix closter
#### Version 2.8.7
>1. fix code
#### Version 2.8.6
>1. fix code retry
#### Version 2.8.5
>1. fix code send
#### Version 2.8.4
>1. load code config from db
#### Version 2.8.3
>1. make del bacoin salary
#### Version 2.8.2
>1. fix chan full
#### Version 2.8.1
>1. summer active add autorenew order check
>2. summer active add tip and send codes
#### Version 2.8.0
>1. push data job
#### Version 2.7.5
>1. sync data user info
#### Version 2.7.4
>1. sync data user info
#### Version 2.7.3
>1. sync data history
#### Version 2.7.2
>1. active add mut activeid
#### Version 2.7.1
>1. check bcoin change history data
#### Version 2.7.0
>1. add auto renew change log
#### Version 2.6.8
>1. clear vip cache
#### Version 2.6.7
>1. clear vip cache
####v2.6.6
>1. change mc vip key
#### Version 2.6.5
>1. clear vip cache by scope
#### Version 2.6.4
>1. clear vip info cache
#### Version 2.6.3
>1. update async handler madel
#### Version 2.6.2
>1. update pay_type
#### Version 2.6.1
>1. update bili_vip databus
#### Version 2.6.0
>1. update summery active
#### Version 2.5.3
>1. sysn vip_user_info data
#### Version 2.5.2
>1. fix check vip_user_info
#### Version 2.5.1
>1. remove ignore file
#### Version 2.5.0
>1. check vip_user_info table data
#### Version 2.4.2
>1. check pay channel id update payType
#### Version 2.4.0
>1. 漫画券
#### Version 2.3.0
>1. update sync user info
#### Version 2.2.1
>1. update sync user info
#### Version 2.2.0
>1. update iap auto status
#### Version 2.1.1
>1. update old recharge order change ttn
#### Version 2.1.0
>1. add clear cache and sync interface
>2. ios_overdue_time data sync
#### Version 2.0.9
>1. vip user cache clear
#### Version 2.0.8
>1.update bm
#### Version 2.0.7
>1. reload all data
#### Version 2.0.6
>1. set defuat
#### Version 2.0.5
>1. config batch size
#### Version 2.0.4
>1.修复vip,order数据同步
#### Version 2.0.3
>1.修复数据同步问题
#### Version 2.0.2
>1.移除clean vip cache
#### Version 2.0.1
>1.注释冻结代码
>2.移除databusutil
#### Version 2.0.0
>1.vip-job重构
>2.update build
#### Version 1.1.8
> 1.salary mc lock
#### Version 1.1.7
> 1.时间兼容 err = nil
#### Version 1.1.6
> 1.时间兼容"0000-00-00 00:00:00"
#### Version 1.1.5
> 1.观影劵发放
#### Version 1.1.4
> 1.move path
#### Version 1.1.3
> 1.refined log
#### Version 1.1.2
> 1.vip purge cache enhance
#### Version 1.1.1
> 1.更新读取方式
#### Version 1.1.0
> 1.更新 缓存清理策略
#### Version 1.0.1
> 1.更改为清除vip缓存类型
##### Version 1.0.0
> 1.资源池基础api

View File

@ -0,0 +1,8 @@
# Owner
zhaogangtao
# Author
zhaozhihao
# Reviewer
lintanghui

14
app/job/main/vip/OWNERS Normal file
View File

@ -0,0 +1,14 @@
# See the OWNERS docs at https://go.k8s.io/owners
approvers:
- zhaogangtao
- zhaozhihao
labels:
- job
- job/main/vip
- main
options:
no_parent_owners: true
reviewers:
- lintanghui
- zhaozhihao

View File

@ -0,0 +1,13 @@
#### vip
##### 项目简介
> 1.大会员job
##### 编译环境
> 请只用golang v1.8.x以上版本编译执行。
##### 依赖包
> 1.公共包go-common
##### 特别说明
> 1.model目录可能会被其他项目引用请谨慎更改并通知各方。

View File

@ -0,0 +1,42 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_binary",
"go_library",
)
go_binary(
name = "cmd",
embed = [":go_default_library"],
tags = ["automanaged"],
)
go_library(
name = "go_default_library",
srcs = ["main.go"],
data = ["vip-job-test.toml"],
importpath = "go-common/app/job/main/vip/cmd",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/job/main/vip/conf:go_default_library",
"//app/job/main/vip/http:go_default_library",
"//app/job/main/vip/service:go_default_library",
"//library/log:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@ -0,0 +1,51 @@
package main
import (
"flag"
"os"
"os/signal"
"syscall"
"time"
"go-common/app/job/main/vip/conf"
"go-common/app/job/main/vip/http"
"go-common/app/job/main/vip/service"
"go-common/library/log"
)
var (
s *service.Service
)
func main() {
flag.Parse()
// init conf,log,trace,stat,perf.
if err := conf.Init(); err != nil {
panic(err)
}
log.Init(conf.Conf.Xlog)
defer log.Close()
s = service.New(conf.Conf)
http.Init(conf.Conf, s)
// rpcSvr := rpc.New(conf.Conf, svr)
// signal handler
log.Info("vip-job start")
c := make(chan os.Signal, 1)
signal.Notify(c, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT)
for {
signal := <-c
log.Info("vip-job get a signal %s", signal.String())
switch signal {
case syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT:
s.Close()
time.Sleep(time.Second * 2)
log.Info("vip-job exit")
return
case syscall.SIGHUP:
// TODO reload
default:
return
}
}
}

View File

@ -0,0 +1,288 @@
# This is a TOML document. Boom.
version = "1.0.0"
vipURI = "http://vip.bilibili.co"
[app]
key = "ad4bb9b8f5d9d4a7"
secret = "6912080d78d58be7cb94f57d50d438f6"
[bm]
addr = "0.0.0.0:6822"
maxListen = 10
timeout = "1s"
[payConf]
CustomerID = "10004"
Token ="0ff3d296ee0d7a28b4db1d761d2db907"
OrderNotifyURL ="http://vip.bilibili.co/pay/payOrderNotify"
SignNotifyURL ="http://vip.bilibili.co/pay/paySignNotify"
PlanID = 108217
ProductID ="vip_buy"
Version ="1.0"
[URLConf]
payCoUrl = "http://pay.bilibili.co"
payUrl = "http://pay.bilibili.com"
MsgUrl = "http://message.bilibili.co"
mallUrl = "http://uat-mall.bilibili.co"
accountUrl = "http://account.bilibili.com"
apiCoUrl = "http://api.bilibili.co"
oldVipCoURL = "http://vip.bilibili.co"
[property]
UpdateUserInfoCron = "0 0 0 * * ?"
willExpireMsgCron = "0 0 0 * * ?"
hadExpiredMsgCron = "0 0 0 * * ?"
AutoRenewCron = "0 0 0 * * ?"
SendMessageCron = "0 0 12 * * ?"
SalaryVideoCouponCron = "0 0 2 1 * ?"
PushDataCron = "0 0 3 * * ?"
SalaryVideoCouponnIterval = "5ms"
Retry = 3
SalaryDay = 10
annualVipSalaryCount = 4
normalVipSalaryCount = 2
frozenExpire = "15m"
frozenDate = "30m"
frozenLimit= 5
frozenCron = "0 1 0 * * ?"
sendBcoinCron = "0 0 0/1 10,11 * *"
handlerThread = 5
ReadThread = 3
PayMapping = {3 = "wechart"}
ActivityID = 142
AnnualVipBcoinCouponMoney = 5
AnnualVipBcoinDay = 10
batchSize = 200
salaryCouponMaps = {1 = {1 = 2, 2 = 4},2 = {1 = 8, 2 = 20}}
salaryCouponTypes = [1,2]
SalaryCouponBatchNoMaps = {1 = "view_%d_%s",2 = "cartoon_%d_%s"}
salaryCouponMsgTitleMaps = {1 = "观影劵到账通知",2 = "漫画阅读劵到账通知"}
salaryCouponMsgContentMaps = {1 = '大会员专享观影券已到账,#{点击查看>>}{"https://big.bilibili.com/mobile/userticket"}',2 = '大会员漫画阅读券已到账 #{点击查看>>}{"http://comic.bilibili.com/coupon.html"}'}
salaryCouponMsgSupplyContentMaps = {1 = '升级年度大会员赠送观影券%d张已到账#{点击查看>>}{"https://big.bilibili.com/mobile/userticket"}',2 = '升级年度大会员赠送漫画阅读券%d张已到账#{点击查看>>}{"http://comic.bilibili.com/coupon.html"}'}
salaryCouponURL = "http://api.bilibili.co/x/internal/coupon/grant"
msgOpen = true
activeStartTime = "2018-06-10 00:00:00"
sendMedalEndTime = "2018-07-08 00:00:00"
sendVipbuyEndTime = "2018-07-02 00:00:00"
summerActiveStartTime = "2018-06-09 00:00:00"
summerActiveEndTime = "2018-09-01 00:00:00"
sendCodeStartTime = "2018-08-20 00:00:00"
SendCodeEndTime = "2018-08-20 16:10:00"
couponIDs =["669748557aba188d","ab9b24dfcc107c6b","fe42eca7ed959a36","00244f64f658d1be"]
MedalID = 1
codeExchangeMap = {1=[2,4],3=[3,8],12=[10,20]}
codeExchangeTimeMap = {1=1,3=1,12=4}
codeExchangePicMap = {1="http://i0.hdslb.com/bfs/activity-plat/static/20180615/d781502035dedd08821dacc88ea19b81/v573vo4y37.png",3="http://i0.hdslb.com/bfs/activity-plat/static/20180615/d781502035dedd08821dacc88ea19b81/89j8xm0019.png",12="http://i0.hdslb.com/bfs/activity-plat/static/20180615/d781502035dedd08821dacc88ea19b81/89j8xm0019.png"}
vipbuyExchangeNameMap={"669748557aba188d"="会员购满349减40优惠券","ab9b24dfcc107c6b"="会员购满269减30优惠券","fe42eca7ed959a36"="会员购满169减20优惠券","00244f64f658d1be"="会员购满69减8优惠券"}
grayScope = 500
pushToken = "fi6xf5xmldudexsh5tgukerohn3mgrl3"
businessId = 1
splitPush = 2
UpdateDB = true
NotGrantLimit = 100
EleEompensateCron = "*/5 * * * * ?"
[RPC]
[RPC.VipRPC]
pullInterval = "10s"
[VipRPC.client]
token = "123456789"
proto = "tcp"
timeout = "1s"
timer = 1000
[VipRPC.client.breaker]
window ="10s"
sleep ="10ms"
bucket = 10
ratio = 0.5
request = 100
[VipRPC.zookeeper]
root = "/microservice/vip/"
addrs = ["172.18.33.50:2199","172.18.33.51:2199","172.18.33.52:2199"]
timeout = "30s"
[databusutil]
size = 100
chan = 1024
num = 4
[httpClient]
key = "ad4bb9b8f5d9d4a7"
secret = "6912080d78d58be7cb94f57d50d438f6"
dial = "2s"
timeout = "2s"
keepAlive = "60s"
timer = 128
[httpClient.breaker]
window = "3s"
sleep = "100ms"
bucket = 10
ratio = 0.5
request = 100
[newMysql]
addr = "172.16.33.205"
dsn = "test:test@tcp(172.16.33.205:3308)/bilibili_vip?timeout=5s&readTimeout=5s&writeTimeout=5s&parseTime=true&loc=Local&charset=utf8,utf8mb4"
active = 5
idle = 2
IdleTimeout ="4h"
queryTimeout = "2000ms"
execTimeout = "2000ms"
tranTimeout = "2000ms"
[newMysql.breaker]
window = "3s"
sleep = "100ms"
bucket = 10
ratio = 0.5
request = 100
[oldMysql]
addr = "172.16.33.205"
dsn = "vip:lqfGWO9n3XihPokr@tcp(172.16.33.205:3306)/vip?timeout=5s&readTimeout=5s&writeTimeout=5s&parseTime=true&loc=Local&charset=utf8,utf8mb4"
active = 5
idle = 2
IdleTimeout ="4h"
queryTimeout = "2000ms"
execTimeout = "2000ms"
tranTimeout = "2000ms"
[oldMysql.breaker]
window = "3s"
sleep = "100ms"
bucket = 10
ratio = 0.5
request = 100
[databus]
[databus.accLogin]
key = "4ba46ba31f9a44ef"
secret = "99985eb4451cfb1b899ca0fbe3c4bdc8"
group = "Passport-MainAccount-S"
topic = "Passport-T"
action = "sub"
offset = "old"
buffer = 1024
name = "vip-job"
proto = "tcp"
addr = "172.16.33.158:6205"
idle = 1
active = 1
dialTimeout = "1s"
readTimeout = "60s"
writeTimeout = "1s"
idleTimeout = "10s"
[databus.oldVipBinLog]
key = "4ba46ba31f9a44ef"
secret = "99985eb4451cfb1b899ca0fbe3c4bdc8"
group = "VipBinlog-MainAccount-S"
topic = "VipBinlog-T"
action = "sub"
offset = "old"
buffer = 1024
name = "vip-job"
proto = "tcp"
addr = "172.16.33.158:6205"
idle = 1
active = 1
dialTimeout = "1s"
readTimeout = "60s"
writeTimeout = "1s"
idleTimeout = "10s"
[databus.newVipBinLog]
key = "4ba46ba31f9a44ef"
secret = "99985eb4451cfb1b899ca0fbe3c4bdc8"
group = "BiliVIPBinlog-MainAccount-S"
topic = "BiliVIPBinlog-T"
action = "sub"
offset = "old"
buffer = 1024
name = "vip-job"
proto = "tcp"
addr = "172.16.33.158:6205"
idle = 1
active = 1
dialTimeout = "1s"
readTimeout = "60s"
writeTimeout = "1s"
idleTimeout = "10s"
[databus.salaryCoupon]
key = "4ba46ba31f9a44ef"
secret = "99985eb4451cfb1b899ca0fbe3c4bdc8"
group = "VipBinlog-MainAccount-S"
topic = "VipBinlog-T"
action = "sub"
offset = "old"
buffer = 1024
name = "vip-job"
proto = "tcp"
addr = "172.16.33.158:6205"
idle = 1
active = 1
dialTimeout = "1s"
readTimeout = "60s"
writeTimeout = "1s"
idleTimeout = "10s"
[databus.accountNotify]
key = "4ba46ba31f9a44ef"
secret = "eab6221e1948b24a7376f6d0535f668a"
group = "AccountNotify-MainAccount-P"
topic = "AccountNotify-T"
action = "pub"
offset = "old"
buffer = 1024
name = "vip-job"
proto = "tcp"
addr = "172.16.33.158:6205"
idle = 1
active = 1
dialTimeout = "1s"
readTimeout = "60s"
writeTimeout = "1s"
idleTimeout = "10s"
[databus.couponNotify]
key = "4ba46ba31f9a44ef"
secret = "99985eb4451cfb1b899ca0fbe3c4bdc8"
group = "BiliVIPBinlog-MainAccount-Coupon-S"
topic = "BiliVIPBinlog-T"
action = "sub"
offset = "old"
buffer = 1024
name = "vip-job"
proto = "tcp"
addr = "172.16.33.158:6205"
idle = 1
active = 1
dialTimeout = "1s"
readTimeout = "60s"
writeTimeout = "1s"
idleTimeout = "10s"
[memcache]
name = "vip"
proto = "tcp"
addr = "172.18.33.60:11234"
idle = 5
active = 10
dialTimeout = "1s"
readTimeout = "1s"
writeTimeout = "1s"
idleTimeout = "10s"
expire = "24h"
[redis]
name = "vip"
proto = "tcp"
addr = "172.18.33.61:6879"
idle = 100
active = 100
dialTimeout = "1s"
readTimeout = "1s"
writeTimeout = "1s"
idleTimeout = "10s"
expire = "24h"
[RPCClient2]
[RPCClient2.coupon]
timeout = "1s"

View File

@ -0,0 +1,42 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = ["conf.go"],
importpath = "go-common/app/job/main/vip/conf",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//library/cache/memcache:go_default_library",
"//library/cache/redis:go_default_library",
"//library/conf:go_default_library",
"//library/database/sql:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/net/rpc:go_default_library",
"//library/net/rpc/warden:go_default_library",
"//library/queue/databus:go_default_library",
"//library/queue/databus/databusutil:go_default_library",
"//library/time:go_default_library",
"//vendor/github.com/BurntSushi/toml:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@ -0,0 +1,222 @@
package conf
import (
"errors"
"flag"
"go-common/library/cache/memcache"
"go-common/library/cache/redis"
"go-common/library/conf"
"go-common/library/database/sql"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
"go-common/library/net/rpc"
"go-common/library/net/rpc/warden"
"go-common/library/queue/databus"
"go-common/library/queue/databus/databusutil"
xtime "go-common/library/time"
"github.com/BurntSushi/toml"
)
// Conf global variable.
var (
Conf = &Config{}
client *conf.Client
confPath string
)
// Config struct of conf.
type Config struct {
VipURI string
// base
App *bm.App
// log
Xlog *log.Config
// http
BM *bm.ServerConfig
// db
NewMysql *sql.Config
//old db
OldMysql *sql.Config
// http client
HTTPClient *bm.ClientConfig
//Property
Property *Property
URLConf *URLConf
//databus group config
DatabusUtil *databusutil.Config
//point databus
Databus *DataSource
// mc
Memcache *Memcache
// redis
Redis *Redis
PayConf *PayConf
// rpc clients
RPCClient2 *RPC
// grpc
VipClient *warden.ClientConfig
}
//RPC rpc clients.
type RPC struct {
Coupon *rpc.ClientConfig
}
//URLConf url conf
type URLConf struct {
PayCoURL string
PayURL string
MsgURL string
MallURL string
AccountURL string
APICoURL string
OldVipCoURL string
}
// Property config for biz logic.
type Property struct {
UpdateUserInfoCron string
AutoRenewCron string
SendMessageCron string
SendBcoinCron string
WillExpireMsgCron string
HadExpiredMsgCron string
PushDataCron string
EleEompensateCron string
HandlerThread int
ReadThread int
Retry int
FrozenExpire xtime.Duration
FrozenDate xtime.Duration
FrozenLimit int64
FrozenCron string
PayMapping map[string]string
MsgURL string
ActivityID int64
AnnualVipBcoinDay int
AnnualVipBcoinCouponMoney int
PayCoURL string
SalaryDay int
AnnualVipSalaryCount int
NormalVipSalaryCount int
SalaryVideoCouponnIterval xtime.Duration
SalaryVideoCouponCron string
MsgOpen bool
BatchSize int
SalaryCouponMaps map[string]map[string]int64 // map[coupontype]map[viptype]salarycount
SalaryCouponTypes []int8
SalaryCouponBatchNoMaps map[string]string // map[coupontype]batchnofmt
SalaryCouponMsgTitleMaps map[string]string // map[ coupontype]msgTitle
SalaryCouponMsgContentMaps map[string]string // map[coupontype]msgsContent
SalaryCouponMsgSupplyContentMaps map[string]string // map[coupontype]msgsContent
SalaryCouponURL string
ActiveStartTime string
SendMedalEndTime string
SendVipbuyEndTime string
SummerActiveStartTime string
SummerActiveEndTime string
SendCodeStartTime string
SendCodeEndTime string
CouponIDs []string
MedalID int64
CodeExchangeMap map[string][]int64
CodeExchangeTimeMap map[string]int
CodeExchangePicMap map[string]string
VipbuyExchangeNameMap map[string]string
GrayScope int64
PushToken string
BusinessID int64
SplitPush int
UpdateDB bool
NotGrantLimit int
}
//PayConf pay conf info
type PayConf struct {
BasicURL string
CustomerID string
Token string
NotifyURL string
OrderNotifyURL string
SignNotifyURL string
PlanID int32
ProductID string
Version string
}
// Memcache memcache
type Memcache struct {
*memcache.Config
Expire xtime.Duration
}
// Redis redis
type Redis struct {
*redis.Config
Expire xtime.Duration
}
// DataSource databus config zone.
type DataSource struct {
AccLogin *databus.Config
OldVipBinLog *databus.Config
SalaryCoupon *databus.Config
NewVipBinLog *databus.Config
AccountNotify *databus.Config
CouponNotify *databus.Config
AutoRenew *databus.Config
}
func init() {
flag.StringVar(&confPath, "conf", "", "default config path")
}
// Init create config instance.
func Init() (err error) {
if confPath != "" {
return local()
}
return remote()
}
func local() (err error) {
_, err = toml.DecodeFile(confPath, &Conf)
return
}
func remote() (err error) {
if client, err = conf.New(); err != nil {
return
}
if err = load(); err != nil {
return
}
go func() {
for range client.Event() {
log.Info("config reload")
if load() != nil {
log.Error("config reload error (%v)", err)
}
}
}()
return
}
func load() (err error) {
var (
s string
ok bool
tmpConf *Config
)
if s, ok = client.Toml2(); !ok {
return errors.New("load config center error")
}
if _, err = toml.Decode(s, &tmpConf); err != nil {
return errors.New("could not decode config")
}
*Conf = *tmpConf
return
}

View File

@ -0,0 +1,92 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = [
"associate_test.go",
"business_test.go",
"coupon_old_test.go",
"coupon_test.go",
"dao_test.go",
"http_test.go",
"memcache_test.go",
"mysql_test.go",
"oldvip_test.go",
"order_test.go",
"push_test.go",
"redis_test.go",
"resource_test.go",
"sync_test.go",
"vip_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/job/main/vip/conf:go_default_library",
"//app/job/main/vip/model:go_default_library",
"//library/database/sql:go_default_library",
"//library/time:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
"//vendor/gopkg.in/h2non/gock.v1:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"associate.go",
"business.go",
"coupon.go",
"coupon_old.go",
"dao.go",
"http.go",
"memcache.go",
"mysql.go",
"oldvip.go",
"order.go",
"push.go",
"redis.go",
"resource.go",
"sync.go",
"vip.go",
],
importpath = "go-common/app/job/main/vip/dao",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/job/main/vip/conf:go_default_library",
"//app/job/main/vip/model:go_default_library",
"//library/cache/memcache:go_default_library",
"//library/cache/redis:go_default_library",
"//library/database/sql:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/stat/prom:go_default_library",
"//library/time:go_default_library",
"//library/xstr:go_default_library",
"//vendor/github.com/google/uuid:go_default_library",
"//vendor/github.com/pkg/errors:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@ -0,0 +1,35 @@
package dao
import (
"context"
"go-common/app/job/main/vip/model"
"go-common/library/database/sql"
"github.com/pkg/errors"
)
const (
_notGrantActOrder = "SELECT id,mid,order_no,product_id,months,panel_type,associate_state,ctime,mtime FROM vip_order_activity_record WHERE associate_state = 0 AND panel_type = ? limit ?;"
)
// NotGrantActOrders not grant activity order.
func (d *Dao) NotGrantActOrders(c context.Context, panelType string, limit int) (res []*model.VipOrderActivityRecord, err error) {
var rows *sql.Rows
if rows, err = d.oldDb.Query(c, _notGrantActOrder, panelType, limit); err != nil {
err = errors.Wrapf(err, "dao associate not grants query (%s,%d)", panelType, limit)
return
}
defer rows.Close()
for rows.Next() {
r := new(model.VipOrderActivityRecord)
if err = rows.Scan(&r.ID, &r.Mid, &r.OrderNo, &r.ProductID, &r.Months, &r.PanelType, &r.AssociateState, &r.Ctime, &r.Mtime); err != nil {
err = errors.Wrapf(err, "dao associate not grants scan (%s,%d)", panelType, limit)
res = nil
return
}
res = append(res, r)
}
err = rows.Err()
return
}

View File

@ -0,0 +1,20 @@
package dao
import (
"context"
"fmt"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
// go test -test.v -test.run TestDaoNotGrantActOrders
func TestDaoNotGrantActOrders(t *testing.T) {
Convey("TestDaoNotGrantActOrders salary coupon", t, func() {
res, err := d.NotGrantActOrders(context.Background(), "ele", 100)
for _, v := range res {
fmt.Println("res:", v)
}
So(err, ShouldBeNil)
})
}

View File

@ -0,0 +1,470 @@
package dao
import (
"bytes"
"context"
"crypto/md5"
"encoding/hex"
"encoding/json"
"fmt"
"io"
"net/http"
"net/url"
"sort"
"strconv"
"strings"
xtime "time"
"go-common/app/job/main/vip/model"
"go-common/library/ecode"
"go-common/library/log"
"go-common/library/time"
"go-common/library/xstr"
"github.com/google/uuid"
"github.com/pkg/errors"
)
const (
_cleanCache = "/notify/cleanCache"
_payOrder = "/payplatform/pay/pay"
_message = "/api/notify/send.user.notify.do"
_addBcoin = "/api/coupon/regular/add"
_sendVipbuyTicket = "/mall-marketing/coupon_code/create"
_sendMedal = "/api/nameplate/get/v2"
_pushData = "/x/internal/push-strategy/task/add"
_retry = 3
_minRead = 1024 * 64
_alreadySend = -804
_alreadyGet = -663
_alreadySendVipbuy = 83110005
_ok = 1
//push
appID = 1
)
//PushData http push data
func (d *Dao) PushData(c context.Context, mids []int64, pushData *model.VipPushData, curtime string) (rel *model.VipPushResq, err error) {
var (
pushTime xtime.Time
expireTime xtime.Time
params = url.Values{}
)
rel = new(model.VipPushResq)
if pushTime, err = xtime.ParseInLocation("2006-01-02 15:04:05", fmt.Sprintf("%v %v", curtime, pushData.PushStartTime), xtime.Local); err != nil {
err = errors.WithStack(err)
return
}
if expireTime, err = xtime.ParseInLocation("2006-01-02 15:04:05", fmt.Sprintf("%v %v", curtime, pushData.PushEndTime), xtime.Local); err != nil {
err = errors.WithStack(err)
return
}
page := len(mids) / d.c.Property.SplitPush
if len(mids)%d.c.Property.SplitPush != 0 {
page++
}
for i := 0; i < page; i++ {
startID := i * d.c.Property.SplitPush
endID := (i + 1) * d.c.Property.SplitPush
if endID > len(mids) {
endID = len(mids)
}
tempMids := mids[startID:endID]
params.Set("app_id", fmt.Sprintf("%v", appID))
params.Set("business_id", fmt.Sprintf("%v", d.c.Property.BusinessID))
params.Set("alert_title", pushData.Title)
params.Set("alert_body", pushData.Content)
params.Set("mids", xstr.JoinInts(tempMids))
params.Set("link_type", fmt.Sprintf("%v", pushData.LinkType))
params.Set("link_value", pushData.LinkURL)
params.Set("builds", pushData.Platform)
params.Set("group", pushData.GroupName)
params.Set("uuid", uuid.New().String())
params.Set("push_time", fmt.Sprintf("%v", pushTime.Unix()))
params.Set("expire_time", fmt.Sprintf("%v", expireTime.Unix()))
header := make(map[string]string)
header["Authorization"] = fmt.Sprintf("token=%v", d.c.Property.PushToken)
header["Content-Type"] = "application/x-www-form-urlencoded"
for i := 0; i < _retry; i++ {
if err = d.doNomalSend(c, d.c.URLConf.APICoURL, _pushData, "127.0.0.1", header, params, rel); err != nil {
log.Error("send error(%v) url(%v)", err, d.c.URLConf.APICoURL+_pushData)
return
}
if rel.Code == int64(ecode.OK.Code()) {
log.Info("send url:%v params:%+v return:%+v error(%+v)", d.c.URLConf.APICoURL+_pushData, params, rel, err)
break
}
}
}
return
}
//SendMedal send medal
func (d *Dao) SendMedal(c context.Context, mid, medalID int64) (status int64) {
var (
err error
)
params := url.Values{}
params.Set("mid", fmt.Sprintf("%v", mid))
params.Set("nid", fmt.Sprintf("%v", medalID))
rel := new(struct {
Code int64 `json:"code"`
Data string `json:"data"`
})
defer func() {
if err == nil {
log.Info("send url:%+v params:%+v return:%+v", d.c.URLConf.AccountURL+_sendMedal, params, rel)
}
}()
for i := 0; i < _retry; i++ {
if err = d.client.Get(c, d.c.URLConf.AccountURL+_sendMedal, "127.0.0.1", params, rel); err != nil {
log.Error("send error(%v) url(%v)", err, d.c.URLConf.AccountURL+_sendMedal)
continue
}
if rel.Code == int64(ecode.OK.Code()) || rel.Code == _alreadyGet {
status = 1
if rel.Code == _alreadyGet {
status = 2
}
return
}
}
return
}
//SendVipBuyTicket send vipbuy ticket
func (d *Dao) SendVipBuyTicket(c context.Context, mid int64, couponID string) (status int64) {
var (
err error
)
header := make(map[string]string)
header["Content-Type"] = "application/json"
params := make(map[string]string)
params["mid"] = fmt.Sprintf("%v", mid)
params["couponId"] = fmt.Sprintf("%v", couponID)
for i := 0; i < _retry; i++ {
repl := new(struct {
Code int64 `json:"code"`
Message string `json:"message"`
})
if err = d.doSend(c, d.c.URLConf.MallURL, _sendVipbuyTicket, "127.0.0.1", header, params, repl); err != nil {
log.Error("send vip buy ticket(%+v) error(%+v)", params, err)
continue
}
if repl.Code == int64(ecode.OK.Code()) || repl.Code == _alreadySendVipbuy {
status = 1
if repl.Code == _alreadySendVipbuy {
status = 2
}
return
}
}
return
}
//SendCleanCache clean cache
func (d *Dao) SendCleanCache(c context.Context, hv *model.HandlerVip) (err error) {
params := url.Values{}
params.Set("mid", strconv.FormatInt(int64(hv.Mid), 10))
if err = d.client.Get(c, d.c.VipURI+_cleanCache, "127.0.0.1", params, nil); err != nil {
log.Error("SendCleanCache error(%v) url(%v)", err, d.c.VipURI+_cleanCache)
return
}
return
}
//SendBcoin send bcoin http
func (d *Dao) SendBcoin(c context.Context, mids []int64, money int32, dueTime time.Time, ip string) (err error) {
if len(mids) <= 0 {
return
}
var midStrs []string
for _, v := range mids {
midStrs = append(midStrs, fmt.Sprintf("%v", v))
}
params := url.Values{}
params.Add("activity_id", fmt.Sprintf("%v", d.c.Property.ActivityID))
params.Add("mids", strings.Join(midStrs, ","))
params.Add("money", fmt.Sprintf("%v", money*100))
params.Add("due_time", dueTime.Time().Format("2006-01-02"))
res := new(struct {
Code int64 `json:"code"`
Message string `json:"message"`
TS int64 `json:"ts"`
Data struct {
CouponMoney int64 `json:"coupon_money"`
Status int8 `json:"status"`
} `json:"data"`
})
if err = d.client.Post(c, d.c.URLConf.PayCoURL+_addBcoin, ip, params, res); err != nil {
err = errors.WithStack(err)
return
}
if res.Code == int64(_alreadySend) {
return
}
if int(res.Code) != ecode.OK.Code() {
err = fmt.Errorf("发放B币失败 message: %s mid: %s resp(%+v)", res.Message, strings.Join(midStrs, ","), res)
return
}
if res.Data.Status != _ok {
err = fmt.Errorf("发放B币失败 message: %s mid: %s resp(%+v)", res.Message, strings.Join(midStrs, ","), res)
return
}
log.Info("发放B币成功 mids %v resp(%+v)", mids, res)
return
}
//SendAppCleanCache notice app clean cache
func (d *Dao) SendAppCleanCache(c context.Context, hv *model.HandlerVip, app *model.VipAppInfo) (err error) {
params := url.Values{}
params.Set("modifiedAttr", "updateVip")
params.Set("mid", fmt.Sprintf("%v", hv.Mid))
params.Set("status", fmt.Sprintf("%v", hv.Type))
params.Set("buyMonths", fmt.Sprintf("%v", hv.Months))
params.Set("days", fmt.Sprintf("%v", hv.Days))
if err = d.client.Get(c, app.PurgeURL, "127.0.0.1", params, nil); err != nil {
log.Error("SendAppCleanCache error(%v) url(%v) params(%v)", err, app.PurgeURL, params)
return
}
return
}
//SendMultipMsg send multip msg
func (d *Dao) SendMultipMsg(c context.Context, mids, content, title, mc string, dataType int) (err error) {
params := url.Values{}
params.Set("mc", mc)
params.Set("title", title)
params.Set("context", content)
params.Set("data_type", strconv.FormatInt(int64(dataType), 10))
params.Set("mid_list", mids)
defer func() {
log.Info("SendMultipMsg(%v) params(%+v) error(%+v)", d.c.URLConf.MsgURL+_message, params, err)
}()
if err = d.client.Post(c, d.c.URLConf.MsgURL+_message, "127.0.0.1", params, nil); err != nil {
log.Error("SendMultipMsg params(%+v) error(%v)", err, params)
return
}
log.Info("cur send mid(%+v)", mids)
return
}
// PayOrder pay order.
func (d *Dao) PayOrder(c context.Context, paramsMap map[string]interface{}) (err error) {
params := make(map[string]string)
for k, v := range paramsMap {
params[k] = fmt.Sprintf("%v", v)
}
header := make(map[string]string)
header["Content-Type"] = "application/json"
success := false
for i := 0; i < 3; i++ {
repl := new(struct {
ErrNo int64 `json:"errno"`
Msg string `json:"msg"`
Data interface{} `json:"data"`
})
if err = d.doPaySend(c, d.c.URLConf.PayURL, _payOrder, "127.0.0.1", header, params, repl); err != nil {
continue
}
if repl.ErrNo == 0 {
success = true
break
}
}
if !success {
err = fmt.Errorf("下单失败")
}
return
}
func (d *Dao) sortParamsKey(v map[string]string) string {
if v == nil {
return ""
}
var buf bytes.Buffer
keys := make([]string, 0, len(v))
for k := range v {
keys = append(keys, k)
}
sort.Strings(keys)
for _, k := range keys {
vs := v[k]
prefix := k + "="
if buf.Len() > 0 {
buf.WriteByte('&')
}
buf.WriteString(prefix)
buf.WriteString(vs)
}
return buf.String()
}
//PaySign pay sign
func (d *Dao) PaySign(params map[string]string, token string) (sign string) {
tmp := d.sortParamsKey(params)
var b bytes.Buffer
b.WriteString(tmp)
b.WriteString(fmt.Sprintf("&token=%s", token))
log.Info("sign params:%v ", b.String())
mh := md5.Sum(b.Bytes())
// query
var qb bytes.Buffer
qb.WriteString(tmp)
qb.WriteString("&sign=")
qb.WriteString(hex.EncodeToString(mh[:]))
sign = hex.EncodeToString(mh[:])
log.Info("sign params(%v) and sign(%v)", b.String(), sign)
return
}
func (d *Dao) doNomalSend(c context.Context, basePath, path, ip string, header map[string]string, params url.Values, data interface{}) (err error) {
var (
req *http.Request
client = new(http.Client)
resp *http.Response
bs []byte
marshal string
)
url := basePath + path
if req, err = d.client.NewRequest(http.MethodPost, url, ip, params); err != nil {
err = errors.WithStack(err)
return
}
for k, v := range header {
req.Header.Add(k, v)
}
if resp, err = client.Do(req); err != nil {
log.Error("call url:%v params:%v", basePath+path, string(marshal))
err = errors.WithStack(err)
return
}
defer resp.Body.Close()
defer func() {
log.Info("call url:%v params:(%v) result:(%+v) header:(%+v)", url, string(marshal), data, header)
}()
if resp.StatusCode >= http.StatusBadRequest {
err = errors.Errorf("incorrect http status:%d host:%s, url:%s", resp.StatusCode, req.URL.Host, req.URL.String())
return
}
if bs, err = readAll(resp.Body, _minRead); err != nil {
err = errors.Wrapf(err, "host:%s, url:%s", req.URL.Host, req.URL.String())
return
}
if err = json.Unmarshal(bs, data); err != nil {
err = errors.WithStack(err)
return
}
return
}
func (d *Dao) doSend(c context.Context, basePath, path, IP string, header map[string]string, params map[string]string, data interface{}) (err error) {
var (
req *http.Request
client = new(http.Client)
resp *http.Response
bs []byte
)
url := basePath + path
marshal, _ := json.Marshal(params)
if req, err = http.NewRequest(http.MethodPost, url, strings.NewReader(string(marshal))); err != nil {
err = errors.WithStack(err)
return
}
for k, v := range header {
req.Header.Add(k, v)
}
if resp, err = client.Do(req); err != nil {
log.Error("call url:%v params:%v", basePath+path, string(marshal))
err = errors.WithStack(err)
return
}
defer resp.Body.Close()
defer func() {
log.Info("call url:%v params:(%v) result:(%+v) header:(%+v)", url, string(marshal), data, header)
}()
if resp.StatusCode >= http.StatusBadRequest {
err = errors.Errorf("incorrect http status:%d host:%s, url:%s", resp.StatusCode, req.URL.Host, req.URL.String())
return
}
if bs, err = readAll(resp.Body, _minRead); err != nil {
err = errors.Wrapf(err, "host:%s, url:%s", req.URL.Host, req.URL.String())
return
}
if err = json.Unmarshal(bs, data); err != nil {
err = errors.WithStack(err)
return
}
return
}
func (d *Dao) doPaySend(c context.Context, basePath, path, IP string, header map[string]string, params map[string]string, data interface{}) (err error) {
sign := d.PaySign(params, d.c.PayConf.Token)
params["sign"] = sign
return d.doSend(c, basePath, path, IP, header, params, data)
}
func readAll(r io.Reader, capacity int64) (b []byte, err error) {
buf := bytes.NewBuffer(make([]byte, 0, capacity))
// If the buffer overflows, we will get bytes.ErrTooLarge.
// Return that as an error. Any other panic remains.
defer func() {
e := recover()
if e == nil {
return
}
if panicErr, ok := e.(error); ok && panicErr == bytes.ErrTooLarge {
err = panicErr
} else {
panic(e)
}
}()
_, err = buf.ReadFrom(r)
return buf.Bytes(), err
}
// SalaryCoupon salary coupon.
func (d *Dao) SalaryCoupon(c context.Context, mid int64, couponType int8, count int64, token string) (err error) {
params := url.Values{}
params.Set("mid", fmt.Sprintf("%d", mid))
params.Set("type", fmt.Sprintf("%d", couponType))
params.Set("count", fmt.Sprintf("%d", count))
params.Set("batch_no", token)
var resp struct {
Code int64 `json:"code"`
}
if err = d.client.Post(c, d.c.Property.SalaryCouponURL, "", params, &resp); err != nil {
log.Error("message url(%s) error(%v)", d.c.Property.SalaryCouponURL+"?"+params.Encode(), err)
return
}
if resp.Code != 0 {
err = fmt.Errorf("POST SalaryCoupon url resp(%v)", resp)
return
}
return
}

View File

@ -0,0 +1,121 @@
package dao
import (
"context"
"testing"
"time"
"go-common/app/job/main/vip/model"
xtime "go-common/library/time"
"github.com/smartystreets/goconvey/convey"
gock "gopkg.in/h2non/gock.v1"
)
// go test -test.v -test.run TestDaoSalaryCoupon
func TestDaoSalaryCoupon(t *testing.T) {
convey.Convey("TestDaoSalaryCoupon salary coupon", t, func() {
var (
c = context.TODO()
mid int64 = 123
ct int8 = 2
count int64 = 2
err error
)
err = d.SalaryCoupon(c, mid, ct, count, "cartoon_1_2018_06")
convey.So(err, convey.ShouldBeNil)
})
}
func TestDao_SendMultipMsg(t *testing.T) {
convey.Convey("send multipmsg", t, func() {
defer gock.OffAll()
httpMock("POST", _message).Reply(200).JSON(`{"code":0,"data":1}`)
err := d.SendMultipMsg(context.TODO(), "27515256", "test", "test", "10_1_2", 4)
convey.So(err, convey.ShouldBeNil)
})
}
func TestDaoPushData(t *testing.T) {
pushData := &model.VipPushData{
Title: "TEST",
PushStartTime: "15:04:05",
PushEndTime: "15:04:05",
}
convey.Convey("PushData", t, func() {
defer gock.OffAll()
httpMock("POST", _pushData).Reply(200).JSON(`{"code":0,"data":1}`)
rel, err := d.PushData(context.TODO(), []int64{7593623}, pushData, "2006-01-02")
convey.So(err, convey.ShouldBeNil)
convey.So(rel, convey.ShouldNotBeNil)
})
}
func TestDaoSendMedal(t *testing.T) {
convey.Convey("SendMedal", t, func() {
defer gock.OffAll()
httpMock("GET", _sendMedal).Reply(200).JSON(`{"code":0,"data":{"status":1}}`)
status := d.SendMedal(context.TODO(), 0, 0)
convey.So(status, convey.ShouldNotBeNil)
})
}
func TestDaoSendCleanCache(t *testing.T) {
hv := &model.HandlerVip{Mid: 7593623}
convey.Convey("SendCleanCache", t, func() {
defer gock.OffAll()
httpMock("GET", _cleanCache).Reply(200).JSON(`{"code":0,"data":{"status":1}}`)
err := d.SendCleanCache(context.TODO(), hv)
convey.So(err, convey.ShouldBeNil)
})
}
func TestDaoSendBcoin(t *testing.T) {
convey.Convey("SendBcoin", t, func() {
defer gock.OffAll()
httpMock("POST", _addBcoin).Reply(200).JSON(`{"code":0,"data":{"status":1}}`)
err := d.SendBcoin(context.TODO(), []int64{7593623}, 0, xtime.Time(time.Now().Unix()), "")
convey.So(err, convey.ShouldBeNil)
})
}
func TestDaoSendAppCleanCache(t *testing.T) {
var (
hv = &model.HandlerVip{Mid: 7593623}
app = &model.VipAppInfo{
PurgeURL: "http://bilibili.com/test",
}
)
convey.Convey("SendAppCleanCache", t, func() {
defer gock.OffAll()
httpMock("GET", app.PurgeURL).Reply(200).JSON(`{"code":0}`)
err := d.SendAppCleanCache(context.TODO(), hv, app)
convey.So(err, convey.ShouldBeNil)
})
}
func TestDaosortParamsKey(t *testing.T) {
var v map[string]string
convey.Convey("sortParamsKey", t, func() {
p1 := d.sortParamsKey(v)
convey.So(p1, convey.ShouldNotBeNil)
})
}
func TestDaoPaySign(t *testing.T) {
var params map[string]string
convey.Convey("PaySign", t, func() {
sign := d.PaySign(params, "test")
convey.So(sign, convey.ShouldNotBeNil)
})
}
func TestDaodoNomalSend(t *testing.T) {
var path = "/x/internal/vip/user/info"
convey.Convey("doNomalSend", t, func() {
defer gock.OffAll()
httpMock("POST", path).Reply(200).JSON(`{"code":0}`)
err := d.doNomalSend(context.TODO(), "http://api.bilibili.com", path, "", nil, nil, new(model.VipPushResq))
convey.So(err, convey.ShouldBeNil)
})
}

View File

@ -0,0 +1,46 @@
package dao
import (
"context"
"fmt"
"go-common/app/job/main/vip/model"
"go-common/library/database/sql"
"github.com/pkg/errors"
)
const (
_SelSalaryVideoCoupon = "SELECT `id`,`mid`,`coupon_count`,`coupon_type`,`state`,`type`,`ver` FROM `vip_view_coupon_salary_log_%s` WHERE `mid` = ?;"
_addSalaryLogSQL = "INSERT INTO `vip_view_coupon_salary_log_%s`(`mid`,`coupon_count`,`coupon_type`,`state`,`type`)VALUES(?,?,?,?,?);"
)
//SalaryVideoCouponList select salary video coupon list.
func (d *Dao) SalaryVideoCouponList(c context.Context, mid int64, dv string) (res []*model.VideoCouponSalaryLog, err error) {
var rows *sql.Rows
if rows, err = d.db.Query(c, fmt.Sprintf(_SelSalaryVideoCoupon, dv), mid); err != nil {
err = errors.WithStack(err)
return
}
defer rows.Close()
for rows.Next() {
r := new(model.VideoCouponSalaryLog)
if err = rows.Scan(&r.ID, &r.Mid, &r.CouponCount, &r.CouponType, &r.State, &r.Type, &r.Ver); err != nil {
err = errors.WithStack(err)
res = nil
return
}
res = append(res, r)
}
err = rows.Err()
return
}
//AddSalaryLog add salary log.
func (d *Dao) AddSalaryLog(c context.Context, l *model.VideoCouponSalaryLog, dv string) (err error) {
if _, err = d.db.Exec(c, fmt.Sprintf(_addSalaryLogSQL, dv), l.Mid, l.CouponCount, l.CouponType, l.State, l.Type); err != nil {
err = errors.WithStack(err)
return
}
return
}

View File

@ -0,0 +1,46 @@
package dao
import (
"context"
"fmt"
"go-common/app/job/main/vip/model"
"go-common/library/database/sql"
"github.com/pkg/errors"
)
const (
_selSalaryMaxID = "SELECT IFNULL(MAX(id),0) id FROM vip_view_coupon_salary_log_%s;"
_selOldSalaryList = "SELECT `mid`,`coupon_count`,`state`,`type` FROM `vip_view_coupon_salary_log_%s` WHERE id>? AND id <=?;"
)
// SalaryLogMaxID select salary log max id.
func (d *Dao) SalaryLogMaxID(c context.Context, dv string) (maxID int, err error) {
var row = d.oldDb.QueryRow(c, fmt.Sprintf(_selSalaryMaxID, dv))
if err = row.Scan(&maxID); err != nil {
err = errors.WithStack(err)
return
}
return
}
//SelOldSalaryList sel old salary list
func (d *Dao) SelOldSalaryList(c context.Context, id, endID int, dv string) (res []*model.OldSalaryLog, err error) {
var rows *sql.Rows
if rows, err = d.oldDb.Query(c, fmt.Sprintf(_selOldSalaryList, dv), id, endID); err != nil {
err = errors.WithStack(err)
return
}
defer rows.Close()
for rows.Next() {
r := new(model.OldSalaryLog)
if err = rows.Scan(&r.Mid, &r.CouponCount, &r.State, &r.Type); err != nil {
err = errors.WithStack(err)
res = nil
return
}
res = append(res, r)
}
err = rows.Err()
return
}

View File

@ -0,0 +1,41 @@
package dao
import (
"context"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestDaoSalaryLogMaxID(t *testing.T) {
convey.Convey("SalaryLogMaxID", t, func(ctx convey.C) {
var (
c = context.Background()
dv = "2018_09"
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
maxID, err := d.SalaryLogMaxID(c, dv)
ctx.Convey("Then err should be nil.maxID should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(maxID, convey.ShouldNotBeNil)
})
})
})
}
func TestDaoSelOldSalaryList(t *testing.T) {
convey.Convey("SelOldSalaryList", t, func(ctx convey.C) {
var (
c = context.Background()
id = int(0)
endID = int(0)
dv = "2018_09"
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
_, err := d.SelOldSalaryList(c, id, endID, dv)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}

View File

@ -0,0 +1,44 @@
package dao
import (
"context"
"go-common/app/job/main/vip/model"
"testing"
"time"
"github.com/smartystreets/goconvey/convey"
)
func TestDaoSalaryVideoCouponList(t *testing.T) {
convey.Convey("SalaryVideoCouponList", t, func(ctx convey.C) {
var (
c = context.Background()
mid = int64(0)
dv = "2018_09"
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
_, err := d.SalaryVideoCouponList(c, mid, dv)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestDaoAddSalaryLog(t *testing.T) {
convey.Convey("AddSalaryLog", t, func(ctx convey.C) {
var (
c = context.Background()
l = &model.VideoCouponSalaryLog{
Mid: time.Now().Unix(),
}
dv = "2018_09"
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.AddSalaryLog(c, l, dv)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}

View File

@ -0,0 +1,77 @@
package dao
import (
"context"
"time"
"go-common/app/job/main/vip/conf"
"go-common/library/cache/memcache"
"go-common/library/cache/redis"
"go-common/library/database/sql"
bm "go-common/library/net/http/blademaster"
"go-common/library/stat/prom"
)
// Dao struct info of Dao.
type Dao struct {
// mysql
db *sql.DB
oldDb *sql.DB
// http
client *bm.Client
// conf
c *conf.Config
// memcache
mc *memcache.Pool
mcExpire int32
//redis pool
redis *redis.Pool
redisExpire int32
errProm *prom.Prom
frozenExpire int32
}
// New new a Dao and return.
func New(c *conf.Config) (d *Dao) {
d = &Dao{
// conf
c: c,
// mc
mc: memcache.NewPool(c.Memcache.Config),
mcExpire: int32(time.Duration(c.Memcache.Expire) / time.Second),
// redis
redis: redis.NewPool(c.Redis.Config),
redisExpire: int32(time.Duration(c.Redis.Expire) / time.Second),
// db
db: sql.NewMySQL(c.NewMysql),
oldDb: sql.NewMySQL(c.OldMysql),
// http client
client: bm.NewClient(c.HTTPClient),
errProm: prom.BusinessErrCount,
frozenExpire: int32(time.Duration(c.Property.FrozenExpire) / time.Second),
}
return
}
// Ping ping health of db.
func (d *Dao) Ping(c context.Context) (err error) {
return d.db.Ping(c)
}
// Close close connections of mc, redis, db.
func (d *Dao) Close() {
if d.db != nil {
d.db.Close()
}
if d.redis != nil {
d.redis.Close()
}
}
//StartTx start tx
func (d *Dao) StartTx(c context.Context) (tx *sql.Tx, err error) {
if d.db != nil {
tx, err = d.db.Begin(c)
}
return
}

View File

@ -0,0 +1,45 @@
package dao
import (
"flag"
"os"
"strings"
"testing"
"go-common/app/job/main/vip/conf"
gock "gopkg.in/h2non/gock.v1"
)
var (
d *Dao
)
func TestMain(m *testing.M) {
if os.Getenv("DEPLOY_ENV") != "" {
flag.Set("app_id", "main.account.vip-job")
flag.Set("conf_token", "9a445028722910ccf99d501d56c6aea0")
flag.Set("tree_id", "14826")
flag.Set("conf_version", "docker-1")
flag.Set("deploy_env", "uat")
flag.Set("conf_host", "config.bilibili.co")
flag.Set("conf_path", "/tmp")
flag.Set("region", "sh")
flag.Set("zone", "sh001")
} else {
flag.Set("conf", "../cmd/vip-job-test.toml")
}
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
d = New(conf.Conf)
d.client.SetTransport(gock.DefaultTransport)
os.Exit(m.Run())
}
func httpMock(method, url string) *gock.Request {
r := gock.New(url)
r.Method = strings.ToUpper(method)
return r
}

View File

@ -0,0 +1,35 @@
package dao
import (
"context"
"fmt"
"net/url"
"go-common/app/job/main/vip/model"
"go-common/library/log"
"github.com/pkg/errors"
)
const (
_retryAutoRenew = "/x/internal/autorenew/retry"
)
//AutoRenewPay auto renew pay.
func (d *Dao) AutoRenewPay(c context.Context, mid int64) (res *model.CommonResq, err error) {
res = new(model.CommonResq)
val := url.Values{}
val.Add("mid", fmt.Sprintf("%d", mid))
url := d.c.VipURI + _retryAutoRenew
if err = d.client.Post(c, url, "", val, res); err != nil {
log.Error("reques fail url %v params:%+v result:%+v, err:%+v", url, val, res, err)
err = errors.WithStack(err)
return
}
if res.Code != 0 {
log.Error("reques fail url %v params:%+v result:%+v, err:%+v", url, val, res, err)
return
}
log.Info("reques success url %v params:%+v result:%+v", url, val, res)
return
}

View File

@ -0,0 +1,16 @@
package dao
import (
"context"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func TestDaoAutoRenewPay(t *testing.T) {
Convey("TestDaoAutoRenewPay", t, func() {
res, err := d.AutoRenewPay(context.Background(), 1234)
t.Logf("%+v,%+v", res, err)
So(res, ShouldNotBeNil)
})
}

View File

@ -0,0 +1,213 @@
package dao
import (
"context"
"fmt"
"strconv"
"go-common/app/job/main/vip/model"
"go-common/library/cache/memcache"
"go-common/library/log"
"github.com/pkg/errors"
)
const (
_vipInfo = "vo:%d"
_vipMadel = "madel:%d"
_vipbuy = "vipbuy:%d"
_vipfrozen = "vipfrozen:%d"
madelExpired = 3600 * 24 * 15
vipbuyExpired = 3600 * 24 * 8
vipFrozenExpired = 60 * 30
vipFrozenFlag = 1
_prefixInfo = "i:"
)
func vipfrozen(mid int64) string {
return fmt.Sprintf(_vipfrozen, mid)
}
func vipbuy(mid int64) string {
return fmt.Sprintf(_vipbuy, mid)
}
func vipInfoKey(mid int64) string {
return fmt.Sprintf(_vipInfo, mid)
}
func vipMadel(mid int64) string {
return fmt.Sprintf(_vipMadel, mid)
}
func keyInfo(mid int64) string {
return _prefixInfo + strconv.FormatInt(mid, 10)
}
//SetVipFrozen .
func (d *Dao) SetVipFrozen(c context.Context, mid int64) (err error) {
var (
key = vipfrozen(mid)
)
conn := d.mc.Get(c)
defer conn.Close()
item := &memcache.Item{Key: key, Object: vipFrozenFlag, Expiration: vipFrozenExpired, Flags: memcache.FlagJSON}
if err = conn.Set(item); err != nil {
err = errors.Wrapf(err, "d.setVipFrozen")
d.errProm.Incr("vip frozen_mc")
return
}
return
}
//DelVipFrozen .
func (d *Dao) DelVipFrozen(c context.Context, mid int64) (err error) {
return d.delCache(c, vipfrozen(mid))
}
//SetVipMadelCache set vip madel cache
func (d *Dao) SetVipMadelCache(c context.Context, mid int64, val int64) (err error) {
var (
key = vipMadel(mid)
)
conn := d.mc.Get(c)
defer conn.Close()
item := &memcache.Item{Key: key, Object: val, Expiration: madelExpired, Flags: memcache.FlagJSON}
if err = conn.Set(item); err != nil {
err = errors.Wrap(err, "d.SetVipMadelCache")
d.errProm.Incr("vipmadel_mc")
}
return
}
//GetVipBuyCache get vipbuy cache by key
func (d *Dao) GetVipBuyCache(c context.Context, mid int64) (val int64, err error) {
var (
key = vipbuy(mid)
item *memcache.Item
)
conn := d.mc.Get(c)
defer conn.Close()
if item, err = conn.Get(key); err != nil {
if err == memcache.ErrNotFound {
err = nil
return
}
err = errors.Wrapf(err, "conn.Get(%s)", key)
d.errProm.Incr("vipinfo_mc")
return
}
if err = conn.Scan(item, &val); err != nil {
err = errors.WithStack(err)
d.errProm.Incr("vipMadelCache_mc")
}
return
}
//SetVipBuyCache set vipbuy cache
func (d *Dao) SetVipBuyCache(c context.Context, mid int64, val int64) (err error) {
var (
key = vipbuy(mid)
)
conn := d.mc.Get(c)
defer conn.Close()
item := &memcache.Item{Key: key, Object: val, Expiration: vipbuyExpired, Flags: memcache.FlagJSON}
if err = conn.Set(item); err != nil {
err = errors.Wrap(err, "d.SetVipBuyCache")
d.errProm.Incr("vipbuy_mc")
}
return
}
//GetVipMadelCache get madel info by mid
func (d *Dao) GetVipMadelCache(c context.Context, mid int64) (val int64, err error) {
var (
key = vipMadel(mid)
item *memcache.Item
)
conn := d.mc.Get(c)
defer conn.Close()
if item, err = conn.Get(key); err != nil {
if err == memcache.ErrNotFound {
err = nil
return
}
err = errors.Wrapf(err, "conn.Get(%s)", key)
d.errProm.Incr("vipinfo_mc")
return
}
if err = conn.Scan(item, &val); err != nil {
err = errors.WithStack(err)
d.errProm.Incr("vipMadelCache_mc")
}
return
}
// SetVipInfoCache set vip info cache.
func (d *Dao) SetVipInfoCache(c context.Context, mid int64, v *model.VipInfo) (err error) {
var (
key = vipInfoKey(mid)
)
conn := d.mc.Get(c)
defer conn.Close()
item := &memcache.Item{Key: key, Object: v, Expiration: d.mcExpire, Flags: memcache.FlagProtobuf}
if err = conn.Set(item); err != nil {
err = errors.Wrap(err, "d.SetVipInfo")
d.errProm.Incr("vipinfo_mc")
}
return
}
// DelVipInfoCache del vip info cache.
func (d *Dao) DelVipInfoCache(c context.Context, mid int64) (err error) {
err = d.delCache(c, vipInfoKey(mid))
return
}
// DelInfoCache del vip info cache.
func (d *Dao) DelInfoCache(c context.Context, mid int64) (err error) {
if err = d.delCache(c, keyInfo(mid)); err != nil {
log.Error("del vipinfo cache(mid:%d) error(%+v)", mid, err)
}
return
}
func (d *Dao) delCache(c context.Context, key string) (err error) {
conn := d.mc.Get(c)
defer conn.Close()
if err = conn.Delete(key); err != nil {
if err == memcache.ErrNotFound {
err = nil
} else {
err = errors.Wrapf(err, "conn.Delete(%s)", key)
d.errProm.Incr("del_mc")
}
}
return
}
// AddTransferLock add lock.
func (d *Dao) AddTransferLock(c context.Context, key string) (succeed bool) {
var (
conn = d.mc.Get(c)
)
defer conn.Close()
item := &memcache.Item{
Key: key,
Value: []byte("0"),
Expiration: 3600,
}
if err := conn.Add(item); err != nil {
if err != memcache.ErrNotStored {
log.Error("conn.Add(%s) error(%v)", key, err)
}
} else {
succeed = true
}
return
}

View File

@ -0,0 +1,74 @@
package dao
import (
"testing"
"context"
"go-common/app/job/main/vip/model"
. "github.com/smartystreets/goconvey/convey"
)
func TestDao_DelVipInfoCache(t *testing.T) {
Convey("should return true where err != nil and res not empty", t, func() {
err := d.DelVipInfoCache(context.TODO(), 1234)
So(err, ShouldBeNil)
})
}
func TestDao_SetVipInfoCache(t *testing.T) {
Convey("set vip info cache", t, func() {
err := d.SetVipInfoCache(context.TODO(), 1234, &model.VipInfo{Mid: 1234, VipType: model.Vip, VipStatus: model.VipStatusNotOverTime})
So(err, ShouldBeNil)
})
}
func TestDao_AddPayOrderLog(t *testing.T) {
Convey("add pay order log", t, func() {
_, err := d.AddPayOrderLog(context.TODO(), &model.VipPayOrderLog{Mid: 1234, Status: 1, OrderNo: "12891723894189"})
So(err, ShouldBeNil)
})
}
func TestDao_GetVipMadelCache(t *testing.T) {
Convey("get vip madel cache ", t, func() {
val, err := d.GetVipMadelCache(context.TODO(), 2089801)
t.Logf("val %v \n", val)
So(err, ShouldBeNil)
})
}
func TestDao_SetVipMadelCache(t *testing.T) {
Convey("set vip madel", t, func() {
err := d.SetVipMadelCache(context.TODO(), 2089801, 1)
So(err, ShouldBeNil)
})
}
func TestDao_SetVipFrozen(t *testing.T) {
Convey("set vip frozen", t, func() {
err := d.SetVipFrozen(context.TODO(), 2089809)
So(err, ShouldBeNil)
})
}
func TestDao_GetVipBuyCache(t *testing.T) {
var val int64 = 1
Convey("SetVipBuyCache", t, func() {
err := d.SetVipBuyCache(context.TODO(), 2089809, val)
So(err, ShouldBeNil)
})
Convey("GetVipBuyCache", t, func() {
res, err := d.GetVipBuyCache(context.TODO(), 2089809)
So(err, ShouldBeNil)
So(val, ShouldEqual, res)
})
}
func TestDao_AddTransferLock(t *testing.T) {
Convey("AddTransferLock", t, func() {
err := d.delCache(context.TODO(), "2089809")
So(err, ShouldBeNil)
bool := d.AddTransferLock(context.TODO(), "2089809")
So(bool, ShouldBeTrue)
})
}

View File

@ -0,0 +1,310 @@
package dao
import (
"context"
"fmt"
"strconv"
"strings"
"go-common/app/job/main/vip/model"
"go-common/library/database/sql"
"go-common/library/log"
"go-common/library/xstr"
"github.com/pkg/errors"
)
const (
_selAppInfo = "SELECT id,name,app_key,purge_url from vip_app_info WHERE `type` = 1"
//bcoin sql
_selBcoinSalarySQL = "SELECT id,mid,status,give_now_status,payday,amount,memo FROM vip_user_bcoin_salary WHERE 1=1"
_selBcoinSalaryDataSQL = "SELECT id,mid,status,give_now_status,payday,amount,memo FROM vip_user_bcoin_salary WHERE id>? AND id<=?"
_selBcoinSalaryByMidSQL = "SELECT id,mid,status,give_now_status,payday,amount,memo FROM vip_user_bcoin_salary WHERE mid IN (%v)"
_selOldBcoinSalaryByMidSQL = "SELECT id,mid,IFNULL(status,0),IFNULL(give_now_status,0),month,IFNULL(amount,0),IFNULL(memo,'') FROM vip_bcoin_salary WHERE mid IN (%v)"
_selOldBcoinSalarySQL = "SELECT id,mid,IFNULL(status,0),IFNULL(give_now_status,0),month,IFNULL(amount,0),IFNULL(memo,'') FROM vip_bcoin_salary WHERE id>? AND id<=?"
_addBcoinSalarySQL = "INSERT INTO vip_user_bcoin_salary(mid,status,give_now_status,payday,amount,memo) VALUES(?,?,?,?,?,?)"
_updateBcoinSalarySQL = "UPDATE vip_user_bcoin_salary set status = ? WHERE mid = ? AND payday = ?"
_updateBcoinSalaryBatchSQL = "UPDATE vip_user_bcoin_salary set status = ? WHERE id in (?)"
_batchAddBcoinSalarySQL = "INSERT INTO vip_user_bcoin_salary(mid,status,give_now_status,payday,amount,memo) VALUES "
_selBcoinMaxIDSQL = "SELECT IFNULL(MAX(id),0) FROM vip_user_bcoin_salary"
_selOldBcoinMaxIDSQL = "SELECT IFNULL(MAX(id),0) FROM vip_bcoin_salary"
_delBcoinSalarySQL = "DELETE FROM vip_user_bcoin_salary WHERE mid = ? AND payday = ?"
_getAbleCodeSQL = "SELECT code FROM vip_resource_code WHERE batch_code_id = ? AND status = 1 AND relation_id = '' LIMIT 1"
_selBatchCodeSQL = "SELECT id,business_id,pool_id,status,type,batch_name,reason,unit,count,surplus_count,price,start_time,end_time FROM vip_resource_batch_code WHERE id = ?"
_updateCodeRelationIDSQL = "UPDATE vip_resource_code SET relation_id=?,bmid=? WHERE code=?"
_selEffectiveVipList = "SELECT id,mid,vip_type,vip_status,vip_overdue_time,annual_vip_overdue_time FROM vip_user_info WHERE id>? AND id <=? "
//push
_selPushDataSQL = "SELECT id,disable_type,group_name,title,content,push_total_count,pushed_count,progress_status,`status`,platform,link_type,link_url,error_code,expired_day_start,expired_day_end,effect_start_date,effect_end_date,push_start_time,push_end_time FROM vip_push_data WHERE effect_start_date <= ? AND effect_end_date >= ? "
_updatePushDataSQL = "UPDATE vip_push_data SET progress_status=?,status=?, pushed_count=?,error_code=?,task_id=? WHERE id=?"
)
//SelOldBcoinMaxID sel oldbcoin maxID
func (d *Dao) SelOldBcoinMaxID(c context.Context) (maxID int64, err error) {
row := d.oldDb.QueryRow(c, _selOldBcoinMaxIDSQL)
if err = row.Scan(&maxID); err != nil {
if err == sql.ErrStmtNil {
err = nil
maxID = 0
return
}
err = errors.WithStack(err)
d.errProm.Incr("db_scan")
}
return
}
//SelBcoinMaxID sel bcoin maxID
func (d *Dao) SelBcoinMaxID(c context.Context) (maxID int64, err error) {
row := d.db.QueryRow(c, _selBcoinMaxIDSQL)
if err = row.Scan(&maxID); err != nil {
err = errors.WithStack(err)
d.errProm.Incr("db_scan")
return
}
return
}
//SelBcoinSalaryData sel bcoinSalary data
func (d *Dao) SelBcoinSalaryData(c context.Context, startID int64, endID int64) (res []*model.VipBcoinSalary, err error) {
var rows *sql.Rows
if rows, err = d.db.Query(c, _selBcoinSalaryDataSQL, startID, endID); err != nil {
err = errors.WithStack(err)
d.errProm.Incr("db_query")
return
}
defer rows.Close()
for rows.Next() {
r := new(model.VipBcoinSalary)
if err = rows.Scan(&r.ID, &r.Mid, &r.Status, &r.GiveNowStatus, &r.Payday, &r.Amount, &r.Memo); err != nil {
err = errors.WithStack(err)
d.errProm.Incr("db_scan")
return
}
res = append(res, r)
}
err = rows.Err()
return
}
//SelBcoinSalaryDataMaps sel bcoin salary data convert map
func (d *Dao) SelBcoinSalaryDataMaps(c context.Context, mids []int64) (res map[int64][]*model.VipBcoinSalary, err error) {
var rows *sql.Rows
if rows, err = d.db.Query(c, fmt.Sprintf(_selBcoinSalaryByMidSQL, xstr.JoinInts(mids))); err != nil {
err = errors.WithStack(err)
d.errProm.Incr("db_query")
return
}
res = make(map[int64][]*model.VipBcoinSalary)
defer rows.Close()
for rows.Next() {
r := new(model.VipBcoinSalary)
if err = rows.Scan(&r.ID, &r.Mid, &r.Status, &r.GiveNowStatus, &r.Payday, &r.Amount, &r.Memo); err != nil {
err = errors.WithStack(err)
d.errProm.Incr("db_scan")
return
}
salaries := res[r.Mid]
salaries = append(salaries, r)
res[r.Mid] = salaries
}
err = rows.Err()
return
}
//SelOldBcoinSalaryDataMaps sel old bcoin salary data convert map
func (d *Dao) SelOldBcoinSalaryDataMaps(c context.Context, mids []int64) (res map[int64][]*model.VipBcoinSalary, err error) {
var rows *sql.Rows
if rows, err = d.oldDb.Query(c, fmt.Sprintf(_selOldBcoinSalaryByMidSQL, xstr.JoinInts(mids))); err != nil {
err = errors.WithStack(err)
d.errProm.Incr("db_query")
return
}
res = make(map[int64][]*model.VipBcoinSalary)
defer rows.Close()
for rows.Next() {
r := new(model.VipBcoinSalary)
if err = rows.Scan(&r.ID, &r.Mid, &r.Status, &r.GiveNowStatus, &r.Payday, &r.Amount, &r.Memo); err != nil {
err = errors.WithStack(err)
d.errProm.Incr("db_scan")
return
}
salaries := res[r.Mid]
salaries = append(salaries, r)
res[r.Mid] = salaries
}
err = rows.Err()
return
}
//SelBcoinSalary sel bcoin salary data by query
func (d *Dao) SelBcoinSalary(c context.Context, arg *model.QueryBcoinSalary) (res []*model.VipBcoinSalary, err error) {
var rows *sql.Rows
sqlStr := ""
if arg.StartID >= 0 {
sqlStr += fmt.Sprintf(" AND id > %v ", arg.StartID)
}
if arg.EndID >= 0 {
sqlStr += fmt.Sprintf(" AND id <= %v ", arg.EndID)
}
if arg.StartMonth > 0 {
sqlStr += fmt.Sprintf(" AND payday>= '%v' ", arg.StartMonth.Time().Format("2006-01-02"))
}
if arg.EndMonth > 0 {
sqlStr += fmt.Sprintf(" AND payday <= '%v' ", arg.EndMonth.Time().Format("2006-01-02"))
}
if arg.GiveNowStatus > -1 {
sqlStr += fmt.Sprintf(" AND give_now_status = %v ", arg.GiveNowStatus)
}
if arg.Status > -1 {
sqlStr += fmt.Sprintf(" AND status = %v ", arg.Status)
}
if rows, err = d.db.Query(c, _selBcoinSalarySQL+sqlStr); err != nil {
err = errors.WithStack(err)
d.errProm.Incr("db_query")
return
}
defer rows.Close()
for rows.Next() {
r := new(model.VipBcoinSalary)
if err = rows.Scan(&r.ID, &r.Mid, &r.Status, &r.GiveNowStatus, &r.Payday, &r.Amount, &r.Memo); err != nil {
err = errors.WithStack(err)
d.errProm.Incr("db_scan")
}
res = append(res, r)
}
err = rows.Err()
return
}
//SelOldBcoinSalary sel old bcoin salary
func (d *Dao) SelOldBcoinSalary(c context.Context, startID, endID int64) (res []*model.VipBcoinSalary, err error) {
var rows *sql.Rows
if rows, err = d.oldDb.Query(c, _selOldBcoinSalarySQL, startID, endID); err != nil {
err = errors.WithStack(err)
d.errProm.Incr("db_query")
return
}
defer rows.Close()
for rows.Next() {
r := new(model.VipBcoinSalary)
if err = rows.Scan(&r.ID, &r.Mid, &r.Status, &r.GiveNowStatus, &r.Payday, &r.Amount, &r.Memo); err != nil {
err = errors.WithStack(err)
d.errProm.Incr("db_scan")
}
res = append(res, r)
}
err = rows.Err()
return
}
//AddBcoinSalary add bcoin salary
func (d *Dao) AddBcoinSalary(c context.Context, arg *model.VipBcoinSalaryMsg) (err error) {
if _, err = d.db.Exec(c, _addBcoinSalarySQL, &arg.Mid, &arg.Status, &arg.GiveNowStatus, &arg.Payday, &arg.Amount, &arg.Memo); err != nil {
err = errors.WithStack(err)
d.errProm.Incr("db_exec")
}
return
}
//UpdateBcoinSalary update bcoin salary
func (d *Dao) UpdateBcoinSalary(c context.Context, payday string, mid int64, status int8) (err error) {
if _, err = d.db.Exec(c, _updateBcoinSalarySQL, status, mid, payday); err != nil {
err = errors.WithStack(err)
d.errProm.Incr("db_exec")
}
return
}
//DelBcoinSalary del bcoin salary
func (d *Dao) DelBcoinSalary(c context.Context, payday string, mid int64) (err error) {
if _, err = d.db.Exec(c, _delBcoinSalarySQL, mid, payday); err != nil {
err = errors.WithStack(err)
return
}
return
}
//UpdateBcoinSalaryBatch update bcoin salary batch
func (d *Dao) UpdateBcoinSalaryBatch(c context.Context, ids []int64, status int8) (err error) {
if len(ids) <= 0 {
return
}
sqlStr := ""
for _, v := range ids {
sqlStr += "," + strconv.FormatInt(v, 10)
}
if _, err = d.db.Exec(c, _updateBcoinSalaryBatchSQL, status, sqlStr[1:]); err != nil {
err = errors.WithStack(err)
return
}
return
}
//BatchAddBcoinSalary batch add bcoin salary data
func (d *Dao) BatchAddBcoinSalary(bcoins []*model.VipBcoinSalary) (err error) {
var values []string
if len(bcoins) <= 0 {
return
}
for _, v := range bcoins {
str := fmt.Sprintf("('%v','%v','%v','%v','%v','%v')", v.Mid, v.Status, v.GiveNowStatus, v.Payday.Time().Format("2006-01-02"), v.Amount, v.Memo)
values = append(values, str)
}
valueStr := strings.Join(values, ",")
if _, err = d.db.Exec(context.TODO(), _batchAddBcoinSalarySQL+valueStr); err != nil {
err = errors.WithStack(err)
d.errProm.Incr("db_exec")
return
}
return
}
//SelAppInfo sel vip_app_info data
func (d *Dao) SelAppInfo(c context.Context) (res []*model.VipAppInfo, err error) {
var rows *sql.Rows
if rows, err = d.oldDb.Query(c, _selAppInfo); err != nil {
log.Error("SelAppInfo db.query() error(%v)", err)
return
}
defer rows.Close()
for rows.Next() {
r := new(model.VipAppInfo)
if err = rows.Scan(&r.ID, &r.Name, &r.AppKey, &r.PurgeURL); err != nil {
log.Error("row.scan() error(%v)", err)
res = nil
return
}
res = append(res, r)
}
err = rows.Err()
return
}
//SelEffectiveVipList sel effective vip data
func (d *Dao) SelEffectiveVipList(c context.Context, id, endID int) (res []*model.VipUserInfo, err error) {
var rows *sql.Rows
if rows, err = d.oldDb.Query(c, _selEffectiveVipList, id, endID); err != nil {
err = errors.WithStack(err)
return
}
defer rows.Close()
for rows.Next() {
r := new(model.VipUserInfo)
if err = rows.Scan(&r.ID, &r.Mid, &r.Type, &r.Status, &r.OverdueTime, &r.AnnualVipOverdueTime); err != nil {
err = errors.WithStack(err)
res = nil
return
}
res = append(res, r)
}
err = rows.Err()
return
}

View File

@ -0,0 +1,162 @@
package dao
import (
"context"
"testing"
"time"
"go-common/app/job/main/vip/model"
. "github.com/smartystreets/goconvey/convey"
)
func Test_SelVipList(t *testing.T) {
var (
res []*model.VipUserInfo
err error
id = 0
mID = 10000
ot = time.Now().Format("2006-01-02")
)
Convey("should return true where err != nil and res not empty", t, func() {
res, err = d.SelVipList(context.TODO(), id, mID, ot)
So(err, ShouldBeNil)
So(res, ShouldNotBeEmpty)
})
}
func Test_UpdateVipUserInfo(t *testing.T) {
vuf := new(model.VipUserInfo)
vuf.ID = 1
vuf.Type = 1
vuf.Status = 0
Convey("should return true where err == nil", t, func() {
tx, err := d.StartTx(context.TODO())
So(err, ShouldBeNil)
_, err = d.UpdateVipUserInfo(tx, vuf)
So(err, ShouldBeNil)
})
}
func Test_SelAppInfo(t *testing.T) {
Convey("should return true where err == nil and res not empty", t, func() {
res, err := d.SelAppInfo(context.TODO())
So(err, ShouldBeNil)
So(res, ShouldNotBeEmpty)
})
}
func Test_SelMaxID(t *testing.T) {
Convey("should return true where err == nil ", t, func() {
r, err := d.SelMaxID(context.TODO())
So(r, ShouldBeGreaterThan, 100)
So(err, ShouldBeNil)
})
}
func TestDao_SelOrderMaxID(t *testing.T) {
Convey("sel order max id", t, func() {
_, err := d.SelOrderMaxID(context.TODO())
So(err, ShouldBeNil)
})
}
func TestDao_SelOldBcoinMaxID(t *testing.T) {
Convey("sel old bcoin Max id", t, func() {
_, err := d.SelOldBcoinMaxID(context.TODO())
So(err, ShouldBeNil)
})
}
func TestDao_SelBcoinMaxID(t *testing.T) {
Convey("sel bcoin maxID", t, func() {
_, err := d.SelBcoinMaxID(context.TODO())
So(err, ShouldBeNil)
})
}
func TestDao_SelChangeHistoryMaxID(t *testing.T) {
Convey("sel change hsitory max id", t, func() {
_, err := d.SelChangeHistoryMaxID(context.TODO())
So(err, ShouldBeNil)
})
}
func TestDao_SelOldOrderMaxID(t *testing.T) {
Convey("sel old Order maxID", t, func() {
_, err := d.SelOldOrderMaxID(context.TODO())
So(err, ShouldBeNil)
})
}
func TestDao_VipStatus(t *testing.T) {
Convey("vip status", t, func() {
_, err := d.VipStatus(context.TODO(), 1)
So(err, ShouldBeNil)
})
}
func TestDao_SelOldBcoinSalaryDataMaps(t *testing.T) {
Convey("vip SelOldBcoinSalaryDataMaps", t, func() {
_, err := d.SelOldBcoinSalaryDataMaps(context.TODO(), []int64{7593623})
So(err, ShouldBeNil)
})
}
func TestDao_SelBcoinSalary(t *testing.T) {
arg := &model.QueryBcoinSalary{
StartID: 1,
EndID: 1,
Status: 1,
}
Convey("vip SelBcoinSalary", t, func() {
_, err := d.SelBcoinSalary(context.TODO(), arg)
So(err, ShouldBeNil)
})
}
func TestDao_SelOldBcoinSalary(t *testing.T) {
arg := &model.VipBcoinSalaryMsg{
Mid: 7593623,
Status: 1,
GiveNowStatus: 1,
Payday: "10",
Amount: 1,
Memo: "memo",
}
Convey("vip AddBcoinSalary", t, func() {
err := d.AddBcoinSalary(context.TODO(), arg)
So(err, ShouldBeNil)
})
Convey("vip UpdateBcoinSalary", t, func() {
err := d.UpdateBcoinSalary(context.TODO(), "10", 7593623, 2)
So(err, ShouldBeNil)
})
Convey("del bcoin salary", t, func() {
err := d.DelBcoinSalary(context.TODO(), "10", 7593623)
So(err, ShouldBeNil)
})
Convey("vip SelOldBcoinSalary", t, func() {
_, err := d.SelOldBcoinSalary(context.TODO(), 1, 1)
So(err, ShouldBeNil)
})
}
func TestDao_SelBcoinSalaryData(t *testing.T) {
Convey("SelBcoinSalaryData", t, func() {
_, err := d.SelBcoinSalaryData(context.TODO(), 1, 1)
So(err, ShouldBeNil)
})
}
func TestDao_SelBcoinSalaryDataMaps(t *testing.T) {
Convey("SelBcoinSalaryDataMaps", t, func() {
_, err := d.SelBcoinSalaryDataMaps(context.TODO(), []int64{1})
So(err, ShouldBeNil)
})
}
func TestDao_SelEffectiveVipList(t *testing.T) {
Convey("SelEffectiveVipList", t, func() {
_, err := d.SelEffectiveVipList(context.TODO(), 1, 1)
So(err, ShouldBeNil)
})
}

View File

@ -0,0 +1,37 @@
package dao
import (
"context"
"fmt"
"go-common/library/ecode"
"go-common/library/log"
"net/url"
)
const (
_frozenChange = "/internal/v1/user/frozenChange"
)
// OldFrozenChange .
func (d *Dao) OldFrozenChange(mid, status int64) (err error) {
var (
c = context.Background()
)
params := url.Values{}
params.Set("mid", fmt.Sprintf("%v", mid))
params.Set("status", fmt.Sprintf("%v", status))
rel := new(struct {
Code int64 `json:"code"`
Data string `json:"data"`
})
if err = d.client.Get(c, d.c.URLConf.OldVipCoURL+_frozenChange, "127.0.0.1", params, rel); err != nil {
log.Error("send error(%v) url(%v)", err, d.c.URLConf.OldVipCoURL+_frozenChange)
return
}
if rel != nil && rel.Code == int64(ecode.OK.Code()) {
return
}
err = ecode.VipJavaAPIErr
return
}

View File

@ -0,0 +1,14 @@
package dao
import (
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestDaoOldFrozenChange(t *testing.T) {
convey.Convey("OldFrozenChange", t, func() {
err := d.OldFrozenChange(7593623, 0)
convey.So(err, convey.ShouldBeNil)
})
}

View File

@ -0,0 +1,252 @@
package dao
import (
"context"
"database/sql"
"fmt"
"strings"
"go-common/app/job/main/vip/model"
xsql "go-common/library/database/sql"
"go-common/library/log"
"github.com/pkg/errors"
)
const (
_insertPayOrder = "INSERT IGNORE INTO vip_pay_order(order_no,app_id,platform,order_type,mid,to_mid,buy_months,money,status,pay_type,recharge_bp,third_trade_no,payment_time,ver,app_sub_id,coupon_money) VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"
_selPayOrder = "SELECT order_no,app_id,platform,order_type,mid,to_mid,buy_months,money,status,pay_type,third_trade_no,payment_time,ver,app_sub_id FROM vip_pay_order WHERE id>? AND id <=?"
_selPayOrderByMidSQL = "SELECT order_no,app_id,platform,order_type,mid,to_mid,buy_months,money,status,pay_type,third_trade_no,payment_time,ver,app_sub_id FROM vip_pay_order WHERE mid=? AND order_type=? AND status=? ORDER BY ID DESC LIMIT 1"
_selOrderByMidSQL = "SELECT order_no,app_id,platform,order_type,mid,to_mid,buy_months,money,status,pay_type,third_trade_no,payment_time,ver,app_sub_id FROM vip_pay_order WHERE order_no=?"
_selPayOrderLogByMidSQL = "SELECT order_no,status,mid FROM vip_pay_order_log WHERE mid=? AND status=? ORDER BY ID DESC LIMIT 1"
_selOldPayOrder = "SELECT order_no,app_id,order_type,mid,IFNULL(buy_months,0),money,IFNULL(pay_type,4),IFNULL(status,1),ver,IFNULL(platform,3),mtime,app_sub_id,bmid,coupon_money from vip_pay_order WHERE id>? AND id<=?"
_selOldRechargeOrder = "SELECT pay_order_no,third_trade_no,recharge_bp FROM vip_recharge_order WHERE pay_order_no IN "
_updatePayOrderStatusSQL = "UPDATE vip_pay_order SET "
_updateRechageOrderSQL = "UPDATE vip_pay_order SET recharge_bp = ?,third_trade_no = ? where order_no = ?"
_insertPayOrderLog = "INSERT INTO vip_pay_order_log(order_no,mid,status) VALUES(?,?,?)"
_batchAddPayOrder = "INSERT INTO vip_pay_order(order_no,app_id,platform,order_type,mid,to_mid,buy_months,money,status,pay_type,recharge_bp,third_trade_no,payment_time,ver,app_sub_id) VALUES"
_selOrderMaxIDSQL = "SELECT IFNULL(MAX(id),0) FROM vip_pay_order"
_selOldOrderMaxIDSQL = "SELECT IFNULL(MAX(id),0) FROM vip_pay_order"
)
//SelPayOrderByMid sel payorder by mid
func (d *Dao) SelPayOrderByMid(c context.Context, mid int64, orderType, status int8) (r *model.VipPayOrder, err error) {
row := d.db.QueryRow(c, _selPayOrderByMidSQL, mid, orderType, status)
r = new(model.VipPayOrder)
if err = row.Scan(&r.OrderNo, &r.AppID, &r.Platform, &r.OrderType, &r.Mid, &r.ToMid, &r.BuyMonths, &r.Money, &r.Status, &r.PayType, &r.ThirdTradeNo, &r.PaymentTime, &r.Ver, &r.AppSubID); err != nil {
if err == sql.ErrNoRows {
err = nil
r = nil
return
}
err = errors.WithStack(err)
d.errProm.Incr("db_scan")
return
}
return
}
//SelOrderByOrderNo sel payorder by orderNo
func (d *Dao) SelOrderByOrderNo(c context.Context, orderNo string) (r *model.VipPayOrder, err error) {
row := d.db.QueryRow(c, _selOrderByMidSQL, orderNo)
r = new(model.VipPayOrder)
if err = row.Scan(&r.OrderNo, &r.AppID, &r.Platform, &r.OrderType, &r.Mid, &r.ToMid, &r.BuyMonths, &r.Money, &r.Status, &r.PayType, &r.ThirdTradeNo, &r.PaymentTime, &r.Ver, &r.AppSubID); err != nil {
if err == sql.ErrNoRows {
err = nil
r = nil
return
}
err = errors.WithStack(err)
d.errProm.Incr("db_scan")
return
}
return
}
//SelPayOrderLog sel pay order log.
func (d *Dao) SelPayOrderLog(c context.Context, mid int64, status int8) (r *model.VipPayOrderLog, err error) {
row := d.db.QueryRow(c, _selPayOrderLogByMidSQL, mid, status)
r = new(model.VipPayOrderLog)
if err = row.Scan(&r.OrderNo, &r.Status, &r.Mid); err != nil {
if err == sql.ErrNoRows {
err = nil
r = nil
return
}
err = errors.WithStack(err)
d.errProm.Incr("db_scan")
return
}
return
}
//AddPayOrder add payorder
func (d *Dao) AddPayOrder(c context.Context, r *model.VipPayOrder) (a int64, err error) {
var result sql.Result
if result, err = d.db.Exec(c, _insertPayOrder, &r.OrderNo, &r.AppID, &r.Platform, &r.OrderType, &r.Mid, &r.ToMid, &r.BuyMonths, &r.Money, &r.Status, &r.PayType, &r.RechargeBp, &r.ThirdTradeNo, &r.PaymentTime, &r.Ver, &r.AppSubID, &r.CouponMoney); err != nil {
log.Error("AddPayOrder d.db.exec(%v) error(%v)", r, err)
return
}
if a, err = result.RowsAffected(); err != nil {
log.Error("AddPayOrder result.RowsAffected() error(%v)", err)
return
}
return
}
//SelOrderMaxID sel order maxID
func (d *Dao) SelOrderMaxID(c context.Context) (maxID int, err error) {
row := d.db.QueryRow(c, _selOrderMaxIDSQL)
if err = row.Scan(&maxID); err != nil {
err = errors.WithStack(err)
d.errProm.Incr("db_scan")
return
}
return
}
//SelOldOrderMaxID sel old order maxID
func (d *Dao) SelOldOrderMaxID(c context.Context) (maxID int, err error) {
row := d.oldDb.QueryRow(c, _selOldOrderMaxIDSQL)
if err = row.Scan(&maxID); err != nil {
err = errors.WithStack(err)
d.errProm.Incr("db_scan")
return
}
return
}
//BatchAddPayOrder batch add pay order
func (d *Dao) BatchAddPayOrder(c context.Context, res []*model.VipPayOrder) (err error) {
var values []string
if len(res) == 0 {
return
}
for _, v := range res {
value := fmt.Sprintf("('%v','%v','%v','%v','%v','%v','%v','%v','%v','%v','%v','%v','%v','%v','%v','%v')", v.OrderNo, v.AppID, v.Platform, v.OrderType, v.Mid, v.ToMid, v.BuyMonths, v.Money, v.Status, v.PayType, v.RechargeBp, v.ThirdTradeNo, v.PaymentTime.Time().Format("2006-01-02 15:04:05"), v.Ver, v.AppSubID, v.CouponMoney)
values = append(values, value)
}
valuesStr := strings.Join(values, ",")
dupStr := " ON DUPLICATE KEY UPDATE app_id = VALUES(app_id),platform=VALUES(platform),order_type=VALUES(order_type)," +
"mid=VALUES(mid),to_mid=VALUES(to_mid),buy_months=VALUES(buy_months),money=VALUES(money),status=VALUES(status),pay_type=VALUES(pay_type),recharge_bp=VALUES(recharge_bp)," +
"third_trade_no=VALUES(third_trade_no) ,payment_time=VALUES(payment_time) ,ver=VALUES(ver),app_sub_id=VALUES(app_sub_id),coupon_money=VALUES(coupon_money) "
if _, err = d.db.Exec(c, _batchAddPayOrder+valuesStr+dupStr); err != nil {
err = errors.WithStack(err)
return
}
return
}
//UpdatePayOrderStatus update payorder status
func (d *Dao) UpdatePayOrderStatus(c context.Context, r *model.VipPayOrder) (a int64, err error) {
var result sql.Result
sqlStr := _updatePayOrderStatusSQL
if r.PayType != 0 {
sqlStr += fmt.Sprintf(" pay_type=%v ,payment_time='%v' ,", r.PayType, r.PaymentTime.Time().Format("2006-01-02 15:04:05"))
}
sqlStr += fmt.Sprintf(" ctime='%v',mtime='%v',ver=%v,status=%v,order_type=%v,coupon_money=%v WHERE order_no='%v' ", r.Ctime.Time().Format("2006-01-02 15:04:05"), r.Mtime.Time().Format("2006-01-02 15:04:05"), r.Ver, r.Status, r.OrderType, r.CouponMoney, r.OrderNo)
if result, err = d.db.Exec(c, sqlStr); err != nil {
err = errors.WithStack(err)
return
}
if a, err = result.RowsAffected(); err != nil {
err = errors.WithStack(err)
return
}
return
}
//UpdateRechargeOrder update recharge order info
func (d *Dao) UpdateRechargeOrder(c context.Context, r *model.VipPayOrder) (a int64, err error) {
var result sql.Result
if result, err = d.db.Exec(c, _updateRechageOrderSQL, &r.RechargeBp, &r.ThirdTradeNo, &r.OrderNo); err != nil {
err = errors.WithStack(err)
return
}
if a, err = result.RowsAffected(); err != nil {
err = errors.WithStack(err)
return
}
return
}
//AddPayOrderLog add payorderlog
func (d *Dao) AddPayOrderLog(c context.Context, r *model.VipPayOrderLog) (a int64, err error) {
var result sql.Result
if result, err = d.db.Exec(c, _insertPayOrderLog, &r.OrderNo, &r.Mid, &r.Status); err != nil {
err = errors.WithStack(err)
return
}
if a, err = result.RowsAffected(); err != nil {
err = errors.WithStack(err)
return
}
return
}
//SelPayOrder sel payorder
func (d *Dao) SelPayOrder(c context.Context, sID, eID int) (res []*model.VipPayOrder, err error) {
var rows *xsql.Rows
if rows, err = d.db.Query(c, _selPayOrder, sID, eID); err != nil {
log.Error("SelPayOrder d.db.query(sID:%v,eID:%v) error(%v)", sID, eID, err)
return
}
defer rows.Close()
for rows.Next() {
r := new(model.VipPayOrder)
if err = rows.Scan(&r.OrderNo, &r.AppID, &r.Platform, &r.OrderType, &r.Mid, &r.ToMid, &r.BuyMonths, &r.Money, &r.Status, &r.PayType, &r.ThirdTradeNo, &r.PaymentTime, &r.Ver, &r.AppSubID); err != nil {
log.Error("SelPayOrder rows.scan() error(%v)", err)
res = nil
return
}
res = append(res, r)
}
err = rows.Err()
return
}
//SelOldPayOrder sel old payorder
func (d *Dao) SelOldPayOrder(c context.Context, sID, eID int) (res []*model.VipPayOrderOld, err error) {
var rows *xsql.Rows
if rows, err = d.oldDb.Query(c, _selOldPayOrder, sID, eID); err != nil {
log.Error("SelOldPayOrder d.db.query(sID:%v,eID:%v) error(%v)", sID, eID, err)
return
}
defer rows.Close()
for rows.Next() {
r := new(model.VipPayOrderOld)
if err = rows.Scan(&r.OrderNo, &r.AppID, &r.OrderType, &r.Mid, &r.BuyMonths, &r.Money, &r.PayType, &r.Status, &r.Ver, &r.Platform, &r.PaymentTime, &r.AppSubID, &r.Bmid, &r.CouponMoney); err != nil {
log.Error("SelOldPayOrder rows.scan() error(%v)", err)
res = nil
return
}
res = append(res, r)
}
err = rows.Err()
return
}
//SelOldRechargeOrder sel old rechargeOrder
func (d *Dao) SelOldRechargeOrder(c context.Context, orderNos []string) (res []*model.VipRechargeOrder, err error) {
var inStr = strings.Join(orderNos, "','")
inStr = "('" + inStr + "')"
var rows *xsql.Rows
if rows, err = d.oldDb.Query(c, _selOldRechargeOrder+inStr); err != nil {
log.Error("SelOldRechargeOrder d.db.query(%v) error(%v)", orderNos, err)
return
}
defer rows.Close()
for rows.Next() {
r := new(model.VipRechargeOrder)
if err = rows.Scan(&r.PayOrderNo, &r.ThirdTradeNo, &r.RechargeBp); err != nil {
log.Error("SelOldRechargeOrder rows.scan(%v) error(%v)", orderNos, err)
res = nil
return
}
res = append(res, r)
}
err = rows.Err()
return
}

View File

@ -0,0 +1,76 @@
package dao
import (
"context"
"testing"
"go-common/app/job/main/vip/model"
xtime "go-common/library/time"
"time"
. "github.com/smartystreets/goconvey/convey"
)
func TestDao_AddPayOrder(t *testing.T) {
Convey("add pay order", t, func() {
d.AddPayOrder(context.TODO(), &model.VipPayOrder{Mid: 123})
})
}
func TestDao_UpdatePayOrderStatus(t *testing.T) {
Convey("update order", t, func() {
r := new(model.VipPayOrder)
r.OrderType = 1
r.PayType = 6
r.Status = 2
r.Ver = 2
r.OrderNo = "1807021929153562939"
r.Mtime = xtime.Time(time.Now().Unix())
_, err := d.UpdatePayOrderStatus(context.TODO(), r)
So(err, ShouldBeNil)
})
}
func TestDao_SelPayOrderByMid(t *testing.T) {
Convey("SelPayOrderByMid", t, func() {
_, err := d.SelPayOrderByMid(context.TODO(), 7593623, 1, 1)
So(err, ShouldBeNil)
})
}
func TestDao_SSelOrderByOrderNo(t *testing.T) {
Convey("SelOrderByOrderNo", t, func() {
_, err := d.SelOrderByOrderNo(context.TODO(), "7593623")
So(err, ShouldBeNil)
})
}
func TestDao_SelPayOrderLog(t *testing.T) {
Convey("SelPayOrderLog", t, func() {
_, err := d.SelPayOrderLog(context.TODO(), 7593623, 1)
So(err, ShouldBeNil)
})
}
func TestDao_SelPayOrder(t *testing.T) {
Convey("SelPayOrder", t, func() {
_, err := d.SelPayOrder(context.TODO(), 1, 1)
So(err, ShouldBeNil)
})
}
func TestDao_SelOldPayOrder(t *testing.T) {
Convey("SelOldPayOrder", t, func() {
_, err := d.SelOldPayOrder(context.TODO(), 1, 1)
So(err, ShouldBeNil)
})
}
func TestDao_SelOldRechargeOrder(t *testing.T) {
Convey("SelOldRechargeOrder", t, func() {
_, err := d.SelOldRechargeOrder(context.TODO(), []string{"test"})
So(err, ShouldBeNil)
})
}

View File

@ -0,0 +1,39 @@
package dao
import (
"context"
"go-common/app/job/main/vip/model"
"go-common/library/database/sql"
"github.com/pkg/errors"
)
//PushDatas get push datas
func (d *Dao) PushDatas(c context.Context, curtime string) (res []*model.VipPushData, err error) {
var rows *sql.Rows
if rows, err = d.db.Query(c, _selPushDataSQL, curtime, curtime); err != nil {
err = errors.WithStack(err)
return
}
defer rows.Close()
for rows.Next() {
r := new(model.VipPushData)
if err = rows.Scan(&r.ID, &r.DisableType, &r.GroupName, &r.Title, &r.Content, &r.PushTotalCount, &r.PushedCount, &r.ProgressStatus, &r.Status, &r.Platform, &r.LinkType, &r.LinkURL, &r.ErrorCode, &r.ExpiredDayStart, &r.ExpiredDayEnd, &r.EffectStartDate, &r.EffectEndDate, &r.PushStartTime, &r.PushEndTime); err != nil {
err = errors.WithStack(err)
return
}
res = append(res, r)
}
err = rows.Err()
return
}
//UpdatePushData update push data
func (d *Dao) UpdatePushData(c context.Context, status, progressStatus int8, pushedCount int32, errcode, data, id int64) (err error) {
if _, err = d.db.Exec(c, _updatePushDataSQL, progressStatus, status, pushedCount, errcode, data, id); err != nil {
err = errors.WithStack(err)
d.errProm.Incr("exec_err")
}
return
}

View File

@ -0,0 +1,43 @@
package dao
import (
"context"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestDaoPushDatas(t *testing.T) {
convey.Convey("PushDatas", t, func(ctx convey.C) {
var (
c = context.Background()
curtime = ""
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
_, err := d.PushDatas(c, curtime)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestDaoUpdatePushData(t *testing.T) {
convey.Convey("UpdatePushData", t, func(ctx convey.C) {
var (
c = context.Background()
status = int8(0)
progressStatus = int8(0)
pushedCount = int32(0)
errcode = int64(0)
data = int64(0)
id = int64(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.UpdatePushData(c, status, progressStatus, pushedCount, errcode, data, id)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}

View File

@ -0,0 +1,123 @@
package dao
import (
"context"
"fmt"
"time"
"go-common/library/cache/redis"
"github.com/pkg/errors"
)
const (
_frozenDelayQueue = "fdq"
_accLogin = "al:%d"
)
func accLoginKey(mid int64) string {
return fmt.Sprintf(_accLogin, mid)
}
// Enqueue put frozen user to redis sortset queue
func (d *Dao) Enqueue(c context.Context, mid, score int64) (err error) {
var (
conn = d.redis.Get(c)
)
defer conn.Close()
if err = conn.Send("ZADD", _frozenDelayQueue, score, mid); err != nil {
err = errors.Wrap(err, "redis send zadd err(%+v)")
return
}
if err = conn.Send("EXPIRE", _frozenDelayQueue, d.redisExpire); err != nil {
err = errors.Wrap(err, "redis send expire err(%+v)")
return
}
if err = conn.Flush(); err != nil {
return
}
for i := 0; i < 2; i++ {
if _, err = conn.Receive(); err != nil {
return
}
}
return
}
// Dequeue get a frozen user from redis sortset queue
func (d *Dao) Dequeue(c context.Context) (mid []int64, err error) {
var (
conn = d.redis.Get(c)
from = time.Now().Add(-1 * time.Minute).Unix()
to = time.Now().Unix()
)
defer conn.Close()
if mid, err = redis.Int64s(conn.Do("ZRANGEBYSCORE", _frozenDelayQueue, from, to)); err != nil {
err = errors.Wrap(err, "redis do zrevrangebyscore err")
return
}
return
}
// RemQueue del a frozen user from redis sortset queue
func (d *Dao) RemQueue(c context.Context, mid int64) (err error) {
var (
conn = d.redis.Get(c)
)
defer conn.Close()
if _, err = conn.Do("ZREM", _frozenDelayQueue, mid); err != nil {
err = errors.Wrap(err, "redis do zrem err")
return
}
return
}
// AddLogginIP save user loggin info to sortset
func (d *Dao) AddLogginIP(c context.Context, mid int64, ip uint32) (err error) {
var (
conn = d.redis.Get(c)
key = accLoginKey(mid)
)
defer conn.Close()
if err = conn.Send("SADD", key, ip); err != nil {
err = errors.Wrap(err, "redis do zadd err")
return
}
if err = conn.Send("EXPIRE", key, d.frozenExpire); err != nil {
err = errors.Wrap(err, "redis send expire err(%+v)")
return
}
if err = conn.Flush(); err != nil {
return
}
for i := 0; i < 2; i++ {
if _, err = conn.Receive(); err != nil {
return
}
}
return
}
//DelCache del cache.
func (d *Dao) DelCache(c context.Context, mid int64) (err error) {
var (
conn = d.redis.Get(c)
key = accLoginKey(mid)
)
defer conn.Close()
if _, err = conn.Do("DEL", key); err != nil {
err = errors.WithStack(err)
return
}
return
}
// LoginCount get user recent loggin count
func (d *Dao) LoginCount(c context.Context, mid int64) (count int64, err error) {
var conn = d.redis.Get(c)
defer conn.Close()
if count, err = redis.Int64(conn.Do("SCARD", accLoginKey(mid))); err != nil {
err = errors.Wrap(err, "redis send zcard err(%+v)")
}
return
}

View File

@ -0,0 +1,54 @@
package dao
import (
"context"
"testing"
"time"
. "github.com/smartystreets/goconvey/convey"
)
var (
ctx = context.TODO()
mid int64 = 7593623
)
func Test_FrozenQueue(t *testing.T) {
Convey("Test_FrozenQueue", t, func() {
var (
err error
score = time.Now().Add(-50 * time.Second).Unix()
)
err = d.Enqueue(ctx, mid, score)
So(err, ShouldBeNil)
res, err2 := d.Dequeue(ctx)
So(err2, ShouldBeNil)
So(res[0], ShouldEqual, mid)
err3 := d.RemQueue(ctx, mid)
So(err3, ShouldBeNil)
})
}
func TestDao_Enqueue(t *testing.T) {
Convey("test enqueue", t, func() {
duration := time.Duration(d.c.Property.FrozenDate)
t.Logf("duration %+v", duration)
err := d.Enqueue(ctx, mid, time.Now().Add(duration).Unix())
So(err, ShouldBeNil)
})
}
func TestDao_Dequeue(t *testing.T) {
Convey("dequeue", t, func() {
res, err := d.Dequeue(ctx)
t.Logf("%+v", res)
So(err, ShouldBeNil)
})
}
func Test_AddLogginIP(t *testing.T) {
Convey("Test_FrozenQueue", t, func() {
err := d.AddLogginIP(ctx, mid, 234231)
So(err, ShouldBeNil)
})
}

View File

@ -0,0 +1,43 @@
package dao
import (
"go-common/app/job/main/vip/model"
"go-common/library/database/sql"
"github.com/pkg/errors"
)
//GetAbleCode get able code
func (d *Dao) GetAbleCode(tx *sql.Tx, batchCodeID int64) (code string, err error) {
row := tx.QueryRow(_getAbleCodeSQL, batchCodeID)
if err = row.Scan(&code); err != nil {
if err == sql.ErrNoRows {
err = nil
return
}
err = errors.WithStack(err)
}
return
}
//UpdateCodeRelationID update code relationID
func (d *Dao) UpdateCodeRelationID(tx *sql.Tx, code, relationID string, bmid int64) (err error) {
if _, err = tx.Exec(_updateCodeRelationIDSQL, relationID, bmid, code); err != nil {
err = errors.WithStack(err)
}
return
}
//SelBatchCodeByID .
func (d *Dao) SelBatchCodeByID(tx *sql.Tx, batchCodeID int64) (r *model.VipResourceBatchCode, err error) {
row := tx.QueryRow(_selBatchCodeSQL, batchCodeID)
r = new(model.VipResourceBatchCode)
if err = row.Scan(&r.ID, &r.BusinessID, &r.PoolID, &r.Status, &r.Type, &r.BatchName, &r.Reason, &r.Unit, &r.Count, &r.SurplusCount, &r.Price, &r.StartTime, &r.EndTime); err != nil {
if err == sql.ErrNoRows {
err = nil
return
}
err = errors.WithStack(err)
}
return
}

View File

@ -0,0 +1,63 @@
package dao
import (
"context"
"go-common/library/database/sql"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestDaoGetAbleCode(t *testing.T) {
convey.Convey("GetAbleCode", t, func(ctx convey.C) {
var (
tx = &sql.Tx{}
batchCodeID = int64(0)
)
tx, err := d.StartTx(context.Background())
ctx.So(err, convey.ShouldBeNil)
ctx.So(tx, convey.ShouldNotBeNil)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
_, err := d.GetAbleCode(tx, batchCodeID)
ctx.Convey("Then err should be nil.code should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestDaoUpdateCodeRelationID(t *testing.T) {
convey.Convey("UpdateCodeRelationID", t, func(ctx convey.C) {
var (
code = ""
relationID = ""
bmid = int64(0)
)
tx, err := d.StartTx(context.Background())
ctx.So(err, convey.ShouldBeNil)
ctx.So(tx, convey.ShouldNotBeNil)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.UpdateCodeRelationID(tx, code, relationID, bmid)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestDaoSelBatchCodeByID(t *testing.T) {
convey.Convey("SelBatchCodeByID", t, func(ctx convey.C) {
var (
batchCodeID = int64(0)
)
tx, err := d.StartTx(context.Background())
ctx.So(err, convey.ShouldBeNil)
ctx.So(tx, convey.ShouldNotBeNil)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
_, err := d.SelBatchCodeByID(tx, batchCodeID)
ctx.Convey("Then err should be nil.r should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}

View File

@ -0,0 +1,37 @@
package dao
import (
"context"
xsql "database/sql"
"go-common/app/job/main/vip/model"
"github.com/pkg/errors"
)
const (
//sync
_syncAddUser = "INSERT INTO vip_user_info(mid,vip_type,vip_pay_type,vip_status,vip_start_time,vip_overdue_time,annual_vip_overdue_time,vip_recent_time,ios_overdue_time,pay_channel_id,ctime,mtime,ver) VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?)"
_syncUpdateUser = "UPDATE vip_user_info SET vip_type=?,vip_pay_type=?,vip_status=?,vip_overdue_time=?,annual_vip_overdue_time=?,vip_recent_time=?,ios_overdue_time=?,pay_channel_id=?,ctime=?,mtime=?,ver=? WHERE mid=? AND ver=?"
)
//SyncAddUser insert vipUserInfo
func (d *Dao) SyncAddUser(c context.Context, r *model.VipUserInfo) (err error) {
if _, err = d.db.Exec(c, _syncAddUser, r.Mid, r.Type, r.PayType, r.Status, r.StartTime, r.OverdueTime, r.AnnualVipOverdueTime, r.RecentTime, r.OverdueTime, r.PayChannelID, r.Ctime, r.Mtime, r.Ver); err != nil {
err = errors.WithStack(err)
}
return
}
//SyncUpdateUser insert vipUserInfo
func (d *Dao) SyncUpdateUser(c context.Context, r *model.VipUserInfo, ver int64) (eff int64, err error) {
var res xsql.Result
if res, err = d.db.Exec(c, _syncUpdateUser, r.Type, r.PayType, r.Status, r.OverdueTime, r.AnnualVipOverdueTime, r.RecentTime, r.IosOverdueTime, r.PayChannelID, r.Ctime, r.Mtime, r.Ver, r.Mid, ver); err != nil {
err = errors.WithStack(err)
return
}
if eff, err = res.RowsAffected(); err != nil {
err = errors.WithStack(err)
}
return
}

View File

@ -0,0 +1,29 @@
package dao
import (
"context"
"go-common/app/job/main/vip/model"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestDaoSyncAddUser(t *testing.T) {
var r = &model.VipUserInfo{Mid: 7993}
convey.Convey("clean data before", t, func() {
d.db.Exec(context.Background(), "delete from vip_user_info where mid = ?", r.Mid)
})
convey.Convey("SyncAddUser", t, func() {
err := d.SyncAddUser(context.Background(), r)
convey.So(err, convey.ShouldBeNil)
})
convey.Convey("SyncUpdateUser", t, func() {
r.Status = 2
eff, err := d.SyncUpdateUser(context.Background(), r, r.Ver)
convey.So(err, convey.ShouldBeNil)
convey.So(eff, convey.ShouldNotBeNil)
})
convey.Convey("clean data", t, func() {
d.db.Exec(context.Background(), "delete from vip_user_info where mid = ?", r.Mid)
})
}

522
app/job/main/vip/dao/vip.go Normal file
View File

@ -0,0 +1,522 @@
package dao
import (
"context"
xsql "database/sql"
"fmt"
"strings"
"go-common/app/job/main/vip/model"
"go-common/library/database/sql"
"go-common/library/log"
"go-common/library/time"
"go-common/library/xstr"
"github.com/pkg/errors"
)
const (
_getVipStatus = "SELECT id,mid,vip_status FROM vip_user_info WHERE mid=?"
_dupUserDiscountHistory = "INSERT INTO vip_user_discount_history(mid,discount_id,order_no,status) VALUES(?,?,?,?) ON DUPLICATE KEY UPDATE order_no= VALUES(order_no) ,status = VALUES(status)"
_insertUserInfo = "INSERT ignore INTO vip_user_info(mid,vip_type,vip_pay_type,vip_status,vip_start_time,vip_recent_time,vip_overdue_time,annual_vip_overdue_time,pay_channel_id,ios_overdue_time,ver) VALUES(?,?,?,?,?,?,?,?,?,?,?) "
_updateUserInfo = "UPDATE vip_user_info SET vip_type=?,vip_pay_type=?,vip_status=?,vip_start_time=?,vip_recent_time=?,vip_overdue_time=?,annual_vip_overdue_time=?,pay_channel_id=?,ios_overdue_time=?,ver=? WHERE mid=? AND ver=? "
_SelUserDiscountHistorys = "SELECT mid,discount_id FROM vip_user_discount_history WHERE id>? AND id<=? AND discount_id=?"
_SelVipUserInfos = "SELECT mid,vip_type,vip_pay_type,vip_status,vip_start_time,vip_recent_time,vip_overdue_time,annual_vip_overdue_time FROM vip_user_info WHERE id>? and id<=? "
_SelOldVipUserInfos = "SELECT mid,vip_type,is_auto_renew,auto_renewed,IFNULL(vip_status,0),vip_recent_time,TIMESTAMP(IFNULL(vip_start_time,'2016-01-01 00:00:00')),TIMESTAMP(IFNULL(vip_overdue_time,'2016-01-01 00:00:00')),TIMESTAMP(IFNULL(annual_vip_overdue_time,'2016-01-01 00:00:00')),ver,ios_overdue_time,pay_channel_id,ctime,mtime FROM vip_user_info WHERE id>? and id<=?"
_SelVipList = "SELECT id,mid,vip_type,vip_status,vip_overdue_time,annual_vip_overdue_time,is_auto_renew,pay_channel_id FROM vip_user_info WHERE id>? AND id <=? AND vip_status != 0 AND annual_vip_overdue_time<=?"
_selVipUsersSQL = "SELECT id,mid,vip_type,vip_status,vip_overdue_time,annual_vip_overdue_time FROM vip_user_info WHERE id>? AND id <=? AND vip_pay_type = 1 AND vip_overdue_time>=? AND vip_overdue_time<?"
_selVipUserInfoSQL = "SELECT mid FROM vip_user_info WHERE id>? AND id <=? AND vip_status = ? AND vip_overdue_time>=? AND vip_overdue_time<?"
_UpdateVipUserInfoByID = "UPDATE vip_user_info SET pay_channel_id=?,vip_pay_type=?,vip_recent_time=?,vip_overdue_time=?,annual_vip_overdue_time=?, vip_type=?, vip_status=? WHERE mid=?"
_updateVipStatus = "UPDATE vip_user_info SET vip_status=? WHERE mid=?"
_updateVipUserSQL = "UPDATE vip_user_info SET vip_status=?,vip_type=?,is_auto_renew=? WHERE mid=?"
_SelMaxID = "SELECT IFNULL(MAX(id),0) id FROM vip_user_info"
_SelEffectiveScopeVipList = "SELECT `id`,`mid`,`ver`,`vip_type`,`vip_pay_type`,`pay_channel_id`,`vip_status`,`vip_start_time`,`vip_recent_time`,`vip_overdue_time`,`annual_vip_overdue_time`,`ios_overdue_time`,`ctime` FROM `vip_user_info` WHERE id>? AND id <=?;"
_selDiscountMaxID = "SELECT IFNULL(MAX(id),0) id FROM vip_user_discount_history"
_selUserInfoMaxID = "SELECT IFNULL(MAX(id),0) id FROM vip_user_info"
//Vip change history
_selOldMaxIDSQL = "SELECT IFNULL(MAX(id),0) FROM vip_change_history"
_selMaxIDSQL = "SELECT IFNULL(MAX(id),0) FROM vip_user_change_history"
_selOldChangeHistorySQL = "SELECT id,mid,change_type,change_time,days,month,operator_id,relation_id,batch_id,IFNULL(remark,''),batch_code_id FROM vip_change_history WHERE id>? AND id<=?"
_selOldChangeHistoryByMidsSQL = "SELECT id,mid,change_type,change_time,days,month,operator_id,relation_id,batch_id,IFNULL(remark,''),batch_code_id FROM vip_change_history WHERE mid IN (%v)"
_selChangeHistorySQL = "SELECT id,mid,change_type,change_time,days,operator_id,relation_id,batch_id,remark,batch_code_id FROM vip_user_change_history WHERE id>? AND id<=?"
_selChangeHistoryByMidsSQL = "SELECT id,mid,change_type,change_time,days,operator_id,relation_id,batch_id,remark,batch_code_id FROM vip_user_change_history WHERE mid IN (%v)"
_addChangeHistoryBatchSQL = "INSERT INTO vip_user_change_history(mid,change_type,change_time,days,operator_id,relation_id,batch_id,remark,batch_code_id) VALUES"
// old vip db
_selOldVipUserInfo = "SELECT mid,vip_type,is_auto_renew,auto_renewed,IFNULL(vip_status,0),vip_recent_time,TIMESTAMP(IFNULL(vip_start_time,'2016-01-01 00:00:00')),TIMESTAMP(IFNULL(vip_overdue_time,'2016-01-01 00:00:00')),annual_vip_overdue_time,ios_overdue_time,ver,pay_channel_id FROM vip_user_info WHERE mid=?"
_selVipByMidsSQL = "SELECT id,mid,vip_type,vip_status,vip_recent_time,vip_start_time,vip_overdue_time,annual_vip_overdue_time,vip_pay_type,pay_channel_id,ios_overdue_time,ctime,mtime,ver FROM vip_user_info WHERE mid IN (%s)"
_selVipUserInfoByMid = "SELECT id,mid,ver,vip_type,vip_pay_type,vip_status,vip_start_time,vip_overdue_time,annual_vip_overdue_time,vip_recent_time FROM vip_user_info WHERE mid = ?"
)
//AddChangeHistoryBatch batch add change history
func (d *Dao) AddChangeHistoryBatch(res []*model.VipChangeHistory) (err error) {
var values []string
if len(res) <= 0 {
return
}
for _, v := range res {
value := fmt.Sprintf("('%v','%v','%v','%v','%v','%v','%v','%v','%v')", v.Mid, v.ChangeType, v.ChangeTime.Time().Format("2006-01-02 15:04:05"), v.Days, v.OperatorID, v.RelationID, v.BatchID, v.Remark, v.BatchCodeID)
values = append(values, value)
}
valuesStr := strings.Join(values, ",")
if _, err = d.db.Exec(context.TODO(), _addChangeHistoryBatchSQL+valuesStr); err != nil {
log.Error("AddChangeHistoryBatch d.db.exec(%v),error(%v)", valuesStr, err)
return
}
return
}
//SelChangeHistory .
func (d *Dao) SelChangeHistory(c context.Context, startID, endID int64) (res []*model.VipChangeHistory, err error) {
var rows *sql.Rows
if rows, err = d.db.Query(c, _selChangeHistorySQL, startID, endID); err != nil {
err = errors.WithStack(err)
return
}
defer rows.Close()
for rows.Next() {
r := new(model.VipChangeHistory)
if err = rows.Scan(&r.ID, &r.Mid, &r.ChangeType, &r.ChangeTime, &r.Days, &r.OperatorID, &r.RelationID, &r.BatchID, &r.Remark, &r.BatchCodeID); err != nil {
err = errors.WithStack(err)
res = nil
return
}
res = append(res, r)
}
err = rows.Err()
return
}
//SelOldChangeHistory .
func (d *Dao) SelOldChangeHistory(c context.Context, startID, endID int64) (res []*model.VipChangeHistory, err error) {
var rows *sql.Rows
if rows, err = d.oldDb.Query(c, _selOldChangeHistorySQL, startID, endID); err != nil {
err = errors.WithStack(err)
return
}
defer rows.Close()
for rows.Next() {
r := new(model.VipChangeHistory)
if err = rows.Scan(&r.ID, &r.Mid, &r.ChangeType, &r.ChangeTime, &r.Days, &r.Month, &r.OperatorID, &r.RelationID, &r.BatchID, &r.Remark, &r.BatchCodeID); err != nil {
err = errors.WithStack(err)
res = nil
return
}
res = append(res, r)
}
err = rows.Err()
return
}
//SelChangeHistoryMaps .
func (d *Dao) SelChangeHistoryMaps(c context.Context, mids []int64) (res map[int64][]*model.VipChangeHistory, err error) {
var rows *sql.Rows
if rows, err = d.db.Query(c, fmt.Sprintf(_selChangeHistoryByMidsSQL, xstr.JoinInts(mids))); err != nil {
err = errors.WithStack(err)
return
}
res = make(map[int64][]*model.VipChangeHistory)
defer rows.Close()
for rows.Next() {
r := new(model.VipChangeHistory)
if err = rows.Scan(&r.ID, &r.Mid, &r.ChangeType, &r.ChangeTime, &r.Days, &r.OperatorID, &r.RelationID, &r.BatchID, &r.Remark, &r.BatchCodeID); err != nil {
err = errors.WithStack(err)
res = nil
return
}
histories := res[r.Mid]
histories = append(histories, r)
res[r.Mid] = histories
}
err = rows.Err()
return
}
//SelOldChangeHistoryMaps .
func (d *Dao) SelOldChangeHistoryMaps(c context.Context, mids []int64) (res map[int64][]*model.VipChangeHistory, err error) {
var rows *sql.Rows
if rows, err = d.oldDb.Query(c, fmt.Sprintf(_selOldChangeHistoryByMidsSQL, xstr.JoinInts(mids))); err != nil {
err = errors.WithStack(err)
return
}
res = make(map[int64][]*model.VipChangeHistory)
defer rows.Close()
for rows.Next() {
r := new(model.VipChangeHistory)
if err = rows.Scan(&r.ID, &r.Mid, &r.ChangeType, &r.ChangeTime, &r.Days, &r.Month, &r.OperatorID, &r.RelationID, &r.BatchID, &r.Remark, &r.BatchCodeID); err != nil {
err = errors.WithStack(err)
res = nil
return
}
histories := res[r.Mid]
histories = append(histories, r)
res[r.Mid] = histories
}
err = rows.Err()
return
}
//SelOldChangeHistoryMaxID .
func (d *Dao) SelOldChangeHistoryMaxID(c context.Context) (id int64, err error) {
var row = d.oldDb.QueryRow(c, _selOldMaxIDSQL)
if err = row.Scan(&id); err != nil {
log.Error("SelMaxID row.Scan() error(%v)", err)
return
}
return
}
//SelChangeHistoryMaxID .
func (d *Dao) SelChangeHistoryMaxID(c context.Context) (id int64, err error) {
var row = d.db.QueryRow(c, _selMaxIDSQL)
if err = row.Scan(&id); err != nil {
log.Error("SelMaxID row.Scan() error(%v)", err)
return
}
return
}
// VipStatus get user vip status.
func (d *Dao) VipStatus(c context.Context, mid int64) (res *model.VipUserInfo, err error) {
row := d.db.QueryRow(c, _getVipStatus, mid)
res = new(model.VipUserInfo)
if err = row.Scan(&res.ID, &res.Mid, &res.Status); err != nil {
if err == sql.ErrNoRows {
err = nil
res = nil
} else {
err = errors.Wrapf(err, "d.VipStatus(%d)", mid)
}
}
return
}
//SelMaxID get max id
func (d *Dao) SelMaxID(c context.Context) (mID int, err error) {
var row = d.db.QueryRow(c, _SelMaxID)
if err = row.Scan(&mID); err != nil {
log.Error("SelMaxID row.Scan() error(%v)", err)
return
}
return
}
//UpdateVipUserInfo update vip user info by id
func (d *Dao) UpdateVipUserInfo(tx *sql.Tx, r *model.VipUserInfo) (a int64, err error) {
var res xsql.Result
if res, err = tx.Exec(_UpdateVipUserInfoByID, r.PayChannelID, r.PayType, r.RecentTime, r.OverdueTime, r.AnnualVipOverdueTime, r.Type, r.Status, r.Mid); err != nil {
log.Error("UpdateVipUserInfo: db.Exec(%v) error(%v)", r, err)
return
}
if a, err = res.RowsAffected(); err != nil {
log.Error("UpdateVipUserInfo: res.RowsAffected error(%v)", err)
}
return
}
// UpdateVipUser update vip user info
func (d *Dao) UpdateVipUser(c context.Context, mid int64, status, vipType int8, payType int8) (eff int64, err error) {
var res xsql.Result
if res, err = d.oldDb.Exec(c, _updateVipUserSQL, status, vipType, payType, mid); err != nil {
err = errors.Wrapf(err, "d.UpdateVipStatus(%d)", mid)
return
}
if eff, err = res.RowsAffected(); err != nil {
err = errors.Wrapf(err, "d.UpdateVipStatus(%d) res.RowsAffected", mid)
}
return
}
//UpdateVipStatus update vip status info by mid
func (d *Dao) UpdateVipStatus(c context.Context, mid int64, status int) (eff int64, err error) {
var res xsql.Result
if res, err = d.db.Exec(c, _updateVipStatus, status, mid); err != nil {
err = errors.Wrapf(err, "d.UpdateVipStatus(%d)", mid)
return
}
if eff, err = res.RowsAffected(); err != nil {
err = errors.Wrapf(err, "d.UpdateVipStatus(%d) res.RowsAffected", mid)
}
return
}
// DupUserDiscountHistory add user discount history.
func (d *Dao) DupUserDiscountHistory(tx *sql.Tx, r *model.VipUserDiscountHistory) (a int64, err error) {
var res xsql.Result
if res, err = tx.Exec(_dupUserDiscountHistory, r.Mid, r.DiscountID, r.OrderNo, r.Status); err != nil {
err = errors.WithStack(err)
return
}
if a, err = res.RowsAffected(); err != nil {
err = errors.WithStack(err)
}
return
}
//AddUserInfo add user info.
func (d *Dao) AddUserInfo(tx *sql.Tx, r *model.VipUserInfo) (eff int64, err error) {
var res xsql.Result
if res, err = tx.Exec(_insertUserInfo, r.Mid, r.Type, r.PayType, r.Status, r.StartTime, r.RecentTime, r.OverdueTime, r.AnnualVipOverdueTime, r.PayChannelID, r.IosOverdueTime, r.Ver); err != nil {
log.Error("AddUserDiscountHistory d.db.exec(%v) error(%v)", r, err)
return
}
if eff, err = res.RowsAffected(); err != nil {
log.Error("AddUserDiscountHistory RowsAffected(%v)", err)
}
return
}
//SelVipUserInfo sel vipuser info
func (d *Dao) SelVipUserInfo(c context.Context, mid int64) (r *model.VipUserInfo, err error) {
var row = d.db.QueryRow(c, _selVipUserInfoByMid, mid)
r = new(model.VipUserInfo)
if err = row.Scan(&r.ID, &r.Mid, &r.Ver, &r.Type, &r.PayType, &r.Status, &r.StartTime, &r.OverdueTime, &r.AnnualVipOverdueTime, &r.RecentTime); err != nil {
if err == sql.ErrNoRows {
r = nil
err = nil
} else {
log.Error("row.Scan() error(%v)", err)
}
}
return
}
//UpdateUserInfo add user info
func (d *Dao) UpdateUserInfo(tx *sql.Tx, r *model.VipUserInfo) (eff int64, err error) {
var res xsql.Result
if res, err = tx.Exec(_updateUserInfo, r.Type, r.PayType, r.Status, r.StartTime, r.RecentTime, r.OverdueTime, r.AnnualVipOverdueTime, r.PayChannelID, r.IosOverdueTime, r.Ver, r.Mid, r.OldVer); err != nil {
err = errors.WithStack(err)
return
}
if eff, err = res.RowsAffected(); err != nil {
err = errors.WithStack(err)
}
return
}
//SelUserDiscountMaxID sel discount maxID
func (d *Dao) SelUserDiscountMaxID(c context.Context) (maxID int, err error) {
var row = d.db.QueryRow(c, _selDiscountMaxID)
if err = row.Scan(&maxID); err != nil {
err = errors.WithStack(err)
d.errProm.Incr("db_scan")
return
}
return
}
//SelUserDiscountHistorys sel user discount hsitorys
func (d *Dao) SelUserDiscountHistorys(c context.Context, sID, eID, discountID int) (res []*model.VipUserDiscountHistory, err error) {
var rows *sql.Rows
if rows, err = d.db.Query(c, _SelUserDiscountHistorys, sID, eID, discountID); err != nil {
log.Error("SelUserDiscountHistorys d.db.query(sID:%d,eID:%d,discountID:%d) error(%+v)", sID, eID, discountID, err)
return
}
defer rows.Close()
for rows.Next() {
r := new(model.VipUserDiscountHistory)
if err = rows.Scan(&r.Mid, &r.DiscountID); err != nil {
log.Error("SelUserDiscountHistorys rows.scan() error(%v)", err)
res = nil
return
}
res = append(res, r)
}
return
}
//SelOldUserInfoMaxID sel old userinfo maxID
func (d *Dao) SelOldUserInfoMaxID(c context.Context) (maxID int, err error) {
var row = d.oldDb.QueryRow(c, _selUserInfoMaxID)
if err = row.Scan(&maxID); err != nil {
err = errors.WithStack(err)
d.errProm.Incr("db_scan")
return
}
return
}
// SelUserInfoMaxID select userinfo maxID.
func (d *Dao) SelUserInfoMaxID(c context.Context) (maxID int, err error) {
var row = d.db.QueryRow(c, _selUserInfoMaxID)
if err = row.Scan(&maxID); err != nil {
err = errors.WithStack(err)
d.errProm.Incr("db_scan")
return
}
return
}
//SelUserInfos sel user infos
func (d *Dao) SelUserInfos(c context.Context, sID, eID int) (res []*model.VipUserInfo, err error) {
var rows *sql.Rows
if rows, err = d.db.Query(c, _SelVipUserInfos, sID, eID); err != nil {
log.Error("SelUserDiscountHistorys d.db.query(sID:%v,eID:%v) error(%v)", sID, eID, err)
return
}
for rows.Next() {
r := new(model.VipUserInfo)
if err = rows.Scan(&r.Mid, &r.Type, &r.PayType, &r.Status, &r.StartTime, &r.RecentTime, &r.OverdueTime, &r.AnnualVipOverdueTime); err != nil {
log.Error("SelUserDiscountHistorys rows.scan() error(%v)", err)
res = nil
return
}
res = append(res, r)
}
return
}
//SelVipList sel vipuserinfo list
func (d *Dao) SelVipList(c context.Context, id, endID int, ot string) (res []*model.VipUserInfo, err error) {
var rows *sql.Rows
if rows, err = d.oldDb.Query(c, _SelVipList, id, endID, ot); err != nil {
log.Error("SelVipList db.query(id:%v,ot:%v,endID:%v) error(%v)", id, ot, endID, err)
return
}
defer rows.Close()
for rows.Next() {
r := new(model.VipUserInfo)
if err = rows.Scan(&r.ID, &r.Mid, &r.Type, &r.Status, &r.OverdueTime, &r.AnnualVipOverdueTime, &r.PayType, &r.PayChannelID); err != nil {
log.Error("row.Scan() error(%v)", err)
res = nil
return
}
res = append(res, r)
}
return
}
//SelVipUsers .
func (d *Dao) SelVipUsers(c context.Context, id, endID int, startTime, endTime time.Time) (res []*model.VipUserInfo, err error) {
var rows *sql.Rows
if rows, err = d.db.Query(c, _selVipUsersSQL, id, endID, startTime, endTime); err != nil {
log.Error("SelVipList db.query(id:%v,endID:%v,st:%v,et:%v) error(%v)", id, endID, startTime, endTime, err)
return
}
defer rows.Close()
for rows.Next() {
r := new(model.VipUserInfo)
if err = rows.Scan(&r.ID, &r.Mid, &r.Type, &r.Status, &r.OverdueTime, &r.AnnualVipOverdueTime); err != nil {
log.Error("row.Scan() error(%v)", err)
res = nil
return
}
res = append(res, r)
}
return
}
//SelVipUserInfos sel vipuser info datas
func (d *Dao) SelVipUserInfos(c context.Context, id, endID int, startTime, endTime time.Time, status int) (res []int64, err error) {
var rows *sql.Rows
if rows, err = d.db.Query(c, _selVipUserInfoSQL, id, endID, status, startTime.Time().Format("2006-01-02"), endTime.Time().Format("2006-01-02")); err != nil {
log.Error("SelVipList db.query(id:%v,endID:%v,st:%v,et:%v) error(%v)", id, endID, startTime, endTime, err)
return
}
defer rows.Close()
for rows.Next() {
var r int64
if err = rows.Scan(&r); err != nil {
log.Error("row.Scan() error(%v)", err)
res = nil
return
}
res = append(res, r)
}
return
}
//OldVipInfo get old user by mid.
func (d *Dao) OldVipInfo(c context.Context, mid int64) (r *model.VipUserInfoOld, err error) {
var row = d.oldDb.QueryRow(c, _selOldVipUserInfo, mid)
r = new(model.VipUserInfoOld)
if err = row.Scan(&r.Mid, &r.Type, &r.IsAutoRenew, &r.AutoRenewed, &r.Status, &r.RecentTime, &r.StartTime, &r.OverdueTime,
&r.AnnualVipOverdueTime, &r.IosOverdueTime, &r.Ver, &r.PayChannelID); err != nil {
if err == sql.ErrNoRows {
r = nil
err = nil
} else {
err = errors.WithStack(err)
d.errProm.Incr("row_scan_db")
}
}
return
}
// SelEffectiveScopeVipList get vip list by id scope.
func (d *Dao) SelEffectiveScopeVipList(c context.Context, id, endID int) (res []*model.VipInfoDB, err error) {
var rows *sql.Rows
if rows, err = d.db.Query(c, _SelEffectiveScopeVipList, id, endID); err != nil {
err = errors.WithStack(err)
return
}
defer rows.Close()
for rows.Next() {
r := new(model.VipInfoDB)
if err = rows.Scan(&r.ID, &r.Mid, &r.Ver, &r.Type, &r.PayType, &r.PayChannelID, &r.Status, &r.StartTime, &r.RecentTime, &r.OverdueTime, &r.AnnualVipOverdueTime,
&r.IosOverdueTime, &r.Ctime); err != nil {
err = errors.WithStack(err)
res = nil
return
}
res = append(res, r)
}
err = rows.Err()
return
}
// SelVipByIds select vip by ids .
func (d *Dao) SelVipByIds(c context.Context, ids []int64) (res map[int64]*model.VipUserInfo, err error) {
var (
rows *sql.Rows
idStr = xstr.JoinInts(ids)
)
res = make(map[int64]*model.VipUserInfo, len(ids))
if rows, err = d.db.Query(c, fmt.Sprintf(_selVipByMidsSQL, idStr)); err != nil {
err = errors.WithStack(err)
return
}
defer rows.Close()
for rows.Next() {
r := new(model.VipUserInfo)
if err = rows.Scan(&r.ID, &r.Mid, &r.Type, &r.Status, &r.RecentTime, &r.StartTime, &r.OverdueTime, &r.AnnualVipOverdueTime, &r.PayType, &r.PayChannelID, &r.IosOverdueTime, &r.Ctime, &r.Mtime, &r.Ver); err != nil {
err = errors.WithStack(err)
res = nil
return
}
res[r.Mid] = r
}
return
}
//SelOldUserInfoMaps sel old user info map.
func (d *Dao) SelOldUserInfoMaps(c context.Context, sID, eID int) (res map[int64]*model.VipUserInfoOld, err error) {
var (
rows *sql.Rows
)
res = make(map[int64]*model.VipUserInfoOld, eID-sID)
if rows, err = d.oldDb.Query(c, _SelOldVipUserInfos, sID, eID); err != nil {
err = errors.WithStack(err)
return
}
for rows.Next() {
r := new(model.VipUserInfoOld)
if err = rows.Scan(&r.Mid, &r.Type, &r.IsAutoRenew, &r.AutoRenewed, &r.Status, &r.RecentTime, &r.StartTime, &r.OverdueTime, &r.AnnualVipOverdueTime, &r.Ver, &r.IosOverdueTime, &r.PayChannelID, &r.Ctime, &r.Mtime); err != nil {
err = errors.WithStack(err)
res = nil
return
}
res[r.Mid] = r
}
return
}

View File

@ -0,0 +1,408 @@
package dao
import (
"context"
"go-common/app/job/main/vip/model"
xtime "go-common/library/time"
"testing"
"time"
"github.com/smartystreets/goconvey/convey"
)
func TestDaoAddChangeHistoryBatch(t *testing.T) {
convey.Convey("AddChangeHistoryBatch", t, func(ctx convey.C) {
var (
res = []*model.VipChangeHistory{}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.AddChangeHistoryBatch(res)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestDaoSelChangeHistory(t *testing.T) {
convey.Convey("SelChangeHistory", t, func(ctx convey.C) {
var (
c = context.Background()
startID = int64(0)
endID = int64(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
_, err := d.SelChangeHistory(c, startID, endID)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestDaoSelOldChangeHistory(t *testing.T) {
convey.Convey("SelOldChangeHistory", t, func(ctx convey.C) {
var (
c = context.Background()
startID = int64(0)
endID = int64(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
_, err := d.SelOldChangeHistory(c, startID, endID)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestDaoSelOldChangeHistoryMaxID(t *testing.T) {
convey.Convey("SelOldChangeHistoryMaxID", t, func(ctx convey.C) {
var (
c = context.Background()
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
_, err := d.SelOldChangeHistoryMaxID(c)
ctx.Convey("Then err should be nil.id should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestDaoSelChangeHistoryMaxID(t *testing.T) {
convey.Convey("SelChangeHistoryMaxID", t, func(ctx convey.C) {
var (
c = context.Background()
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
_, err := d.SelChangeHistoryMaxID(c)
ctx.Convey("Then err should be nil.id should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestDaoVipStatus(t *testing.T) {
convey.Convey("VipStatus", t, func(ctx convey.C) {
var (
c = context.Background()
mid = int64(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
_, err := d.VipStatus(c, mid)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestDaoSelMaxID(t *testing.T) {
convey.Convey("SelMaxID", t, func(ctx convey.C) {
var (
c = context.Background()
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
_, err := d.SelMaxID(c)
ctx.Convey("Then err should be nil.mID should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestDaoUpdateVipUserInfo(t *testing.T) {
convey.Convey("UpdateVipUserInfo", t, func(ctx convey.C) {
var (
r = &model.VipUserInfo{}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
tx, err := d.StartTx(context.Background())
ctx.So(err, convey.ShouldBeNil)
ctx.So(tx, convey.ShouldNotBeNil)
_, err = d.UpdateVipUserInfo(tx, r)
ctx.Convey("Then err should be nil.a should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestDaoUpdateVipUser(t *testing.T) {
convey.Convey("UpdateVipUser", t, func(ctx convey.C) {
var (
c = context.Background()
mid = int64(0)
status = int8(0)
vipType = int8(0)
payType = int8(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
_, err := d.UpdateVipUser(c, mid, status, vipType, payType)
ctx.Convey("Then err should be nil.eff should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestDaoDupUserDiscountHistory(t *testing.T) {
convey.Convey("DupUserDiscountHistory", t, func(ctx convey.C) {
var (
r = &model.VipUserDiscountHistory{}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
tx, err := d.StartTx(context.Background())
ctx.So(err, convey.ShouldBeNil)
ctx.So(tx, convey.ShouldNotBeNil)
_, err = d.DupUserDiscountHistory(tx, r)
ctx.Convey("Then err should be nil.a should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestDaoAddUserInfo(t *testing.T) {
convey.Convey("AddUserInfo", t, func(ctx convey.C) {
var (
r = &model.VipUserInfo{}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
tx, err := d.StartTx(context.Background())
ctx.So(err, convey.ShouldBeNil)
ctx.So(tx, convey.ShouldNotBeNil)
_, err = d.AddUserInfo(tx, r)
ctx.Convey("Then err should be nil.eff should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestDaoSelVipUserInfo(t *testing.T) {
convey.Convey("SelVipUserInfo", t, func(ctx convey.C) {
var (
c = context.Background()
mid = int64(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
_, err := d.SelVipUserInfo(c, mid)
ctx.Convey("Then err should be nil.r should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestDaoUpdateUserInfo(t *testing.T) {
convey.Convey("UpdateUserInfo", t, func(ctx convey.C) {
var (
r = &model.VipUserInfo{}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
tx, err := d.StartTx(context.Background())
ctx.So(err, convey.ShouldBeNil)
ctx.So(tx, convey.ShouldNotBeNil)
_, err = d.UpdateUserInfo(tx, r)
ctx.Convey("Then err should be nil.eff should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestDaoSelUserDiscountMaxID(t *testing.T) {
convey.Convey("SelUserDiscountMaxID", t, func(ctx convey.C) {
var (
c = context.Background()
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
_, err := d.SelUserDiscountMaxID(c)
ctx.Convey("Then err should be nil.maxID should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestDaoSelUserDiscountHistorys(t *testing.T) {
convey.Convey("SelUserDiscountHistorys", t, func(ctx convey.C) {
var (
c = context.Background()
sID = int(0)
eID = int(0)
discountID = int(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
_, err := d.SelUserDiscountHistorys(c, sID, eID, discountID)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestDaoSelOldUserInfoMaxID(t *testing.T) {
convey.Convey("SelOldUserInfoMaxID", t, func(ctx convey.C) {
var (
c = context.Background()
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
_, err := d.SelOldUserInfoMaxID(c)
ctx.Convey("Then err should be nil.maxID should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestDaoSelUserInfoMaxID(t *testing.T) {
convey.Convey("SelUserInfoMaxID", t, func(ctx convey.C) {
var (
c = context.Background()
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
_, err := d.SelUserInfoMaxID(c)
ctx.Convey("Then err should be nil.maxID should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestDaoSelUserInfos(t *testing.T) {
convey.Convey("SelUserInfos", t, func(ctx convey.C) {
var (
c = context.Background()
sID = int(0)
eID = int(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
_, err := d.SelUserInfos(c, sID, eID)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestDaoSelVipList(t *testing.T) {
convey.Convey("SelVipList", t, func(ctx convey.C) {
var (
c = context.Background()
id = int(0)
endID = int(0)
ot = ""
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
_, err := d.SelVipList(c, id, endID, ot)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestDaoSelVipUsers(t *testing.T) {
convey.Convey("SelVipUsers", t, func(ctx convey.C) {
var (
c = context.Background()
id = int(0)
endID = int(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
_, err := d.SelVipUsers(c, id, endID, xtime.Time(time.Now().Unix()), xtime.Time(time.Now().Unix()))
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestDaoSelVipUserInfos(t *testing.T) {
convey.Convey("SelVipUserInfos", t, func(ctx convey.C) {
var (
c = context.Background()
id = int(0)
endID = int(0)
status = int(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
_, err := d.SelVipUserInfos(c, id, endID, xtime.Time(time.Now().Unix()), xtime.Time(time.Now().Unix()), status)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestDaoOldVipInfo(t *testing.T) {
convey.Convey("OldVipInfo", t, func(ctx convey.C) {
var (
c = context.Background()
mid = int64(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
_, err := d.OldVipInfo(c, mid)
ctx.Convey("Then err should be nil.r should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestDaoSelEffectiveScopeVipList(t *testing.T) {
convey.Convey("SelEffectiveScopeVipList", t, func(ctx convey.C) {
var (
c = context.Background()
id = int(0)
endID = int(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
_, err := d.SelEffectiveScopeVipList(c, id, endID)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestDaoSelOldUserInfoMaps(t *testing.T) {
convey.Convey("SelOldUserInfoMaps", t, func(ctx convey.C) {
var (
c = context.Background()
sID = int(0)
eID = int(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
_, err := d.SelOldUserInfoMaps(c, sID, eID)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func Test_SelChangeHistoryMaps(t *testing.T) {
convey.Convey("SelChangeHistoryMaps", t, func(ctx convey.C) {
_, err := d.SelChangeHistoryMaps(context.Background(), []int64{7593623})
ctx.So(err, convey.ShouldBeNil)
})
}
func Test_SelOldChangeHistoryMaps(t *testing.T) {
convey.Convey("SelOldChangeHistoryMaps", t, func(ctx convey.C) {
_, err := d.SelOldChangeHistoryMaps(context.Background(), []int64{7593623})
ctx.So(err, convey.ShouldBeNil)
})
}
func Test_SelVipByIds(t *testing.T) {
convey.Convey("SelVipByIds", t, func(ctx convey.C) {
_, err := d.SelVipByIds(context.Background(), []int64{7593623})
ctx.So(err, convey.ShouldBeNil)
})
}

View File

@ -0,0 +1,35 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = ["http.go"],
importpath = "go-common/app/job/main/vip/http",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/job/main/vip/conf:go_default_library",
"//app/job/main/vip/model:go_default_library",
"//app/job/main/vip/service:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@ -0,0 +1,181 @@
package http
import (
"go-common/app/job/main/vip/conf"
"go-common/app/job/main/vip/model"
"go-common/app/job/main/vip/service"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
)
var (
s *service.Service
)
// Init init http sever instance.
func Init(c *conf.Config, ss *service.Service) {
// init inner router
engine := bm.DefaultServer(c.BM)
innerRouter(engine)
// init inner server
if err := engine.Start(); err != nil {
log.Error("engine start error(%v)", err)
panic(err)
}
s = ss
}
// innerRouter init inner router.
func innerRouter(r *bm.Engine) {
r.Ping(ping)
r.GET("/scanUserInfo", checkscanUserInfo)
r.GET("/handlerOrder", handlerOrder)
r.GET("/handlerChangeHistory", handlerVipChangeHistory)
r.GET("/handlerVipSendBcoin", handlerVipSendBcoin)
r.GET("/sendBcoinJob", sendBcoinJob)
r.GET("/hadExpiredJob", hadExpireJob)
r.GET("/willExpiredJob", willExpireJob)
r.GET("/sendMessageJob", sendMessageJob)
r.GET("/autoRenewJob", autoRenewJob)
r.GET("/syncvipdata", syncVipInfoData)
r.GET("/clearcache", clearUserCache)
r.GET("/scansalarylog", scanSalaryLog)
r.GET("/checkuserdata", checkUserData)
r.GET("/checkBcoinSalary", checkBcoinSalary)
r.GET("/checkChangeHistory", checkHistory)
r.GET("/sync/all/user", syncAllUser)
r.GET("/frozen", frozen)
}
func syncAllUser(c *bm.Context) {
log.Info("syncAllUser start........................................")
s.SyncAllUser(c)
log.Info("syncAllUser end........................................")
}
func checkHistory(c *bm.Context) {
log.Info("check history info start........................................")
mids, err := s.CheckChangeHistory(c)
log.Info("check history info end..............error mids(%+v) error(%+v)", mids, err)
c.JSON(mids, err)
}
func checkBcoinSalary(c *bm.Context) {
log.Info("check bcoin info start........................................")
mids, err := s.CheckBcoinData(c)
log.Info("check bcoin info end..............error mids(%+v) error(%+v)", mids, err)
c.JSON(mids, err)
}
func autoRenewJob(c *bm.Context) {
//s.AutoRenewJob()
}
func sendBcoinJob(c *bm.Context) {
//s.SendBcoinJob()
}
func hadExpireJob(c *bm.Context) {
//s.HadExpiredMsgJob()
}
func willExpireJob(c *bm.Context) {
//s.WillExpiredMsgJob()
}
func sendMessageJob(c *bm.Context) {
//s.SendMessageJob()
}
// ping check server ok.
func ping(c *bm.Context) {}
func handlerOrder(c *bm.Context) {
log.Info("handler order start.........................................")
s.HandlerPayOrder()
log.Info("handler order end ............................................")
}
func handlerVipChangeHistory(c *bm.Context) {
log.Info("handler vip change history start ...................... ")
s.HandlerVipChangeHistory()
log.Info("handler vip change history end ...................... ")
}
func handlerVipSendBcoin(c *bm.Context) {
log.Info(" handler vip send bcoin start ..............")
s.HandlerBcoin()
log.Info("handler vip send bcoin end ...............")
}
func checkscanUserInfo(c *bm.Context) {
log.Info("scan user info start ..........................")
s.ScanUserInfo(c)
log.Info("scan user info end ...........................")
}
func syncVipInfoData(c *bm.Context) {
var err error
arg := new(struct {
Mid int64 `form:"mid" validate:"required"`
})
if err = c.Bind(arg); err != nil {
log.Error("c.Bind err(%+v)", err)
return
}
if err = s.SyncUserInfoByMid(c, arg.Mid); err != nil {
c.JSON(nil, err)
return
}
c.JSON(nil, nil)
}
func clearUserCache(c *bm.Context) {
var err error
arg := new(struct {
Mid int64 `form:"mid" validate:"required"`
})
if err = c.Bind(arg); err != nil {
log.Error("c.Bind err(%+v)", err)
return
}
s.ClearUserCache(arg.Mid)
c.JSON(nil, nil)
}
func scanSalaryLog(c *bm.Context) {
log.Info("scan salary log start ..........................")
var err error
if err = s.ScanSalaryLog(c); err != nil {
log.Error("scan salary log err(%+v)", err)
c.JSON(nil, err)
return
}
log.Info("scan salary log end ...........................")
c.JSON(nil, nil)
}
func checkUserData(c *bm.Context) {
log.Info("check vip_user_info data start ..........................")
var (
err error
diffs map[int64]string
)
if diffs, err = s.CheckUserData(c); err != nil {
c.JSON(diffs, err)
return
}
log.Info("check vip_user_info data end diffs(%v) size(%d)...........................", diffs, len(diffs))
c.JSON(diffs, err)
}
func frozen(c *bm.Context) {
var err error
arg := new(model.LoginLog)
if err = c.Bind(arg); err != nil {
log.Error("c.Bind err(%+v)", err)
return
}
c.JSON(nil, s.Frozen(c, arg))
}

View File

@ -0,0 +1,68 @@
load(
"@io_bazel_rules_go//proto:def.bzl",
"go_proto_library",
)
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = [
"associate.go",
"coupon.go",
"databus.go",
"handler.go",
"http.go",
"model.go",
"oldVip.go",
"query.go",
"vip.go",
],
embed = [":model_go_proto"],
importpath = "go-common/app/job/main/vip/model",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//library/time:go_default_library",
"@com_github_gogo_protobuf//gogoproto:go_default_library",
"@com_github_golang_protobuf//proto:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)
proto_library(
name = "model_proto",
srcs = ["vip.proto"],
tags = ["automanaged"],
deps = ["@gogo_special_proto//github.com/gogo/protobuf/gogoproto"],
)
go_proto_library(
name = "model_go_proto",
compilers = ["@io_bazel_rules_go//proto:gogofast_proto"],
importpath = "go-common/app/job/main/vip/model",
proto = ":model_proto",
tags = ["automanaged"],
deps = [
"//library/time:go_default_library",
"@com_github_gogo_protobuf//gogoproto:go_default_library",
],
)

View File

@ -0,0 +1,16 @@
package model
import "go-common/library/time"
// VipOrderActivityRecord vip record.
type VipOrderActivityRecord struct {
ID int64
Mid int64
OrderNo string
ProductID string
Months int32
PanelType string
AssociateState int32
Ctime time.Time
Mtime time.Time
}

View File

@ -0,0 +1,23 @@
package model
// VideoCouponSalaryLog videl coupon salary log.
type VideoCouponSalaryLog struct {
ID int64 `json:"id"`
Mid int64 `json:"mid"`
CouponCount int64 `json:"coupon_count"`
CouponType int8 `json:"coupon_type"`
State int8 `json:"state"`
Type int8 `json:"type"`
ExpireTime int64 `json:"expire_time"`
StartTime int64 `json:"start_time"`
Ver int64 `json:"ver"`
}
// OldSalaryLog def.
type OldSalaryLog struct {
ID int64 `json:"id"`
Mid int64 `json:"mid"`
CouponCount int64 `json:"coupon_count"`
State int8 `json:"state"`
Type int8 `json:"type"`
}

View File

@ -0,0 +1,155 @@
package model
import (
"encoding/json"
"go-common/library/time"
)
//VipUserInfoMsg get databus vip_user_info msg
type VipUserInfoMsg struct {
ID int64 `json:"id"`
Mid int64 `json:"mid"`
Type int8 `json:"vip_type"`
Status int8 `json:"vip_status"`
StartTime string `json:"vip_start_time"`
OverdueTime string `json:"vip_overdue_time"`
AnnualVipOverdueTime string `json:"annual_vip_overdue_time"`
RecentTime string `json:"vip_recent_time"`
Wander int8 `json:"wander"`
AutoRenewed int8 `json:"auto_renewed"`
IsAutoRenew int8 `json:"is_auto_renew"`
Ver int64 `json:"ver"`
PayChannelID int64 `json:"pay_channel_id"`
IosOverdueTime string `json:"ios_overdue_time"`
}
//VipUserInfoNewMsg .
type VipUserInfoNewMsg struct {
ID int64 `json:"id"`
Mid int64 `json:"mid"`
Ver int64 `json:"ver"`
VipType int8 `json:"vip_type"`
VipPayType int8 `json:"vip_pay_type"`
PayChannelID int64 `json:"pay_channel_id"`
VipStatus int8 `json:"vip_status"`
VipStartTime string `json:"vip_start_time"`
VipRecentTime string `json:"vip_recent_time"`
VipOverdueTime string `json:"vip_overdue_time"`
AnnualVipOverdueTime string `json:"annual_vip_overdue_time"`
IosOverdueTime string `json:"ios_overdue_time"`
}
//VipPointChangeHistoryMsg get databus json data
type VipPointChangeHistoryMsg struct {
ID int `json:"id"`
Mid int `json:"mid"`
Point int `json:"point"`
OrderID string `json:"order_id"`
ChangeType int `json:"change_type"`
ChangeTime string `json:"change_time"`
RelationID string `json:"relation_id"`
PointBalance int `json:"point_balance"`
Remark string `json:"remark"`
Operator string `json:"operator"`
}
//VipPayOrderOldMsg get databus json data
type VipPayOrderOldMsg struct {
ID int64 `json:"id"`
OrderNo string `json:"order_no"`
AppID int64 `json:"app_id"`
Platform int8 `json:"platform"`
OrderType int8 `json:"order_type"`
Mid int64 `json:"mid"`
Bmid int64 `json:"bmid"`
BuyMonths int16 `json:"buy_months"`
Money float64 `json:"money"`
RechargeBp float64 `json:"recharge_bp"`
Status int8 `json:"status"`
PayType int8 `json:"pay_type"`
PaymentTime string `json:"payment_time"`
Ver int64 `json:"ver"`
AppSubID string `json:"app_sub_id"`
CouponMoney float64 `json:"coupon_money"`
Ctime string `json:"ctime"`
Mtime string `json:"mtime"`
}
//VipPayOrderNewMsg .
type VipPayOrderNewMsg struct {
ID int64 `json:"id"`
OrderNo string `json:"order_no"`
AppID int64 `json:"app_id"`
Platform int8 `json:"platform"`
OrderType int8 `json:"order_type"`
Mid int64 `json:"mid"`
ToMid int64 `json:"to_mid"`
BuyMonths int16 `json:"buy_months"`
Money float64 `json:"money"`
RechargeBp float64 `json:"recharge_bp"`
ThirdTradeNo string `json:"third_trade_no"`
Status int8 `json:"status"`
PayType string `json:"pay_type"`
PaymentTime string `json:"payment_time"`
Ver int64 `json:"ver"`
AppSubID string `json:"app_sub_id"`
CouponMoney float64 `json:"coupon_money"`
}
//VipRechargeOrderMsg get databus json data
type VipRechargeOrderMsg struct {
ID int64 `json:"id"`
AppID int64 `json:"app_id"`
PayMid int64 `json:"pay_mid"`
OrderNo string `json:"order_no"`
RechargeBp float64 `json:"recharge_bp"`
ThirdTradeNo string `json:"third_trade_no"`
PayOrderNo string `json:"pay_order_no"`
Status int8 `json:"status"`
Ver int64 `json:"ver"`
Bmid int64 `json:"bmid"`
}
//VipChangeHistoryMsg vip change history msg
type VipChangeHistoryMsg struct {
Mid int64 `json:"mid"`
ChangeType int8 `json:"change_type"`
ChangeTime string `json:"change_time"`
Days int32 `json:"days"`
Month int16 `json:"month"`
OperatorID string `json:"operator_id"`
RelationID string `json:"relation_id"`
BatchID int64 `json:"batch_id"`
Remark string `json:"remark"`
BatchCodeID int64 `json:"batch_code_id"`
}
//VipBcoinSalaryMsg .
type VipBcoinSalaryMsg struct {
ID int64 `json:"id"`
Mid int64 `json:"mid"`
Status int8 `json:"status"`
GiveNowStatus int8 `json:"give_now_status"`
Payday string `json:"month"`
Amount int32 `json:"amount"`
Memo string `json:"memo"`
}
//Message databus message
type Message struct {
Action string `json:"action"`
Table string `json:"table"`
New json.RawMessage `json:"new"`
Old json.RawMessage `json:"old"`
}
// LoginLog login log.
type LoginLog struct {
Mid int64 `json:"mid,omitempty" form:"mid"`
IP uint32 `json:"loginip" form:"ip"`
Location string `json:"location"`
LocationID int64 `json:"location_id,omitempty"`
Time time.Time `json:"timestamp,omitempty"`
Type int8 `json:"type,omitempty"`
}

View File

@ -0,0 +1,37 @@
package model
import "go-common/library/time"
//HandlerVip vip handler
type HandlerVip struct {
Days int32
Months int16
Mid int64
Type int8
}
//AppCache appCache
type AppCache struct {
AppID int64 `json:"appID"`
Mid int64 `json:"mid"`
}
//BcoinSendInfo .
type BcoinSendInfo struct {
Amount int32 `json:"amount"`
DueDate time.Time `json:"dueDate"`
DayOfMonth int `json:"dayOfMonth"`
}
//VipBuyResq .
type VipBuyResq struct {
Mid int64 `json:"mid"`
CouponID string `json:"coupon_id"`
OrderNo string `json:"order_no"`
}
//VipPushResq .
type VipPushResq struct {
Code int64 `json:"code"`
Data int64 `json:"data"`
}

View File

@ -0,0 +1,8 @@
package model
// CommonResq response params.
type CommonResq struct {
Code int64 `json:"code"`
TS int64 `json:"ts"`
Message string `json:"message"`
}

View File

@ -0,0 +1,102 @@
package model
//Eunm vip enum value
const (
//ChangeType
ChangeTypePointExhchange = 1 // 积分兑换
ChangeTypeRechange = 2 //充值开通
ChangeTypeSystem = 3 // 系统发放
ChangeTypeActiveGive = 4 //活动赠送
ChangeTypeRepeatDeduction = 5 //重复领取扣除
VipDaysMonth = 31
VipDaysYear = 366
NotVip = 0 //非大会员
Vip = 1 //月度大会员
AnnualVip = 2 //年度会员
VipStatusOverTime = 0 //过期
VipStatusNotOverTime = 1 //未过期
VipStatusFrozen = 2 //冻结
VipStatusBan = 3 //封禁
VipAppUser = 1 //大会员对接业务方user缓存
VipAppPoint = 2 //大会员对接业务方积分缓存
VipChangeFrozen = -1 //冻结
VipChangeUnFrozen = 0 //解冻
VipChangeOpen = 1 //开通
VipChangeModify = 2 //变更
VipBusinessStatusOpen = 0 //有效
VipBusinessStatusClose = 1 //无效
VipUserFirstDiscount = 1
AnnualVipBcoinDay = "annual_vip_bcoin_day" //年费VIPB券发放每月第几天
AnnualVipBcoinCouponMoney = "annual_vip_bcoin_coupon_money" //年费VIP返回B券金额
AnnualVipBcoinCouponActivityID = "annual_vip_bcoin_coupon_activity_id" //年费VIP返B券活动ID
HadSalaryState = 1 // 已发放
NormalVipSalaryType = 1
AnnualVipSalaryType = 2
VipSupplyType = 3
TimingSalaryType = 4
SalaryVipOrigin = 1
TimeFormatSec = "2006-01-02 15:04:05"
DayOfHour = 24
IsAutoRenew = 1
IAPChannelID = 100
MsgSystemNotify = 4
MsgCouponSalaryMc = "10_99_2"
CouponSalaryTitle = `观影劵到账通知`
CouponSalaryMsg = `大会员专享观影券已到账,#{点击查看>>}{"https://big.bilibili.com/mobile/userticket"}`
CouponToAnnualSalaryMsg = `升级年度大会员赠送观影券%d张已到账#{点击查看>>}{"https://big.bilibili.com/mobile/userticket"}`
CouponCartoonSalaryTitle = `漫画阅读劵到账通知`
CouponCartoonSalaryMsg = `大会员漫画阅读券已到账 #{点击查看>>}{"https://big.bilibili.com/mobile/userticket"}`
CouponCartoonToAnnualSalaryMsg = `升级年度大会员赠送漫画阅读券%d张已到账#{点击查看>>}{"https://big.bilibili.com/mobile/userticket"}`
)
// dicount type
const (
DiscountNotUse = iota
DiscountUsed
)
// coupon salary type
const (
CouponSalaryTiming int8 = iota
CouponSalaryAtonce
)
// coupon type
const (
SalaryCouponType int8 = iota + 1
SalaryCartoonCouponType
)
//pay order type
const (
Normal = iota
AutoRenew
IAPAutoRenew
)
//pay order status
const (
PAYING = iota + 1
SUCCESS
FAILED
SIGN
UNSIGN
)

View File

@ -0,0 +1,91 @@
package model
import "go-common/library/time"
//VipUserInfoOld vip_user_info table
type VipUserInfoOld struct {
ID int64 `json:"id"`
Mid int64 `json:"mid"`
Type int8 `json:"vipType"`
Status int8 `json:"vipStatus"`
StartTime time.Time `json:"vipStartTime"`
OverdueTime time.Time `json:"vipOverdueTime"`
AnnualVipOverdueTime time.Time `json:"annualVipOverdueTime"`
RecentTime time.Time `json:"vip_recent_time"`
Wander int8 `json:"wander"`
AccessStatus int8 `json:"accessStatus"`
AutoRenewed int8 `json:"auto_renewed"`
IsAutoRenew int8 `json:"is_auto_renew"`
IosOverdueTime time.Time `json:"ios_overdue_time"`
PayChannelID int64 `json:"pay_channel_id"`
Ver int64 `json:"ver"`
Ctime time.Time `json:"ctime"`
Mtime time.Time `json:"mtime"`
}
// ToNew convert old model to new.
func (v *VipUserInfoOld) ToNew() (n *VipUserInfo) {
return &VipUserInfo{
Mid: v.Mid,
Type: v.Type,
PayType: v.IsAutoRenew,
PayChannelID: v.PayChannelID,
Status: v.Status,
StartTime: v.StartTime,
RecentTime: v.RecentTime,
OverdueTime: v.OverdueTime,
AnnualVipOverdueTime: v.AnnualVipOverdueTime,
Ctime: v.Ctime,
Mtime: v.Mtime,
IosOverdueTime: v.IosOverdueTime,
Ver: v.Ver,
}
}
//VipPayOrderOld vip pay order table
type VipPayOrderOld struct {
ID int64 `json:"id"`
OrderNo string `json:"orderNo"`
AppID int64 `json:"appId"`
Platform int8 `json:"platform"`
OrderType int8 `json:"orderType"`
Mid int64 `json:"mid"`
Bmid int64 `json:"bmid"`
BuyMonths int16 `json:"buyMonths"`
Money float64 `json:"money"`
Status int8 `json:"status"`
PayType int8 `json:"payType"`
PaymentTime time.Time `json:"paymentTime"`
Ver int64 `json:"ver"`
AppSubID string `json:"appSubId"`
CouponMoney float64 `json:"coupon_money"`
}
//VipRechargeOrder vip recharge order table
type VipRechargeOrder struct {
ID int `json:"id"`
AppID int `json:"appId"`
PayMid int `json:"payMid"`
OrderNo string `json:"orderNo"`
RechargeBp float64 `json:"rechargeBp"`
ThirdTradeNo string `json:"thirdTradeNo"`
PayOrderNo string `json:"payOrderNo"`
Status int `json:"status"`
Ver int `json:"ver"`
Bmid int `json:"bmid"`
}
//VipChangeHistory .
type VipChangeHistory struct {
ID int64 `json:"id"`
Mid int64 `json:"mid"`
ChangeType int8 `json:"change_type"`
ChangeTime time.Time `json:"change_time"`
Month int16 `json:"month"`
Days int32 `json:"days"`
OperatorID string `json:"operator_id"`
RelationID string `json:"relation_id"`
BatchCodeID int64 `json:"batch_code_id"`
BatchID int64 `json:"batch_id"`
Remark string `json:"remark"`
}

View File

@ -0,0 +1,13 @@
package model
import "go-common/library/time"
//QueryBcoinSalary .
type QueryBcoinSalary struct {
StartID int64 `json:"start_id"`
EndID int64 `json:"end_id"`
StartMonth time.Time `json:"start_month"`
EndMonth time.Time `json:"end_month"`
GiveNowStatus int8 `json:"give_now_status"`
Status int8 `json:"status"`
}

View File

@ -0,0 +1,185 @@
package model
import (
"go-common/library/time"
)
//VipAppInfo app info
type VipAppInfo struct {
ID int64 `json:"id"`
Type int8 `json:"type"`
Name string `json:"name"`
PurgeURL string `json:"purgeUrl"`
AppKey string `json:"appKey"`
}
// VipPoint vip_point table
type VipPoint struct {
ID int `json:"id"`
Mid int `json:"mid"`
PointBalance int `json:"point_balance"`
Ver int `json:"ver"`
}
//VipPointChangeHistory vip_point_change_history table
type VipPointChangeHistory struct {
ID int `json:"id"`
Mid int `json:"mid"`
Point int `json:"point"`
OrderID string `json:"orderId"`
ChangeType int `json:"changeType"`
ChangeTime time.Time `json:"changeTime"`
RelationID string `json:"relationId"`
PointBalance int `json:"pointBalance"`
Remark string `json:"remark"`
Operator string `json:"operator"`
}
//VipPayOrderLog vip pay order log table
type VipPayOrderLog struct {
ID int64 `json:"id"`
OrderNo string `json:"orderNo"`
Mid int64 `json:"mid"`
Status int8 `json:"status"`
}
//VipPayOrder VipPayOrder table
type VipPayOrder struct {
ID int64 `json:"id"`
OrderNo string `json:"orderNo"`
AppID int64 `json:"appId"`
Platform int8 `json:"platform"`
OrderType int8 `json:"orderType"`
Mid int64 `json:"mid"`
ToMid int64 `json:"toMid"`
BuyMonths int16 `json:"buyMonths"`
Money float64 `json:"money"`
RechargeBp float64 `json:"rechargeBp"`
Status int8 `json:"status"`
PayType int8 `json:"payType"`
ThirdTradeNo string `json:"thirdTradeNo"`
PaymentTime time.Time `json:"paymentTime"`
Ver int64 `json:"ver"`
AppSubID string `json:"appSubId"`
CouponMoney float64 `json:"coupon_money"`
Ctime time.Time `json:"ctime"`
Mtime time.Time `json:"mtime"`
}
//VipUserInfo vip user info table
type VipUserInfo struct {
ID int64 `json:"id"`
Mid int64 `json:"mid"`
Type int8 `json:"vipType"`
PayType int8 `json:"payType"`
PayChannelID int64 `json:"payChannelId"`
Status int8 `json:"vipStatus"`
Ver int64 `json:"ver"`
OldVer int64 `json:"old_ver"`
StartTime time.Time `json:"vipStartTime"`
RecentTime time.Time `json:"vipRecentTime"`
OverdueTime time.Time `json:"vipOverdueTime"`
AnnualVipOverdueTime time.Time `json:"annualVipOverdueTime"`
AutoRenewed int8 `json:"auto_renewed"`
IosOverdueTime time.Time `json:"ios_overdue_time"`
Ctime time.Time `json:"ctime"`
Mtime time.Time `json:"mtime"`
}
//VipPushData .
type VipPushData struct {
ID int64 `json:"id"`
DisableType int8 `json:"disable_type"`
GroupName string `json:"group_name"`
Title string `json:"title" `
Content string `json:"content"`
PushTotalCount int32 `json:"-"`
PushedCount int32 `json:"-"`
PushProgress string `json:"push_progress"`
ProgressStatus int8 `json:"progress_status"`
Status int8 `json:"status"`
Platform string `json:"platform"`
LinkType int32 `json:"link_type"`
ErrorCode int32 `json:"error_code"`
LinkURL string `json:"link_url"`
ExpiredDayStart int32 `json:"expired_day_start" `
ExpiredDayEnd int64 `json:"expired_day_end" `
EffectStartDate time.Time `json:"effect_start_date" `
EffectEndDate time.Time `json:"effect_end_date" `
PushStartTime string `json:"push_start_time" `
PushEndTime string `json:"push_end_time" `
}
//VipUserDiscountHistory vip user discount history table
type VipUserDiscountHistory struct {
ID int64 `json:"id"`
Mid int64 `json:"mid"`
DiscountID int32 `json:"discountId"`
OrderNo string `json:"orderNo"`
Status int8 `json:"status"`
}
//VipBcoinSalary .
type VipBcoinSalary struct {
ID int64 `json:"id"`
Mid int64 `json:"mid"`
Status int8 `json:"status"`
GiveNowStatus int8 `json:"giveNowStatus"`
Payday time.Time `json:"month"`
Amount int32 `json:"amount"`
Memo string `json:"memo"`
Ctime time.Time `json:"ctime"`
Mtime time.Time `json:"mtime"`
}
//VipInfoDB vip user info db
type VipInfoDB struct {
ID int64 `json:"id"`
Mid int64 `json:"mid"`
Ver int64 `json:"ver"`
Type int8 `json:"vip_type"`
PayType int8 `json:"vip_pay_type"`
PayChannelID int64 `json:"pay_channel_id"`
Status int8 `json:"vip_status"`
StartTime time.Time `json:"vip_start_time"`
RecentTime time.Time `json:"vip_recent_time"`
OverdueTime time.Time `json:"vip_overdue_time"`
AnnualVipOverdueTime time.Time `json:"annual_vip_overdue_time"`
IosOverdueTime time.Time `json:"ios_overdue_time"`
Ctime time.Time `json:"ctime"`
Mtime time.Time `json:"mtime"`
}
//VipConfig .
type VipConfig struct {
ID int64 `json:"id"`
ConfigKey string `json:"config_key"`
Content string `json:"content"`
}
//VipResourceBatchCode .
type VipResourceBatchCode struct {
ID int64 `json:"id"`
BusinessID int64 `json:"business_id"`
PoolID int64 `json:"pool_id"`
Status int8 `json:"status"`
Type int8 `json:"type"`
BatchName string `json:"batch_name"`
Reason string `json:"reason"`
Unit int32 `json:"unit"`
Count int64 `json:"count"`
SurplusCount int64 `json:"surplus_count"`
Price float64 `json:"price"`
StartTime time.Time `json:"start_time"`
EndTime time.Time `json:"end_time"`
}
//VipResourceCode vip resource code
type VipResourceCode struct {
ID int64 `json:"id"`
Bmid int64 `json:"bmid"`
RelationID string `json:"relation_id"`
Code string `json:"code"`
Status int8 `json:"status"`
BatchCodeID int64 `json:"batch_code_id"`
}

View File

@ -0,0 +1,570 @@
// Code generated by protoc-gen-gogo. DO NOT EDIT.
// source: vip.proto
/*
Package model is a generated protocol buffer package.
It is generated from these files:
vip.proto
It has these top-level messages:
VipInfo
*/
package model
import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
import _ "github.com/gogo/protobuf/gogoproto"
import go_common_time "go-common/library/time"
import io "io"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
type VipInfo struct {
Mid int64 `protobuf:"varint,1,opt,name=Mid,proto3" json:"mid"`
VipType int32 `protobuf:"varint,2,opt,name=VipType,proto3" json:"vip_type"`
VipStatus int32 `protobuf:"varint,3,opt,name=VipStatus,proto3" json:"vip_status"`
VipStartTime go_common_time.Time `protobuf:"varint,4,opt,name=VipStartTime,proto3,casttype=go-common/library/time.Time" json:"vip_start_time"`
VipOverdueTime go_common_time.Time `protobuf:"varint,5,opt,name=VipOverdueTime,proto3,casttype=go-common/library/time.Time" json:"vip_overdue_time"`
AnnualVipOverdueTime go_common_time.Time `protobuf:"varint,6,opt,name=AnnualVipOverdueTime,proto3,casttype=go-common/library/time.Time" json:"annual_vip_overdue_time"`
AccessStatus int32 `protobuf:"varint,7,opt,name=AccessStatus,proto3" json:"access_status"`
FrozenDate go_common_time.Time `protobuf:"varint,8,opt,name=FrozenDate,proto3,casttype=go-common/library/time.Time" json:"frozen_date"`
VipStatusWarn string `protobuf:"bytes,9,opt,name=VipStatusWarn,proto3" json:"vip_status_warn"`
VipRecentTime go_common_time.Time `protobuf:"varint,10,opt,name=VipRecentTime,proto3,casttype=go-common/library/time.Time" json:"vip_recent_time"`
}
func (m *VipInfo) Reset() { *m = VipInfo{} }
func (m *VipInfo) String() string { return proto.CompactTextString(m) }
func (*VipInfo) ProtoMessage() {}
func (*VipInfo) Descriptor() ([]byte, []int) { return fileDescriptorVip, []int{0} }
func init() {
proto.RegisterType((*VipInfo)(nil), "model.VipInfo")
}
func (m *VipInfo) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalTo(dAtA)
if err != nil {
return nil, err
}
return dAtA[:n], nil
}
func (m *VipInfo) MarshalTo(dAtA []byte) (int, error) {
var i int
_ = i
var l int
_ = l
if m.Mid != 0 {
dAtA[i] = 0x8
i++
i = encodeVarintVip(dAtA, i, uint64(m.Mid))
}
if m.VipType != 0 {
dAtA[i] = 0x10
i++
i = encodeVarintVip(dAtA, i, uint64(m.VipType))
}
if m.VipStatus != 0 {
dAtA[i] = 0x18
i++
i = encodeVarintVip(dAtA, i, uint64(m.VipStatus))
}
if m.VipStartTime != 0 {
dAtA[i] = 0x20
i++
i = encodeVarintVip(dAtA, i, uint64(m.VipStartTime))
}
if m.VipOverdueTime != 0 {
dAtA[i] = 0x28
i++
i = encodeVarintVip(dAtA, i, uint64(m.VipOverdueTime))
}
if m.AnnualVipOverdueTime != 0 {
dAtA[i] = 0x30
i++
i = encodeVarintVip(dAtA, i, uint64(m.AnnualVipOverdueTime))
}
if m.AccessStatus != 0 {
dAtA[i] = 0x38
i++
i = encodeVarintVip(dAtA, i, uint64(m.AccessStatus))
}
if m.FrozenDate != 0 {
dAtA[i] = 0x40
i++
i = encodeVarintVip(dAtA, i, uint64(m.FrozenDate))
}
if len(m.VipStatusWarn) > 0 {
dAtA[i] = 0x4a
i++
i = encodeVarintVip(dAtA, i, uint64(len(m.VipStatusWarn)))
i += copy(dAtA[i:], m.VipStatusWarn)
}
if m.VipRecentTime != 0 {
dAtA[i] = 0x50
i++
i = encodeVarintVip(dAtA, i, uint64(m.VipRecentTime))
}
return i, nil
}
func encodeVarintVip(dAtA []byte, offset int, v uint64) int {
for v >= 1<<7 {
dAtA[offset] = uint8(v&0x7f | 0x80)
v >>= 7
offset++
}
dAtA[offset] = uint8(v)
return offset + 1
}
func (m *VipInfo) Size() (n int) {
var l int
_ = l
if m.Mid != 0 {
n += 1 + sovVip(uint64(m.Mid))
}
if m.VipType != 0 {
n += 1 + sovVip(uint64(m.VipType))
}
if m.VipStatus != 0 {
n += 1 + sovVip(uint64(m.VipStatus))
}
if m.VipStartTime != 0 {
n += 1 + sovVip(uint64(m.VipStartTime))
}
if m.VipOverdueTime != 0 {
n += 1 + sovVip(uint64(m.VipOverdueTime))
}
if m.AnnualVipOverdueTime != 0 {
n += 1 + sovVip(uint64(m.AnnualVipOverdueTime))
}
if m.AccessStatus != 0 {
n += 1 + sovVip(uint64(m.AccessStatus))
}
if m.FrozenDate != 0 {
n += 1 + sovVip(uint64(m.FrozenDate))
}
l = len(m.VipStatusWarn)
if l > 0 {
n += 1 + l + sovVip(uint64(l))
}
if m.VipRecentTime != 0 {
n += 1 + sovVip(uint64(m.VipRecentTime))
}
return n
}
func sovVip(x uint64) (n int) {
for {
n++
x >>= 7
if x == 0 {
break
}
}
return n
}
func sozVip(x uint64) (n int) {
return sovVip(uint64((x << 1) ^ uint64((int64(x) >> 63))))
}
func (m *VipInfo) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowVip
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: VipInfo: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: VipInfo: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field Mid", wireType)
}
m.Mid = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowVip
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.Mid |= (int64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
case 2:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field VipType", wireType)
}
m.VipType = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowVip
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.VipType |= (int32(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
case 3:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field VipStatus", wireType)
}
m.VipStatus = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowVip
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.VipStatus |= (int32(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
case 4:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field VipStartTime", wireType)
}
m.VipStartTime = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowVip
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.VipStartTime |= (go_common_time.Time(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
case 5:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field VipOverdueTime", wireType)
}
m.VipOverdueTime = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowVip
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.VipOverdueTime |= (go_common_time.Time(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
case 6:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field AnnualVipOverdueTime", wireType)
}
m.AnnualVipOverdueTime = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowVip
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.AnnualVipOverdueTime |= (go_common_time.Time(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
case 7:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field AccessStatus", wireType)
}
m.AccessStatus = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowVip
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.AccessStatus |= (int32(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
case 8:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field FrozenDate", wireType)
}
m.FrozenDate = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowVip
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.FrozenDate |= (go_common_time.Time(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
case 9:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field VipStatusWarn", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowVip
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthVip
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.VipStatusWarn = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 10:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field VipRecentTime", wireType)
}
m.VipRecentTime = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowVip
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.VipRecentTime |= (go_common_time.Time(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
default:
iNdEx = preIndex
skippy, err := skipVip(dAtA[iNdEx:])
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthVip
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func skipVip(dAtA []byte) (n int, err error) {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowVip
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
wireType := int(wire & 0x7)
switch wireType {
case 0:
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowVip
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
iNdEx++
if dAtA[iNdEx-1] < 0x80 {
break
}
}
return iNdEx, nil
case 1:
iNdEx += 8
return iNdEx, nil
case 2:
var length int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowVip
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
length |= (int(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
iNdEx += length
if length < 0 {
return 0, ErrInvalidLengthVip
}
return iNdEx, nil
case 3:
for {
var innerWire uint64
var start int = iNdEx
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowVip
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
innerWire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
innerWireType := int(innerWire & 0x7)
if innerWireType == 4 {
break
}
next, err := skipVip(dAtA[start:])
if err != nil {
return 0, err
}
iNdEx = start + next
}
return iNdEx, nil
case 4:
return iNdEx, nil
case 5:
iNdEx += 4
return iNdEx, nil
default:
return 0, fmt.Errorf("proto: illegal wireType %d", wireType)
}
}
panic("unreachable")
}
var (
ErrInvalidLengthVip = fmt.Errorf("proto: negative length found during unmarshaling")
ErrIntOverflowVip = fmt.Errorf("proto: integer overflow")
)
func init() { proto.RegisterFile("vip.proto", fileDescriptorVip) }
var fileDescriptorVip = []byte{
// 429 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x92, 0xcf, 0x6e, 0xd3, 0x40,
0x10, 0xc6, 0x63, 0x42, 0x9a, 0x66, 0x49, 0x03, 0x6c, 0x91, 0x30, 0x1c, 0xbc, 0x11, 0x87, 0x2a,
0xfc, 0x69, 0x22, 0x81, 0x38, 0x70, 0xac, 0x85, 0x2a, 0x71, 0xa8, 0x40, 0x6e, 0x15, 0x8e, 0xd6,
0xc6, 0x5e, 0x9b, 0x95, 0xea, 0xdd, 0xd5, 0x7a, 0x1d, 0x54, 0x1e, 0x83, 0x13, 0x8f, 0xd4, 0x63,
0x9f, 0x60, 0x45, 0xc3, 0x6d, 0x1f, 0x81, 0x13, 0xf2, 0xb8, 0xa1, 0xb8, 0x82, 0x88, 0x9b, 0x67,
0xbe, 0xef, 0xfb, 0xed, 0x68, 0xc6, 0x68, 0xb0, 0xe4, 0x6a, 0xaa, 0xb4, 0x34, 0x12, 0xf7, 0x0a,
0x99, 0xb2, 0xd3, 0xc7, 0xfb, 0x39, 0x37, 0x9f, 0xaa, 0xc5, 0x34, 0x91, 0xc5, 0x2c, 0x97, 0xb9,
0x9c, 0x81, 0xba, 0xa8, 0x32, 0xa8, 0xa0, 0x80, 0xaf, 0x26, 0xf5, 0xe4, 0x6b, 0x0f, 0xf5, 0xe7,
0x5c, 0xbd, 0x13, 0x99, 0xc4, 0x8f, 0x50, 0xf7, 0x88, 0xa7, 0xbe, 0x37, 0xf6, 0x26, 0xdd, 0xb0,
0xef, 0x2c, 0xe9, 0x16, 0x3c, 0x8d, 0xea, 0x1e, 0xde, 0x03, 0xd7, 0xc9, 0x99, 0x62, 0xfe, 0xad,
0xb1, 0x37, 0xe9, 0x85, 0x43, 0x67, 0xc9, 0xf6, 0x92, 0xab, 0xd8, 0x9c, 0x29, 0x16, 0xad, 0x45,
0xfc, 0x02, 0x0d, 0xe6, 0x5c, 0x1d, 0x1b, 0x6a, 0xaa, 0xd2, 0xef, 0x82, 0x73, 0xe4, 0x2c, 0x41,
0xb5, 0xb3, 0x84, 0x6e, 0x74, 0x6d, 0xc0, 0x47, 0x68, 0xd8, 0x14, 0xda, 0x9c, 0xf0, 0x82, 0xf9,
0xb7, 0xe1, 0xe5, 0xa7, 0xce, 0x92, 0xd1, 0x55, 0x40, 0x9b, 0xd8, 0xf0, 0x82, 0xfd, 0xb4, 0x64,
0x37, 0x97, 0xfb, 0x89, 0x2c, 0x0a, 0x29, 0x66, 0x75, 0x67, 0x5a, 0x07, 0xa2, 0x56, 0x1c, 0x1f,
0xa3, 0xd1, 0x9c, 0xab, 0xf7, 0x4b, 0xa6, 0xd3, 0x8a, 0x01, 0xb0, 0x07, 0xc0, 0xe7, 0xce, 0x92,
0x7b, 0x35, 0x50, 0x36, 0xd2, 0x46, 0xe4, 0x0d, 0x04, 0xce, 0xd0, 0x83, 0x03, 0x21, 0x2a, 0x7a,
0x7a, 0x03, 0xbd, 0x05, 0xe8, 0x97, 0xce, 0x92, 0x87, 0x14, 0xf4, 0xf8, 0x7f, 0x5f, 0xf8, 0x2b,
0x0f, 0xbf, 0x46, 0xc3, 0x83, 0x24, 0x61, 0x65, 0x79, 0xb5, 0xbc, 0x3e, 0x2c, 0xef, 0xbe, 0xb3,
0x64, 0x87, 0x42, 0x7f, 0xbd, 0xbf, 0x96, 0x0d, 0x1f, 0x22, 0x74, 0xa8, 0xe5, 0x17, 0x26, 0xde,
0x52, 0xc3, 0xfc, 0x6d, 0x18, 0x6a, 0xcf, 0x59, 0x72, 0x27, 0x83, 0x6e, 0x9c, 0x52, 0xf3, 0xcf,
0x41, 0xfe, 0x48, 0xe2, 0x37, 0x68, 0xe7, 0xf7, 0x5d, 0x3e, 0x52, 0x2d, 0xfc, 0xc1, 0xd8, 0x9b,
0x0c, 0xc2, 0x5d, 0x67, 0xc9, 0xdd, 0xeb, 0xe3, 0xc5, 0x9f, 0xa9, 0x16, 0x51, 0xdb, 0x89, 0x3f,
0x40, 0x34, 0x62, 0x09, 0x13, 0xcd, 0x19, 0x11, 0x4c, 0xf1, 0x6c, 0x1d, 0xd5, 0xa0, 0x6c, 0x5c,
0x49, 0x1b, 0x10, 0xfa, 0xe7, 0x97, 0x41, 0xe7, 0xe2, 0x32, 0xe8, 0x9c, 0xaf, 0x02, 0xef, 0x62,
0x15, 0x78, 0xdf, 0x57, 0x81, 0xf7, 0xed, 0x47, 0xd0, 0x59, 0x6c, 0xc1, 0x5f, 0xfb, 0xea, 0x57,
0x00, 0x00, 0x00, 0xff, 0xff, 0x0f, 0x38, 0x57, 0xb5, 0xf8, 0x02, 0x00, 0x00,
}

View File

@ -0,0 +1,23 @@
syntax = "proto3";
package model;
import "github.com/gogo/protobuf/gogoproto/gogo.proto";
option (gogoproto.goproto_enum_prefix_all) = false;
option (gogoproto.goproto_getters_all) = false;
option (gogoproto.unmarshaler_all) = true;
option (gogoproto.marshaler_all) = true;
option (gogoproto.sizer_all) = true;
message VipInfo {
int64 Mid = 1 [(gogoproto.jsontag) = "mid"];
int32 VipType = 2 [(gogoproto.jsontag) = "vip_type"];
int32 VipStatus = 3 [(gogoproto.jsontag) = "vip_status"];
int64 VipStartTime = 4 [(gogoproto.jsontag) = "vip_start_time", (gogoproto.casttype) = "go-common/library/time.Time"];
int64 VipOverdueTime = 5 [(gogoproto.jsontag) = "vip_overdue_time", (gogoproto.casttype) = "go-common/library/time.Time"];
int64 AnnualVipOverdueTime = 6 [(gogoproto.jsontag) = "annual_vip_overdue_time", (gogoproto.casttype) = "go-common/library/time.Time"];
int32 AccessStatus = 7 [(gogoproto.jsontag) = "access_status"];
int64 FrozenDate = 8 [(gogoproto.jsontag) = "frozen_date", (gogoproto.casttype) = "go-common/library/time.Time"];
string VipStatusWarn = 9 [(gogoproto.jsontag) = "vip_status_warn"];
int64 VipRecentTime = 10 [(gogoproto.jsontag) = "vip_recent_time", (gogoproto.casttype) = "go-common/library/time.Time"];
}

View File

@ -0,0 +1,84 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = [
"associate_test.go",
"autorenew_test.go",
"coupon_test.go",
"frozen_test.go",
"order_test.go",
"salary_test.go",
"service_test.go",
"sync_test.go",
"vip_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/job/main/vip/conf:go_default_library",
"//app/job/main/vip/model:go_default_library",
"//library/log:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"associate.go",
"autorenew.go",
"bcoin.go",
"check_data.go",
"coupon.go",
"frozen.go",
"message.go",
"order.go",
"push.go",
"salary.go",
"salary_data.go",
"service.go",
"sync.go",
"vip.go",
],
importpath = "go-common/app/job/main/vip/service",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/job/main/vip/conf:go_default_library",
"//app/job/main/vip/dao:go_default_library",
"//app/job/main/vip/model:go_default_library",
"//app/service/main/coupon/model:go_default_library",
"//app/service/main/coupon/rpc/client:go_default_library",
"//app/service/main/vip/api:go_default_library",
"//app/service/main/vip/model:go_default_library",
"//library/database/sql:go_default_library",
"//library/log:go_default_library",
"//library/queue/databus:go_default_library",
"//library/sync/errgroup:go_default_library",
"//library/time:go_default_library",
"//vendor/github.com/pkg/errors:go_default_library",
"//vendor/github.com/robfig/cron:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@ -0,0 +1,37 @@
package service
import (
"context"
"time"
"go-common/app/job/main/vip/model"
v1 "go-common/app/service/main/vip/api"
vipmol "go-common/app/service/main/vip/model"
"go-common/library/log"
)
func (s *Service) eleEompensateJob() {
log.Info("ele grant eompensate job start..................")
if succeed := s.dao.AddTransferLock(context.TODO(), "lock:elegrant"); succeed {
if err := s.EleGrantCompensate(context.TODO()); err != nil {
log.Error("error(%+v)", err)
}
}
log.Info("ele grant eompensate job end..................")
}
// EleGrantCompensate ele frant compensate.
func (s *Service) EleGrantCompensate(c context.Context) (err error) {
var res []*model.VipOrderActivityRecord
if res, err = s.dao.NotGrantActOrders(c, vipmol.PanelTypeEle, s.c.Property.NotGrantLimit); err != nil {
return
}
for _, v := range res {
if _, err = s.vipgRPC.EleVipGrant(c, &v1.EleVipGrantReq{OrderNo: v.OrderNo}); err != nil {
log.Error("EleVipGrant a(%s) err(%+v)", v.OrderNo, err)
continue
}
time.Sleep(time.Second)
}
return
}

View File

@ -0,0 +1,22 @@
package service
import (
"testing"
. "github.com/smartystreets/goconvey/convey"
)
//go test -test.v -test.run TestEleEompensateJob
func TestEleEompensateJob(t *testing.T) {
Convey("TestEleEompensateJob ", t, func() {
s.eleEompensateJob()
})
}
//go test -test.v -test.run TestEleGrantCompensate
func TestEleGrantCompensate(t *testing.T) {
Convey("TestEleGrantCompensate ", t, func() {
err := s.EleGrantCompensate(c)
So(err, ShouldNotBeNil)
})
}

View File

@ -0,0 +1,66 @@
package service
import (
"context"
"encoding/json"
"go-common/app/job/main/vip/model"
"go-common/library/log"
)
func (s *Service) autoRenewPay(c context.Context, n *model.VipUserInfoMsg, o *model.VipUserInfoMsg) (err error) {
// wechat autorenew 扣款重放条件:
// 1.自动续费用户
// 2.非IAP支付方式
// 3.用户状态发生变化
// 4.旧状态为未过期
// 5.新状态为过期
// 6.新旧类型都是不是NotVip type
if n.IsAutoRenew == model.AutoRenew &&
o.IsAutoRenew == model.AutoRenew &&
n.PayChannelID != model.IAPChannelID &&
o.PayChannelID != model.IAPChannelID &&
n.Status != o.Status &&
o.Status == model.VipStatusNotOverTime &&
n.Status == model.VipStatusOverTime &&
n.Type != model.NotVip && o.Type != model.NotVip {
_, err = s.dao.AutoRenewPay(c, n.Mid)
}
return
}
func (s *Service) retryautorenewpayproc() {
defer s.waiter.Done()
msgs := s.autoRenewdDatabus.Messages()
var err error
for {
msg, ok := <-msgs
if !ok {
log.Warn("[service.retryautorenewpayproc|vip] dataConsumer has been closed.")
return
}
if err = msg.Commit(); err != nil {
log.Error("retryautorenewpayproc msg.Commit err(%+v)", err)
}
log.Info("cur consumer retryautorenewpayproc(%v)", string(msg.Value))
v := &model.Message{}
if err = json.Unmarshal([]byte(msg.Value), v); err != nil {
log.Error("retryautorenewpayproc json.Unmarshal(%v) err(%v)", v, err)
continue
}
if v.Table != _tableUserInfo || v.Action != _updateAction {
continue
}
n := new(model.VipUserInfoMsg)
if err = json.Unmarshal(v.New, n); err != nil {
log.Error("retryautorenewpayproc json.Unmarshal val(%v) error(%v)", string(v.New), err)
continue
}
o := new(model.VipUserInfoMsg)
if err = json.Unmarshal(v.Old, o); err != nil {
log.Error("retryautorenewpayproc json.Unmarshal val(%v) error(%v)", string(v.Old), err)
continue
}
s.autoRenewPay(context.Background(), n, o)
}
}

View File

@ -0,0 +1,39 @@
package service
import (
"testing"
"go-common/app/job/main/vip/model"
. "github.com/smartystreets/goconvey/convey"
)
//go test -test.v -test.run TestAutoRenewPay
func TestAutoRenewPay(t *testing.T) {
Convey("TestAutoRenewPay ", t, func() {
err := s.autoRenewPay(c, &model.VipUserInfoMsg{
IsAutoRenew: model.AutoRenew,
PayChannelID: 100,
Status: 0,
Type: 1,
}, &model.VipUserInfoMsg{
Type: 1,
Status: 1,
IsAutoRenew: model.AutoRenew,
PayChannelID: 1,
})
So(err, ShouldBeNil)
err = s.autoRenewPay(c, &model.VipUserInfoMsg{
IsAutoRenew: model.AutoRenew,
PayChannelID: 1,
Status: 0,
Type: 1,
}, &model.VipUserInfoMsg{
Type: 1,
Status: 1,
IsAutoRenew: model.AutoRenew,
PayChannelID: 1,
})
So(err, ShouldBeNil)
})
}

View File

@ -0,0 +1,256 @@
package service
import (
"context"
"crypto/md5"
"encoding/hex"
"fmt"
"time"
"go-common/app/job/main/vip/model"
"go-common/library/log"
xtime "go-common/library/time"
"github.com/pkg/errors"
)
//HandlerBcoin handler bcoin
func (s *Service) HandlerBcoin() (err error) {
var (
batchSize int64 = 2000
oldMaxID int64
newMaxID int64
exitMap = make(map[string]int)
batch []*model.VipBcoinSalary
)
if oldMaxID, err = s.dao.SelOldBcoinMaxID(context.TODO()); err != nil {
log.Error("s.dao.SelOldBcoinMaxID error(%+v)", err)
return
}
if newMaxID, err = s.dao.SelBcoinMaxID(context.TODO()); err != nil {
log.Error("s.dao.SelBcoinMaxID error(%v)", err)
return
}
page := newMaxID / batchSize
if newMaxID%batchSize != 0 {
page++
}
for i := 0; i < int(page); i++ {
arg := new(model.QueryBcoinSalary)
arg.StartID = int64(i) * batchSize
arg.EndID = int64(i+1) * batchSize
if arg.EndID > newMaxID {
arg.EndID = newMaxID
}
arg.GiveNowStatus = -1
var res []*model.VipBcoinSalary
if res, err = s.dao.SelBcoinSalaryData(context.TODO(), arg.StartID, arg.EndID); err != nil {
log.Error("s.dao.SelBcoinSalary(%+v) error(%+v)", arg, err)
return
}
for _, v := range res {
exitMap[s.makeBcoinMD5(v)] = 1
}
}
page = oldMaxID / batchSize
if oldMaxID%batchSize != 0 {
page++
}
for i := 0; i < int(page); i++ {
startID := int64(i) * batchSize
EndID := int64(i+1) * batchSize
if EndID > oldMaxID {
EndID = oldMaxID
}
var res []*model.VipBcoinSalary
if res, err = s.dao.SelOldBcoinSalary(context.TODO(), startID, EndID); err != nil {
log.Error("sel.OldBcoinSalary(startID:%v endID:%v) error(%+v)", startID, EndID, err)
return
}
for _, v := range res {
if exitMap[s.makeBcoinMD5(v)] == 0 {
batch = append(batch, v)
}
}
if err = s.dao.BatchAddBcoinSalary(batch); err != nil {
log.Error("s.dao.BatchAddBcoinSalary (%+v)", err)
return
}
batch = nil
}
return
}
func (s *Service) handleraddbcoinproc() {
defer func() {
if x := recover(); x != nil {
log.Error("service.handlerupdaterechargeorderproc panic(%v)", x)
go s.handleraddbcoinproc()
log.Info("service.handlerupdaterechargeorderproc recover")
}
}()
for {
msg := <-s.handlerAddBcoinSalary
log.Info("cur bcoin msage:%+v", msg)
for i := 0; i < s.c.Property.Retry; i++ {
if err := s.dao.AddBcoinSalary(context.TODO(), msg); err != nil {
log.Error("s.dao.addbcoinsalary(%+v) error(%+v)", msg, err)
} else if err == nil {
break
}
}
}
}
func (s *Service) handlerdelbcoinproc() {
defer func() {
if x := recover(); x != nil {
log.Error("service.handlerdelbcoinproc panic(%v)", x)
go s.handlerdelbcoinproc()
log.Info("service.handlerdelbcoinproc recover")
}
}()
var err error
for {
msg := <-s.handlerDelBcoinSalary
for i := 0; i < s.c.Property.Retry; i++ {
if err = s.dao.DelBcoinSalary(context.TODO(), msg.Payday, msg.Mid); err == nil {
break
}
log.Error("s.dao.DelBcoinSalary(msg:%+v) error(%+v)", msg, err)
}
}
}
func (s *Service) handlerupdatebcoinproc() {
defer func() {
if x := recover(); x != nil {
log.Error("service.handlerupdaterechargeorderproc panic(%v)", x)
go s.handlerupdatebcoinproc()
log.Info("service.handlerupdaterechargeorderproc recover")
}
}()
var err error
for {
msg := <-s.handlerUpdateBcoinSalary
for i := 0; i < s.c.Property.Retry; i++ {
if err = s.dao.UpdateBcoinSalary(context.TODO(), msg.Payday, msg.Mid, msg.Status); err == nil {
break
}
log.Error("s.dao.UpdateBcoinSalary(msg:%+v) error(%+v)", msg, err)
}
}
}
func (s *Service) sendBcoinJob() {
defer func() {
if r := recover(); r != nil {
r = errors.WithStack(r.(error))
log.Error("recover panic error(%+v)", r)
}
}()
log.Info("sen bcoin job start ........................................ ")
s.sendBcoin()
log.Info("sen bcoin job end ........................................ ")
}
func (s *Service) sendBcoin() {
var (
maxID int64
batchSize int64 = 3000
sendSize = 50
err error
)
if maxID, err = s.dao.SelBcoinMaxID(context.TODO()); err != nil {
log.Error("s.dao.selBcoinMaxID() error(%+v)", err)
return
}
page := maxID / batchSize
if maxID%batchSize != 0 {
page++
}
now := time.Now()
startMonth := now.AddDate(0, 0, 1-now.Day())
endMonth := startMonth.AddDate(0, 1, 0)
sendInfo := s.sendInfo()
for i := 0; i < int(page); i++ {
arg := new(model.QueryBcoinSalary)
arg.StartID = int64(i) * batchSize
arg.EndID = int64(i+1) * batchSize
arg.GiveNowStatus = 0
arg.Status = 0
arg.StartMonth = xtime.Time(startMonth.Unix())
arg.EndMonth = xtime.Time(endMonth.Unix())
var res []*model.VipBcoinSalary
if res, err = s.dao.SelBcoinSalary(context.TODO(), arg); err != nil {
log.Error("s.dao.selBcoinSalary(%+v) error(%+v)", arg, err)
return
}
pageSend := len(res) / sendSize
if len(res)%sendSize != 0 {
pageSend++
}
for j := 0; j < pageSend; j++ {
start := j * sendSize
end := int(j+1) * sendSize
if end > len(res) {
end = len(res)
}
if err = s.sendBocinNow(res[start:end], sendInfo.Amount, sendInfo.DueDate); err != nil {
log.Error("%+v", err)
return
}
}
}
}
func (s *Service) sendInfo() (r *model.BcoinSendInfo) {
var (
c time.Time
day = s.c.Property.AnnualVipBcoinDay
amount = s.c.Property.AnnualVipBcoinCouponMoney
)
r = new(model.BcoinSendInfo)
r.Amount = int32(amount)
r.DayOfMonth = day
c = time.Now()
c = c.AddDate(0, 1, int(day)-1-c.Day())
r.DueDate = xtime.Time(c.Unix())
return
}
func (s *Service) sendBocinNow(res []*model.VipBcoinSalary, amount int32, duTime xtime.Time) (err error) {
var (
mids []int64
ids []int64
)
for _, v := range res {
mids = append(mids, v.Mid)
ids = append(ids, v.ID)
}
if err = s.dao.SendBcoin(context.TODO(), mids, amount, duTime, "127.0.0.1"); err != nil {
err = errors.WithStack(err)
return
}
if err = s.dao.UpdateBcoinSalaryBatch(context.TODO(), ids, 1); err != nil {
err = errors.WithStack(err)
return
}
return
}
func (s *Service) makeBcoinMD5(r *model.VipBcoinSalary) string {
key := fmt.Sprintf("%v,%v,%v,%v,%v,%v", r.Mid, r.Memo, r.Amount, r.Payday.Time().Format("2006-01-02"), r.GiveNowStatus, r.Status)
hash := md5.New()
hash.Write([]byte(key))
sum := hash.Sum(nil)
return hex.EncodeToString(sum)
}

View File

@ -0,0 +1,226 @@
package service
import (
"context"
"time"
"go-common/app/job/main/vip/model"
"go-common/library/log"
"github.com/pkg/errors"
)
// CheckUserData check vip_user_info data.
func (s *Service) CheckUserData(c context.Context) (diffs map[int64]string, err error) {
var (
maxID int
size = s.c.Property.BatchSize
ids = []int64{}
ousers = make(map[int64]*model.VipUserInfoOld, size)
nusers = make(map[int64]*model.VipUserInfo, _ps)
ou *model.VipUserInfoOld
nu *model.VipUserInfo
ok bool
)
diffs = make(map[int64]string)
if maxID, err = s.dao.SelOldUserInfoMaxID(context.TODO()); err != nil {
err = errors.WithStack(err)
return
}
page := maxID / size
if maxID%size != 0 {
page++
}
log.Info("check vip_user_info total(%d)", page)
for i := 0; i < page; i++ {
log.Info("check vip_user_info page index(%d) total(%d)", i, page)
startID := i * size
endID := (i + 1) * size
if endID > maxID {
endID = maxID
}
if ousers, err = s.dao.SelOldUserInfoMaps(context.TODO(), startID, endID); err != nil {
return
}
j := 1
for _, v := range ousers {
ids = append(ids, v.Mid)
if j%_ps == 0 || j == len(ousers) {
if nusers, err = s.dao.SelVipByIds(context.TODO(), ids); err != nil {
return
}
for _, mid := range ids {
if ou, ok = ousers[mid]; !ok {
diffs[mid] = "old not found"
continue
}
if nu, ok = nusers[mid]; !ok {
diffs[mid] = "new not found"
continue
}
if nu.Type != ou.Type {
diffs[mid] = "vip_type"
continue
}
if nu.Status != ou.Status {
diffs[mid] = "vip_status"
continue
}
if !nu.OverdueTime.Time().Equal(ou.OverdueTime.Time()) {
diffs[mid] = "vip_overdue_time"
continue
}
if !nu.AnnualVipOverdueTime.Time().Equal(ou.AnnualVipOverdueTime.Time()) {
diffs[mid] = "annual_vip_overdue_time"
continue
}
if nu.PayType != ou.IsAutoRenew {
diffs[mid] = "vip_pay_type"
continue
}
if nu.PayChannelID != ou.PayChannelID {
diffs[mid] = "pay_channel_id"
continue
}
if !nu.IosOverdueTime.Time().Equal(ou.IosOverdueTime.Time()) {
diffs[mid] = "ios_overdue_time"
continue
}
}
// reset
ids = []int64{}
}
j++
}
log.Info("check index (%d) vip_user_info diff len (%d)", i, len(diffs))
log.Info("check index (%d) vip_user_info diff data mids(%v)", i, diffs)
time.Sleep(time.Millisecond * _defsleepmsec)
}
return
}
//CheckBcoinData check bcoin data
func (s *Service) CheckBcoinData(c context.Context) (mids []int64, err error) {
var (
maxID int
size = s.c.Property.BatchSize
)
if maxID, err = s.dao.SelMaxID(context.TODO()); err != nil {
err = errors.WithStack(err)
return
}
page := maxID / size
if maxID%size != 0 {
page++
}
for i := 0; i < page; i++ {
startID := size * i
endID := (i + 1) * size
var res []*model.VipUserInfo
if res, err = s.dao.SelUserInfos(context.TODO(), startID, endID); err != nil {
err = errors.WithStack(err)
return
}
var (
tempMids []int64
bcoinMap map[int64][]*model.VipBcoinSalary
oldBcoinMap map[int64][]*model.VipBcoinSalary
)
for _, v := range res {
tempMids = append(tempMids, v.Mid)
}
if bcoinMap, err = s.dao.SelBcoinSalaryDataMaps(context.TODO(), tempMids); err != nil {
err = errors.WithStack(err)
return
}
if oldBcoinMap, err = s.dao.SelOldBcoinSalaryDataMaps(context.TODO(), tempMids); err != nil {
err = errors.WithStack(err)
return
}
if len(bcoinMap) > len(oldBcoinMap) {
for key, val := range bcoinMap {
salaries := oldBcoinMap[key]
if len(salaries) != len(val) {
mids = append(mids, key)
}
}
} else {
for key, val := range oldBcoinMap {
salaries := bcoinMap[key]
if len(salaries) != len(val) {
mids = append(mids, key)
}
}
}
}
log.Info("cur not sync data mid is(%+v)", mids)
return
}
//CheckChangeHistory check change history data
func (s *Service) CheckChangeHistory(c context.Context) (mids []int64, err error) {
var (
maxID int
size = 2000
)
if maxID, err = s.dao.SelMaxID(context.TODO()); err != nil {
err = errors.WithStack(err)
return
}
page := maxID / size
if maxID%size != 0 {
page++
}
for i := 0; i < page; i++ {
startID := size * i
endID := (i + 1) * size
var res []*model.VipUserInfo
if res, err = s.dao.SelUserInfos(context.TODO(), startID, endID); err != nil {
err = errors.WithStack(err)
return
}
var (
tempMids []int64
historyMap map[int64][]*model.VipChangeHistory
oldHistoryMap map[int64][]*model.VipChangeHistory
)
for _, v := range res {
tempMids = append(tempMids, v.Mid)
}
if historyMap, err = s.dao.SelChangeHistoryMaps(context.TODO(), tempMids); err != nil {
err = errors.WithStack(err)
return
}
if oldHistoryMap, err = s.dao.SelOldChangeHistoryMaps(context.TODO(), tempMids); err != nil {
err = errors.WithStack(err)
return
}
if len(historyMap) > len(oldHistoryMap) {
for key, val := range historyMap {
histories := oldHistoryMap[key]
if len(histories) != len(val) {
mids = append(mids, key)
}
}
} else {
for key, val := range oldHistoryMap {
histories := historyMap[key]
if len(histories) != len(val) {
mids = append(mids, key)
}
}
}
}
log.Info("cur not sync data mid is(%+v)", mids)
return
}

View File

@ -0,0 +1,66 @@
package service
import (
"context"
xlog "log"
"time"
"go-common/app/job/main/vip/model"
comol "go-common/app/service/main/coupon/model"
"go-common/library/log"
)
func (s *Service) couponnotifyproc() {
defer func() {
if x := recover(); x != nil {
log.Error("couponnotifyproc panic(%v)", x)
go s.couponnotifyproc()
log.Info("couponnotifyproc recover")
}
}()
for {
f := <-s.notifycouponchan
time.AfterFunc(2*time.Second, f)
}
}
func (s *Service) couponnotify(f func()) {
defer func() {
if x := recover(); x != nil {
log.Error("couponnotifyproc panic(%v)", x)
}
}()
select {
case s.notifycouponchan <- f:
default:
xlog.Panic("s.couponnotifyproc chan full!")
}
}
// CouponNotify coupon notify.
func (s *Service) CouponNotify(c context.Context, o *model.VipPayOrderNewMsg) (err error) {
var (
state int8
retrytimes = 3
)
if o == nil {
return
}
if o.Status == model.SUCCESS {
state = comol.AllowanceUseSuccess
} else {
state = comol.AllowanceUseFaild
}
for i := 0; i < retrytimes; i++ {
if err = s.couponRPC.CouponNotify(c, &comol.ArgNotify{
Mid: o.Mid,
OrderNo: o.OrderNo,
State: state,
}); err != nil {
log.Error("rpc.CouponNotify(%+v) error(%+v)", o, err)
continue
}
break
}
return
}

View File

@ -0,0 +1,22 @@
package service
import (
"testing"
"go-common/app/job/main/vip/model"
. "github.com/smartystreets/goconvey/convey"
)
//go test -test.v -test.run TestCouponNotify
func TestCouponNotify(t *testing.T) {
Convey("TestCouponNotify ", t, func() {
o := &model.VipPayOrderNewMsg{
OrderNo: "1807211806450011799",
Status: model.SUCCESS,
Mid: 1,
}
err := s.CouponNotify(c, o)
So(err, ShouldBeNil)
})
}

View File

@ -0,0 +1,131 @@
package service
import (
"context"
"encoding/json"
"time"
"go-common/app/job/main/vip/model"
"go-common/library/log"
"go-common/library/queue/databus"
"github.com/pkg/errors"
)
func (s *Service) accloginproc() {
defer func() {
if r := recover(); r != nil {
r = errors.WithStack(r.(error))
log.Error("Runtime error caught: %+v", r)
go s.accloginproc()
}
}()
var (
err error
msgChan = s.accLogin.Messages()
msg *databus.Message
ok bool
)
for {
msg, ok = <-msgChan
log.Info("login ip msg %+v", string(msg.Value))
if !ok {
log.Info("accLogin msgChan closed")
}
if err = msg.Commit(); err != nil {
log.Error("msg.Commit err(%+v)", err)
}
m := &model.LoginLog{}
if err = json.Unmarshal([]byte(msg.Value), m); err != nil {
log.Error("json.Unmarshal(%v) err(%+v)", m, err)
continue
}
s.Frozen(context.TODO(), m)
}
}
// Frozen handle vip frozen logic.
func (s *Service) Frozen(c context.Context, ll *model.LoginLog) (err error) {
var (
lc int64
uvs *model.VipUserInfo
ctx = context.TODO()
)
// 判定用户是否为vip
if uvs, err = s.dao.VipStatus(ctx, ll.Mid); err != nil {
log.Error("s.dao.VipStatus%derr(%+v)", ll.Mid, err)
return
}
if uvs == nil || uvs.Status == model.VipStatusOverTime {
log.Warn("user(%d) not vip.(%+v)", ll.Mid, uvs)
return
}
// 判定是否为15分钟4次以上不同ip登录
if err = s.dao.AddLogginIP(ctx, ll.Mid, ll.IP); err != nil {
log.Error("s.dao.AddLogginIP(%derr(%+v)", ll.Mid, err)
return
}
if lc, err = s.dao.LoginCount(ctx, ll.Mid); err != nil {
log.Error("s.dao.LoginCount(%derr(%+v)", ll.Mid, err)
return
}
if lc >= s.c.Property.FrozenLimit {
if err = s.dao.Enqueue(ctx, ll.Mid, time.Now().Add(s.frozenDate).Unix()); err != nil {
log.Error("enqueue error(%+v)", err)
}
if err = s.dao.SetVipFrozen(ctx, ll.Mid); err != nil {
log.Error("set vip frozen err(%+v)", err)
}
//通知业务方清理缓存
s.cleanCache(ll.Mid)
if err = s.notifyOldVip(ll.Mid, -1); err != nil {
log.Error("del vip java frozen err(%+v)", err)
}
log.Info("mid(%+v) frozen success", ll.Mid)
}
return
}
// unFrozenJob timing to unFrozen vip user
func (s *Service) unFrozenJob() {
log.Info("unfrozen job start........................................")
defer func() {
if r := recover(); r != nil {
r = errors.WithStack(r.(error))
log.Error("recover panic error(%+v)", r)
}
log.Info("unfrozen job end.............................")
}()
var (
err error
mids []int64
ctx = context.TODO()
)
if mids, err = s.dao.Dequeue(ctx); err != nil {
log.Error("s.dao.Dequeue err(%+v)", err)
return
}
for _, mid := range mids {
if err = s.dao.RemQueue(ctx, mid); err != nil {
log.Error("s.dao.RemQueue(%derr(%+v)", mid, err)
continue
}
if err = s.dao.DelCache(ctx, mid); err != nil {
log.Error("del cache mid(%+v) err(%+v)", mid, err)
}
if err = s.dao.DelVipFrozen(ctx, mid); err != nil {
log.Error("del vip frozen err(%+v)", err)
}
if err = s.notifyOldVip(mid, 0); err != nil {
log.Error("del vip java frozen err(%+v)", err)
}
s.cleanCache(mid)
log.Info("mid(%+v) unfrozen success", mid)
}
}
// FIXME AFTER REMOVE JAVA.
func (s *Service) notifyOldVip(mid, status int64) error {
return s.dao.OldFrozenChange(mid, status)
}

View File

@ -0,0 +1,31 @@
package service
import (
"context"
"testing"
"go-common/app/job/main/vip/model"
. "github.com/smartystreets/goconvey/convey"
)
var (
ctx = context.TODO()
)
func Test_Frozen(t *testing.T) {
Convey("test user frozen", t, func() {
la := []uint32{1, 2, 3, 4, 5}
for _, i := range la {
s.dao.AddLogginIP(ctx, 7593666, i)
}
s.Frozen(ctx, &model.LoginLog{Mid: 7593666, IP: 234566})
})
}
func Test_UnFrozen(t *testing.T) {
Test_Frozen(t)
Convey("test user unfrozen", t, func() {
s.unFrozenJob()
})
}

View File

@ -0,0 +1,151 @@
package service
import (
"context"
"fmt"
"strings"
xtime "time"
"go-common/app/job/main/vip/model"
"go-common/library/log"
"go-common/library/time"
"github.com/pkg/errors"
)
const (
maxSendMsgCount = 200
willExpiredDay = 7
hadExpiredDays = 14
willExpiredMsg = "您还有%d天大会员即将到期请尽快续期享受更多特权"
willExpiredTitle = "大会员即将到期提醒"
hadExpiredMsg = "很抱歉的通知您,您的大会员已过期,请尽快续期享受更多特权!"
hadExpiredTitle = "大会员过期提醒"
vipWillExpiredMsgCode = "10_1_2"
vipHadExpiredMsgCode = "10_1_3"
systemNotify = 4
)
func (s *Service) hadExpiredMsgJob() {
defer func() {
if x := recover(); x != nil {
log.Error("service.hadExpiredMsgJob panic(%v)", x)
go s.hadExpiredMsgJob()
log.Info("service.hadExpiredMsgJob recover")
}
}()
log.Info("start send had expire msg job ...................")
var (
err error
mids []int64
)
now := xtime.Now()
startTime := now.AddDate(0, 0, -hadExpiredDays-1)
endTime := now.AddDate(0, 0, -hadExpiredDays)
if mids, err = s.willExpireUser(time.Time(startTime.Unix()), time.Time(endTime.Unix()), model.VipStatusOverTime); err != nil {
log.Error("will expire user(startTime:%v endTime:%v status:%v) error(%+v)", startTime, endTime, model.VipStatusOverTime, err)
return
}
log.Info("send startTime(%v) endDate(%v) mids(%v)", startTime.Format("2006-01-02"), endTime.Format("2006-01-02"), mids)
if err = s.batchSendMsg(mids, hadExpiredMsg, hadExpiredTitle, vipHadExpiredMsgCode, systemNotify); err != nil {
log.Error("batch send msg error(%+v)", err)
return
}
log.Info("end send had expire msg job..........................")
}
func (s *Service) willExpiredMsgJob() {
defer func() {
if x := recover(); x != nil {
log.Error("service.hadExpiredMsgJob panic(%v)", x)
go s.willExpiredMsgJob()
log.Info("service.hadExpiredMsgJob recover")
}
}()
log.Info("start send will expire msg job............................")
var (
err error
mids []int64
)
now := xtime.Now()
startTime := now.AddDate(0, 0, willExpiredDay)
endTime := now.AddDate(0, 0, willExpiredDay+1)
if mids, err = s.willExpireUser(time.Time(startTime.Unix()), time.Time(endTime.Unix()), model.VipStatusNotOverTime); err != nil {
log.Error("will expire user(startTime:%v endTime:%v status:%v) error(%+v)", startTime, endTime, model.VipStatusNotOverTime, err)
return
}
log.Info("send startTime(%v) endDate(%v) mids(%v)", startTime.Format("2006-01-02"), endTime.Format("2006-01-02"), mids)
if err = s.batchSendMsg(mids, fmt.Sprintf(willExpiredMsg, willExpiredDay), willExpiredTitle, vipWillExpiredMsgCode, systemNotify); err != nil {
log.Error("batch send msg error(%+v)", err)
return
}
log.Info("end send will expire msg job............................")
}
func (s *Service) willExpireUser(startTime time.Time, endTime time.Time, status int) (mids []int64, err error) {
var (
maxID int
size = 10000
)
if maxID, err = s.dao.SelMaxID(context.TODO()); err != nil {
err = errors.WithStack(err)
return
}
page := maxID / size
if maxID%size != 0 {
page++
}
for i := 0; i < page; i++ {
startID := i * size
endID := (i + 1) * size
var tempMid []int64
if tempMid, err = s.dao.SelVipUserInfos(context.TODO(), startID, endID, startTime, endTime, status); err != nil {
err = errors.WithStack(err)
return
}
mids = append(mids, tempMid...)
}
return
}
func (s *Service) batchSendMsg(mids []int64, content string, title string, ms string, dataType int) (err error) {
if len(mids) <= maxSendMsgCount && len(mids) >= 1 {
var midsStr = ""
for _, v := range mids {
midsStr += fmt.Sprintf(",%v", v)
}
if err = s.dao.SendMultipMsg(context.TODO(), midsStr, content, title, ms, dataType); err != nil {
err = errors.WithStack(err)
return
}
} else if len(mids) > maxSendMsgCount {
page := len(mids) / maxSendMsgCount
if len(mids)%maxSendMsgCount != 0 {
page++
}
for i := 0; i < page; i++ {
start := i * maxSendMsgCount
end := (i + 1) * maxSendMsgCount
if len(mids) < end {
end = len(mids)
}
tempMids := mids[start:end]
var midsStr []string
for _, v := range tempMids {
midsStr = append(midsStr, fmt.Sprintf("%v", v))
}
if err = s.dao.SendMultipMsg(context.TODO(), strings.Join(midsStr, ","), content, title, ms, dataType); err != nil {
err = errors.WithStack(err)
continue
}
}
}
return
}

View File

@ -0,0 +1,471 @@
package service
import (
"context"
"fmt"
"time"
"go-common/app/job/main/vip/model"
"go-common/library/log"
xtime "go-common/library/time"
"github.com/pkg/errors"
)
const (
_autoRenewFailTwoMsg = "连续包月大会员今天凌晨续费又失败了,服务已暂停。如果想要再次享受连续包月大会员服务,请先取消连续包月,再去开通哦~"
_autoRenewFailOneMsg = "连续包月大会员今天凌晨续费失败了,%s 0点将会再次重试。"
_deadlineAutoRenewMsg = "您的连续包月服务将在%s 0点续费。"
_autoRenewFailTitle = "连续包月服务续费失败"
_deadlineAutoRenewTitle = "连续包月服务即将续费"
_sleep = 20 * time.Millisecond
_maxtime = 20
)
func (s *Service) handlerinsertorderproc() {
var (
err error
)
defer func() {
if x := recover(); x != nil {
log.Error("service.handlerinsertorderproc panic(%v)", x)
go s.handlerinsertorderproc()
log.Info("service.handlerinsertorderproc recover")
}
}()
for {
order := <-s.handlerInsertOrder
for i := 0; i < s.c.Property.Retry; i++ {
if err = s.insertOrder(order); err == nil {
break
}
log.Error("error(%+v)", err)
}
}
}
func (s *Service) insertOrder(r *model.VipPayOrder) (err error) {
var aff int64
if aff, err = s.dao.AddPayOrder(context.TODO(), r); err != nil {
err = errors.WithStack(err)
return
}
if aff != 1 {
return
}
log.Info("vip_pay_order sysn data(%+v)", r)
rlog := new(model.VipPayOrderLog)
rlog.Mid = r.Mid
rlog.OrderNo = r.OrderNo
rlog.Status = r.Status
if _, err = s.dao.AddPayOrderLog(context.TODO(), rlog); err != nil {
log.Error("add pay order log(%+v) error(%+v)", rlog, err)
err = nil
}
return
}
func (s *Service) handlerupdateorderproc() {
var (
err error
flag bool
)
defer func() {
if x := recover(); x != nil {
log.Error("service.handlerupdateorderproc panic(%v)", x)
go s.handlerupdateorderproc()
log.Info("service.handlerupdateorderproc recover")
}
}()
for {
order := <-s.handlerUpdateOrder
flag = true
for i := 0; i < s.c.Property.Retry; i++ {
if err = s.updatePayOrder(context.TODO(), order); err == nil {
flag = false
break
}
log.Error("error(%+v)", err)
}
if flag {
s.handlerFailPayOrder <- order
}
}
}
func (s *Service) handlerfailpayorderproc() {
var (
err error
)
defer func() {
if x := recover(); x != nil {
log.Error("service.handlerfailpayorderproc panic(%v)", x)
go s.handlerfailpayorderproc()
log.Info("service.handlerfailpayorderproc recover")
}
}()
for {
order := <-s.handlerFailPayOrder
_time := 0
for {
if err = s.updatePayOrder(context.TODO(), order); err == nil {
break
}
log.Error("pay order error(%+v)", err)
_time++
if _time > _maxtime {
break
}
}
}
}
func (s *Service) handlerfailrechargeorderproc() {
var (
eff int64
err error
)
defer func() {
if x := recover(); x != nil {
log.Error("service.handlerfailrechargeorderproc panic(%v)", x)
go s.handlerfailrechargeorderproc()
log.Info("service.handlerfailrechargeorderproc recover")
}
}()
for {
order := <-s.handlerFailRechargeOrder
_time := 0
for {
if eff, err = s.dao.UpdateRechargeOrder(context.TODO(), order); err != nil {
log.Error("error(%+v)", err)
break
}
if eff > 0 {
break
}
_time++
if _time > _maxtime {
break
}
time.Sleep(_sleep)
}
}
}
func (s *Service) handlerupdaterechargeorderproc() {
var (
eff int64
err error
flag bool
)
defer func() {
if x := recover(); x != nil {
log.Error("service.handlerupdaterechargeorderproc panic(%v)", x)
go s.handlerupdaterechargeorderproc()
log.Info("service.handlerupdaterechargeorderproc recover")
}
}()
for {
order := <-s.handlerRechargeOrder
flag = true
for i := 0; i < s.c.Property.Retry; i++ {
if eff, err = s.dao.UpdateRechargeOrder(context.TODO(), order); err != nil {
log.Error("error(%+v)", err)
continue
}
if eff > 0 {
log.Info("update recharge order(%+v)", order)
flag = false
break
}
time.Sleep(_sleep)
}
if flag {
s.handlerFailRechargeOrder <- order
}
}
}
func (s *Service) updatePayOrder(c context.Context, r *model.VipPayOrder) (err error) {
var eff int64
if eff, err = s.dao.UpdatePayOrderStatus(c, r); err != nil {
err = errors.WithStack(err)
return
}
if eff <= 0 {
err = fmt.Errorf("order更新未执行(%+v)", r)
time.Sleep(_sleep)
return
}
log.Info("cur pay order update order(%+v)", r)
rlogKey := fmt.Sprintf("%v:%v", r.OrderNo, r.Status)
if succeed := s.dao.AddTransferLock(c, rlogKey); succeed {
rlog := new(model.VipPayOrderLog)
rlog.Mid = r.Mid
rlog.OrderNo = r.OrderNo
rlog.Status = r.Status
if _, err = s.dao.AddPayOrderLog(context.TODO(), rlog); err != nil {
log.Error("add pay order log(%+v) error(%+v)", rlog, err)
err = nil
}
return
}
return
}
func (s *Service) convertPayOrder(r *model.VipPayOrderOldMsg) (res *model.VipPayOrder) {
res = new(model.VipPayOrder)
res.Mid = r.Mid
res.AppID = r.AppID
res.AppSubID = r.AppSubID
res.BuyMonths = r.BuyMonths
res.Money = r.Money
res.RechargeBp = r.RechargeBp
res.OrderNo = r.OrderNo
res.OrderType = r.OrderType
res.PayType = r.PayType
res.Platform = r.Platform
res.Status = r.Status
res.ToMid = r.Bmid
res.Ver = r.Ver
res.CouponMoney = r.CouponMoney
if paymentTime, err := time.ParseInLocation("2006-01-02 15:04:05", r.PaymentTime, time.Local); err == nil {
res.PaymentTime = xtime.Time(paymentTime.Unix())
}
res.Ctime = xtime.Time(parseTime(r.Ctime).Unix())
res.Mtime = xtime.Time(parseTime(r.Mtime).Unix())
return
}
func (s *Service) convertPayOrderByMsg(r *model.VipRechargeOrderMsg) (res *model.VipPayOrder) {
res = new(model.VipPayOrder)
res.Mid = r.PayMid
res.OrderNo = r.PayOrderNo
res.ThirdTradeNo = r.ThirdTradeNo
res.RechargeBp = r.RechargeBp
return
}
func convertPayOrderOldToNew(r *model.VipPayOrderOld) (res *model.VipPayOrder) {
res = new(model.VipPayOrder)
res.Mid = r.Mid
res.AppID = r.AppID
res.AppSubID = r.AppSubID
res.BuyMonths = r.BuyMonths
res.Money = r.Money
res.OrderNo = r.OrderNo
res.OrderType = r.OrderType
res.PayType = r.PayType
res.Platform = r.Platform
res.Status = r.Status
res.ToMid = r.Bmid
res.Ver = r.Ver
res.PaymentTime = r.PaymentTime
res.CouponMoney = r.CouponMoney
return
}
//HandlerPayOrder handler pay order
func (s *Service) HandlerPayOrder() (err error) {
var (
size = 1000
oldMaxID int
)
if oldMaxID, err = s.dao.SelOldOrderMaxID(context.TODO()); err != nil {
log.Error("selOldOrderMaxID error(%+v)", err)
return
}
page := oldMaxID / size
if oldMaxID%size != 0 {
page++
}
for i := 0; i < page; i++ {
startID := i * size
endID := (i + 1) * size
if endID > oldMaxID {
endID = oldMaxID
}
var (
res []*model.VipPayOrderOld
batchOrder []*model.VipPayOrder
orderNos []string
oldRechargeOrder []*model.VipRechargeOrder
)
rechargeMap := make(map[string]*model.VipRechargeOrder)
if res, err = s.dao.SelOldPayOrder(context.TODO(), startID, endID); err != nil {
log.Error("selOldPayOrder(startID:%v endID:%v) error(%+v)", startID, endID, err)
return
}
for _, v := range res {
batchOrder = append(batchOrder, convertPayOrderOldToNew(v))
}
for _, v := range batchOrder {
orderNos = append(orderNos, v.OrderNo)
}
if oldRechargeOrder, err = s.dao.SelOldRechargeOrder(context.TODO(), orderNos); err != nil {
return
}
for _, v := range oldRechargeOrder {
rechargeMap[v.PayOrderNo] = v
}
for _, v := range batchOrder {
rechargeOrder := rechargeMap[v.OrderNo]
if rechargeOrder != nil {
v.ThirdTradeNo = rechargeOrder.ThirdTradeNo
v.RechargeBp = rechargeOrder.RechargeBp
}
}
if err = s.dao.BatchAddPayOrder(context.TODO(), batchOrder); err != nil {
return
}
}
return
}
func (s *Service) willDedutionMsg() (err error) {
var (
size = 5000
endID int
now time.Time
vips []*model.VipUserInfo
)
if now, err = time.ParseInLocation("2006-01-02", time.Now().Format("2006-01-02"), time.Local); err != nil {
log.Error("time.ParseInLocation(%v) error(%+v)", time.Now(), err)
return
}
start := now.AddDate(0, 0, 1)
end := start.AddDate(0, 0, 3)
if endID, err = s.dao.SelMaxID(context.TODO()); err != nil {
return
}
page := endID / size
if endID%size != 0 {
page++
}
for i := 0; i < page; i++ {
startID := i * size
eID := (i + 1) * size
if vips, err = s.dao.SelVipUsers(context.TODO(), startID, eID, xtime.Time(start.Unix()), xtime.Time(end.Unix())); err != nil {
continue
}
for _, v := range vips {
if v.OverdueTime.Time().Equal(start) {
s.dao.SendMultipMsg(context.TODO(), fmt.Sprintf("%v", v.Mid),
_autoRenewFailTwoMsg,
_autoRenewFailTitle,
vipWillExpiredMsgCode,
systemNotify)
} else if start.AddDate(0, 0, 1).Equal(v.OverdueTime.Time()) {
s.dao.SendMultipMsg(context.TODO(), fmt.Sprintf("%v", v.Mid),
fmt.Sprint(_autoRenewFailOneMsg, v.OverdueTime.Time().AddDate(0, 0, -1).Format("2006-01-02")),
_autoRenewFailTitle,
vipWillExpiredMsgCode,
systemNotify)
} else if start.AddDate(0, 0, 2).Equal(v.OverdueTime.Time()) {
s.dao.SendMultipMsg(context.TODO(), fmt.Sprintf("%v", v.Mid),
fmt.Sprint(_deadlineAutoRenewMsg, start.Format("2006-01-02")),
_deadlineAutoRenewTitle,
vipWillExpiredMsgCode,
systemNotify)
}
}
}
return
}
func (s *Service) autoRenews() (err error) {
//var (
// size = 5000
// endID int
// now time.Time
// vips []*model.VipUserInfo
// price float64
//)
//if now, err = time.ParseInLocation("2006-01-02", time.Now().Format("2006-01-02"), time.Local); err != nil {
// log.Error("time.ParseInLocation(%v) error(%+v)", time.Now(), err)
// return
//}
//
//start := now.AddDate(0, 0, 1)
//
//end := start.AddDate(0, 0, 3)
//if price, err = s.vipRPC.Price(context.TODO(), 1, xmodel.DevicePC, xmodel.AutoRenew, 1); err != nil {
// err = errors.WithStack(err)
// return
//}
//if endID, err = s.dao.SelMaxID(context.TODO()); err != nil {
// return
//}
//
//page := endID / size
//if endID%size != 0 {
// page++
//}
//for i := 0; i < page; i++ {
// startID := i * size
// eID := (i + 1) * size
// if vips, err = s.dao.SelVipUsers(context.TODO(), startID, eID, xtime.Time(start.Unix()), xtime.Time(end.Unix())); err != nil {
// err = errors.WithStack(err)
// continue
// }
// for _, v := range vips {
// var params = make(map[string]interface{}, 0)
// if params, err = s.vipRPC.CreateOrderPlatfrom(context.TODO(), int64(v.Mid), 0, 0, 1, price, xmodel.DevicePC, 5, xmodel.AutoRenew, ""); err != nil {
// log.Error("CreateOrderPlatform error(%+v)", err)
// continue
// }
// params["payChannelId"] = v.PayChannelId
// params["payChannel"] = s.c.Property.PayMapping[strconv.Itoa(int(v.PayChannelId))]
// if err = s.dao.PayOrder(context.TODO(), params); err != nil {
// log.Error("handler fail orderId->%v mid:%v", params["orderId"], v.Mid)
// continue
// }
// log.Info("handler success orderId:%v mid:%v", params["orderId"], v.Mid)
// }
//}
return
}
// AutoRenewJob auto renew job.
//func (s *Service) autoRenewJob() {
// defer func() {
// if x := recover(); x != nil {
// log.Error("service.autoRenewJob panic(%v)", x)
// go s.autoRenewJob()
// log.Info("service.autoRenewJob recover")
// }
// }()
// log.Info("auto renew job start.................................")
// var err error
// if err = s.autoRenews(); err != nil {
// log.Error("autoRenews error(%+v)", err)
// }
// log.Info("auto renew job end...................................")
//}
// SendMessageJob send message job.
func (s *Service) sendMessageJob() {
defer func() {
if x := recover(); x != nil {
log.Error("service.sendMessageJob panic(%v)", x)
go s.sendMessageJob()
log.Info("service.sendMessageJob recover")
}
}()
log.Info("sendMessage job start .........................")
s.willDedutionMsg()
log.Info("sendMessage job end .........................")
}

View File

@ -0,0 +1,20 @@
package service
import (
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func Test_handlerPayOrder(t *testing.T) {
Convey("handler pay order", t, func() {
s.HandlerPayOrder()
})
}
func Test_autoRenews(t *testing.T) {
Convey("autorenews ", t, func() {
err := s.autoRenews()
So(err, ShouldBeNil)
})
}

View File

@ -0,0 +1,115 @@
package service
import (
"context"
"time"
"go-common/app/job/main/vip/model"
"go-common/library/log"
"github.com/pkg/errors"
)
const (
_fail = 2
_handlering = 2
_finish = 3
_nomarl = 0
_statusnomarl = 1
)
func (s *Service) pushDataJob() {
log.Info("push data job start..................")
if succeed := s.dao.AddTransferLock(context.TODO(), "lock:pushDatajob"); succeed {
if err := s.pushData(context.TODO()); err != nil {
log.Error("error(%+v)", err)
}
}
log.Info("push data job end.....................")
}
func (s *Service) pushData(c context.Context) (err error) {
var (
res []*model.VipPushData
pushDataMap = make(map[int64]*model.VipPushData)
pushMidsMap = make(map[int64][]int64)
maxID int
size = s.c.Property.BatchSize
vips []*model.VipUserInfo
curDate time.Time
rel *model.VipPushResq
)
now := time.Now()
format := now.Format("2006-01-02")
if curDate, err = time.ParseInLocation("2006-01-02", format, time.Local); err != nil {
err = errors.WithStack(err)
return
}
if res, err = s.dao.PushDatas(c, format); err != nil {
err = errors.WithStack(err)
return
}
if len(res) == 0 {
log.Info("not need reduce push data.........")
return
}
for _, v := range res {
pushDataMap[v.ID] = v
}
if maxID, err = s.dao.SelMaxID(c); err != nil {
err = errors.WithStack(err)
return
}
page := maxID / size
if maxID%size != 0 {
page++
}
for i := 0; i < page; i++ {
startID := i * size
endID := (i + 1) * size
if vips, err = s.dao.SelUserInfos(context.TODO(), startID, endID); err != nil {
err = errors.WithStack(err)
return
}
for _, v := range vips {
for key, val := range pushDataMap {
startDate := curDate.AddDate(0, 0, int(val.ExpiredDayStart))
endDate := curDate.AddDate(0, 0, int(val.ExpiredDayEnd))
if !(v.OverdueTime.Time().Before(startDate) || v.OverdueTime.Time().After(endDate)) && v.PayType == model.Normal && val.DisableType == _nomarl && val.Status != _fail {
mids := pushMidsMap[key]
mids = append(mids, v.Mid)
pushMidsMap[key] = mids
}
}
}
}
for key, val := range pushMidsMap {
data := pushDataMap[key]
var status int8
progressStatus := data.ProgressStatus
pushedCount := data.PushedCount
if rel, err = s.dao.PushData(context.TODO(), val, data, format); err != nil {
log.Error("push data error(%+v)", err)
continue
}
if rel.Code != 0 {
status = _fail
} else {
pushedCount++
if pushedCount == data.PushTotalCount {
progressStatus = _finish
} else {
progressStatus = _handlering
}
status = _statusnomarl
}
if err = s.dao.UpdatePushData(context.TODO(), status, progressStatus, pushedCount, rel.Code, rel.Data, data.ID); err != nil {
err = errors.WithStack(err)
return
}
}
return
}

View File

@ -0,0 +1,349 @@
package service
import (
"context"
"fmt"
"time"
"go-common/app/job/main/vip/model"
"go-common/library/log"
"github.com/pkg/errors"
)
//ScanSalaryVideoCoupon scan all vip user to salary video coupon.
func (s *Service) ScanSalaryVideoCoupon(c context.Context) (err error) {
var (
userInfos []*model.VipInfoDB
size = 100
endID int
now = time.Now()
dv = now.Format("2006_01")
y = now.Year()
m = now.Month()
salaryDate = time.Date(y, m, s.c.Property.SalaryDay, 0, 0, 0, 0, time.Local)
)
for {
if endID, err = s.dao.SelUserInfoMaxID(context.TODO()); err != nil {
log.Error("s.dao.SelMaxID error(%v)", err)
time.Sleep(time.Minute * 2)
continue
}
break
}
page := endID / size
if endID%size != 0 {
page++
}
for i := 0; i < page; {
log.Info("salary page(%d) total(%d) ....................................", i, page)
startID := i * size
eID := (i + 1) * size
if userInfos, err = s.dao.SelEffectiveScopeVipList(context.TODO(), startID, eID); err != nil {
log.Error("s.dao.SelEffectiveScopeVipList error(%v)", err)
time.Sleep(time.Second * 5)
continue
}
i++
for _, v := range userInfos {
time.Sleep(time.Duration(s.c.Property.SalaryVideoCouponnIterval))
var (
vipType = model.NotVip
)
if v.Status != model.VipStatusNotOverTime && v.Status != model.VipStatusFrozen {
continue
}
if salaryDate.Before(v.OverdueTime.Time()) {
vipType = model.Vip
if salaryDate.Before(v.AnnualVipOverdueTime.Time()) {
vipType = model.AnnualVip
}
}
if vipType == model.NotVip {
continue
}
day := v.OverdueTime.Time().Sub(v.RecentTime.Time()).Hours() / model.DayOfHour
if day < model.VipDaysMonth {
continue
}
if err = s.salaryCoupon(c, v.Mid, model.TimingSalaryType, int8(vipType), dv, model.CouponSalaryTiming); err != nil {
err = errors.Wrapf(err, "salaryCoupon mid(%d)(%v)", v.Mid, v)
log.Error("%+v", err)
continue
}
log.Info("salary suc mid(%d) ....................................", v.Mid)
}
}
return
}
// salaryCoupon salary coupon.
func (s *Service) salaryCoupon(c context.Context, mid int64, salaryType int8, vipType int8, dv string, atonce int8) (err error) {
var (
logs []*model.VideoCouponSalaryLog
hs = map[int8]int64{} // key:coupontype value:salarycount
ms map[string]int64 // key:viptype value:salarycount
)
if logs, err = s.dao.SalaryVideoCouponList(c, mid, dv); err != nil {
err = errors.WithStack(err)
return
}
for _, v := range logs {
hs[v.CouponType] = hs[v.CouponType] + v.CouponCount
}
for _, v := range s.c.Property.SalaryCouponTypes {
ms = s.c.Property.SalaryCouponMaps[fmt.Sprintf("%d", v)]
if len(ms) != 0 {
if salaryType == model.VipSupplyType {
if hs[v] == 0 {
hs[v] = ms[fmt.Sprintf("%d", model.AnnualVip)] - ms[fmt.Sprintf("%d", model.Vip)]
} else {
hs[v] = ms[fmt.Sprintf("%d", model.AnnualVip)] - hs[v]
}
} else {
hs[v] = ms[fmt.Sprintf("%d", vipType)] - hs[v]
}
}
}
for k, count := range hs {
var (
token string
tokenfmt string
)
if count <= 0 {
continue
}
tokenfmt = s.c.Property.SalaryCouponBatchNoMaps[fmt.Sprintf("%d", k)]
if len(tokenfmt) == 0 {
continue
}
token = fmt.Sprintf(tokenfmt, atonce, dv)
if err = s.dao.SalaryCoupon(c, mid, k, count, token); err != nil {
err = errors.Wrapf(err, "s.dao.SalaryCoupon(%d)", mid)
return
}
l := &model.VideoCouponSalaryLog{
Mid: mid,
CouponCount: count,
State: model.HadSalaryState,
Type: salaryType,
CouponType: k,
}
if err = s.dao.AddSalaryLog(c, l, dv); err != nil {
err = errors.WithStack(err)
return
}
if s.c.Property.MsgOpen {
var (
title string
content string
)
title = s.c.Property.SalaryCouponMsgTitleMaps[fmt.Sprintf("%d", k)]
if len(title) == 0 {
continue
}
if salaryType == model.VipSupplyType {
content = s.c.Property.SalaryCouponMsgSupplyContentMaps[fmt.Sprintf("%d", k)]
if len(content) == 0 {
continue
}
content = fmt.Sprintf(content, count)
} else {
content = s.c.Property.SalaryCouponMsgContentMaps[fmt.Sprintf("%d", k)]
if len(content) == 0 {
continue
}
}
s.sendmessage(func() {
s.dao.SendMultipMsg(context.TODO(), fmt.Sprintf("%d", mid), content,
title, model.MsgCouponSalaryMc, model.MsgSystemNotify)
})
}
}
return
}
// SalaryVideoCouponAtOnce salary video coupon at once.
func (s *Service) SalaryVideoCouponAtOnce(c context.Context, nvip *model.VipUserInfoMsg, ovip *model.VipUserInfoMsg, act string) (res int, err error) {
if act == _insertAction {
if err = s.salaryInsertAct(c, nvip); err != nil {
err = errors.Wrapf(err, "salaryInsertAct (%v)", nvip)
return
}
} else if act == _updateAction {
if err = s.salaryUpdateAct(c, nvip, ovip); err != nil {
err = errors.Wrapf(err, "salaryInsertAct (%v)", nvip)
return
}
}
return
}
func (s *Service) salaryInsertAct(c context.Context, nvip *model.VipUserInfoMsg) (err error) {
var (
now = time.Now()
otime time.Time
aotime time.Time
vipType = model.NotVip
zeroTime = now.AddDate(-10, 0, 0)
salaryType int8
dv = now.Format("2006_01")
)
otime, err = time.ParseInLocation(model.TimeFormatSec, nvip.OverdueTime, time.Local)
if err != nil {
log.Error("time.ParseInLocation error(%v)", errors.Wrapf(err, "time(%s)", nvip.OverdueTime))
otime = zeroTime
err = nil
}
aotime, err = time.ParseInLocation(model.TimeFormatSec, nvip.AnnualVipOverdueTime, time.Local)
if err != nil {
aotime = zeroTime
err = nil
}
if nvip.Status != model.VipStatusNotOverTime && nvip.Status != model.VipStatusFrozen {
return
}
days := otime.Sub(now).Hours() / model.DayOfHour
if days < model.VipDaysMonth {
log.Info("cur user not enough send coupon (%+v)", nvip)
return
}
if now.Before(otime) {
vipType = model.Vip
if now.Before(aotime) {
vipType = model.AnnualVip
}
}
switch vipType {
case model.Vip:
salaryType = model.NormalVipSalaryType
case model.AnnualVip:
salaryType = model.AnnualVipSalaryType
default:
return
}
if err = s.salaryCoupon(c, int64(nvip.Mid), salaryType, int8(vipType), dv, model.CouponSalaryAtonce); err != nil {
err = errors.Wrapf(err, "salaryCoupon mid(%d)(%v)", nvip.Mid, nvip)
}
return
}
func (s *Service) salaryUpdateAct(c context.Context, nvip *model.VipUserInfoMsg, ovip *model.VipUserInfoMsg) (err error) {
var (
ovType int
nvType int
expire bool
now = time.Now()
zeroTime = now.AddDate(-10, 0, 0)
ntime time.Time
oatime time.Time
natime time.Time
salaryType int8
dv = now.Format("2006_01")
)
ntime, err = time.ParseInLocation(model.TimeFormatSec, nvip.OverdueTime, time.Local)
if err != nil {
log.Error("time.ParseInLocation error(%v)", errors.Wrapf(err, "time(%s)", nvip.OverdueTime))
ntime = zeroTime
err = nil
}
natime, err = time.ParseInLocation(model.TimeFormatSec, nvip.AnnualVipOverdueTime, time.Local)
if err != nil {
natime = zeroTime
err = nil
}
// check OverdueTime time.
if ntime.Before(now) {
return
}
nvType = model.Vip
// check AnnualVipOverdueTime time.
if now.Before(natime) {
nvType = model.AnnualVip
}
// check old vip info expire.
expire, _ = s.judgeVipExpire(c, ovip)
if expire {
//check open days is enough 31
days := ntime.Sub(now).Hours() / model.DayOfHour
if days < model.VipDaysMonth {
log.Info("cur user not enough send coupon (%+v)", nvip)
return
}
if nvType == model.Vip {
// expire vip -> vip
salaryType = model.NormalVipSalaryType
} else if nvType == model.AnnualVip {
// expire vip -> annual vip
salaryType = model.AnnualVipSalaryType
}
} else {
if ovip.Type == model.Vip {
ovType = model.Vip
}
oatime, err = time.ParseInLocation(model.TimeFormatSec, ovip.AnnualVipOverdueTime, time.Local)
if err != nil {
oatime = zeroTime
err = nil
}
if ovip.Type == model.AnnualVip && oatime.After(now) {
ovType = model.AnnualVip
}
if ovType == model.Vip && nvType == model.AnnualVip {
// normal vip -> annual vip
salaryType = model.VipSupplyType
}
// short vip -> normal vip
recentTime := parseTime(ovip.RecentTime)
otime := parseTime(ovip.OverdueTime)
days := otime.Sub(recentTime).Hours() / model.DayOfHour
if days < model.VipDaysMonth {
//check open days is enough 31
days := ntime.Sub(now).Hours() / model.DayOfHour
if days < model.VipDaysMonth {
log.Info("cur user not enough send coupon (%+v)", nvip)
return
}
if nvType == model.Vip {
// expire vip -> vip
salaryType = model.NormalVipSalaryType
} else if nvType == model.AnnualVip {
// expire vip -> annual vip
salaryType = model.AnnualVipSalaryType
}
}
}
switch salaryType {
case model.NormalVipSalaryType, model.AnnualVipSalaryType, model.VipSupplyType:
if err = s.salaryCoupon(c, int64(nvip.Mid), salaryType, int8(nvType), dv, model.CouponSalaryAtonce); err != nil {
err = errors.Wrapf(err, "salaryCoupon mid(%d)(%v)", int64(nvip.Mid), nvip)
}
}
return
}
// judgeVipExpire judge vip is expire.
func (s *Service) judgeVipExpire(c context.Context, v *model.VipUserInfoMsg) (expire bool, err error) {
var (
now = time.Now()
overdueTime time.Time
zeroTime = now.AddDate(-10, 0, 0)
)
if v.Status != model.VipStatusNotOverTime && v.Status != model.VipStatusFrozen {
expire = true
return
}
overdueTime, err = time.ParseInLocation(model.TimeFormatSec, v.OverdueTime, time.Local)
if err != nil {
log.Error("time.ParseInLocation error(%v)", errors.Wrapf(err, "time(%s)", v.OverdueTime))
overdueTime = zeroTime
err = nil
}
if overdueTime.Before(now) {
expire = true
return
}
return
}

View File

@ -0,0 +1,53 @@
package service
import (
"context"
"time"
"go-common/app/job/main/vip/model"
"go-common/library/log"
"github.com/pkg/errors"
)
//ScanSalaryLog scan salary log.
func (s *Service) ScanSalaryLog(c context.Context) (err error) {
var (
dv = time.Now().Format("2006_01")
olds []*model.OldSalaryLog
size = 1000
endID = 0
)
if endID, err = s.dao.SalaryLogMaxID(context.TODO(), dv); err != nil {
err = errors.WithStack(err)
return
}
page := endID / size
if endID%size != 0 {
page++
}
for i := 0; i < page; {
startID := i * size
eID := (i + 1) * size
if olds, err = s.dao.SelOldSalaryList(context.TODO(), startID, eID, dv); err != nil {
err = errors.WithStack(err)
return
}
i++
for _, v := range olds {
l := &model.VideoCouponSalaryLog{
Mid: v.Mid,
CouponCount: v.CouponCount,
State: v.State,
Type: v.Type,
CouponType: model.SalaryCouponType,
}
if err = s.dao.AddSalaryLog(context.TODO(), l, dv); err != nil {
err = errors.WithStack(err)
log.Error("+%v", err)
continue
}
}
}
return
}

View File

@ -0,0 +1,99 @@
package service
import (
"testing"
"time"
"go-common/app/job/main/vip/model"
. "github.com/smartystreets/goconvey/convey"
)
// go test -test.v -test.run TestServiceSalaryCoupon
func TestServiceSalaryCoupon(t *testing.T) {
Convey("TestServiceSalaryCoupon", t, func() {
var (
err error
mid int64 = 999
st int8 = model.TimingSalaryType
vt int8 = model.AnnualVip
dv = time.Now().Format("2006_01")
atonce = model.CouponSalaryTiming
)
err = s.salaryCoupon(c, mid, st, vt, dv, atonce)
So(err, ShouldBeNil)
})
}
// go test -test.v -test.run TestServiceSalaryInsertAct
func TestServiceSalaryInsertAct(t *testing.T) {
Convey("TestServiceSalaryCoupon", t, func() {
var (
err error
nvip = &model.VipUserInfoMsg{
Mid: 9995,
Status: 1,
OverdueTime: "2018-06-11 18:27:12",
AnnualVipOverdueTime: "2018-06-09 18:27:12",
}
)
err = s.salaryInsertAct(c, nvip)
So(err, ShouldBeNil)
nvip.Mid = 88881
nvip.OverdueTime = "2018-07-31 18:27:12"
nvip.AnnualVipOverdueTime = "2018-07-31 18:27:12"
err = s.salaryInsertAct(c, nvip)
So(err, ShouldBeNil)
})
}
// go test -test.v -test.run TestServiceSalaryUpdateAct
func TestServiceSalaryUpdateAct(t *testing.T) {
Convey("TestServiceSalaryUpdateAct", t, func() {
var (
err error
nvip = &model.VipUserInfoMsg{
Mid: 65,
Status: 2,
OverdueTime: "2019-06-11 18:27:12",
AnnualVipOverdueTime: "2019-06-11 18:27:12",
}
ovip = &model.VipUserInfoMsg{
Mid: 65,
Status: 2,
OverdueTime: "2018-06-16 18:27:12",
AnnualVipOverdueTime: "2018-06-09 18:27:12",
Type: 1,
}
)
// vip -> a vip
err = s.salaryUpdateAct(c, nvip, ovip)
So(err, ShouldBeNil)
// not vip -> vip
ovip.OverdueTime = "2017-06-11 18:27:12"
nvip.OverdueTime = "2018-07-31 18:27:12"
nvip.AnnualVipOverdueTime = "2018-07-31 18:27:12"
ovip.Mid = 66
nvip.Mid = 66
err = s.salaryUpdateAct(c, nvip, ovip)
So(err, ShouldBeNil)
// vip - > a vip
ovip.OverdueTime = "2018-08-19 18:27:12"
nvip.AnnualVipOverdueTime = "2019-06-11 18:27:12"
ovip.Mid = 66
nvip.Mid = 66
err = s.salaryUpdateAct(c, nvip, ovip)
So(err, ShouldBeNil)
nvip.Mid = 67
err = s.salaryInsertAct(c, nvip)
So(err, ShouldBeNil)
})
}
// go test -test.v -test.run TestServiceScanSalaryLog
func TestServiceScanSalaryLog(t *testing.T) {
Convey("TestServiceScanSalaryLog", t, func() {
err := s.ScanSalaryLog(c)
So(err, ShouldBeNil)
})
}

View File

@ -0,0 +1,728 @@
package service
import (
"context"
"encoding/json"
xlog "log"
"strconv"
"sync"
"time"
"go-common/app/job/main/vip/conf"
"go-common/app/job/main/vip/dao"
"go-common/app/job/main/vip/model"
couponrpc "go-common/app/service/main/coupon/rpc/client"
v1 "go-common/app/service/main/vip/api"
"go-common/library/log"
"go-common/library/queue/databus"
"github.com/pkg/errors"
"github.com/robfig/cron"
)
const (
_tableUserInfo = "vip_user_info"
_tablePayOrder = "vip_pay_order"
_insertAction = "insert"
_updateAction = "update"
_deleteAction = "delete"
notifyAction = "updateVip"
_ps = 50
_defsleepmsec = 100
)
//Service vip service
type Service struct {
dao *dao.Dao
c *conf.Config
//vipRPC *client.Service
reducePayOrder map[string]*model.VipPayOrder
appMap map[int64]*model.VipAppInfo
confMap map[string]*model.VipConfig
cleanVipCache chan int64
cleanAppCache chan *model.AppCache
ds *databus.Databus
handlerFailPayOrder chan *model.VipPayOrder
handlerFailUserInfo chan *model.VipUserInfo
handlerFailRechargeOrder chan *model.VipPayOrder
handlerFailVipbuy chan *model.VipBuyResq
handlerInsertOrder chan *model.VipPayOrder
handlerUpdateOrder chan *model.VipPayOrder
handlerRechargeOrder chan *model.VipPayOrder
handlerInsertUserInfo chan *model.VipUserInfo
handlerUpdateUserInfo chan *model.VipUserInfo
handlerStationActive chan *model.VipPayOrder
handlerAutoRenewLog chan *model.VipUserInfo
handlerAddVipHistory chan *model.VipChangeHistoryMsg
handlerAddBcoinSalary chan *model.VipBcoinSalaryMsg
handlerUpdateBcoinSalary chan *model.VipBcoinSalaryMsg
handlerDelBcoinSalary chan *model.VipBcoinSalaryMsg
notifycouponchan chan func()
accLogin *databus.Databus
frozenDate time.Duration
newVipDatabus *databus.Databus
salaryCoupnDatabus *databus.Databus
accountNoitfyDatabus *databus.Databus
couponNotifyDatabus *databus.Databus
autoRenewdDatabus *databus.Databus
// waiter
waiter sync.WaitGroup
closed bool
sendmsgchan chan func()
couponRPC *couponrpc.Service
// vip service
vipgRPC v1.VipClient
}
//New new service
func New(c *conf.Config) (s *Service) {
s = &Service{
c: c,
dao: dao.New(c),
//vipRPC: client.New(c.VipRPC),
cleanVipCache: make(chan int64, 10240),
confMap: make(map[string]*model.VipConfig),
cleanAppCache: make(chan *model.AppCache, 10240),
handlerFailPayOrder: make(chan *model.VipPayOrder, 10240),
handlerFailUserInfo: make(chan *model.VipUserInfo, 10240),
handlerFailRechargeOrder: make(chan *model.VipPayOrder, 10240),
handlerInsertOrder: make(chan *model.VipPayOrder, 10240),
handlerRechargeOrder: make(chan *model.VipPayOrder, 10240),
handlerUpdateOrder: make(chan *model.VipPayOrder, 10240),
handlerInsertUserInfo: make(chan *model.VipUserInfo, 10240),
handlerUpdateUserInfo: make(chan *model.VipUserInfo, 10240),
handlerStationActive: make(chan *model.VipPayOrder, 10240),
handlerAutoRenewLog: make(chan *model.VipUserInfo, 10240),
handlerAddVipHistory: make(chan *model.VipChangeHistoryMsg, 10240),
handlerAddBcoinSalary: make(chan *model.VipBcoinSalaryMsg, 10240),
handlerUpdateBcoinSalary: make(chan *model.VipBcoinSalaryMsg, 10240),
handlerDelBcoinSalary: make(chan *model.VipBcoinSalaryMsg, 10240),
handlerFailVipbuy: make(chan *model.VipBuyResq, 10240),
notifycouponchan: make(chan func(), 10240),
ds: databus.New(c.Databus.OldVipBinLog),
newVipDatabus: databus.New(c.Databus.NewVipBinLog),
accLogin: databus.New(c.Databus.AccLogin),
frozenDate: time.Duration(c.Property.FrozenDate),
reducePayOrder: make(map[string]*model.VipPayOrder),
sendmsgchan: make(chan func(), 10240),
accountNoitfyDatabus: databus.New(c.Databus.AccountNotify),
couponRPC: couponrpc.New(c.RPCClient2.Coupon),
}
vipgRPC, err := v1.NewClient(c.VipClient)
if err != nil {
panic(err)
}
s.vipgRPC = vipgRPC
t := cron.New()
go s.loadappinfoproc()
go s.cleanappcacheretryproc()
go s.cleanvipretryproc()
go s.sendmessageproc()
go s.handlerfailpayorderproc()
go s.handlerfailrechargeorderproc()
go s.handlerfailuserinfoproc()
go s.handlerautorenewlogproc()
go s.handlerdelbcoinproc()
if c.Databus.SalaryCoupon != nil {
s.salaryCoupnDatabus = databus.New(c.Databus.SalaryCoupon)
s.waiter.Add(1)
go s.salarycouponproc()
}
if c.Databus.CouponNotify != nil {
s.couponNotifyDatabus = databus.New(c.Databus.CouponNotify)
go s.couponnotifyproc()
s.waiter.Add(1)
go s.couponnotifybinlogproc()
}
for i := 0; i < s.c.Property.HandlerThread; i++ {
go s.handlerinsertorderproc()
go s.handlerupdateorderproc()
go s.handlerinsertuserinfoproc()
go s.handlerupdateuserinfoproc()
go s.handleraddchangehistoryproc()
go s.handleraddbcoinproc()
go s.handlerupdatebcoinproc()
go s.handlerupdaterechargeorderproc()
}
for i := 0; i < s.c.Property.ReadThread; i++ {
go s.readdatabusproc()
}
go s.readnewvipdatabusproc()
if c.Property.FrozenCron != "" {
go s.accloginproc()
t.AddFunc(c.Property.FrozenCron, s.unFrozenJob)
}
t.AddFunc(c.Property.UpdateUserInfoCron, s.updateUserInfoJob)
t.AddFunc(c.Property.SalaryVideoCouponCron, s.salaryVideoCouponJob)
t.AddFunc(c.Property.PushDataCron, s.pushDataJob)
t.AddFunc(c.Property.EleEompensateCron, s.eleEompensateJob)
//t.AddFunc(c.Property.HadExpiredMsgCron, s.hadExpiredMsgJob)
//t.AddFunc(c.Property.WillExpireMsgCron, s.willExpiredMsgJob)
//t.AddFunc(c.Property.SendMessageCron, s.sendMessageJob)
//t.AddFunc(c.Property.AutoRenewCron, s.autoRenewJob)
//t.AddFunc(c.Property.SendBcoinCron, s.sendBcoinJob)
t.Start()
go s.consumercheckproc()
if c.Databus.AutoRenew != nil {
s.autoRenewdDatabus = databus.New(c.Databus.AutoRenew)
s.waiter.Add(1)
go s.retryautorenewpayproc()
}
return
}
func (s *Service) readnewvipdatabusproc() {
defer func() {
if r := recover(); r != nil {
r = errors.WithStack(r.(error))
log.Error("Runtime error caught: %+v", r)
go s.readnewvipdatabusproc()
}
}()
var err error
for msg := range s.newVipDatabus.Messages() {
val := msg.Value
if err = msg.Commit(); err != nil {
log.Error("readdatabusproc msg.commit() error(%v)", err)
msg.Commit()
}
log.Info("cur consumer new vip db message(%v)", string(msg.Value))
message := new(model.Message)
if err = json.Unmarshal(val, message); err != nil {
log.Error("readnewvipdatabusproc json.unmarshal val(%+v) error(%+v)", string(val), err)
continue
}
if message.Table == "vip_user_info" {
userInfo := new(model.VipUserInfoNewMsg)
if err = json.Unmarshal(message.New, userInfo); err != nil {
log.Error("readdatabusproc json.Unmarshal val(%v) error(%v)", string(message.New), err)
continue
}
vipUser := convertUserInfoByNewMsg(userInfo)
s.dao.DelInfoCache(context.Background(), vipUser.Mid)
if message.Action == _insertAction {
if vipUser.PayType == model.AutoRenew {
select {
case s.handlerAutoRenewLog <- vipUser:
default:
log.Error("s.handlerAutoRenewLog full!")
}
}
} else if message.Action == _updateAction {
oldUserMsg := new(model.VipUserInfoNewMsg)
if err = json.Unmarshal(message.Old, oldUserMsg); err != nil {
log.Error("readdatabusproc json.Unmarshal val(%v) error(%v)", string(message.Old), err)
continue
}
oldUser := convertUserInfoByNewMsg(oldUserMsg)
if oldUser.PayType != vipUser.PayType {
select {
case s.handlerAutoRenewLog <- vipUser:
default:
log.Error("s.handlerAutoRenewLog full update!")
}
}
}
s.pubAccountNotify(vipUser.Mid)
}
}
}
func (s *Service) readdatabusproc() {
defer func() {
if r := recover(); r != nil {
r = errors.WithStack(r.(error))
log.Error("Runtime error caught: %+v", r)
go s.readdatabusproc()
}
}()
var err error
for msg := range s.ds.Messages() {
val := msg.Value
message := new(model.Message)
if err = json.Unmarshal(val, message); err != nil {
log.Error("readdatabusproc json.Unmarshal val(%v) error(%v)", string(val), err)
if err = msg.Commit(); err != nil {
log.Error("msg.commit() error(%v)", err)
}
continue
}
if message.Table == "vip_pay_order" {
order := new(model.VipPayOrderOldMsg)
if err = json.Unmarshal(message.New, order); err != nil {
log.Error("readdatabusproc json.Unmarshal val(%v) error(%v)", string(message.New), err)
if err = msg.Commit(); err != nil {
log.Error("msg.commit() error(%v)", err)
}
continue
}
payOrder := s.convertPayOrder(order)
if message.Action == "insert" {
select {
case s.handlerInsertOrder <- payOrder:
default:
xlog.Panic("s.handlerInsertOrder full!")
}
} else if message.Action == "update" {
select {
case s.handlerUpdateOrder <- payOrder:
default:
xlog.Panic("s.handlerUpdateOrder full!")
}
}
} else if message.Table == "vip_recharge_order" {
order := new(model.VipRechargeOrderMsg)
if err = json.Unmarshal(message.New, order); err != nil {
log.Error("readdatabusproc json.Unmarshal val(%v) error(%v)", string(message.New), err)
if err = msg.Commit(); err != nil {
log.Error("msg.commit() error(%v)", err)
}
continue
}
payOrder := s.convertPayOrderByMsg(order)
if message.Action == "update" {
select {
case s.handlerRechargeOrder <- payOrder:
default:
xlog.Panic("s.handlerRechargeOrder full!")
}
} else if message.Action == "insert" {
if len(payOrder.ThirdTradeNo) > 0 {
select {
case s.handlerRechargeOrder <- payOrder:
default:
xlog.Panic("s.handlerRechargeOrder full!")
}
}
}
} else if message.Table == "vip_user_info" {
userInfo := new(model.VipUserInfoMsg)
if err = json.Unmarshal(message.New, userInfo); err != nil {
log.Error("readdatabusproc json.Unmarshal val(%v) error(%v)", string(message.New), err)
if err = msg.Commit(); err != nil {
log.Error("msg.commit() error(%v)", err)
}
continue
}
vipUser := convertMsgToUserInfo(userInfo)
if message.Action == "insert" {
select {
case s.handlerInsertUserInfo <- vipUser:
default:
xlog.Panic("s.handlerInsertUserInfo full!")
}
} else if message.Action == "update" {
oldUser := new(model.VipUserInfoMsg)
if err = json.Unmarshal(message.Old, oldUser); err != nil {
log.Error("readdatabusproc json.Unmarshal val(%v) error(%v)", string(message.Old), err)
if err = msg.Commit(); err != nil {
log.Error("msg.commit() error(%v)", err)
}
continue
}
vipUser.OldVer = oldUser.Ver
select {
case s.handlerUpdateUserInfo <- vipUser:
default:
xlog.Panic("s.handlerUpdateUserInfo full!")
}
}
if !s.grayScope(userInfo.Mid) {
s.cleanCache(userInfo.Mid)
}
} else if message.Table == "vip_change_history" {
historyMsg := new(model.VipChangeHistoryMsg)
if err = json.Unmarshal(message.New, historyMsg); err != nil {
log.Error("readdatabusproc json.Unmarshal val(%v) error(%v)", string(message.New), err)
if err = msg.Commit(); err != nil {
log.Error("msg.commit() error(%v)", err)
}
continue
}
if message.Action == "insert" {
select {
case s.handlerAddVipHistory <- historyMsg:
default:
xlog.Panic("s.handlerAddVipHistory full!")
}
}
} else if message.Table == "vip_bcoin_salary" {
bcoinMsg := new(model.VipBcoinSalaryMsg)
if err = json.Unmarshal(message.New, bcoinMsg); err != nil {
log.Error("readdatabusproc json.Unmarshal val(%v) error(%v)", string(message.New), err)
if err = msg.Commit(); err != nil {
log.Error("msg.commit() error(%v)", err)
}
continue
}
if message.Action == _insertAction {
select {
case s.handlerAddBcoinSalary <- bcoinMsg:
default:
xlog.Panic("s.handlerAddBcoinSalary full!")
}
} else if message.Action == _updateAction {
select {
case s.handlerUpdateBcoinSalary <- bcoinMsg:
default:
xlog.Panic("s.handlerUpdateBcoinSalary full!")
}
} else if message.Action == _deleteAction {
select {
case s.handlerDelBcoinSalary <- bcoinMsg:
default:
xlog.Panic("s.handlerDelBcoinSalary full!")
}
}
}
if err = msg.Commit(); err != nil {
log.Error("readdatabusproc msg.commit() error(%v)", err)
msg.Commit()
}
log.Info("cur consumer message(%v)", string(msg.Value))
}
}
func (s *Service) cleanCache(mid int64) {
var (
hv = new(model.HandlerVip)
err error
)
hv.Type = 2
hv.Days = 0
hv.Months = 0
hv.Mid = mid
if err = s.cleanCacheAndNotify(context.TODO(), hv); err != nil {
select {
case s.cleanVipCache <- hv.Mid:
default:
xlog.Panic("s.cleanVipCache full!")
}
}
s.pubAccountNotify(mid)
}
func (s *Service) pubAccountNotify(mid int64) (err error) {
data := new(struct {
Mid int64 `json:"mid"`
Action string `json:"action"`
})
data.Mid = mid
data.Action = notifyAction
if err = s.accountNoitfyDatabus.Send(context.TODO(), strconv.FormatInt(mid, 10), data); err != nil {
log.Error("send (%+v) error(%+v)", data, err)
}
log.Info("send(mid:%+v) data:%+v", mid, data)
return
}
func (s *Service) loadappinfoproc() {
defer func() {
if r := recover(); r != nil {
r = errors.WithStack(r.(error))
log.Error("Runtime error caught: %+v", r)
go s.loadappinfoproc()
}
}()
for {
s.loadAppInfo()
time.Sleep(time.Minute * 2)
}
}
func (s *Service) loadAppInfo() {
var (
res []*model.VipAppInfo
err error
)
if res, err = s.dao.SelAppInfo(context.TODO()); err != nil {
log.Error("loadAppInfo SelAppInfo error(%v)", err)
return
}
aMap := make(map[int64]*model.VipAppInfo, len(res))
for _, v := range res {
aMap[v.ID] = v
}
s.appMap = aMap
bytes, _ := json.Marshal(res)
log.Info("load app success :%v", string(bytes))
}
func (s *Service) cleanvipretryproc() {
defer func() {
if r := recover(); r != nil {
r = errors.WithStack(r.(error))
log.Error("Runtime error caught: %+v", r)
go s.cleanvipretryproc()
}
}()
for {
mid := <-s.cleanVipCache
s.cleanVipRetry(mid)
}
}
func (s *Service) cleanVipRetry(mid int64) {
hv := new(model.HandlerVip)
hv.Type = 2
hv.Days = 0
hv.Months = 0
hv.Mid = mid
s.dao.DelInfoCache(context.Background(), mid)
for i := 0; i < s.c.Property.Retry; i++ {
if err := s.cleanCacheAndNotify(context.TODO(), hv); err == nil {
break
}
s.dao.DelVipInfoCache(context.TODO(), int64(hv.Mid))
}
log.Info("handler success cache fail mid(%v)", mid)
}
func (s *Service) cleanappcacheretryproc() {
defer func() {
if r := recover(); r != nil {
r = errors.WithStack(r.(error))
log.Error("Runtime error caught: %+v", r)
go s.cleanappcacheretryproc()
}
}()
for {
ac := <-s.cleanAppCache
s.cleanAppCacheRetry(ac)
}
}
func (s *Service) cleanAppCacheRetry(ac *model.AppCache) {
appInfo := s.appMap[ac.AppID]
hv := new(model.HandlerVip)
hv.Type = 2
hv.Days = 0
hv.Months = 0
hv.Mid = ac.Mid
for i := 0; i < s.c.Property.Retry; i++ {
if err := s.dao.SendAppCleanCache(context.TODO(), hv, appInfo); err == nil {
break
}
}
log.Info("handler success cache app fail appInfo(%v)", ac)
}
func (s *Service) salarycouponproc() {
defer func() {
if r := recover(); r != nil {
r = errors.WithStack(r.(error))
log.Error("Runtime error caught: %+v", r)
go s.salarycouponproc()
}
}()
defer s.waiter.Done()
var (
err error
msg *databus.Message
msgChan = s.salaryCoupnDatabus.Messages()
ok bool
c = context.Background()
)
for {
msg, ok = <-msgChan
if !ok || s.closed {
log.Info("salary coupon msgChan closed")
return
}
msg.Commit()
v := &model.Message{}
if err = json.Unmarshal([]byte(msg.Value), v); err != nil {
log.Error("json.Unmarshal(%v) err(%v)", v, err)
continue
}
if v.Table != _tableUserInfo {
continue
}
nvip := &model.VipUserInfoMsg{}
if err = json.Unmarshal(v.New, &nvip); err != nil {
log.Error("salary new json.Unmarshal values(%v),error(%v)", string(v.New), err)
continue
}
ovip := &model.VipUserInfoMsg{}
if v.Action != _insertAction {
if err = json.Unmarshal(v.Old, &ovip); err != nil {
log.Error("salary old json.Unmarshal values(%v),error(%v)", string(v.Old), err)
continue
}
}
log.Info("salary coupon start mid(%d)", nvip.Mid)
if _, err = s.SalaryVideoCouponAtOnce(c, nvip, ovip, v.Action); err != nil {
log.Error("SalaryVideoCouponAtOnce fail(%d) nvip(%v) ovip(%v) %s error(%v)", nvip.Mid, nvip, ovip, v.Action, err)
continue
}
log.Info("salary coupon suc mid(%d)", nvip.Mid)
}
}
func (s *Service) couponnotifybinlogproc() {
defer func() {
if r := recover(); r != nil {
r = errors.WithStack(r.(error))
log.Error("Runtime error couponnotifybinlogproc caught: %+v", r)
go s.couponnotifybinlogproc()
}
}()
defer s.waiter.Done()
var (
err error
msg *databus.Message
msgChan = s.couponNotifyDatabus.Messages()
ok bool
c = context.Background()
)
for {
msg, ok = <-msgChan
if !ok || s.closed {
log.Info("coupon notify couponnotifybinlogproc msgChan closed")
return
}
if err = msg.Commit(); err != nil {
log.Error("couponnotifybinlogproc msg.Commit err(%v)", err)
continue
}
log.Info("cur consumer couponnotifybinlogproc(%v)", string(msg.Value))
v := &model.Message{}
if err = json.Unmarshal([]byte(msg.Value), v); err != nil {
log.Error("couponnotifybinlogproc json.Unmarshal(%v) err(%v)", v, err)
continue
}
if v.Table != _tablePayOrder || v.Action != _updateAction {
continue
}
newo := new(model.VipPayOrderNewMsg)
if err = json.Unmarshal(v.New, newo); err != nil {
log.Error("couponnotifybinlogproc json.Unmarshal val(%v) error(%v)", string(v.New), err)
continue
}
oldo := new(model.VipPayOrderNewMsg)
if err = json.Unmarshal(v.Old, oldo); err != nil {
log.Error("couponnotifybinlogproc json.Unmarshal val(%v) error(%v)", string(v.Old), err)
continue
}
if newo == nil || oldo == nil {
continue
}
if oldo.Status != model.PAYING {
continue
}
if newo.Status != model.SUCCESS && newo.Status != model.FAILED {
continue
}
if newo.CouponMoney <= 0 {
continue
}
s.couponnotify(func() {
s.CouponNotify(c, newo)
})
}
}
func (s *Service) updateUserInfoJob() {
log.Info("update user info job start ....................................")
s.ScanUserInfo(context.TODO())
log.Info("update user info job end ........................................")
}
func (s *Service) salaryVideoCouponJob() {
log.Info("salary video coupon job start ....................................")
var err error
if ok := s.dao.AddTransferLock(context.TODO(), "_transferLock"); !ok {
log.Info("salary video coupon job had run ....................................")
return
}
if err = s.ScanSalaryVideoCoupon(context.TODO()); err != nil {
log.Error("ScanSalaryVideoCoupon error(%v)", err)
return
}
log.Info("salary video coupon job end ........................................")
}
//Ping check db live
func (s *Service) Ping(c context.Context) (err error) {
return s.dao.Ping(c)
}
// Close all resource.
func (s *Service) Close() {
defer s.waiter.Wait()
s.closed = true
s.salaryCoupnDatabus.Close()
s.dao.Close()
s.ds.Close()
s.newVipDatabus.Close()
}
func (s *Service) sendmessageproc() {
defer func() {
if x := recover(); x != nil {
log.Error("service.sendmessageproc panic(%v)", x)
go s.sendmessageproc()
log.Info("service.sendmessageproc recover")
}
}()
for {
f := <-s.sendmsgchan
f()
}
}
func (s *Service) sendmessage(f func()) {
defer func() {
if x := recover(); x != nil {
log.Error("service.sendmessage panic(%v)", x)
}
}()
select {
case s.sendmsgchan <- f:
default:
log.Error("service.sendmessage chan full")
}
}
func (s *Service) consumercheckproc() {
for {
time.Sleep(time.Second)
log.Info("consumercheckproc chan(cleanVipCache) size: %d", len(s.cleanVipCache))
log.Info("consumercheckproc chan(cleanAppCache) size: %d", len(s.cleanAppCache))
log.Info("consumercheckproc chan(handlerFailPayOrder) size: %d", len(s.handlerFailPayOrder))
log.Info("consumercheckproc chan(handlerFailUserInfo) size: %d", len(s.handlerFailUserInfo))
log.Info("consumercheckproc chan(handlerFailRechargeOrder) size: %d", len(s.handlerFailRechargeOrder))
log.Info("consumercheckproc chan(handlerFailVipbuy) size: %d", len(s.handlerFailVipbuy))
log.Info("consumercheckproc chan(handlerInsertOrder) size: %d", len(s.handlerInsertOrder))
log.Info("consumercheckproc chan(handlerUpdateOrder) size: %d", len(s.handlerUpdateOrder))
log.Info("consumercheckproc chan(handlerRechargeOrder) size: %d", len(s.handlerRechargeOrder))
log.Info("consumercheckproc chan(handlerInsertUserInfo) size: %d", len(s.handlerInsertUserInfo))
log.Info("consumercheckproc chan(handlerUpdateUserInfo) size: %d", len(s.handlerUpdateUserInfo))
log.Info("consumercheckproc chan(handlerStationActive) size: %d", len(s.handlerStationActive))
log.Info("consumercheckproc chan(handlerAutoRenewLog) size: %d", len(s.handlerAutoRenewLog))
log.Info("consumercheckproc chan(handlerAddVipHistory) size: %d", len(s.handlerAddVipHistory))
log.Info("consumercheckproc chan(handlerAddBcoinSalary) size: %d", len(s.handlerAddBcoinSalary))
log.Info("consumercheckproc chan(handlerUpdateBcoinSalary) size: %d", len(s.handlerUpdateBcoinSalary))
log.Info("consumercheckproc chan(handlerDelBcoinSalary) size: %d", len(s.handlerDelBcoinSalary))
log.Info("consumercheckproc chan(sendmsgchan) size: %d", len(s.sendmsgchan))
log.Info("consumercheckproc chan(notifycouponchan) size: %d", len(s.notifycouponchan))
}
}

View File

@ -0,0 +1,117 @@
package service
import (
"context"
"flag"
"testing"
"time"
"go-common/app/job/main/vip/conf"
"go-common/app/job/main/vip/model"
"go-common/library/log"
. "github.com/smartystreets/goconvey/convey"
)
var (
s *Service
c context.Context
)
func init() {
flag.Set("conf", "../cmd/vip-job-test.toml")
if err := conf.Init(); err != nil {
panic(err)
}
c = context.TODO()
log.Init(conf.Conf.Xlog)
defer log.Close()
s = New(conf.Conf)
time.Sleep(time.Second * 2)
}
func Test_ScanUserInfo(t *testing.T) {
Convey("should return true err == nil", t, func() {
err := s.ScanUserInfo(context.TODO())
So(err, ShouldBeNil)
})
}
func TestService_HadExpiredMsgJob(t *testing.T) {
Convey("had expireMsg job", t, func() {
s.hadExpiredMsgJob()
})
}
func TestService_WillExpiredMsgJob(t *testing.T) {
Convey("had expire msg job", t, func() {
s.willExpiredMsgJob()
})
}
func TestService_SendMessageJob(t *testing.T) {
Convey("send message job", t, func() {
s.sendMessageJob()
})
}
func TestService_SendBcoinJob(t *testing.T) {
Convey("send bcoin job", t, func() {
s.sendBcoinJob()
})
}
func TestSalaryVideoCouponJob(t *testing.T) {
Convey("salaryVideoCouponJob err == nil", t, func() {
s.salaryVideoCouponJob()
s.salaryVideoCouponJob()
})
}
func TestService_HandlerVipChangeHistory(t *testing.T) {
Convey("handlervip change history ", t, func() {
err := s.HandlerVipChangeHistory()
So(err, ShouldBeNil)
})
}
func TestService_HandlerBcoin(t *testing.T) {
Convey(" handler bcoin history ", t, func() {
err := s.HandlerBcoin()
So(err, ShouldBeNil)
})
}
func TestService_HandlerPayOrder(t *testing.T) {
Convey("handler pay order", t, func() {
err := s.HandlerPayOrder()
So(err, ShouldBeNil)
})
}
func Test_push(t *testing.T) {
Convey("handler push data err should be nil", t, func() {
err := s.pushData(context.TODO())
So(err, ShouldBeNil)
})
}
func TestService_CheckBcoinData(t *testing.T) {
Convey("check bcoin data", t, func() {
mids, err := s.CheckBcoinData(context.TODO())
So(mids, ShouldBeEmpty)
So(err, ShouldBeNil)
})
}
func TestService_CheckChangeHistory(t *testing.T) {
Convey("check change history", t, func() {
mids, err := s.CheckChangeHistory(context.TODO())
So(mids, ShouldBeEmpty)
So(err, ShouldBeNil)
})
}
func Test_HandlerAutoRenewLogInfo(t *testing.T) {
Convey("err should be nil", t, func() {
err := s.handlerAutoRenewLogInfo(context.TODO(), &model.VipUserInfo{Mid: 2089809, PayType: model.AutoRenew, PayChannelID: 100})
So(err, ShouldBeNil)
})
}

View File

@ -0,0 +1,96 @@
package service
import (
"context"
"time"
"go-common/app/job/main/vip/model"
"go-common/library/log"
)
// SyncAllUser 同步旧user——info到新db.
// FIXME 切新db后删除.
func (s *Service) SyncAllUser(c context.Context) {
var (
err error
maxID int
size = s.c.Property.BatchSize
ids = []int64{}
ousers = make(map[int64]*model.VipUserInfoOld, size)
nusers = make(map[int64]*model.VipUserInfo, _ps)
updateDB = s.c.Property.UpdateDB
nu *model.VipUserInfo
ok bool
)
if maxID, err = s.dao.SelOldUserInfoMaxID(context.TODO()); err != nil {
log.Error("sync job s.dao.SelOldUserInfoMaxID err(%+v)", err)
return
}
page := maxID / size
if maxID%size != 0 {
page++
}
log.Info("sync job vip_user_info total(%d)", page)
for i := 0; i < page; i++ {
log.Info("sync job vip_user_info page index(%d) total(%d)", i, page)
startID := i * size
endID := (i + 1) * size
if endID > maxID {
endID = maxID
}
if ousers, err = s.dao.SelOldUserInfoMaps(context.TODO(), startID, endID); err != nil {
log.Error("sync job s.dao.SelOldUserInfoMaps(%d, %d) err(%+v)", startID, endID, err)
return
}
j := 1
for _, v := range ousers {
ids = append(ids, v.Mid)
if j%_ps == 0 || j == len(ousers) {
if nusers, err = s.dao.SelVipByIds(context.TODO(), ids); err != nil {
return
}
for _, mid := range ids {
var ou *model.VipUserInfoOld
if ou, ok = ousers[mid]; !ok {
log.Warn("sync job old not found %d", mid)
continue
}
if nu, ok = nusers[mid]; !ok {
log.Warn("sync job need insert to new %d, old(%+v), toNew(%+v)", mid, ou, ou.ToNew())
if updateDB {
s.dao.SyncAddUser(context.Background(), ou.ToNew())
}
continue
}
if ou.RecentTime <= 0 {
ou.RecentTime = ou.Mtime
}
if nu.Type != ou.Type ||
nu.Status != ou.Status ||
!nu.StartTime.Time().Equal(ou.StartTime.Time()) ||
!nu.OverdueTime.Time().Equal(ou.OverdueTime.Time()) ||
!nu.AnnualVipOverdueTime.Time().Equal(ou.AnnualVipOverdueTime.Time()) ||
!nu.Ctime.Time().Equal(ou.Ctime.Time()) ||
!nu.Mtime.Time().Equal(ou.Mtime.Time()) ||
nu.PayType != ou.IsAutoRenew ||
nu.PayChannelID != ou.PayChannelID ||
!nu.IosOverdueTime.Time().Equal(ou.IosOverdueTime.Time()) ||
nu.Ver != ou.Ver ||
!nu.RecentTime.Time().Equal(ou.RecentTime.Time()) {
log.Warn("sync job need update to new %d, old(%+v), new(%+v), toNew(%+v)", mid, ou, nu, ou.ToNew())
if updateDB {
s.dao.SyncUpdateUser(context.Background(), ou.ToNew(), nu.Ver)
}
continue
}
}
log.Info("sync job vip_user_info page index(%d) ids(%+v)", j, ids)
// reset
ids = []int64{}
}
j++
}
log.Info("sync job vip_user_info page index(%d) end", i)
time.Sleep(time.Millisecond * _defsleepmsec)
}
}

View File

@ -0,0 +1,14 @@
package service
import (
"context"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func Test_SyncAllUser(t *testing.T) {
Convey("Test_SyncAllUser", t, func() {
s.SyncAllUser(context.Background())
})
}

View File

@ -0,0 +1,595 @@
package service
import (
"context"
"crypto/md5"
"encoding/hex"
"fmt"
"time"
"go-common/app/job/main/vip/model"
"go-common/library/database/sql"
"go-common/library/log"
"go-common/library/sync/errgroup"
xtime "go-common/library/time"
"github.com/pkg/errors"
)
const (
iapChannelID = 100
)
func (s *Service) cleanCacheAndNotify(c context.Context, hv *model.HandlerVip) (err error) {
s.dao.DelInfoCache(c, hv.Mid)
if err = s.dao.SendCleanCache(c, hv); err != nil {
return
}
if err = s.dao.DelVipInfoCache(c, int64(hv.Mid)); err != nil {
log.Error("del vip info cache (mid:%v) error(%+v)", hv.Mid, err)
return
}
eg, ec := errgroup.WithContext(c)
for _, app := range s.appMap {
ta := app
eg.Go(func() error {
if err = s.dao.SendAppCleanCache(ec, hv, ta); err == nil {
log.Info("SendAppCleanCache success hv(%v) app(%v)", hv, ta)
} else {
ac := new(model.AppCache)
ac.AppID = ta.ID
ac.Mid = hv.Mid
s.cleanAppCache <- ac
}
return nil
})
}
if err = eg.Wait(); err != nil {
log.Error(" eg.Wait err(%+v)", err)
}
err = nil
return
}
//ScanUserInfo scan all userinfo update status
func (s *Service) ScanUserInfo(c context.Context) (err error) {
var (
ot = time.Now().Format("2006-01-02 15:04:05")
userInfos []*model.VipUserInfo
size = 2000
endID = 0
)
for {
if endID, err = s.dao.SelOldUserInfoMaxID(context.TODO()); err != nil {
time.Sleep(time.Minute * 2)
continue
}
break
}
page := endID / size
if endID%size != 0 {
page++
}
for i := 0; i < page; {
startID := i * size
eID := (i + 1) * size
if userInfos, err = s.dao.SelVipList(context.TODO(), startID, eID, ot); err != nil {
time.Sleep(time.Second * 5)
continue
}
i++
for _, v := range userInfos {
s.updateUserInfo(context.TODO(), v)
}
}
return
}
func (s *Service) updateUserInfo(c context.Context, v *model.VipUserInfo) (err error) {
var (
curTime = time.Now()
fType = v.Type
fStatus = v.Status
)
if v.AnnualVipOverdueTime.Time().Before(curTime) {
fType = model.Vip
}
if v.OverdueTime.Time().Before(curTime) {
fStatus = model.VipStatusOverTime
}
if fType != v.Type || fStatus != v.Status {
v.Type = fType
v.Status = fStatus
if v.Status == model.VipStatusOverTime && v.PayChannelID == iapChannelID {
v.PayType = model.Normal
}
if _, err = s.dao.UpdateVipUser(c, int64(v.Mid), v.Status, v.Type, v.PayType); err != nil {
return
}
s.dao.DelInfoCache(c, v.Mid)
s.dao.DelVipInfoCache(c, int64(v.Mid))
}
return
}
func (s *Service) handlerautorenewlogproc() {
var (
err error
)
defer func() {
if x := recover(); x != nil {
log.Error("service.handlerautorenewlogproc panic(%v)", x)
go s.handlerautorenewlogproc()
log.Info("service.handlerautorenewlogproc recover")
}
}()
for {
user := <-s.handlerAutoRenewLog
for i := 0; i <= s.c.Property.Retry; i++ {
if err = s.handlerAutoRenewLogInfo(context.TODO(), user); err == nil {
break
}
log.Error("%+v", err)
time.Sleep(2 * time.Second)
}
}
}
func (s *Service) handlerAutoRenewLogInfo(c context.Context, user *model.VipUserInfo) (err error) {
var (
payOrder *model.VipPayOrder
paylog *model.VipPayOrderLog
rlog *model.VipPayOrderLog
)
if user.PayType == model.AutoRenew {
if user.PayChannelID == iapChannelID {
if payOrder, err = s.dao.SelPayOrderByMid(c, user.Mid, model.IAPAutoRenew, model.SUCCESS); err != nil {
err = errors.WithStack(err)
return
}
if payOrder == nil {
err = errors.Errorf("订单号不能为空......")
return
}
rlog = new(model.VipPayOrderLog)
rlog.Mid = payOrder.Mid
rlog.OrderNo = payOrder.OrderNo
rlog.Status = model.SIGN
} else {
if payOrder, err = s.dao.SelPayOrderByMid(c, user.Mid, model.AutoRenew, model.SUCCESS); err != nil {
err = errors.WithStack(err)
return
}
if payOrder == nil {
err = errors.Errorf("订单号不能为空......")
return
}
rlog = new(model.VipPayOrderLog)
rlog.Mid = payOrder.Mid
rlog.OrderNo = payOrder.OrderNo
rlog.Status = model.SIGN
}
} else {
if paylog, err = s.dao.SelPayOrderLog(c, user.Mid, model.SIGN); err != nil {
err = errors.WithStack(err)
return
}
rlog = new(model.VipPayOrderLog)
rlog.Mid = paylog.Mid
rlog.Status = model.UNSIGN
rlog.OrderNo = paylog.OrderNo
}
if rlog != nil {
if _, err = s.dao.AddPayOrderLog(c, rlog); err != nil {
err = errors.WithStack(err)
return
}
}
return
}
func (s *Service) handlerinsertuserinfoproc() {
var (
err error
)
defer func() {
if x := recover(); x != nil {
log.Error("service.handlerinsertuserinfoproc panic(%v)", x)
go s.handlerinsertuserinfoproc()
log.Info("service.handlerinsertuserinfoproc recover")
}
}()
for {
userInfo := <-s.handlerInsertUserInfo
for i := 0; i < s.c.Property.Retry; i++ {
if err = s.addUserInfo(context.TODO(), userInfo); err == nil {
s.dao.DelInfoCache(context.Background(), userInfo.Mid)
s.dao.DelVipInfoCache(context.TODO(), userInfo.Mid)
if s.grayScope(userInfo.Mid) {
s.cleanCache(userInfo.Mid)
}
break
}
log.Error("add info error(%+v)", err)
}
}
}
func (s *Service) addUserInfo(c context.Context, ui *model.VipUserInfo) (err error) {
var (
tx *sql.Tx
udh *model.VipUserDiscountHistory
)
if tx, err = s.dao.StartTx(c); err != nil {
return
}
defer func() {
if err == nil {
if err = tx.Commit(); err != nil {
log.Error("commit(%+v)", err)
return
}
} else {
tx.Rollback()
}
}()
if _, err = s.dao.AddUserInfo(tx, ui); err != nil {
err = errors.WithStack(err)
return
}
if ui.AutoRenewed == 1 {
udh = new(model.VipUserDiscountHistory)
udh.DiscountID = model.VipUserFirstDiscount
udh.Status = model.DiscountUsed
udh.Mid = ui.Mid
if _, err = s.dao.DupUserDiscountHistory(tx, udh); err != nil {
err = errors.WithStack(err)
return
}
}
return
}
func (s *Service) updateVipUserInfo(c context.Context, ui *model.VipUserInfo) (err error) {
var (
tx *sql.Tx
udh *model.VipUserDiscountHistory
eff int64
)
if tx, err = s.dao.StartTx(c); err != nil {
return
}
defer func() {
if err == nil {
if err = tx.Commit(); err != nil {
log.Error("commit(%+v)", err)
return
}
} else {
tx.Rollback()
}
}()
if eff, err = s.dao.UpdateUserInfo(tx, ui); err != nil {
err = errors.WithStack(err)
return
}
if eff <= 0 {
log.Warn("update vip RowsAffected 0 vip(%+v)", ui)
return
}
if ui.AutoRenewed == 1 {
udh = new(model.VipUserDiscountHistory)
udh.DiscountID = model.VipUserFirstDiscount
udh.Status = model.DiscountUsed
udh.Mid = ui.Mid
if _, err = s.dao.DupUserDiscountHistory(tx, udh); err != nil {
err = errors.WithStack(err)
return
}
}
return
}
func (s *Service) handlerfailuserinfoproc() {
var (
err error
)
defer func() {
if x := recover(); x != nil {
log.Error("service.handlerfailuserinfoproc panic(%v)", x)
go s.handlerfailuserinfoproc()
log.Info("service.handlerfailuserinfoproc recover")
}
}()
for {
userInfo := <-s.handlerFailUserInfo
_time := 0
for {
if err = s.updateVipUserInfo(context.TODO(), userInfo); err == nil {
s.dao.DelInfoCache(context.Background(), userInfo.Mid)
s.dao.DelVipInfoCache(context.TODO(), userInfo.Mid)
if s.grayScope(userInfo.Mid) {
s.cleanCache(userInfo.Mid)
}
break
}
log.Error("info error(%+v)", err)
_time++
if _time > _maxtime {
break
}
time.Sleep(_sleep)
}
}
}
func (s *Service) handlerupdateuserinfoproc() {
var (
err error
flag bool
)
defer func() {
if x := recover(); x != nil {
log.Error("service.handlerupdateuserinfoproc panic(%v)", x)
go s.handlerupdateuserinfoproc()
log.Info("service.handlerupdateuserinfoproc recover")
}
}()
for {
userInfo := <-s.handlerUpdateUserInfo
flag = true
for i := 0; i < s.c.Property.Retry; i++ {
if err = s.updateVipUserInfo(context.TODO(), userInfo); err == nil {
s.dao.DelInfoCache(context.Background(), userInfo.Mid)
s.dao.DelVipInfoCache(context.TODO(), userInfo.Mid)
if s.grayScope(userInfo.Mid) {
s.cleanCache(userInfo.Mid)
}
flag = false
break
}
log.Error("info error(%+v)", err)
}
if flag {
s.handlerFailUserInfo <- userInfo
}
}
}
func (s *Service) handleraddchangehistoryproc() {
defer func() {
if x := recover(); x != nil {
log.Error("service.handleraddchangehistoryproc panic(%v)", x)
go s.handleraddchangehistoryproc()
log.Info("service.handleraddchangehistoryproc recover")
}
}()
for {
msg := <-s.handlerAddVipHistory
history := convertMsgToHistory(msg)
var res []*model.VipChangeHistory
res = append(res, history)
for i := 0; i < s.c.Property.Retry; i++ {
if err := s.dao.AddChangeHistoryBatch(res); err == nil {
break
}
}
}
}
func convertMsgToHistory(msg *model.VipChangeHistoryMsg) (r *model.VipChangeHistory) {
r = new(model.VipChangeHistory)
r.Mid = msg.Mid
r.Days = msg.Days
r.Month = msg.Month
r.ChangeType = msg.ChangeType
r.OperatorID = msg.OperatorID
r.RelationID = msg.RelationID
r.BatchID = msg.BatchID
r.Remark = msg.Remark
r.ChangeTime = xtime.Time(parseTime(msg.ChangeTime).Unix())
r.BatchCodeID = msg.BatchCodeID
return
}
func parseTime(timeStr string) (t time.Time) {
var err error
if t, err = time.ParseInLocation("2006-01-02 15:04:05", timeStr, time.Local); err != nil {
t = time.Now()
}
return
}
func convertMsgToUserInfo(msg *model.VipUserInfoMsg) (r *model.VipUserInfo) {
r = new(model.VipUserInfo)
r.AnnualVipOverdueTime = xtime.Time(parseTime(msg.AnnualVipOverdueTime).Unix())
r.Mid = msg.Mid
r.OverdueTime = xtime.Time(parseTime(msg.OverdueTime).Unix())
r.PayType = msg.IsAutoRenew
r.RecentTime = xtime.Time(parseTime(msg.RecentTime).Unix())
r.StartTime = xtime.Time(parseTime(msg.StartTime).Unix())
r.Status = msg.Status
r.Type = msg.Type
r.PayChannelID = msg.PayChannelID
r.AutoRenewed = msg.AutoRenewed
r.IosOverdueTime = xtime.Time(parseTime(msg.IosOverdueTime).Unix())
r.Ver = msg.Ver
return
}
func convertUserInfoByNewMsg(msg *model.VipUserInfoNewMsg) (r *model.VipUserInfo) {
r = new(model.VipUserInfo)
r.AnnualVipOverdueTime = xtime.Time(parseTime(msg.AnnualVipOverdueTime).Unix())
r.Mid = msg.Mid
r.OverdueTime = xtime.Time(parseTime(msg.VipOverdueTime).Unix())
r.PayType = msg.VipPayType
r.RecentTime = xtime.Time(parseTime(msg.VipRecentTime).Unix())
r.StartTime = xtime.Time(parseTime(msg.VipStartTime).Unix())
r.Status = msg.VipStatus
r.Type = msg.VipType
r.PayChannelID = msg.PayChannelID
r.IosOverdueTime = xtime.Time(parseTime(msg.IosOverdueTime).Unix())
r.Ver = msg.Ver
return
}
func convertOldToNew(old *model.VipUserInfoOld) (r *model.VipUserInfo) {
r = new(model.VipUserInfo)
r.AnnualVipOverdueTime = old.AnnualVipOverdueTime
r.Mid = old.Mid
r.OverdueTime = old.OverdueTime
r.PayType = old.IsAutoRenew
r.RecentTime = old.RecentTime
r.PayChannelID = old.PayChannelID
if old.RecentTime.Time().Unix() < 0 {
r.RecentTime = xtime.Time(1451577600)
}
r.StartTime = old.StartTime
r.Status = old.Status
r.Type = old.Type
r.IosOverdueTime = old.IosOverdueTime
r.Ver = old.Ver
return
}
//HandlerVipChangeHistory handler sync change history data
func (s *Service) HandlerVipChangeHistory() (err error) {
var (
newMaxID int64
oldMaxID int64
size = int64(s.c.Property.BatchSize)
startID int64
endID = size
exitMap = make(map[string]int)
)
if oldMaxID, err = s.dao.SelOldChangeHistoryMaxID(context.TODO()); err != nil {
log.Error("selOldChangeHistory error(%+v)", err)
return
}
if newMaxID, err = s.dao.SelChangeHistoryMaxID(context.TODO()); err != nil {
log.Error("selChangeHistoryMaxID error(%+v)", err)
return
}
page := newMaxID / size
if newMaxID%size != 0 {
page++
}
for i := 0; i < int(page); i++ {
startID = int64(i) * size
endID = int64((i + 1)) * size
if endID > newMaxID {
endID = newMaxID
}
var res []*model.VipChangeHistory
if res, err = s.dao.SelChangeHistory(context.TODO(), startID, endID); err != nil {
log.Error("selChangeHistory(startID:%v endID:%v) error(%+v)", startID, endID, endID)
return
}
for _, v := range res {
exitMap[s.madeChangeHistoryMD5(v)] = 1
}
}
page = oldMaxID / size
if oldMaxID%size != 0 {
page++
}
var batch []*model.VipChangeHistory
for i := 0; i < int(page); i++ {
startID = int64(i) * size
endID = int64(i+1) * size
if endID > oldMaxID {
endID = oldMaxID
}
var res []*model.VipChangeHistory
if res, err = s.dao.SelOldChangeHistory(context.TODO(), startID, endID); err != nil {
log.Error("sel old change history (startID:%v endID:%v) error(%+v)", startID, endID, err)
return
}
for _, v := range res {
v.Days = s.calcDay(v)
madeMD5 := s.madeChangeHistoryMD5(v)
if exitMap[madeMD5] == 0 {
batch = append(batch, v)
}
}
if err = s.dao.AddChangeHistoryBatch(batch); err != nil {
log.Error("add change history batch(%+v) error(%+v)", batch, err)
return
}
batch = nil
}
return
}
func (s *Service) calcDay(r *model.VipChangeHistory) int32 {
if r.Month != 0 {
year := r.Month / 12
month := r.Month % 12
return int32(year)*model.VipDaysYear + int32(month)*model.VipDaysMonth
}
return r.Days
}
func (s *Service) madeChangeHistoryMD5(r *model.VipChangeHistory) string {
str := fmt.Sprintf("%v,%v,%v,%v,%v,%v,%v,%v,%v", r.Mid, r.Remark, r.BatchID, r.RelationID, r.OperatorID, r.Days, r.ChangeTime.Time().Format("2006-01-02 15:04:05"), r.ChangeType, r.BatchCodeID)
b := []byte(str)
hash := md5.New()
hash.Write(b)
sum := hash.Sum(nil)
return hex.EncodeToString(sum)
}
//SyncUserInfoByMid sync user by mid.
func (s *Service) SyncUserInfoByMid(c context.Context, mid int64) (err error) {
var (
old *model.VipUserInfoOld
user *model.VipUserInfo
)
if old, err = s.dao.OldVipInfo(c, mid); err != nil {
err = errors.WithStack(err)
return
}
if user, err = s.dao.SelVipUserInfo(c, mid); err != nil {
err = errors.WithStack(err)
return
}
r := convertOldToNew(old)
r.OldVer = user.Ver
if err = s.updateVipUserInfo(c, r); err != nil {
err = errors.WithStack(err)
return
}
// clear cache.
s.cleanVipRetry(mid)
return
}
// ClearUserCache clear user cache.
func (s *Service) ClearUserCache(mid int64) {
s.cleanVipRetry(mid)
}
// ClearUserCache clear user cache.
func (s *Service) grayScope(mid int64) bool {
return mid%10000 < s.c.Property.GrayScope
}

View File

@ -0,0 +1,46 @@
package service
import (
"context"
"go-common/app/job/main/vip/model"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
// go test -test.v -test.run TestSyncUserInfoByMid
func TestSyncUserInfoByMid(t *testing.T) {
Convey("SyncUserInfoByMid err == nil", t, func() {
err := s.SyncUserInfoByMid(context.TODO(), 1002)
So(err, ShouldBeNil)
})
}
// go test -test.v -test.run TestUpdateDatabusUserInfo
func TestUpdateDatabusUserInfo(t *testing.T) {
Convey("TestUpdateDatabusUserInfo err == nil", t, func() {
var (
mid int64 = 2089809
old *model.VipUserInfoOld
msg = new(model.VipUserInfoMsg)
err error
)
old, err = s.dao.OldVipInfo(context.TODO(), mid)
So(err, ShouldBeNil)
msg.Mid = old.Mid
msg.Type = old.Type
msg.Status = old.Status
msg.StartTime = old.StartTime.Time().Format("2006-01-02 15:04:05")
msg.OverdueTime = old.OverdueTime.Time().Format("2006-01-02 15:04:05")
msg.AnnualVipOverdueTime = old.AnnualVipOverdueTime.Time().Format("2006-01-02 15:04:05")
msg.RecentTime = old.RecentTime.Time().Format("2006-01-02 15:04:05")
msg.Wander = old.Wander
msg.AutoRenewed = old.AutoRenewed
msg.IsAutoRenew = old.IsAutoRenew
msg.IosOverdueTime = old.IosOverdueTime.Time().Format("2006-01-02 15:04:05")
userInfo := convertMsgToUserInfo(msg)
err = s.addUserInfo(context.TODO(), userInfo)
So(err, ShouldBeNil)
})
}