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

View File

@@ -0,0 +1,25 @@
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//app/service/main/coupon/api:all-srcs",
"//app/service/main/coupon/cmd:all-srcs",
"//app/service/main/coupon/conf:all-srcs",
"//app/service/main/coupon/dao:all-srcs",
"//app/service/main/coupon/http:all-srcs",
"//app/service/main/coupon/model:all-srcs",
"//app/service/main/coupon/rpc/client:all-srcs",
"//app/service/main/coupon/rpc/server:all-srcs",
"//app/service/main/coupon/server/grpc:all-srcs",
"//app/service/main/coupon/service:all-srcs",
],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,97 @@
# v2.9.1
1. 锁定中提示
# v2.9.0
1. 代金券【最优选择+兑换功能】
# v2.8.1
1. platform 迁移到配置中
# v2.8.0
1. 大会员元旦活动
# v2.7.0
1. 新增大会员代金券限制商品
# v2.6.0
> 1. 大会员-饿了么&bilibili联合会员
# v2.5.4
1. expire using coupon
# v2.5.3
1. open using
# v2.5.2
1. 清洗萌节劵已使用数据
# v2.5.1
1. notify check
# v2.5.0
1. refined coupon notify
# v2.4.4
1. add coupon notify api
# v2.4.3
1. fix using
# v2.4.2
1. update mtime desc
# v2.4.1
1. business receive allowance
# v2.4.0
1. allowance count rpc
# v2.3.0
1. 新增业务方领取代金券
# v2.2.8
1. dao test
# v2.2.7
1. cache del order
# v2.2.6
1. update platfrom
# v2.2.5
1. add using allowance coupon
# v2.2.4
1. notify success remark
# v2.2.3
1. change coupon pc name
# v2.2.2
1. add using status coupon
# v2.2.1
1. remove outer gateway
# v2.2.0
1. 代金券
# v2.1.0
1. modify coupon name
# v2.0.0
1. 漫画劵
# v1.0.4
1. add coupon page rpc
# v1.0.3
1. add register
# v1.0.2
1. http path
# v1.0.1
1. remove auto load conf
# v1.0.0
1. 观影劵一期

View File

@@ -0,0 +1,10 @@
# Owner
zhaogangtao
yubaihai
# Author
yubaihai
wangyuzhe
# Reviewer
zhaogangtao

View File

@@ -0,0 +1,16 @@
# See the OWNERS docs at https://go.k8s.io/owners
approvers:
- wangyuzhe
- yubaihai
- zhaogangtao
labels:
- main
- service
- service/main/coupon
options:
no_parent_owners: true
reviewers:
- wangyuzhe
- yubaihai
- zhaogangtao

View File

@@ -0,0 +1,14 @@
# coupon
# 项目简介
1.
# 编译环境
# 依赖包
# 编译执行

View File

@@ -0,0 +1,57 @@
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",
)
proto_library(
name = "v1_proto",
srcs = ["api.proto"],
tags = ["automanaged"],
deps = ["@gogo_special_proto//github.com/gogo/protobuf/gogoproto"],
)
go_proto_library(
name = "v1_go_proto",
compilers = ["@io_bazel_rules_go//proto:gogofast_grpc"],
importpath = "go-common/app/service/main/coupon/api",
proto = ":v1_proto",
tags = ["automanaged"],
deps = ["@com_github_gogo_protobuf//gogoproto:go_default_library"],
)
go_library(
name = "go_default_library",
srcs = ["client.go"],
embed = [":v1_go_proto"],
importpath = "go-common/app/service/main/coupon/api",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//library/net/rpc/warden:go_default_library",
"@com_github_gogo_protobuf//gogoproto:go_default_library",
"@com_github_gogo_protobuf//proto:go_default_library",
"@org_golang_google_grpc//:go_default_library",
"@org_golang_x_net//context: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"],
)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,77 @@
syntax = "proto3";
// use {app_id}.{version} as package name
package account.coupon;
import "github.com/gogo/protobuf/gogoproto/gogo.proto";
option go_package = "v1";
message CaptchaTokenReq {
string ip = 1;
}
message CaptchaTokenReply {
string token = 1;
string url = 2;
}
message UseCouponCodeReq{
string token =1;
string code = 2;
string verify =3;
string ip =4;
int64 mid = 5;
}
message UseCouponCodeResp{
string coupon_token = 1;
double coupon_amount = 2;
double full_amount = 3;
string platfrom_limit_explain = 4;
int32 product_limit_month = 5;
int32 product_limit_renewal = 6;
}
message UsableAllowanceCouponV2Req{
int64 mid =1;
repeated ModelPriceInfo priceInfo = 2;
}
message ModelPriceInfo {
double price = 1;
int64 plat = 2;
int32 prodLimMonth = 3;
int32 prodLimRenewal = 4;
}
message UsableAllowanceCouponV2Reply{
string coupon_tip = 1;
ModelCouponAllowancePanelInfo coupon_info = 2;
}
message ModelCouponAllowancePanelInfo{
string coupon_token = 1;
double coupon_amount = 2;
int32 state = 3;
string full_limit_explain = 4;
string scope_explain = 5;
double full_amount = 6;
double coupon_discount_price = 7;
int64 start_time = 8;
int64 expire_time = 9;
int32 selected = 10;
string disables_explains = 11;
string order_no = 12;
string name = 13;
int32 usable = 14;
}
service Coupon {
// CaptchaToken captcha token.
rpc CaptchaToken(CaptchaTokenReq) returns(CaptchaTokenReply);
// UseCouponCode use coupon code.
rpc UseCouponCode(UseCouponCodeReq) returns(UseCouponCodeResp);
// UsableAllowanceCouponV2 use allowance coupon v2.
rpc UsableAllowanceCouponV2(UsableAllowanceCouponV2Req) returns(UsableAllowanceCouponV2Reply);
}

View File

@@ -0,0 +1,23 @@
package v1
import (
"fmt"
"go-common/library/net/rpc/warden"
context "golang.org/x/net/context"
grpc "google.golang.org/grpc"
)
// AppID .
const AppID = "account.service.coupon"
// NewClient new grpc client
func NewClient(cfg *warden.ClientConfig, opts ...grpc.DialOption) (CouponClient, error) {
client := warden.NewClient(cfg, opts...)
cc, err := client.Dial(context.Background(), fmt.Sprintf("discovery://default/%s", AppID))
if err != nil {
return nil, err
}
return NewCouponClient(cc), nil
}

View File

@@ -0,0 +1,46 @@
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 = ["coupon-service.toml"],
importpath = "go-common/app/service/main/coupon/cmd",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/main/coupon/conf:go_default_library",
"//app/service/main/coupon/http:go_default_library",
"//app/service/main/coupon/rpc/server:go_default_library",
"//app/service/main/coupon/server/grpc:go_default_library",
"//app/service/main/coupon/service:go_default_library",
"//library/ecode/tip:go_default_library",
"//library/log:go_default_library",
"//library/net/rpc: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,163 @@
# This is a TOML document. Boom
version = "1.0.0"
user = "nobody"
pid = "/tmp/coupon.pid"
dir = "./"
[log]
stdout = true
[bm]
timeout = "1s"
[property]
messageURL = "http://message.bilibili.com"
captchaBID = "account"
captchaTokenURL = "http://api.bilibili.co/x/internal/v1/captcha/token"
captchaVerifyURL = "http://api.bilibili.co/x/internal/v1/captcha/verify"
[platform]
1 = "iPhone"
# 2 = "iPad"
# 3 = "网页"
# 4 = "Android"
# 5 = "iPad HD"
# 6 = "iOS概念版"
# 7 = "安卓概念版"
# 8 = "微信公众号"
# 9 = "赠送好友"
[identify]
whiteAccessKey = ""
whiteMid = 0
[identify.app]
key = "6a29f8ed87407c11"
secret = "d3c5a85f5b895a03735b5d20a273bc57"
[identify.memcache]
name = "go-business/identify"
proto = "tcp"
addr = "172.16.33.54:11211"
active = 5
idle = 3
dialTimeout = "1s"
readTimeout = "1s"
writeTimeout = "1s"
idleTimeout = "80s"
[identify.host]
auth = "http://passport.bilibili.com"
secret = "http://open.bilibili.com"
[identify.httpClient]
key = "f022126a8a365e20"
secret = "b7b86838145d634b487e67b811b8fab2"
dial = "30ms"
timeout = "100ms"
keepAlive = "60s"
[identify.httpClient.breaker]
window = "10s"
sleep = "100ms"
bucket = 10
ratio = 0.5
request = 100
[identify.httpClient.url]
"http://passport.bilibili.co/intranet/auth/tokenInfo" = {timeout = "100ms"}
"http://passport.bilibili.co/intranet/auth/cookieInfo" = {timeout = "100ms"}
"http://open.bilibili.co/api/getsecret" = {timeout = "500ms"}
[mysql]
addr = "127.0.0.1:3306"
dsn = "root:123456@tcp(127.0.0.1:3306)/bilibili_coupon?timeout=2s&readTimeout=2s&writeTimeout=2s&parseTime=true&loc=Local&charset=utf8,utf8mb4"
active = 20
idle = 10
idleTimeout ="4h"
queryTimeout = "1s"
execTimeout = "1s"
tranTimeout = "2s"
[mysql.breaker]
window = "3s"
sleep = "100ms"
bucket = 10
ratio = 0.5
request = 100
[vipMysql]
addr = "172.16.33.205"
dsn = "zhaozhihao:MN9havOfnzY3kd6L78IVucRxgywe0p2P@tcp(172.16.33.205:3308)/bilibili_vip?timeout=5s&readTimeout=5s&writeTimeout=5s&parseTime=true&loc=Local&charset=utf8,utf8mb4"
active = 5
idle = 5
IdleTimeout ="4h"
QueryTimeout = "5s"
ExecTimeout = "5s"
TranTimeout = "5s"
[vipMysql.breaker]
window = "3s"
sleep = "100ms"
bucket = 10
ratio = 0.5
request = 100
[memcache]
name = "coupon"
proto = "tcp"
addr = "172.18.33.60:11237"
idle = 5
active = 10
dialTimeout = "1s"
readTimeout = "1s"
writeTimeout = "1s"
idleTimeout = "10s"
expire = "24h"
prizeExpire = "30h"
[rpcServer]
proto = "tcp"
addr = "0.0.0.0:6869"
weight = 10
[httpClient]
key = "f022126a8a365e20"
secret = "b7b86838145d634b487e67b811b8fab2"
dial = "30ms"
timeout = "300ms"
keepAlive = "60s"
[httpClient.breaker]
window = "10s"
sleep = "100ms"
bucket = 10
ratio = 0.5
request = 100
[vipinfoRPC]
timeout = "3s"
[newYearConf]
# 活动id
actID = 1
# 2019年1月1日00:00:00
startTime = 1545797400
# 2019年1月14日23:59:59
endTime = 1545883800
# 随机
randNum = 5
# 历史从未充值过大会员
noVipBatchToken1 = "210957721620181224153121"
noVipBatchToken3 = "850691829320181224153235"
noVipBatchToken12 = "798157449920181224153338"
# 年度大会员且还有180天以上才到期
more180BatchToken1 = "763272400820181225165235"
more180BatchToken3 = "947668794420181225165208"
more180BatchToken12 = "115331401920181225165136"
# 年度大会员且还有180天(含)以内才到期
less180BatchToken1 = "234526007120181224153625"
less180BatchToken3 = "231042916920181224153654"
less180BatchToken12 = "862417541120181224153722"
# 月度会员(包括连续包月)& 大会员过期
monthBatchToken1 = "360059523020181224153817"
monthBatchToken3 = "425909138520181224153843"
monthBatchToken12 = "3557982522201812241509"
[wardenServer]
addr = "0.0.0.0:9000"
timeout = "1s"

View File

@@ -0,0 +1,65 @@
package main
import (
"context"
"flag"
"os"
"os/signal"
"syscall"
"time"
"go-common/app/service/main/coupon/conf"
"go-common/app/service/main/coupon/http"
rpc "go-common/app/service/main/coupon/rpc/server"
grpc "go-common/app/service/main/coupon/server/grpc"
"go-common/app/service/main/coupon/service"
ecode "go-common/library/ecode/tip"
"go-common/library/log"
xrpc "go-common/library/net/rpc"
)
var (
svc *service.Service
rpcSvr *xrpc.Server
)
func main() {
flag.Parse()
if err := conf.Init(); err != nil {
log.Error("conf.Init() error(%v)", err)
panic(err)
}
// init log
log.Init(conf.Conf.Log)
defer log.Close()
log.Info("coupon start")
// ecode init
ecode.Init(conf.Conf.Ecode)
// service init
svc = service.New(conf.Conf)
// rpc init
rpcSvr = rpc.New(conf.Conf, svc)
// http init
http.Init(conf.Conf, svc)
// grpc
ws := grpc.New(conf.Conf.WardenServer, svc)
// init pprof conf.Conf.Perf
// init signal
c := make(chan os.Signal, 1)
signal.Notify(c, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT)
for {
s := <-c
log.Info("coupon get a signal %s", s.String())
switch s {
case syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT:
rpcSvr.Close()
ws.Shutdown(context.Background())
time.Sleep(time.Second * 1)
log.Info("coupon exit")
return
case syscall.SIGHUP:
default:
return
}
}
}

View File

@@ -0,0 +1,40 @@
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/service/main/coupon/conf",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//library/cache/memcache:go_default_library",
"//library/conf:go_default_library",
"//library/database/sql:go_default_library",
"//library/ecode/tip: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/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,130 @@
package conf
import (
"errors"
"flag"
"go-common/library/cache/memcache"
"go-common/library/conf"
"go-common/library/database/sql"
ecode "go-common/library/ecode/tip"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
"go-common/library/net/rpc"
"go-common/library/net/rpc/warden"
xtime "go-common/library/time"
"github.com/BurntSushi/toml"
)
// global var
var (
confPath string
client *conf.Client
// Conf config
Conf = &Config{}
)
// Config config set
type Config struct {
// elk
Log *log.Config
// http
BM *bm.ServerConfig
// memcache
Memcache *Memcache
// MySQL
MySQL *sql.Config
// ecode
Ecode *ecode.Config
// biz property.
Property *Property
// rpc server
RPCServer *rpc.ServerConfig
// http client
HTTPClient *bm.ClientConfig
// vipinfo grpc
VipinfoRPC *warden.ClientConfig
NewYearConf *NewYearConf
// grpc server
WardenServer *warden.ServerConfig
Platform map[string]string
}
// NewYearConf .
type NewYearConf struct {
ActID int64
StartTime int64
EndTime int64
RandNum int64
NoVipBatchToken1 string
NoVipBatchToken3 string
NoVipBatchToken12 string
More180BatchToken1 string
More180BatchToken3 string
More180BatchToken12 string
Less180BatchToken1 string
Less180BatchToken3 string
Less180BatchToken12 string
MonthBatchToken1 string
MonthBatchToken3 string
MonthBatchToken12 string
}
// Property def.
type Property struct {
MessageURL string
CaptchaTokenURL string
CaptchaVerifyURL string
CaptchaBID string
}
// Memcache memcache
type Memcache struct {
*memcache.Config
Expire xtime.Duration
PrizeExpire xtime.Duration
}
func init() {
flag.StringVar(&confPath, "conf", "", "default config path")
}
// Init init conf
func Init() 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
}
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,77 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = [
"allowance_test.go",
"captcha_api_test.go",
"code_test.go",
"dao_test.go",
"http_test.go",
"memcache_test.go",
"mysql_test.go",
"prize_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/service/main/coupon/conf:go_default_library",
"//app/service/main/coupon/model:go_default_library",
"//library/database/sql:go_default_library",
"//library/ecode: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 = [
"allowance.go",
"captcha_api.go",
"code.go",
"dao.go",
"http.go",
"memcache.go",
"mysql.go",
"prize.go",
],
importpath = "go-common/app/service/main/coupon/dao",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/main/coupon/conf:go_default_library",
"//app/service/main/coupon/model:go_default_library",
"//library/cache/memcache: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/net/metadata:go_default_library",
"//library/stat/prom:go_default_library",
"//library/xstr: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,277 @@
package dao
import (
"bytes"
"context"
xsql "database/sql"
"fmt"
"go-common/app/service/main/coupon/model"
"go-common/library/database/sql"
"strconv"
"time"
"github.com/pkg/errors"
)
const (
_couponAllowanceNoStartCheckSQL = "SELECT id,coupon_token,mid,state,start_time,expire_time,origin,ver,batch_token,order_no,amount,full_amount,ctime,mtime FROM coupon_allowance_info_%02d WHERE mid = ? AND expire_time > ? AND state = ?;"
_couponByOrderNOSQL = "SELECT id,coupon_token,mid,state,start_time,expire_time,origin,ver,batch_token,order_no,amount,full_amount,ctime,mtime,remark FROM coupon_allowance_info_%02d WHERE order_no = ?;"
_couponUsableAllowanceSQL = "SELECT id,coupon_token,mid,state,start_time,expire_time,origin,ver,batch_token,order_no,amount,full_amount,ctime,mtime FROM coupon_allowance_info_%02d WHERE mid = ? AND expire_time > ? AND start_time < ? AND state = ?;"
_couponAllowanceByTokenSQL = "SELECT id,coupon_token,mid,state,start_time,expire_time,origin,ver,batch_token,order_no,amount,full_amount,ctime,mtime FROM coupon_allowance_info_%02d WHERE coupon_token = ?;"
_updateCouponAllowanceInUseSQL = "UPDATE coupon_allowance_info_%02d SET state =?, order_no = ?, remark = ?, ver =ver+1 WHERE coupon_token = ? AND ver = ?;"
_updateCouponAllowanceToUseSQL = "UPDATE coupon_allowance_info_%02d SET state =?, order_no = ?, ver =ver+1 WHERE coupon_token = ? AND ver = ? AND state = ?;"
_getCouponByOrderNoSQL = "SELECT mid,coupon_token,order_no,amount,full_amount,state,ver FROM coupon_allowance_info_%02d WHERE order_no = ?"
_addCouponAllowanceChangeLogSQL = "INSERT INTO coupon_allowance_change_log_%02d (coupon_token,order_no,mid,state,ctime, change_type) VALUES(?,?,?,?,?,?);"
_batchAllowanceCountByMid = "SELECT COUNT(1) FROM coupon_allowance_info_%02d WHERE mid = ? AND batch_token = ?;"
_batchAddAllowanceCouponSQL = "INSERT INTO coupon_allowance_info_%02d(coupon_token,mid,state,start_time,expire_time,origin,batch_token,amount,full_amount,ctime,app_id) VALUES "
_addAllowanceCouponSQL = "INSERT INTO coupon_allowance_info_%02d(coupon_token,mid,state,start_time,expire_time,origin,batch_token,amount,full_amount,app_id) VALUES (?,?,?,?,?,?,?,?,?,?)"
_couponAllowancePageNotUsedSQL = "SELECT id,coupon_token,mid,state,start_time,expire_time,origin,ver,batch_token,order_no,amount,full_amount,ctime,mtime,remark FROM coupon_allowance_info_%02d WHERE mid = ? AND (state = 0 OR state = 1) AND expire_time > ? AND start_time < ? AND ctime > ? ORDER BY id DESC"
_couponAllowancePageUsedSQL = "SELECT id,coupon_token,mid,state,start_time,expire_time,origin,ver,batch_token,order_no,amount,full_amount,ctime,mtime,remark FROM coupon_allowance_info_%02d WHERE mid = ? AND state = 2 AND ctime > ? ORDER BY id DESC "
_couponAllowancePageExpireSQL = "SELECT id,coupon_token,mid,state,start_time,expire_time,origin,ver,batch_token,order_no,amount,full_amount,ctime,mtime,remark FROM coupon_allowance_info_%02d WHERE mid = ? AND state <> 2 AND expire_time < ? AND ctime > ? ORDER BY id DESC "
)
func hitAllowanceInfo(mid int64) int64 {
return mid % 10
}
func hitAllowanceChangeLog(mid int64) int64 {
return mid % 10
}
// ByStateAndExpireAllowances query by coupon state and expire .
func (d *Dao) ByStateAndExpireAllowances(c context.Context, mid int64, state int8, t int64) (res []*model.CouponAllowanceInfo, err error) {
var rows *sql.Rows
if rows, err = d.db.Query(c, fmt.Sprintf(_couponAllowanceNoStartCheckSQL, hitAllowanceInfo(mid)), mid, t, state); err != nil {
err = errors.WithStack(err)
return
}
defer rows.Close()
for rows.Next() {
r := &model.CouponAllowanceInfo{}
if err = rows.Scan(&r.ID, &r.CouponToken, &r.Mid, &r.State, &r.StartTime, &r.ExpireTime, &r.Origin, &r.Ver, &r.BatchToken,
&r.OrderNO, &r.Amount, &r.FullAmount, &r.CTime, &r.MTime); err != nil {
err = errors.WithStack(err)
res = nil
return
}
res = append(res, r)
}
err = rows.Err()
return
}
// AllowanceByOrderNO query coupon by orderno.
func (d *Dao) AllowanceByOrderNO(c context.Context, mid int64, orderNO string) (r *model.CouponAllowanceInfo, err error) {
var row *sql.Row
r = &model.CouponAllowanceInfo{}
row = d.db.QueryRow(c, fmt.Sprintf(_couponByOrderNOSQL, hitAllowanceInfo(mid)), orderNO)
if err = row.Scan(&r.ID, &r.CouponToken, &r.Mid, &r.State, &r.StartTime, &r.ExpireTime, &r.Origin, &r.Ver, &r.BatchToken,
&r.OrderNO, &r.Amount, &r.FullAmount, &r.CTime, &r.MTime, &r.Remark); err != nil {
if err == sql.ErrNoRows {
err = nil
r = nil
return
}
err = errors.WithStack(err)
return
}
return
}
// UsableAllowances usable allowance .
func (d *Dao) UsableAllowances(c context.Context, mid int64, state int8, t int64) (res []*model.CouponAllowanceInfo, err error) {
var rows *sql.Rows
if rows, err = d.db.Query(c, fmt.Sprintf(_couponUsableAllowanceSQL, hitAllowanceInfo(mid)), mid, t, t, state); err != nil {
err = errors.WithStack(err)
return
}
defer rows.Close()
for rows.Next() {
r := &model.CouponAllowanceInfo{}
if err = rows.Scan(&r.ID, &r.CouponToken, &r.Mid, &r.State, &r.StartTime, &r.ExpireTime, &r.Origin, &r.Ver, &r.BatchToken,
&r.OrderNO, &r.Amount, &r.FullAmount, &r.CTime, &r.MTime); err != nil {
err = errors.WithStack(err)
res = nil
return
}
res = append(res, r)
}
err = rows.Err()
return
}
// AllowanceByToken query coupon by token.
func (d *Dao) AllowanceByToken(c context.Context, mid int64, token string) (r *model.CouponAllowanceInfo, err error) {
var row *sql.Row
r = &model.CouponAllowanceInfo{}
row = d.db.QueryRow(c, fmt.Sprintf(_couponAllowanceByTokenSQL, hitAllowanceInfo(mid)), token)
if err = row.Scan(&r.ID, &r.CouponToken, &r.Mid, &r.State, &r.StartTime, &r.ExpireTime, &r.Origin, &r.Ver, &r.BatchToken,
&r.OrderNO, &r.Amount, &r.FullAmount, &r.CTime, &r.MTime); err != nil {
if err == sql.ErrNoRows {
err = nil
r = nil
return
}
err = errors.WithStack(err)
return
}
return
}
// UpdateAllowanceCouponInUse update coupon in use.
func (d *Dao) UpdateAllowanceCouponInUse(c context.Context, tx *sql.Tx, cp *model.CouponAllowanceInfo) (a int64, err error) {
var res xsql.Result
if res, err = tx.Exec(fmt.Sprintf(_updateCouponAllowanceInUseSQL, hitAllowanceInfo(cp.Mid)), cp.State, cp.OrderNO, cp.Remark, cp.CouponToken, cp.Ver); err != nil {
err = errors.WithStack(err)
return
}
if a, err = res.RowsAffected(); err != nil {
err = errors.WithStack(err)
return
}
return
}
// UpdateAllowanceCouponToUse update coupon in use.
func (d *Dao) UpdateAllowanceCouponToUse(c context.Context, tx *sql.Tx, cp *model.CouponAllowanceInfo) (a int64, err error) {
var res xsql.Result
if res, err = tx.Exec(fmt.Sprintf(_updateCouponAllowanceToUseSQL, hitAllowanceInfo(cp.Mid)), cp.State, cp.OrderNO, cp.CouponToken, cp.Ver, model.InUse); err != nil {
err = errors.WithStack(err)
return
}
if a, err = res.RowsAffected(); err != nil {
err = errors.WithStack(err)
return
}
return
}
// UpdateAllowanceCouponToUsed update coupon in used.
func (d *Dao) UpdateAllowanceCouponToUsed(c context.Context, tx *sql.Tx, cp *model.CouponAllowanceInfo) (a int64, err error) {
var res xsql.Result
if res, err = tx.Exec(fmt.Sprintf(_updateCouponAllowanceToUseSQL, hitAllowanceInfo(cp.Mid)), cp.State, cp.OrderNO, cp.CouponToken, cp.Ver, model.NotUsed); err != nil {
err = errors.WithStack(err)
return
}
if a, err = res.RowsAffected(); err != nil {
err = errors.WithStack(err)
return
}
return
}
//InsertCouponAllowanceHistory insert coupon history .
func (d *Dao) InsertCouponAllowanceHistory(c context.Context, tx *sql.Tx, l *model.CouponAllowanceChangeLog) (a int64, err error) {
var res xsql.Result
if res, err = tx.Exec(fmt.Sprintf(_addCouponAllowanceChangeLogSQL, hitAllowanceChangeLog(l.Mid)), l.CouponToken, l.OrderNO, l.Mid, l.State, l.Ctime, l.ChangeType); err != nil {
err = errors.WithStack(err)
return
}
if a, err = res.RowsAffected(); err != nil {
err = errors.WithStack(err)
}
return
}
// CountByAllowanceBranchToken get user count by bratch token.
func (d *Dao) CountByAllowanceBranchToken(c context.Context, mid int64, token string) (count int64, err error) {
row := d.db.QueryRow(c, fmt.Sprintf(_batchAllowanceCountByMid, hitAllowanceInfo(mid)), mid, token)
if err = row.Scan(&count); err != nil {
err = errors.WithStack(err)
}
return
}
// GetCouponByOrderNo .
func (d *Dao) GetCouponByOrderNo(c context.Context, mid int64, orderNo string) (res *model.CouponAllowanceInfo, err error) {
res = &model.CouponAllowanceInfo{}
row := d.db.QueryRow(c, fmt.Sprintf(_getCouponByOrderNoSQL, hitAllowanceInfo(mid)), orderNo)
if err = row.Scan(&res.Mid, &res.CouponToken, &res.OrderNO, &res.Amount, &res.FullAmount, &res.State, &res.Ver); err != nil {
err = errors.WithStack(err)
}
return
}
//TxAddAllowanceCoupon tx add lowance coupon
func (d *Dao) TxAddAllowanceCoupon(tx *sql.Tx, cp *model.CouponAllowanceInfo) (err error) {
if _, err = tx.Exec(fmt.Sprintf(_addAllowanceCouponSQL, hitAllowanceInfo(cp.Mid)), cp.CouponToken, cp.Mid, cp.State, cp.StartTime, cp.ExpireTime, cp.Origin, cp.BatchToken, cp.Amount, cp.FullAmount, cp.AppID); err != nil {
err = errors.WithStack(err)
}
return
}
// BatchAddAllowanceCoupon batch add allowance coupon.
func (d *Dao) BatchAddAllowanceCoupon(c context.Context, tx *sql.Tx, mid int64, cps []*model.CouponAllowanceInfo) (a int64, err error) {
var (
buf bytes.Buffer
res xsql.Result
sql string
)
buf.WriteString(fmt.Sprintf(_batchAddAllowanceCouponSQL, hitAllowanceInfo(mid)))
for _, v := range cps {
buf.WriteString("('")
buf.WriteString(v.CouponToken)
buf.WriteString("',")
buf.WriteString(strconv.FormatInt(v.Mid, 10))
buf.WriteString(",")
buf.WriteString(fmt.Sprintf("%d", v.State))
buf.WriteString(",")
buf.WriteString(strconv.FormatInt(v.StartTime, 10))
buf.WriteString(",")
buf.WriteString(strconv.FormatInt(v.ExpireTime, 10))
buf.WriteString(",")
buf.WriteString(fmt.Sprintf("%d", v.Origin))
buf.WriteString(",'")
buf.WriteString(v.BatchToken)
buf.WriteString("',")
buf.WriteString(fmt.Sprintf("%f", v.Amount))
buf.WriteString(",")
buf.WriteString(fmt.Sprintf("%f", v.FullAmount))
buf.WriteString(",'")
buf.WriteString(v.CTime.Time().Format("2006-01-02 15:04:05"))
buf.WriteString("',")
buf.WriteString(strconv.FormatInt(v.AppID, 10))
buf.WriteString("),")
}
sql = buf.String()
if res, err = tx.Exec(sql[0 : len(sql)-1]); err != nil {
err = errors.WithStack(err)
return
}
if a, err = res.RowsAffected(); err != nil {
err = errors.WithStack(err)
}
return
}
// AllowanceList list.
func (d *Dao) AllowanceList(c context.Context, mid int64, state int8, t int64, stime time.Time) (res []*model.CouponAllowanceInfo, err error) {
var rows *sql.Rows
switch state {
case model.NotUsed:
rows, err = d.db.Query(c, fmt.Sprintf(_couponAllowancePageNotUsedSQL, hitAllowanceInfo(mid)), mid, t, t, stime)
case model.Used:
rows, err = d.db.Query(c, fmt.Sprintf(_couponAllowancePageUsedSQL, hitAllowanceInfo(mid)), mid, stime)
case model.Expire:
rows, err = d.db.Query(c, fmt.Sprintf(_couponAllowancePageExpireSQL, hitAllowanceInfo(mid)), mid, t, stime)
default:
return
}
if err != nil {
err = errors.WithStack(err)
return
}
defer rows.Close()
for rows.Next() {
r := new(model.CouponAllowanceInfo)
if err = rows.Scan(&r.ID, &r.CouponToken, &r.Mid, &r.State, &r.StartTime, &r.ExpireTime, &r.Origin, &r.Ver, &r.BatchToken, &r.OrderNO, &r.Amount, &r.FullAmount,
&r.CTime, &r.MTime, &r.Remark); err != nil {
err = errors.WithStack(err)
res = nil
return
}
res = append(res, r)
}
err = rows.Err()
return
}

View File

@@ -0,0 +1,279 @@
package dao
import (
"context"
"math/rand"
"strconv"
"testing"
"time"
"go-common/app/service/main/coupon/model"
"go-common/library/database/sql"
xtime "go-common/library/time"
"github.com/smartystreets/goconvey/convey"
)
func TestDaohitAllowanceInfo(t *testing.T) {
var (
mid = int64(1)
)
convey.Convey("hitAllowanceInfo", t, func(ctx convey.C) {
p1 := hitAllowanceInfo(mid)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
}
func TestDaohitAllowanceChangeLog(t *testing.T) {
var (
mid = int64(1)
)
convey.Convey("hitAllowanceChangeLog", t, func(ctx convey.C) {
p1 := hitAllowanceChangeLog(mid)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
}
func TestDaoByStateAndExpireAllowances(t *testing.T) {
var (
c = context.TODO()
mid = int64(1)
state = int8(0)
no = int64(0)
)
convey.Convey("ByStateAndExpireAllowances", t, func(ctx convey.C) {
res, err := d.ByStateAndExpireAllowances(c, mid, state, no)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(res, convey.ShouldNotBeNil)
})
})
}
func TestDaoAllowanceByOrderNO(t *testing.T) {
var (
c = context.TODO()
mid = int64(0)
orderNO = "1"
)
convey.Convey("AllowanceByOrderNO", t, func(ctx convey.C) {
_, err := d.AllowanceByOrderNO(c, mid, orderNO)
ctx.Convey("Then err should be nil.r should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestDaoUsableAllowances(t *testing.T) {
var (
c = context.TODO()
mid = int64(1)
state = int8(0)
no = int64(0)
)
convey.Convey("UsableAllowances", t, func(ctx convey.C) {
_, err := d.UsableAllowances(c, mid, state, no)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestDaoAllowanceByToken(t *testing.T) {
var (
c = context.TODO()
mid = int64(0)
token = "1"
)
convey.Convey("AllowanceByToken", t, func(ctx convey.C) {
_, err := d.AllowanceByToken(c, mid, token)
ctx.Convey("Then err should be nil.r should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestDaoUpdateAllowanceCouponInUse(t *testing.T) {
var (
c = context.TODO()
tx = &sql.Tx{}
cp = &model.CouponAllowanceInfo{}
err error
)
convey.Convey("UpdateAllowanceCouponInUse", t, func(ctx convey.C) {
tx, err = d.BeginTran(c)
ctx.So(err, convey.ShouldBeNil)
a, err := d.UpdateAllowanceCouponInUse(c, tx, cp)
ctx.Convey("Then err should be nil.a should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(a, convey.ShouldNotBeNil)
})
})
}
func TestDaoUpdateAllowanceCouponToUse(t *testing.T) {
var (
c = context.Background()
tx, _ = d.BeginTran(c)
cp = &model.CouponAllowanceInfo{}
)
convey.Convey("UpdateAllowanceCouponToUse ", t, func(ctx convey.C) {
a, err := d.UpdateAllowanceCouponToUse(c, tx, cp)
if err == nil {
if err = tx.Commit(); err != nil {
tx.Rollback()
}
} else {
tx.Rollback()
}
ctx.Convey("Then err should be nil.a should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(a, convey.ShouldBeGreaterThanOrEqualTo, 0)
})
})
}
func TestDaoUpdateAllowanceCouponToUsed(t *testing.T) {
var (
c = context.Background()
tx, _ = d.BeginTran(c)
cp = &model.CouponAllowanceInfo{}
)
convey.Convey("UpdateAllowanceCouponToUsed ", t, func(ctx convey.C) {
a, err := d.UpdateAllowanceCouponToUsed(c, tx, cp)
if err == nil {
if err = tx.Commit(); err != nil {
tx.Rollback()
}
} else {
tx.Rollback()
}
ctx.Convey("Then err should be nil.a should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(a, convey.ShouldBeGreaterThanOrEqualTo, 0)
})
})
}
func TestDaoInsertCouponAllowanceHistory(t *testing.T) {
var (
c = context.TODO()
tx = &sql.Tx{}
l = &model.CouponAllowanceChangeLog{
CouponToken: token(),
OrderNO: "1",
}
err error
)
convey.Convey("InsertCouponAllowanceHistory", t, func(ctx convey.C) {
tx, err = d.BeginTran(c)
ctx.So(err, convey.ShouldBeNil)
a, err := d.InsertCouponAllowanceHistory(c, tx, l)
ctx.Convey("Then err should be nil.a should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(a, convey.ShouldNotBeNil)
})
})
}
func TestDaoCountByAllowanceBranchToken(t *testing.T) {
var (
c = context.TODO()
mid = int64(0)
token = "allowance_test1"
)
convey.Convey("CountByAllowanceBranchToken", t, func(ctx convey.C) {
count, err := d.CountByAllowanceBranchToken(c, mid, token)
ctx.Convey("Then err should be nil.count should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(count, convey.ShouldNotBeNil)
})
})
}
func TestDaoGetCouponByOrderNo(t *testing.T) {
var (
c = context.TODO()
mid = int64(0)
orderNo = "allowance_test1"
)
convey.Convey("GetCouponByOrderNo ", t, func(ctx convey.C) {
res, err := d.GetCouponByOrderNo(c, mid, orderNo)
ctx.Convey("Then err should be not nil.res should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldNotBeNil)
ctx.So(res, convey.ShouldNotBeNil)
})
})
}
func TestDaoTxAddAllowanceCoupon(t *testing.T) {
var (
c = context.Background()
tx, _ = d.BeginTran(c)
cp = &model.CouponAllowanceInfo{CouponToken: strconv.FormatInt(rand.Int63n(999999), 10)}
)
convey.Convey("TxAddAllowanceCoupon ", t, func(ctx convey.C) {
err := d.TxAddAllowanceCoupon(tx, cp)
if err == nil {
if err = tx.Commit(); err != nil {
tx.Rollback()
}
} else {
tx.Rollback()
}
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestDaoBatchAddAllowanceCoupon(t *testing.T) {
var (
c = context.TODO()
tx = &sql.Tx{}
mid = int64(0)
cps = []*model.CouponAllowanceInfo{}
err error
)
convey.Convey("BatchAddAllowanceCoupon", t, func(ctx convey.C) {
cps = append(cps, &model.CouponAllowanceInfo{
CouponToken: token(),
Mid: mid,
State: model.NotUsed,
StartTime: time.Now().Unix(),
ExpireTime: time.Now().AddDate(0, 0, 10).Unix(),
Origin: int64(1),
CTime: xtime.Time(time.Now().Unix()),
BatchToken: "1",
Amount: float64(1),
FullAmount: float64(100),
AppID: int64(1),
})
tx, err = d.BeginTran(c)
ctx.So(err, convey.ShouldBeNil)
_, err = d.BatchAddAllowanceCoupon(c, tx, mid, cps)
ctx.Convey("Then err should be nil.a should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestDaoAllowanceList(t *testing.T) {
var (
c = context.TODO()
mid = int64(0)
state = int8(0)
no = int64(0)
stime = time.Now()
)
convey.Convey("AllowanceList", t, func(ctx convey.C) {
_, err := d.AllowanceList(c, mid, state, no, stime)
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,50 @@
package dao
import (
"context"
"net/url"
"go-common/app/service/main/coupon/model"
"go-common/library/ecode"
"github.com/pkg/errors"
)
//CaptchaToken get captcha token.
func (d *Dao) CaptchaToken(c context.Context, bid string, ip string) (res *model.Token, err error) {
args := url.Values{}
args.Add("bid", bid)
resq := new(struct {
Code int `json:"code"`
Data *model.Token `json:"data"`
})
if err = d.client.Get(c, d.c.Property.CaptchaTokenURL, ip, args, resq); err != nil {
err = errors.Wrapf(err, "dao captcha token do")
return
}
if resq.Code != ecode.OK.Code() {
err = ecode.Int(resq.Code)
err = errors.Wrapf(err, "dao captcha token code")
return
}
res = resq.Data
return
}
//CaptchaVerify get captcha verify.
func (d *Dao) CaptchaVerify(c context.Context, code string, token string, ip string) (err error) {
args := url.Values{}
args.Add("token", token)
args.Add("code", code)
resq := new(struct {
Code int `json:"code"`
})
if err = d.client.Post(c, d.c.Property.CaptchaVerifyURL, ip, args, resq); err != nil {
err = errors.Wrapf(err, "dao captcha verify do")
return
}
if resq.Code != ecode.OK.Code() {
err = ecode.CouponCodeVerifyFaildErr
}
return
}

View File

@@ -0,0 +1,45 @@
package dao
import (
"context"
"testing"
"go-common/library/ecode"
"github.com/smartystreets/goconvey/convey"
)
func TestDaoCaptchaToken(t *testing.T) {
convey.Convey("CaptchaToken", t, func(convCtx convey.C) {
var (
c = context.Background()
bid = d.c.Property.CaptchaBID
ip = "127.0.0.1"
)
convCtx.Convey("When everything goes positive", func(convCtx convey.C) {
res, err := d.CaptchaToken(c, bid, ip)
convCtx.Convey("Then err should be nil.res should not be nil.", func(convCtx convey.C) {
convCtx.So(err, convey.ShouldBeNil)
convCtx.So(res, convey.ShouldNotBeNil)
})
})
})
}
func TestDaoCaptchaVerify(t *testing.T) {
convey.Convey("CaptchaVerify", t, func(convCtx convey.C) {
var (
c = context.Background()
code = "xxxx"
token = "xxxx"
ip = ""
)
convCtx.Convey("When everything goes positive", func(convCtx convey.C) {
err := d.CaptchaVerify(c, code, token, ip)
if err == ecode.CouponCodeVerifyFaildErr {
err = nil
}
convCtx.So(err, convey.ShouldBeNil)
})
})
}

View File

@@ -0,0 +1,50 @@
package dao
import (
"context"
xsql "database/sql"
"go-common/app/service/main/coupon/model"
"go-common/library/database/sql"
"github.com/pkg/errors"
)
const (
_couponCodeSQL = "SELECT id,batch_token,state,code,mid,coupon_type,ver FROM coupon_code WHERE code = ?;"
_countCouponCountSQL = "SELECT COUNT(1) FROM coupon_code WHERE mid = ? AND batch_token = ?;"
_updateCodeStateSQL = "UPDATE coupon_code SET state = ?, mid = ?,coupon_token = ?, ver = ver + 1 WHERE code = ? AND ver = ? AND state = 1;"
)
// CouponCode get open info by code.
func (d *Dao) CouponCode(c context.Context, code string) (res *model.CouponCode, err error) {
res = new(model.CouponCode)
if err = d.db.QueryRow(c, _couponCodeSQL, code).
Scan(&res.ID, &res.BatchToken, &res.State, &res.Code, &res.Mid, &res.CouponType, &res.Ver); err != nil {
if err == sql.ErrNoRows {
res = nil
err = nil
return
}
err = errors.Wrapf(err, "dao coupon code(%s)", code)
}
return
}
// CountCodeByMid get count code by mid.
func (d *Dao) CountCodeByMid(c context.Context, mid int64, batckToken string) (count int64, err error) {
if err = d.db.QueryRow(c, _countCouponCountSQL, mid, batckToken).Scan(&count); err != nil {
err = errors.Wrapf(err, "dao count code")
}
return
}
// TxUpdateCodeState update code state.
func (d *Dao) TxUpdateCodeState(tx *sql.Tx, a *model.CouponCode) (aff int64, err error) {
var res xsql.Result
if res, err = tx.Exec(_updateCodeStateSQL, a.State, a.Mid, a.CouponToken, a.Code, a.Ver); err != nil {
err = errors.Wrapf(err, "dao update code state(%+v)", a)
return
}
return res.RowsAffected()
}

View File

@@ -0,0 +1,67 @@
package dao
import (
"context"
"testing"
"go-common/app/service/main/coupon/model"
"go-common/library/database/sql"
"github.com/smartystreets/goconvey/convey"
)
func TestDaoCouponCode(t *testing.T) {
convey.Convey("CouponCode", t, func(convCtx convey.C) {
var (
c = context.Background()
code = "2asazxcvfdsb"
)
convCtx.Convey("When everything goes positive", func(convCtx convey.C) {
res, err := d.CouponCode(c, code)
convCtx.Convey("Then err should be nil.res should not be nil.", func(convCtx convey.C) {
convCtx.So(err, convey.ShouldBeNil)
convCtx.So(res, convey.ShouldNotBeNil)
})
})
})
}
func TestDaoCountCodeByMid(t *testing.T) {
convey.Convey("CountCodeByMid", t, func(convCtx convey.C) {
var (
c = context.Background()
mid = int64(1)
batckToken = "allowance_batch100"
)
convCtx.Convey("When everything goes positive", func(convCtx convey.C) {
count, err := d.CountCodeByMid(c, mid, batckToken)
convCtx.Convey("Then err should be nil.count should not be nil.", func(convCtx convey.C) {
convCtx.So(err, convey.ShouldBeNil)
convCtx.So(count, convey.ShouldNotBeNil)
})
})
})
}
func TestDaoTxUpdateCodeState(t *testing.T) {
convey.Convey("TxUpdateCodeState", t, func(convCtx convey.C) {
var (
tx = &sql.Tx{}
a = &model.CouponCode{
State: 2,
Mid: 1,
Ver: 1,
}
err error
)
convCtx.Convey("When everything goes positive", func(convCtx convey.C) {
tx, err = d.BeginTran(context.Background())
convCtx.So(err, convey.ShouldBeNil)
aff, err := d.TxUpdateCodeState(tx, a)
convCtx.Convey("Then err should be nil.aff should not be nil.", func(convCtx convey.C) {
convCtx.So(err, convey.ShouldBeNil)
convCtx.So(aff, convey.ShouldNotBeNil)
})
})
})
}

View File

@@ -0,0 +1,61 @@
package dao
import (
"context"
"time"
"go-common/app/service/main/coupon/conf"
"go-common/library/cache/memcache"
xsql "go-common/library/database/sql"
bm "go-common/library/net/http/blademaster"
"go-common/library/stat/prom"
)
// Dao dao
type Dao struct {
c *conf.Config
mc *memcache.Pool
db *xsql.DB
errProm *prom.Prom
mcExpire int32
prizeExpire int32
client *bm.Client
}
// New init mysql db
func New(c *conf.Config) (dao *Dao) {
dao = &Dao{
c: c,
mc: memcache.NewPool(c.Memcache.Config),
db: xsql.NewMySQL(c.MySQL),
errProm: prom.BusinessErrCount,
mcExpire: int32(time.Duration(c.Memcache.Expire) / time.Second),
prizeExpire: int32(time.Duration(c.Memcache.PrizeExpire) / time.Second),
client: bm.NewClient(c.HTTPClient),
}
return
}
// Close close the resource.
func (d *Dao) Close() {
d.mc.Close()
d.db.Close()
}
// Ping dao ping
func (d *Dao) Ping(c context.Context) (err error) {
if err = d.db.Ping(c); err != nil {
d.errProm.Incr("ping_db")
return
}
err = d.pingMC(c)
return
}
// pingMc ping
func (d *Dao) pingMC(c context.Context) (err error) {
conn := d.mc.Get(c)
defer conn.Close()
item := memcache.Item{Key: "ping", Value: []byte{1}, Expiration: d.mcExpire}
return conn.Set(&item)
}

View File

@@ -0,0 +1,65 @@
package dao
import (
"context"
"flag"
"os"
"strings"
"testing"
"go-common/app/service/main/coupon/conf"
"github.com/smartystreets/goconvey/convey"
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.coupon-service")
flag.Set("conf_token", "6f73e99036aecfafd140c193c036120b")
flag.Set("tree_id", "22595")
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/coupon-service.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
}
func TestDaoPing(t *testing.T) {
convey.Convey("TestDaoPing", t, func(convCtx convey.C) {
err := d.Ping(context.Background())
convCtx.Convey("Then err should be nil.", func(convCtx convey.C) {
convCtx.So(err, convey.ShouldBeNil)
})
})
}
func TestDaopingMC(t *testing.T) {
convey.Convey("TestDaopingMC", t, func(convCtx convey.C) {
err := d.pingMC(context.Background())
convCtx.Convey("Then err should be nil.", func(convCtx convey.C) {
convCtx.So(err, convey.ShouldBeNil)
})
})
}

View File

@@ -0,0 +1,36 @@
package dao
import (
"context"
"go-common/library/log"
"go-common/library/net/metadata"
"net/url"
"strconv"
"github.com/pkg/errors"
)
const (
couponSystemNotify = 4
couponMC = "10_99_1"
sendMessage = "/api/notify/send.user.notify.do"
)
//SendMessage send message.
func (d *Dao) SendMessage(c context.Context, mids, content, title string) (err error) {
params := url.Values{}
params.Set("mc", couponMC)
params.Set("title", title)
params.Set("context", content)
params.Set("data_type", strconv.FormatInt(couponSystemNotify, 10))
params.Set("mid_list", mids)
defer func() {
log.Info("send message url:%+v params:%+v err:%+v ", d.c.Property.MessageURL+sendMessage, params, err)
}()
ip := metadata.String(c, metadata.RemoteIP)
if err = d.client.Post(c, d.c.Property.MessageURL+sendMessage, ip, params, nil); err != nil {
err = errors.WithStack(err)
}
return
}

View File

@@ -0,0 +1,29 @@
package dao
import (
"context"
"testing"
gock "gopkg.in/h2non/gock.v1"
"github.com/smartystreets/goconvey/convey"
)
func TestDaoSendMessage(t *testing.T) {
convey.Convey("SendMessage", t, func(convCtx convey.C) {
var (
c = context.Background()
mids = ""
content = ""
title = ""
)
convCtx.Convey("When everything goes positive", func(convCtx convey.C) {
defer gock.OffAll()
httpMock("POST", sendMessage).Reply(200).JSON(`{"code":0}`)
err := d.SendMessage(c, mids, content, title)
convCtx.Convey("Then err should be nil.", func(convCtx convey.C) {
convCtx.So(err, convey.ShouldBeNil)
})
})
})
}

View File

@@ -0,0 +1,507 @@
package dao
import (
"context"
"fmt"
"go-common/app/service/main/coupon/model"
gmc "go-common/library/cache/memcache"
"go-common/library/log"
"github.com/pkg/errors"
)
const (
_prefixCoupons = "cs:%d:%d"
_prefixUseUnique = "cu:%s:%d"
_prefixCouponBlance = "cbl:%d:%d"
_prefixGrantUnique = "gr:%s:%d"
_prefixBranchCount = "bcu:%s"
_useLockTimeout = 10
_prefixCouponAllowances = "cas:%d:%d"
_receiveLog = "rl:%s%s%d"
_uniqueNo = "uq:%s"
_useUniqueNoTimeout = 1296000 //15天
_prefixprizeCard = "nypc:%d:%d:%d" // 元旦活动卡片
_prefixprizeCards = "nypcs:%d:%d" // 元旦活动卡片列表
)
func receiveLogKey(appkey, orderNo string, ct int8) string {
return fmt.Sprintf(_receiveLog, appkey, orderNo, ct)
}
func couponsKey(mid int64, ct int8) string {
return fmt.Sprintf(_prefixCoupons, ct, mid)
}
func useUniqueKey(orderNO string, ct int8) string {
return fmt.Sprintf(_prefixUseUnique, orderNO, ct)
}
func couponBalancesKey(mid int64, ct int8) string {
return fmt.Sprintf(_prefixCouponBlance, ct, mid)
}
func userGrantKey(token string, mid int64) string {
return fmt.Sprintf(_prefixGrantUnique, token, mid)
}
func branchCurrentCount(token string) string {
return fmt.Sprintf(_prefixBranchCount, token)
}
func couponAllowancesKey(mid int64, state int8) string {
return fmt.Sprintf(_prefixCouponAllowances, mid, state)
}
func prizeCardKey(mid, actID int64, cardType int8) string {
return fmt.Sprintf(_prefixprizeCard, mid, actID, cardType)
}
func prizeCardsKey(mid, actID int64) string {
return fmt.Sprintf(_prefixprizeCards, mid, actID)
}
func couponuniqueNoKey(uniqueno string) string {
return fmt.Sprintf(_uniqueNo, uniqueno)
}
// DelUniqueKey delete use coupon lock cache.
func (d *Dao) DelUniqueKey(c context.Context, orderNO string, ct int8) (err error) {
return d.delCache(c, useUniqueKey(orderNO, ct))
}
// DelCouponsCache delete user coupons cache.
func (d *Dao) DelCouponsCache(c context.Context, mid int64, ct int8) (err error) {
return d.delCache(c, couponsKey(mid, ct))
}
// DelCouponBalancesCache delete user coupons blance cache.
func (d *Dao) DelCouponBalancesCache(c context.Context, mid int64, ct int8) (err error) {
return d.delCache(c, couponBalancesKey(mid, ct))
}
// DelGrantKey delete user grant lock cache.
func (d *Dao) DelGrantKey(c context.Context, token string, mid int64) (err error) {
return d.delCache(c, userGrantKey(token, mid))
}
// DelBranchCurrentCountKey delete branch current cache.
func (d *Dao) DelBranchCurrentCountKey(c context.Context, token string) (err error) {
return d.delCache(c, branchCurrentCount(token))
}
// DelCouponAllowancesKey delete allowances cache.
func (d *Dao) DelCouponAllowancesKey(c context.Context, mid int64, state int8) (err error) {
return d.delCache(c, couponAllowancesKey(mid, state))
}
// DelPrizeCardKey .
func (d *Dao) DelPrizeCardKey(c context.Context, mid, actID int64, cardType int8) (err error) {
return d.delCache(c, prizeCardKey(mid, actID, cardType))
}
// DelPrizeCardsKey .
func (d *Dao) DelPrizeCardsKey(c context.Context, mid, actID int64) (err error) {
return d.delCache(c, prizeCardsKey(mid, actID))
}
// CouponsCache coupons cache.
func (d *Dao) CouponsCache(c context.Context, mid int64, ct int8) (coupons []*model.CouponInfo, err error) {
var (
key = couponsKey(mid, ct)
item *gmc.Item
)
conn := d.mc.Get(c)
defer conn.Close()
item, err = conn.Get(key)
if err != nil {
if err == gmc.ErrNotFound {
err = nil
return
}
err = errors.Wrapf(err, "mc.Get(%s)", key)
d.errProm.Incr("get_mc")
return
}
couponInfoList := &model.PointInfoList{}
if err = conn.Scan(item, couponInfoList); err != nil {
err = errors.Wrapf(err, "mc.Scan(%s)", key)
d.errProm.Incr("scan_mc")
return
}
coupons = couponInfoList.PointInfoList
if coupons == nil {
coupons = []*model.CouponInfo{}
}
return
}
// SetCouponsCache set coupons cache.
func (d *Dao) SetCouponsCache(c context.Context, mid int64, ct int8, coupons []*model.CouponInfo) (err error) {
var (
expire = d.mcExpire
key = couponsKey(mid, ct)
)
conn := d.mc.Get(c)
defer conn.Close()
item := &gmc.Item{Key: key, Object: &model.PointInfoList{PointInfoList: coupons}, Expiration: expire, Flags: gmc.FlagProtobuf}
if err = conn.Set(item); err != nil {
err = errors.Wrapf(err, "mc.Set(%s)", key)
d.errProm.Incr("set_mc")
}
return
}
// AddUseUniqueLock add coupon use lock.
func (d *Dao) AddUseUniqueLock(c context.Context, orderNO string, ct int8) (succeed bool) {
var (
key = useUniqueKey(orderNO, ct)
conn = d.mc.Get(c)
err error
)
defer conn.Close()
item := &gmc.Item{
Key: key,
Value: []byte("0"),
Expiration: _useLockTimeout,
}
if err = conn.Add(item); err != nil {
if err != gmc.ErrNotStored {
log.Error("mc.Add(%s) error(%v)", key, err)
d.errProm.Incr("add_mc")
}
} else {
succeed = true
}
return
}
// AddReceiveUniqueLock add coupon use lock.
func (d *Dao) AddReceiveUniqueLock(c context.Context, appkey, orderNO string, ct int8) (succeed bool) {
var (
key = receiveLogKey(appkey, orderNO, ct)
conn = d.mc.Get(c)
err error
)
defer conn.Close()
item := &gmc.Item{
Key: key,
Value: []byte("0"),
Expiration: _useLockTimeout,
}
if err = conn.Add(item); err != nil {
if err != gmc.ErrNotStored {
log.Error("mc.Add(%s) error(%v)", key, err)
d.errProm.Incr("add_mc")
}
} else {
succeed = true
}
return
}
//DelReceiveUniqueLock del receive lock.
func (d *Dao) DelReceiveUniqueLock(c context.Context, appkey, orderNO string, ct int8) (err error) {
err = d.delCache(c, receiveLogKey(appkey, orderNO, ct))
return
}
// DelCache del cache.
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 == gmc.ErrNotFound {
err = nil
} else {
err = errors.Wrapf(err, "mc.Delete(%s)", key)
d.errProm.Incr("del_mc")
}
}
return
}
// CouponBlanceCache coupon blance cache.
func (d *Dao) CouponBlanceCache(c context.Context, mid int64, ct int8) (coupons []*model.CouponBalanceInfo, err error) {
var (
key = couponBalancesKey(mid, ct)
item *gmc.Item
)
conn := d.mc.Get(c)
defer conn.Close()
item, err = conn.Get(key)
if err != nil {
if err == gmc.ErrNotFound {
err = nil
return
}
err = errors.Wrapf(err, "mc.Get(%s)", key)
d.errProm.Incr("get_mc")
return
}
couponBlanceList := &model.CouponBalanceList{}
if err = conn.Scan(item, couponBlanceList); err != nil {
err = errors.Wrapf(err, "mc.Scan(%s)", key)
d.errProm.Incr("scan_mc")
return
}
coupons = couponBlanceList.CouponBalanceList
if coupons == nil {
coupons = []*model.CouponBalanceInfo{}
}
return
}
// SetCouponBlanceCache set coupon blance cache.
func (d *Dao) SetCouponBlanceCache(c context.Context, mid int64, ct int8, coupons []*model.CouponBalanceInfo) (err error) {
var (
expire = d.mcExpire
key = couponBalancesKey(mid, ct)
)
conn := d.mc.Get(c)
defer conn.Close()
item := &gmc.Item{Key: key, Object: &model.CouponBalanceList{CouponBalanceList: coupons}, Expiration: expire, Flags: gmc.FlagProtobuf}
if err = conn.Set(item); err != nil {
err = errors.Wrapf(err, "mc.Set(%s)", key)
d.errProm.Incr("set_mc")
}
return
}
// AddUniqueNoLock add grant coupon use lock.
func (d *Dao) AddUniqueNoLock(c context.Context, uniqueno string) (succeed bool) {
var (
key = couponuniqueNoKey(uniqueno)
conn = d.mc.Get(c)
err error
)
defer conn.Close()
item := &gmc.Item{
Key: key,
Value: []byte("0"),
Expiration: _useUniqueNoTimeout,
}
if err = conn.Add(item); err != nil {
if err != gmc.ErrNotStored {
log.Error("mc.Add(%s) error(%v)", key, err)
d.errProm.Incr("add_mc")
}
} else {
succeed = true
}
return
}
// AddGrantUniqueLock add grant unique coupon use lock.
func (d *Dao) AddGrantUniqueLock(c context.Context, token string, mid int64) (succeed bool) {
var (
key = userGrantKey(token, mid)
conn = d.mc.Get(c)
err error
)
defer conn.Close()
item := &gmc.Item{
Key: key,
Value: []byte("0"),
Expiration: _useLockTimeout,
}
if err = conn.Add(item); err != nil {
if err != gmc.ErrNotStored {
log.Error("mc.Add(%s) error(%v)", key, err)
d.errProm.Incr("add_mc")
}
} else {
succeed = true
}
return
}
//BranchCurrentCountCache branchInfo current count cache.
func (d *Dao) BranchCurrentCountCache(c context.Context, token string) (count int, err error) {
var (
key = branchCurrentCount(token)
conn = d.mc.Get(c)
item *gmc.Item
)
defer conn.Close()
if item, err = conn.Get(key); err != nil {
if err == gmc.ErrNotFound {
err = nil
count = -1
return
}
err = errors.Wrapf(err, "conn.Get(%s)", key)
return
}
if err = conn.Scan(item, &count); err != nil {
err = errors.Wrapf(err, "conn.Scan(%+v)", item)
return
}
return
}
// SetBranchCurrentCountCache set branch current cache.
func (d *Dao) SetBranchCurrentCountCache(c context.Context, token string, count int) (err error) {
var (
key = branchCurrentCount(token)
conn = d.mc.Get(c)
)
defer conn.Close()
if err = conn.Set(&gmc.Item{Key: key, Object: count, Flags: gmc.FlagJSON, Expiration: d.mcExpire}); err != nil {
err = errors.Wrapf(err, "conn.Set(%s,%+v)", key, count)
return
}
return
}
// IncreaseBranchCurrentCountCache increase branch current count cache.
func (d *Dao) IncreaseBranchCurrentCountCache(c context.Context, token string, count uint64) (err error) {
var (
key = branchCurrentCount(token)
conn = d.mc.Get(c)
)
defer conn.Close()
if _, err = conn.Increment(key, count); err != nil {
err = errors.Wrapf(err, "conn.Increment(%s,%d)", key, count)
return
}
return
}
// CouponAllowanceCache coupon allowance cache.
func (d *Dao) CouponAllowanceCache(c context.Context, mid int64, state int8) (coupons []*model.CouponAllowanceInfo, err error) {
var (
key = couponAllowancesKey(mid, state)
item *gmc.Item
)
conn := d.mc.Get(c)
defer conn.Close()
item, err = conn.Get(key)
if err != nil {
if err == gmc.ErrNotFound {
err = nil
coupons = nil
return
}
err = errors.Wrapf(err, "mc.Get(%s)", key)
d.errProm.Incr("get_mc")
return
}
couponAllowanceList := &model.CouponAllowanceList{}
if err = conn.Scan(item, couponAllowanceList); err != nil {
err = errors.Wrapf(err, "mc.Scan(%s)", key)
d.errProm.Incr("scan_mc")
return
}
coupons = couponAllowanceList.CouponAllowanceList
if coupons == nil {
coupons = []*model.CouponAllowanceInfo{}
}
return
}
// SetCouponAllowanceCache set coupon allowance cache.
func (d *Dao) SetCouponAllowanceCache(c context.Context, mid int64, state int8, coupons []*model.CouponAllowanceInfo) (err error) {
var (
expire = d.mcExpire
key = couponAllowancesKey(mid, state)
)
conn := d.mc.Get(c)
defer conn.Close()
item := &gmc.Item{Key: key, Object: &model.CouponAllowanceList{CouponAllowanceList: coupons}, Expiration: expire, Flags: gmc.FlagProtobuf}
if err = conn.Set(item); err != nil {
err = errors.Wrapf(err, "mc.Set(%s)", key)
d.errProm.Incr("set_mc")
}
return
}
// SetPrizeCardCache .
func (d *Dao) SetPrizeCardCache(c context.Context, mid, actID int64, prizeCard *model.PrizeCardRep) (err error) {
var (
expire = d.prizeExpire
key = prizeCardKey(mid, actID, prizeCard.CardType)
)
conn := d.mc.Get(c)
defer conn.Close()
item := &gmc.Item{Key: key, Object: prizeCard, Expiration: expire, Flags: gmc.FlagJSON}
if err = conn.Set(item); err != nil {
err = errors.Wrapf(err, "mc.Set(%s)", key)
d.errProm.Incr("set_mc")
}
return
}
// SetPrizeCardsCache .
func (d *Dao) SetPrizeCardsCache(c context.Context, mid, actID int64, prizeCards []*model.PrizeCardRep) (err error) {
var (
expire = d.prizeExpire
key = prizeCardsKey(mid, actID)
)
conn := d.mc.Get(c)
defer conn.Close()
item := &gmc.Item{Key: key, Object: &model.PrizeCards{List: prizeCards}, Expiration: expire, Flags: gmc.FlagJSON}
if err = conn.Set(item); err != nil {
err = errors.Wrapf(err, "mc.Set(%s)", key)
d.errProm.Incr("set_mc")
}
return
}
// PrizeCardCache .
func (d *Dao) PrizeCardCache(c context.Context, mid, actID int64, cardType int8) (prizeCard *model.PrizeCardRep, err error) {
var (
key = prizeCardKey(mid, actID, cardType)
item *gmc.Item
)
conn := d.mc.Get(c)
defer conn.Close()
item, err = conn.Get(key)
if err != nil {
if err == gmc.ErrNotFound {
err = nil
return
}
err = errors.Wrapf(err, "mc.Get(%s)", key)
d.errProm.Incr("get_mc")
return
}
prizeCard = &model.PrizeCardRep{}
if err = conn.Scan(item, &prizeCard); err != nil {
err = errors.Wrapf(err, "mc.Scan(%s)", key)
d.errProm.Incr("scan_mc")
return
}
return
}
// PrizeCardsCache .
func (d *Dao) PrizeCardsCache(c context.Context, mid, actID int64) (prizeCards []*model.PrizeCardRep, err error) {
var (
key = prizeCardsKey(mid, actID)
item *gmc.Item
)
conn := d.mc.Get(c)
defer conn.Close()
item, err = conn.Get(key)
if err != nil {
if err == gmc.ErrNotFound {
err = nil
return
}
err = errors.Wrapf(err, "mc.Get(%s)", key)
d.errProm.Incr("get_mc")
return
}
PrizeCardlist := &model.PrizeCards{}
if err = conn.Scan(item, PrizeCardlist); err != nil {
err = errors.Wrapf(err, "mc.Scan(%s)", key)
d.errProm.Incr("scan_mc")
return
}
prizeCards = PrizeCardlist.List
if prizeCards == nil {
prizeCards = []*model.PrizeCardRep{}
}
return
}

View File

@@ -0,0 +1,519 @@
package dao
import (
"context"
"testing"
"go-common/app/service/main/coupon/model"
"github.com/smartystreets/goconvey/convey"
)
func TestDaoreceiveLogKey(t *testing.T) {
var (
appkey = "123"
orderNo = "456"
ct = int8(0)
)
convey.Convey("TestDaoreceiveLogKey ", t, func(ctx convey.C) {
p1 := receiveLogKey(appkey, orderNo, ct)
ctx.Convey("Then p1 should equal.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldEqual, "rl:1234560")
})
})
}
func TestDaoprizeCardKey(t *testing.T) {
var (
mid int64 = 22
actID int64 = 1
ct = int8(0)
)
convey.Convey("TestDaoprizeCardKey ", t, func(ctx convey.C) {
p1 := prizeCardKey(mid, actID, ct)
ctx.Convey("Then p1 should equal.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldEqual, "nypc:22:1:0")
})
})
}
func TestDaoprizeCardsKey(t *testing.T) {
var (
mid int64 = 22
actID int64 = 1
)
convey.Convey("TestDaoprizeCardsKey ", t, func(ctx convey.C) {
p1 := prizeCardsKey(mid, actID)
ctx.Convey("Then p1 should equal.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldEqual, "nypcs:22:1")
})
})
}
func TestDaocouponuniqueNoKey(t *testing.T) {
var (
uniqueno string = "uniqueno"
)
convey.Convey("TestDaocouponuniqueNoKey ", t, func(ctx convey.C) {
p1 := couponuniqueNoKey(uniqueno)
ctx.Convey("Then p1 should equal.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldEqual, "uq:uniqueno")
})
})
}
func TestDaocouponsKey(t *testing.T) {
var (
mid = int64(0)
ct = int8(0)
)
convey.Convey("couponsKey ", t, func(ctx convey.C) {
p1 := couponsKey(mid, ct)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
}
func TestDaouseUniqueKey(t *testing.T) {
var (
orderNO = "1"
ct = int8(0)
)
convey.Convey("useUniqueKey", t, func(ctx convey.C) {
p1 := useUniqueKey(orderNO, ct)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
}
func TestDaocouponBalancesKey(t *testing.T) {
var (
mid = int64(0)
ct = int8(0)
)
convey.Convey("couponBalancesKey", t, func(ctx convey.C) {
p1 := couponBalancesKey(mid, ct)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
}
func TestDaouserGrantKey(t *testing.T) {
var (
token = "1"
mid = int64(0)
)
convey.Convey("userGrantKey", t, func(ctx convey.C) {
p1 := userGrantKey(token, mid)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
}
func TestDaobranchCurrentCount(t *testing.T) {
var (
token = "1"
)
convey.Convey("branchCurrentCount", t, func(ctx convey.C) {
p1 := branchCurrentCount(token)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
}
func TestDaocouponAllowancesKey(t *testing.T) {
var (
mid = int64(0)
)
convey.Convey("couponAllowancesKey", t, func(ctx convey.C) {
p1 := couponAllowancesKey(mid, 0)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
}
func TestDaoDelUniqueKey(t *testing.T) {
var (
c = context.TODO()
orderNO = "1"
ct = int8(0)
)
convey.Convey("DelUniqueKey", t, func(ctx convey.C) {
err := d.DelUniqueKey(c, orderNO, ct)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestDaoDelCouponsCache(t *testing.T) {
var (
c = context.TODO()
mid = int64(0)
ct = int8(0)
)
convey.Convey("DelCouponsCache", t, func(ctx convey.C) {
err := d.DelCouponsCache(c, mid, ct)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestDaoDelCouponBalancesCache(t *testing.T) {
var (
c = context.TODO()
mid = int64(0)
ct = int8(0)
)
convey.Convey("DelCouponBalancesCache", t, func(ctx convey.C) {
err := d.DelCouponBalancesCache(c, mid, ct)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestDaoDelGrantKey(t *testing.T) {
var (
c = context.TODO()
token = "1"
mid = int64(0)
)
convey.Convey("DelGrantKey", t, func(ctx convey.C) {
err := d.DelGrantKey(c, token, mid)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestDaoDelBranchCurrentCountKey(t *testing.T) {
var (
c = context.TODO()
token = "1"
)
convey.Convey("DelBranchCurrentCountKey", t, func(ctx convey.C) {
err := d.DelBranchCurrentCountKey(c, token)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestDaoDelCouponAllowancesKey(t *testing.T) {
var (
c = context.Background()
mid = int64(0)
)
convey.Convey("DelCouponAllowancesKey", t, func(ctx convey.C) {
err := d.DelCouponAllowancesKey(c, mid, 0)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestDaoDelPrizeCardKey(t *testing.T) {
var (
c = context.Background()
mid int64 = 22
actID int64 = 1
ct = int8(0)
)
convey.Convey("DelPrizeCardKey", t, func(ctx convey.C) {
err := d.DelPrizeCardKey(c, mid, actID, ct)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestDaoDelPrizeCardsKey(t *testing.T) {
var (
c = context.Background()
mid int64 = 22
actID int64 = 1
)
convey.Convey("DelCouponAllowancesKey", t, func(ctx convey.C) {
err := d.DelPrizeCardsKey(c, mid, actID)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestDaoCouponsCache(t *testing.T) {
var (
c = context.TODO()
mid = int64(0)
ct = int8(0)
coupons = []*model.CouponInfo{}
err error
)
convey.Convey("CouponsCache", t, func(ctx convey.C) {
coupons, err = d.CouponsCache(c, mid, ct)
ctx.Convey("Then err should be nil.coupons should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(coupons, convey.ShouldBeNil)
})
err = d.SetCouponsCache(c, mid, ct, coupons)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
coupons, err = d.CouponsCache(c, mid, ct)
ctx.Convey("Then err should be nil.coupons should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(coupons, convey.ShouldNotBeNil)
})
})
}
func TestDaoAddUseUniqueLock(t *testing.T) {
var (
c = context.TODO()
orderNO = "1"
ct = int8(0)
)
convey.Convey("AddUseUniqueLock", t, func(ctx convey.C) {
succeed := d.AddUseUniqueLock(c, orderNO, ct)
ctx.Convey("Then succeed should not be nil.", func(ctx convey.C) {
ctx.So(succeed, convey.ShouldNotBeNil)
})
})
}
func TestDaoAddReceiveUniqueLock(t *testing.T) {
var (
c = context.TODO()
appkey = "1"
orderNO = "2"
ct = int8(0)
)
convey.Convey("AddReceiveUniqueLock", t, func(ctx convey.C) {
succeed := d.AddReceiveUniqueLock(c, appkey, orderNO, ct)
ctx.Convey("Then succeed should not be nil.", func(ctx convey.C) {
ctx.So(succeed, convey.ShouldNotBeNil)
})
})
}
func TestDaoDelReceiveUniqueLock(t *testing.T) {
var (
c = context.TODO()
appkey = "1"
orderNO = "1"
ct = int8(0)
)
convey.Convey("DelReceiveUniqueLock ", t, func(ctx convey.C) {
err := d.DelReceiveUniqueLock(c, appkey, orderNO, ct)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestDaodelCache(t *testing.T) {
var (
c = context.TODO()
key = "1"
)
convey.Convey("delCache", t, func(ctx convey.C) {
err := d.delCache(c, key)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestDaoCouponBlanceCache(t *testing.T) {
var (
c = context.TODO()
mid = int64(0)
ct = int8(0)
coupons = []*model.CouponBalanceInfo{}
)
convey.Convey("CouponBlanceCache", t, func(ctx convey.C) {
err := d.SetCouponBlanceCache(c, mid, ct, coupons)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
coupons, err := d.CouponBlanceCache(c, mid, ct)
ctx.Convey("Then err should be nil.coupons should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(coupons, convey.ShouldNotBeNil)
})
})
}
func TestDaoAddUniqueNoLock(t *testing.T) {
var (
c = context.TODO()
uniqueno = "1"
)
convey.Convey("AddUniqueNoLock", t, func(ctx convey.C) {
succeed := d.AddUniqueNoLock(c, uniqueno)
ctx.Convey("Then succeed should not be nil.", func(ctx convey.C) {
ctx.So(succeed, convey.ShouldNotBeNil)
})
})
}
func TestDaoAddGrantUniqueLock(t *testing.T) {
var (
c = context.TODO()
token = "1"
mid = int64(0)
)
convey.Convey("AddGrantUniqueLock", t, func(ctx convey.C) {
succeed := d.AddGrantUniqueLock(c, token, mid)
ctx.Convey("Then succeed should not be nil.", func(ctx convey.C) {
ctx.So(succeed, convey.ShouldNotBeNil)
})
})
}
func TestDaoBranchCurrentCountCache(t *testing.T) {
var (
c = context.TODO()
token = "1"
)
convey.Convey("BranchCurrentCountCache", t, func(ctx convey.C) {
count, err := d.BranchCurrentCountCache(c, token)
ctx.Convey("Then err should be nil.count should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(count, convey.ShouldNotBeNil)
})
})
}
func TestDaoSetBranchCurrentCountCache(t *testing.T) {
var (
c = context.TODO()
token = "1"
count = int(0)
)
convey.Convey("SetBranchCurrentCountCache", t, func(ctx convey.C) {
err := d.SetBranchCurrentCountCache(c, token, count)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestDaoIncreaseBranchCurrentCountCache(t *testing.T) {
var (
c = context.TODO()
token = "1"
count = uint64(0)
)
convey.Convey("IncreaseBranchCurrentCountCache", t, func(ctx convey.C) {
err := d.IncreaseBranchCurrentCountCache(c, token, count)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestDaoCouponAllowanceCache(t *testing.T) {
var (
c = context.TODO()
mid = int64(0)
coupons = []*model.CouponAllowanceInfo{}
)
convey.Convey("CouponAllowanceCache", t, func(ctx convey.C) {
err := d.SetCouponAllowanceCache(c, mid, 0, coupons)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
coupons, err := d.CouponAllowanceCache(c, mid, 0)
ctx.Convey("Then err should be nil.coupons should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(coupons, convey.ShouldNotBeNil)
})
})
}
func TestDaoSetPrizeCardCache(t *testing.T) {
var (
c = context.TODO()
mid int64 = 1
actID int64 = 1
prizeCard = &model.PrizeCardRep{}
)
convey.Convey("SetPrizeCardCache ", t, func(ctx convey.C) {
err := d.SetPrizeCardCache(c, mid, actID, prizeCard)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestDaoSetPrizeCardsCache(t *testing.T) {
var (
c = context.TODO()
mid = int64(1)
actID = int64(1)
prizeCards = make([]*model.PrizeCardRep, 0)
prizeCard = &model.PrizeCardRep{}
)
prizeCards = append(prizeCards, prizeCard)
convey.Convey("SetPrizeCardsCache ", t, func(ctx convey.C) {
err := d.SetPrizeCardsCache(c, mid, actID, prizeCards)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestDaoPrizeCardCache(t *testing.T) {
var (
c = context.TODO()
mid = int64(1)
actID = int64(1)
ct = int8(0)
prizeCard = &model.PrizeCardRep{}
)
convey.Convey("PrizeCardCache", t, func(ctx convey.C) {
d.SetPrizeCardCache(c, mid, actID, prizeCard)
res, err := d.PrizeCardCache(c, mid, actID, ct)
ctx.Convey("Then err should be nil.res should be not nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(res, convey.ShouldNotBeNil)
})
d.DelPrizeCardKey(c, mid, actID, ct)
res, err = d.PrizeCardCache(c, mid, actID, ct)
ctx.Convey("Then err should be nil.res should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(res, convey.ShouldBeNil)
})
})
}
func TestDaoPrizeCardsCache(t *testing.T) {
var (
c = context.TODO()
mid = int64(1)
actID = int64(1)
prizeCards = make([]*model.PrizeCardRep, 0)
prizeCard = &model.PrizeCardRep{}
)
prizeCards = append(prizeCards, prizeCard)
convey.Convey("PrizeCardCache", t, func(ctx convey.C) {
d.SetPrizeCardsCache(c, mid, actID, prizeCards)
res, err := d.PrizeCardsCache(c, mid, actID)
ctx.Convey("Then err should be nil.res should be not nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(res, convey.ShouldNotBeNil)
})
d.DelPrizeCardsKey(c, mid, actID)
res, err = d.PrizeCardsCache(c, mid, actID)
ctx.Convey("Then err should be nil.res should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(res, convey.ShouldBeNil)
})
})
}

View File

@@ -0,0 +1,741 @@
package dao
import (
"bytes"
"context"
xsql "database/sql"
"fmt"
"strconv"
"time"
"go-common/app/service/main/coupon/model"
"go-common/library/database/sql"
"go-common/library/xstr"
"github.com/pkg/errors"
)
const (
_couponsSQL = "SELECT id,coupon_token,mid,state,start_time,expire_time,origin,coupon_type,order_no,oid,remark,use_ver,ver,ctime,mtime FROM coupon_info_%02d WHERE mid = ? AND state = ? AND coupon_type = ? AND expire_time > ? AND start_time < ? ORDER BY expire_time;"
_couponsNoStartCheckSQL = "SELECT id,coupon_token,mid,state,start_time,expire_time,origin,coupon_type,order_no,oid,remark,use_ver,ver,ctime,mtime FROM coupon_info_%02d WHERE mid = ? AND state = ? AND coupon_type = ? AND expire_time > ? ORDER BY expire_time;"
_couponByOrderNOAndTypeSQL = "SELECT id,coupon_token,mid,state,start_time,expire_time,origin,coupon_type,order_no,oid,remark,use_ver,ver,ctime,mtime FROM coupon_info_%02d WHERE order_no = ? AND coupon_type = ?;"
_updateCouponInUseSQL = "UPDATE coupon_info_%02d SET state =?, order_no = ?, oid = ?, remark = ?,use_ver = ?,ver = ? WHERE coupon_token = ? AND ver = ?;"
_addCouponChangeLogSQL = "INSERT INTO coupon_change_log_%02d (coupon_token,mid,state,ctime) VALUES(?,?,?,?);"
_couponByTokenSQL = "SELECT id,coupon_token,mid,state,start_time,expire_time,origin,coupon_type,order_no,oid,remark,use_ver,ver,ctime,mtime FROM coupon_info_%02d WHERE coupon_token = ?;"
_couponPageNotUsedSQL = "SELECT id,coupon_token,mid,state,start_time,expire_time,origin,coupon_type,order_no,oid,remark,use_ver,ver,ctime,mtime FROM coupon_info_%02d WHERE mid = ? AND state = ? AND expire_time > ? AND start_time < ? AND ctime > ? ORDER BY mtime DESC LIMIT ?,?;"
_couponPageUsedSQL = "SELECT id,coupon_token,mid,state,start_time,expire_time,origin,coupon_type,order_no,oid,remark,use_ver,ver,ctime,mtime FROM coupon_info_%02d WHERE mid = ? AND state = ? AND ctime > ? ORDER BY mtime DESC LIMIT ?,?;"
_couponPageExpireSQL = "SELECT id,coupon_token,mid,state,start_time,expire_time,origin,coupon_type,order_no,oid,remark,use_ver,ver,ctime,mtime FROM coupon_info_%02d WHERE mid = ? AND state = 0 AND expire_time < ? AND ctime > ? ORDER BY mtime DESC LIMIT ?,?;"
_countNotUsedSQL = "SELECT COUNT(1) FROM coupon_info_%02d WHERE mid = ? AND state = ? AND expire_time > ? AND start_time < ? AND ctime > ? ;"
_countUsedSQL = "SELECT COUNT(1) FROM coupon_info_%02d WHERE mid = ? AND state = ? AND ctime > ? ;"
_countExpireSQL = "SELECT COUNT(1) FROM coupon_info_%02d WHERE mid = ? AND state = 0 AND expire_time < ? AND ctime > ? ;"
_addCouponSQL = "INSERT INTO coupon_info_%02d (coupon_token,mid,state,start_time,expire_time,origin,coupon_type,ctime)VALUES(?,?,?,?,?,?,?,?);"
_updateStateSQL = "UPDATE coupon_info_%02d SET state = ?,use_ver = ?,ver = ? WHERE coupon_token = ? AND ver = ? "
_batchAddCouponSQL = "INSERT INTO coupon_info_%02d (coupon_token,mid,state,start_time,expire_time,origin,coupon_type,ctime,batch_token)VALUES "
_batchCountByMid = "SELECT COUNT(1) FROM coupon_info_%02d WHERE mid = ? AND batch_token = ?;"
//coupon blance
_couponBlanceNoStartCheckSQL = "SELECT id,batch_token,mid,balance,start_time,expire_time,origin,coupon_type,ver,ctime,mtime FROM coupon_balance_info_%02d WHERE mid = ? AND expire_time > ? AND coupon_type = ? ORDER BY expire_time;"
_couponBlanceSQL = "SELECT id,batch_token,mid,balance,start_time,expire_time,origin,coupon_type,ver,ctime,mtime FROM coupon_balance_info_%02d WHERE mid = ? AND expire_time > ? AND coupon_type = ? AND start_time < ? ORDER BY expire_time;"
_orderByThirdTradeNoSQL = "SELECT id,order_no,mid,count,state,coupon_type,third_trade_no,remark,tips,use_ver,ver,ctime,mtime FROM coupon_order WHERE third_trade_no = ? AND coupon_type= ?;"
_updateBlanceSQL = "UPDATE coupon_balance_info_%02d SET balance = ?,ver = ver + 1 WHERE id = ? AND ver = ?;"
_addOrderSQL = "INSERT INTO coupon_order(order_no,mid,count,state,coupon_type,third_trade_no,remark,tips,use_ver,ver,ctime)VALUES(?,?,?,?,?,?,?,?,?,?,?);"
_addOrderLogSQL = "INSERT INTO coupon_order_log(order_no,mid,state,ctime)VALUES(?,?,?,?);"
_addBalanceLogSQL = "INSERT INTO coupon_balance_change_log_%02d(order_no,mid,batch_token,balance,change_balance,change_type,ctime)VALUES "
_batchUpdateBalance = "UPDATE coupon_balance_info_%02d SET ver =ver + 1, balance = CASE id"
_countBalanceNotUsed = "SELECT COUNT(1) FROM coupon_balance_info_%02d WHERE mid = ? AND expire_time > ? AND start_time < ? AND coupon_type = ? AND balance > 0 AND ctime > ? ;"
_countUseListSQL = "SELECT COUNT(1) FROM coupon_order WHERE mid= ? AND state= ? AND coupon_type = ? AND ctime > ? ;"
_countBalanceExpire = "SELECT COUNT(1) FROM coupon_balance_info_%02d WHERE mid = ? AND expire_time < ? AND coupon_type = ? AND balance > 0 AND ctime > ? ;"
_balanceNotUsedPageSQL = "SELECT id,batch_token,mid,balance,start_time,expire_time,origin,coupon_type,ver,ctime,mtime FROM coupon_balance_info_%02d WHERE mid = ? AND expire_time > ? AND start_time < ? AND coupon_type = ? AND balance > 0 AND ctime > ? ORDER BY id DESC LIMIT ?,?;"
_useOrderPageSQL = "SELECT id,order_no,mid,count,state,coupon_type,third_trade_no,remark,tips,use_ver,ver,ctime,mtime FROM coupon_order WHERE mid= ? AND state= ? AND coupon_type = ? AND ctime > ? ORDER BY id DESC LIMIT ?,?;"
_balanceExpirePageSQL = "SELECT id,batch_token,mid,balance,start_time,expire_time,origin,coupon_type,ver,ctime,mtime FROM coupon_balance_info_%02d WHERE mid = ? AND expire_time < ? AND coupon_type = ? AND balance > 0 AND ctime > ? ORDER BY id DESC LIMIT ?,?;"
_addBalanceCouponSQL = "INSERT INTO coupon_balance_info_%02d(batch_token,mid,balance,start_time,expire_time,origin,coupon_type,ver,ctime) VALUES(?,?,?,?,?,?,?,?,?) ON DUPLICATE KEY UPDATE balance = balance + ?,ver = ver + 1 ;"
_byMidAndBatchTokenSQL = "SELECT id,batch_token,mid,balance,start_time,expire_time,origin,coupon_type,ver,ctime,mtime FROM coupon_balance_info_%02d WHERE mid = ? AND batch_token = ? ;"
_addBlanceChangeLog = "INSERT INTO coupon_balance_change_log_%02d(order_no,mid,batch_token,balance,change_balance,change_type,ctime)VALUES(?,?,?,?,?,?,?);"
_batchInfoSQL = "SELECT id,app_id,name,batch_token,max_count,current_count,start_time,expire_time,expire_day,ver,ctime,limit_count,full_amount,amount,state,coupon_type FROM coupon_batch_info WHERE batch_token = ?;"
_updateBatchSQL = "UPDATE coupon_batch_info SET current_count = current_count + ? WHERE batch_token = ?;"
_updateBatchLimitSQL = "UPDATE coupon_batch_info SET current_count = current_count + ? WHERE batch_token = ? AND current_count + ? <= max_count;"
_grantCouponLogSQL = "SELECT id,order_no,mid,batch_token,balance,change_balance,change_type,ctime,mtime FROM coupon_balance_change_log_%02d WHERE mid = ? AND batch_token = ? AND change_type = ?;"
_allBatchInfoSQL = "SELECT id,app_id,name,batch_token,max_count,current_count,start_time,expire_time,expire_day,ver,ctime,limit_count,full_amount,amount,state,coupon_type,platform_limit,product_limit_month,product_limit_renewal FROM coupon_batch_info;"
_couponReceiveSQL = "SELECT id,appkey,order_no,mid,coupon_token,coupon_type FROM coupon_receive_log WHERE order_no=? AND appkey=? AND coupon_type=?"
_addReceiveSQL = "INSERT INTO coupon_receive_log(appkey,order_no,mid,coupon_token,coupon_type) VALUES(?,?,?,?,?)"
)
func hitInfo(mid int64) int64 {
return mid % 100
}
func hitChangeLog(mid int64) int64 {
return mid % 100
}
func hitUser(mid int64) int64 {
return mid % 10
}
func hitUserLog(mid int64) int64 {
return mid % 10
}
// BeginTran begin transaction.
func (d *Dao) BeginTran(c context.Context) (*sql.Tx, error) {
return d.db.Begin(c)
}
// CouponList query .
func (d *Dao) CouponList(c context.Context, mid int64, state int8, ct int8, t int64) (res []*model.CouponInfo, err error) {
var rows *sql.Rows
if rows, err = d.db.Query(c, fmt.Sprintf(_couponsSQL, hitInfo(mid)), mid, state, ct, t, t); err != nil {
err = errors.WithStack(err)
return
}
defer rows.Close()
for rows.Next() {
r := &model.CouponInfo{}
if err = rows.Scan(&r.ID, &r.CouponToken, &r.Mid, &r.State, &r.StartTime, &r.ExpireTime, &r.Origin, &r.CouponType, &r.OrderNO, &r.Oid, &r.Remark,
&r.UseVer, &r.Ver, &r.CTime, &r.MTime); err != nil {
err = errors.WithStack(err)
res = nil
return
}
res = append(res, r)
}
err = rows.Err()
return
}
// CouponNoStartCheckList had not check start query .
func (d *Dao) CouponNoStartCheckList(c context.Context, mid int64, state int8, ct int8, t int64) (res []*model.CouponInfo, err error) {
var rows *sql.Rows
if rows, err = d.db.Query(c, fmt.Sprintf(_couponsNoStartCheckSQL, hitInfo(mid)), mid, state, ct, t); err != nil {
err = errors.WithStack(err)
return
}
defer rows.Close()
for rows.Next() {
r := &model.CouponInfo{}
if err = rows.Scan(&r.ID, &r.CouponToken, &r.Mid, &r.State, &r.StartTime, &r.ExpireTime, &r.Origin, &r.CouponType, &r.OrderNO, &r.Oid, &r.Remark,
&r.UseVer, &r.Ver, &r.CTime, &r.MTime); err != nil {
err = errors.WithStack(err)
res = nil
return
}
res = append(res, r)
}
err = rows.Err()
return
}
// BlanceNoStartCheckList had not check start query .
func (d *Dao) BlanceNoStartCheckList(c context.Context, mid int64, ct int8, t int64) (res []*model.CouponBalanceInfo, err error) {
var rows *sql.Rows
if rows, err = d.db.Query(c, fmt.Sprintf(_couponBlanceNoStartCheckSQL, hitUser(mid)), mid, t, ct); err != nil {
err = errors.WithStack(err)
return
}
defer rows.Close()
for rows.Next() {
r := &model.CouponBalanceInfo{}
if err = rows.Scan(&r.ID, &r.BatchToken, &r.Mid, &r.Balance, &r.StartTime, &r.ExpireTime, &r.Origin, &r.CouponType, &r.Ver, &r.CTime, &r.MTime); err != nil {
err = errors.WithStack(err)
res = nil
return
}
res = append(res, r)
}
err = rows.Err()
return
}
// ByOrderNO query coupon by orderno and type.
func (d *Dao) ByOrderNO(c context.Context, mid int64, orderNO string, ct int8) (r *model.CouponInfo, err error) {
var row *sql.Row
r = &model.CouponInfo{}
row = d.db.QueryRow(c, fmt.Sprintf(_couponByOrderNOAndTypeSQL, hitInfo(mid)), orderNO, ct)
if err = row.Scan(&r.ID, &r.CouponToken, &r.Mid, &r.State, &r.StartTime, &r.ExpireTime, &r.Origin, &r.CouponType, &r.OrderNO, &r.Oid, &r.Remark,
&r.UseVer, &r.Ver, &r.CTime, &r.MTime); err != nil {
if err == sql.ErrNoRows {
err = nil
r = nil
return
}
err = errors.WithStack(err)
return
}
return
}
// UpdateCouponInUse update coupon in use.
func (d *Dao) UpdateCouponInUse(c context.Context, tx *sql.Tx, cp *model.CouponInfo) (a int64, err error) {
var res xsql.Result
if res, err = tx.Exec(fmt.Sprintf(_updateCouponInUseSQL, hitInfo(cp.Mid)), cp.State, cp.OrderNO, cp.Oid, cp.Remark, cp.UseVer, cp.Ver+1,
cp.CouponToken, cp.Ver); err != nil {
err = errors.WithStack(err)
return
}
if a, err = res.RowsAffected(); err != nil {
err = errors.WithStack(err)
return
}
return
}
//InsertPointHistory .
func (d *Dao) InsertPointHistory(c context.Context, tx *sql.Tx, l *model.CouponChangeLog) (a int64, err error) {
var res xsql.Result
if res, err = tx.Exec(fmt.Sprintf(_addCouponChangeLogSQL, hitChangeLog(l.Mid)), l.CouponToken, l.Mid, l.State, l.Ctime); err != nil {
err = errors.WithStack(err)
return
}
if a, err = res.RowsAffected(); err != nil {
err = errors.WithStack(err)
}
return
}
// CouponInfo coupon info.
func (d *Dao) CouponInfo(c context.Context, mid int64, token string) (r *model.CouponInfo, err error) {
var row *sql.Row
r = &model.CouponInfo{}
row = d.db.QueryRow(c, fmt.Sprintf(_couponByTokenSQL, hitInfo(mid)), token)
if err = row.Scan(&r.ID, &r.CouponToken, &r.Mid, &r.State, &r.StartTime, &r.ExpireTime, &r.Origin, &r.CouponType, &r.OrderNO, &r.Oid, &r.Remark,
&r.UseVer, &r.Ver, &r.CTime, &r.MTime); err != nil {
if err == sql.ErrNoRows {
err = nil
r = nil
return
}
err = errors.WithStack(err)
return
}
return
}
// CountByState coupon count buy state.
func (d *Dao) CountByState(c context.Context, mid int64, state int8, t int64, stime time.Time) (count int64, err error) {
var row *sql.Row
switch state {
case model.NotUsed:
row = d.db.QueryRow(c, fmt.Sprintf(_countNotUsedSQL, hitInfo(mid)), mid, state, t, t, stime)
case model.Used:
row = d.db.QueryRow(c, fmt.Sprintf(_countUsedSQL, hitInfo(mid)), mid, state, stime)
case model.Expire:
row = d.db.QueryRow(c, fmt.Sprintf(_countExpireSQL, hitInfo(mid)), mid, t, stime)
default:
return
}
if err = row.Scan(&count); err != nil {
if err == sql.ErrNoRows {
err = nil
} else {
err = errors.WithStack(err)
}
}
return
}
// CouponPage page.
func (d *Dao) CouponPage(c context.Context, mid int64, state int8, t int64, start int, ps int, stime time.Time) (res []*model.CouponInfo, err error) {
var rows *sql.Rows
switch state {
case model.NotUsed:
rows, err = d.db.Query(c, fmt.Sprintf(_couponPageNotUsedSQL, hitInfo(mid)), mid, state, t, t, stime, start, ps)
case model.Used:
rows, err = d.db.Query(c, fmt.Sprintf(_couponPageUsedSQL, hitInfo(mid)), mid, state, stime, start, ps)
case model.Expire:
rows, err = d.db.Query(c, fmt.Sprintf(_couponPageExpireSQL, hitInfo(mid)), mid, t, stime, start, ps)
default:
return
}
if err != nil {
err = errors.WithStack(err)
return
}
defer rows.Close()
for rows.Next() {
r := &model.CouponInfo{}
if err = rows.Scan(&r.ID, &r.CouponToken, &r.Mid, &r.State, &r.StartTime, &r.ExpireTime, &r.Origin, &r.CouponType, &r.OrderNO, &r.Oid, &r.Remark,
&r.UseVer, &r.Ver, &r.CTime, &r.MTime); err != nil {
err = errors.WithStack(err)
res = nil
return
}
res = append(res, r)
}
err = rows.Err()
return
}
// AddCoupon add coupon.
func (d *Dao) AddCoupon(c context.Context, cp *model.CouponInfo) (a int64, err error) {
var res xsql.Result
if res, err = d.db.Exec(c, fmt.Sprintf(_addCouponSQL, hitInfo(cp.Mid)), cp.CouponToken, cp.Mid, cp.State, cp.StartTime, cp.ExpireTime, cp.Origin, cp.CouponType, cp.CTime); err != nil {
err = errors.WithStack(err)
return
}
if a, err = res.RowsAffected(); err != nil {
err = errors.WithStack(err)
return
}
return
}
// BatchAddCoupon batch add coupon.
func (d *Dao) BatchAddCoupon(c context.Context, tx *sql.Tx, mid int64, cps []*model.CouponInfo) (a int64, err error) {
var (
buf bytes.Buffer
res xsql.Result
sql string
)
buf.WriteString(fmt.Sprintf(_batchAddCouponSQL, hitInfo(mid)))
for _, v := range cps {
buf.WriteString("('")
buf.WriteString(v.CouponToken)
buf.WriteString("',")
buf.WriteString(strconv.FormatInt(v.Mid, 10))
buf.WriteString(",")
buf.WriteString(strconv.FormatInt(v.State, 10))
buf.WriteString(",")
buf.WriteString(strconv.FormatInt(v.StartTime, 10))
buf.WriteString(",")
buf.WriteString(strconv.FormatInt(v.ExpireTime, 10))
buf.WriteString(",")
buf.WriteString(strconv.FormatInt(v.Origin, 10))
buf.WriteString(",")
buf.WriteString(strconv.FormatInt(v.CouponType, 10))
buf.WriteString(",'")
buf.WriteString(v.CTime.Time().Format("2006-01-02 15:04:05"))
buf.WriteString("','")
buf.WriteString(v.BatchToken)
buf.WriteString("'),")
}
sql = buf.String()
if res, err = tx.Exec(sql[0 : len(sql)-1]); err != nil {
err = errors.WithStack(err)
return
}
if a, err = res.RowsAffected(); err != nil {
err = errors.WithStack(err)
}
return
}
// UpdateCoupon update coupon in use.
func (d *Dao) UpdateCoupon(c context.Context, mid int64, state int8, useVer int64, ver int64, couponToken string) (a int64, err error) {
var res xsql.Result
if res, err = d.db.Exec(c, fmt.Sprintf(_updateStateSQL, hitInfo(mid)), state, useVer, ver+1, couponToken, ver); err != nil {
err = errors.WithStack(err)
return
}
if a, err = res.RowsAffected(); err != nil {
err = errors.WithStack(err)
return
}
return
}
// ByThirdTradeNo query order by third trade no.
func (d *Dao) ByThirdTradeNo(c context.Context, thirdTradeNo string, ct int8) (r *model.CouponOrder, err error) {
var row *sql.Row
r = &model.CouponOrder{}
row = d.db.QueryRow(c, _orderByThirdTradeNoSQL, thirdTradeNo, ct)
if err = row.Scan(&r.ID, &r.OrderNo, &r.Mid, &r.Count, &r.State, &r.CouponType, &r.ThirdTradeNo, &r.Remark, &r.Tips, &r.UseVer, &r.Ver, &r.Ctime, &r.Mtime); err != nil {
if err == sql.ErrNoRows {
err = nil
r = nil
return
}
err = errors.WithStack(err)
return
}
return
}
// CouponBlances query coupon blances .
func (d *Dao) CouponBlances(c context.Context, mid int64, ct int8, t int64) (res []*model.CouponBalanceInfo, err error) {
var rows *sql.Rows
if rows, err = d.db.Query(c, fmt.Sprintf(_couponBlanceSQL, hitUser(mid)), mid, t, ct, t); err != nil {
err = errors.WithStack(err)
return
}
defer rows.Close()
for rows.Next() {
r := &model.CouponBalanceInfo{}
if err = rows.Scan(&r.ID, &r.BatchToken, &r.Mid, &r.Balance, &r.StartTime, &r.ExpireTime, &r.Origin, &r.CouponType, &r.Ver, &r.CTime, &r.MTime); err != nil {
err = errors.WithStack(err)
res = nil
return
}
res = append(res, r)
}
err = rows.Err()
return
}
// UpdateBlance update blance.
func (d *Dao) UpdateBlance(c context.Context, tx *sql.Tx, id int64, mid int64, ver int64, balance int64) (a int64, err error) {
var res xsql.Result
if res, err = tx.Exec(fmt.Sprintf(_updateBlanceSQL, hitUser(mid)), balance, id, ver); err != nil {
err = errors.WithStack(err)
return
}
if a, err = res.RowsAffected(); err != nil {
err = errors.WithStack(err)
return
}
return
}
// BatchUpdateBlance batch update blance.
func (d *Dao) BatchUpdateBlance(c context.Context, tx *sql.Tx, mid int64, blances []*model.CouponBalanceInfo) (a int64, err error) {
var (
res xsql.Result
buf bytes.Buffer
ids []int64
)
buf.WriteString(fmt.Sprintf(_batchUpdateBalance, hitUser(mid)))
for _, v := range blances {
buf.WriteString(" WHEN ")
buf.WriteString(strconv.FormatInt(v.ID, 10))
buf.WriteString(" THEN ")
buf.WriteString(strconv.FormatInt(v.Balance, 10))
ids = append(ids, v.ID)
}
buf.WriteString(" END WHERE `id` in (")
buf.WriteString(xstr.JoinInts(ids))
buf.WriteString(") AND `ver` = CASE id ")
for _, v := range blances {
buf.WriteString(" WHEN ")
buf.WriteString(strconv.FormatInt(v.ID, 10))
buf.WriteString(" THEN ")
buf.WriteString(strconv.FormatInt(v.Ver, 10))
}
buf.WriteString(" END;")
if res, err = tx.Exec(buf.String()); err != nil {
err = errors.WithStack(err)
return
}
if a, err = res.RowsAffected(); err != nil {
err = errors.WithStack(err)
return
}
return
}
// BatchInsertBlanceLog Batch Insert Balance log
func (d *Dao) BatchInsertBlanceLog(c context.Context, tx *sql.Tx, mid int64, ls []*model.CouponBalanceChangeLog) (a int64, err error) {
var (
buf bytes.Buffer
res xsql.Result
sql string
)
buf.WriteString(fmt.Sprintf(_addBalanceLogSQL, hitUserLog(mid)))
for _, v := range ls {
buf.WriteString("('")
buf.WriteString(v.OrderNo)
buf.WriteString("',")
buf.WriteString(strconv.FormatInt(v.Mid, 10))
buf.WriteString(",'")
buf.WriteString(v.BatchToken)
buf.WriteString("',")
buf.WriteString(strconv.FormatInt(v.Balance, 10))
buf.WriteString(",")
buf.WriteString(strconv.FormatInt(v.ChangeBalance, 10))
buf.WriteString(",")
buf.WriteString(strconv.Itoa(int(v.ChangeType)))
buf.WriteString(",'")
buf.WriteString(fmt.Sprintf("%v", v.Ctime.Time().Format("2006-01-02 15:04:05")))
buf.WriteString("'),")
}
sql = buf.String()
if res, err = tx.Exec(sql[0 : len(sql)-1]); err != nil {
err = errors.WithStack(err)
return
}
if a, err = res.RowsAffected(); err != nil {
err = errors.WithStack(err)
}
return
}
// AddOrder add order.
func (d *Dao) AddOrder(c context.Context, tx *sql.Tx, o *model.CouponOrder) (a int64, err error) {
var res xsql.Result
if res, err = tx.Exec(_addOrderSQL, o.OrderNo, o.Mid, o.Count, o.State, o.CouponType, o.ThirdTradeNo, o.Remark, o.Tips, o.UseVer, o.Ver, o.Ctime); err != nil {
err = errors.WithStack(err)
return
}
if a, err = res.RowsAffected(); err != nil {
err = errors.WithStack(err)
}
return
}
// AddOrderLog add order log.
func (d *Dao) AddOrderLog(c context.Context, tx *sql.Tx, o *model.CouponOrderLog) (a int64, err error) {
var res xsql.Result
if res, err = tx.Exec(_addOrderLogSQL, o.OrderNo, o.Mid, o.State, o.Ctime); err != nil {
err = errors.WithStack(err)
return
}
if a, err = res.RowsAffected(); err != nil {
err = errors.WithStack(err)
}
return
}
// CouponCarToonCount coupon cartoon page.
func (d *Dao) CouponCarToonCount(c context.Context, mid int64, t int64, ct int8, state int8, stime time.Time) (count int64, err error) {
var row *sql.Row
switch state {
case model.NotUsed:
row = d.db.QueryRow(c, fmt.Sprintf(_countBalanceNotUsed, hitUser(mid)), mid, t, t, ct, stime)
case model.Used:
row = d.db.QueryRow(c, _countUseListSQL, mid, state, ct, stime)
case model.Expire:
row = d.db.QueryRow(c, fmt.Sprintf(_countBalanceExpire, hitUser(mid)), mid, t, ct, stime)
default:
return
}
if err = row.Scan(&count); err != nil {
if err == sql.ErrNoRows {
err = nil
} else {
err = errors.WithStack(err)
}
}
return
}
// CouponNotUsedPage query coupon page .
func (d *Dao) CouponNotUsedPage(c context.Context, mid int64, ct int8, t int64, stime time.Time, pn int, ps int) (res []*model.CouponBalanceInfo, err error) {
var rows *sql.Rows
if rows, err = d.db.Query(c, fmt.Sprintf(_balanceNotUsedPageSQL, hitUser(mid)), mid, t, t, ct, stime, (pn-1)*ps, ps); err != nil {
err = errors.WithStack(err)
return
}
defer rows.Close()
for rows.Next() {
r := &model.CouponBalanceInfo{}
if err = rows.Scan(&r.ID, &r.BatchToken, &r.Mid, &r.Balance, &r.StartTime, &r.ExpireTime, &r.Origin, &r.CouponType, &r.Ver, &r.CTime, &r.MTime); err != nil {
err = errors.WithStack(err)
res = nil
return
}
res = append(res, r)
}
err = rows.Err()
return
}
// CouponExpirePage query coupon page .
func (d *Dao) CouponExpirePage(c context.Context, mid int64, ct int8, t int64, stime time.Time, pn int, ps int) (res []*model.CouponBalanceInfo, err error) {
var rows *sql.Rows
if rows, err = d.db.Query(c, fmt.Sprintf(_balanceExpirePageSQL, hitUser(mid)), mid, t, ct, stime, (pn-1)*ps, ps); err != nil {
err = errors.WithStack(err)
return
}
defer rows.Close()
for rows.Next() {
r := &model.CouponBalanceInfo{}
if err = rows.Scan(&r.ID, &r.BatchToken, &r.Mid, &r.Balance, &r.StartTime, &r.ExpireTime, &r.Origin, &r.CouponType, &r.Ver, &r.CTime, &r.MTime); err != nil {
err = errors.WithStack(err)
res = nil
return
}
res = append(res, r)
}
err = rows.Err()
return
}
// OrderUsedPage order used page.
func (d *Dao) OrderUsedPage(c context.Context, mid int64, state int8, ct int8, stime time.Time, pn int, ps int) (res []*model.CouponOrder, err error) {
var rows *sql.Rows
if rows, err = d.db.Query(c, _useOrderPageSQL, mid, state, ct, stime, (pn-1)*ps, ps); err != nil {
err = errors.WithStack(err)
return
}
defer rows.Close()
for rows.Next() {
r := &model.CouponOrder{}
if err = rows.Scan(&r.ID, &r.OrderNo, &r.Mid, &r.Count, &r.State, &r.CouponType, &r.ThirdTradeNo, &r.Remark, &r.Tips, &r.UseVer,
&r.Ver, &r.Ctime, &r.Mtime); err != nil {
if err == sql.ErrNoRows {
err = nil
res = nil
return
}
err = errors.WithStack(err)
return
}
res = append(res, r)
}
err = rows.Err()
return
}
// AddBalanceCoupon add balance coupon.
func (d *Dao) AddBalanceCoupon(c context.Context, tx *sql.Tx, b *model.CouponBalanceInfo) (a int64, err error) {
var res xsql.Result
if res, err = tx.Exec(fmt.Sprintf(_addBalanceCouponSQL, hitUser(b.Mid)), b.BatchToken, b.Mid, b.Balance, b.StartTime, b.ExpireTime, b.Origin, b.CouponType, b.Ver, b.CTime,
b.Balance); err != nil {
err = errors.WithStack(err)
return
}
if a, err = res.RowsAffected(); err != nil {
err = errors.WithStack(err)
}
return
}
// ByMidAndBatchToken query coupon by batch token and mid.
func (d *Dao) ByMidAndBatchToken(c context.Context, mid int64, batchToken string) (r *model.CouponBalanceInfo, err error) {
var row *sql.Row
r = &model.CouponBalanceInfo{}
row = d.db.QueryRow(c, fmt.Sprintf(_byMidAndBatchTokenSQL, hitUser(mid)), mid, batchToken)
if err = row.Scan(&r.ID, &r.BatchToken, &r.Mid, &r.Balance, &r.StartTime, &r.ExpireTime, &r.Origin, &r.CouponType, &r.Ver, &r.CTime, &r.MTime); err != nil {
if err == sql.ErrNoRows {
err = nil
r = nil
return
}
err = errors.WithStack(err)
return
}
return
}
// AddBalanceChangeLog add coupon balance change log.
func (d *Dao) AddBalanceChangeLog(c context.Context, tx *sql.Tx, bl *model.CouponBalanceChangeLog) (a int64, err error) {
var res xsql.Result
if res, err = tx.Exec(fmt.Sprintf(_addBlanceChangeLog, hitUserLog(bl.Mid)), bl.OrderNo, bl.Mid, bl.BatchToken, bl.Balance, bl.ChangeBalance, bl.ChangeType, bl.Ctime); err != nil {
err = errors.WithStack(err)
return
}
if a, err = res.RowsAffected(); err != nil {
err = errors.WithStack(err)
return
}
return
}
// BatchInfo batch info.
func (d *Dao) BatchInfo(c context.Context, token string) (r *model.CouponBatchInfo, err error) {
var row *sql.Row
r = new(model.CouponBatchInfo)
row = d.db.QueryRow(c, _batchInfoSQL, token)
if err = row.Scan(&r.ID, &r.AppID, &r.Name, &r.BatchToken, &r.MaxCount, &r.CurrentCount, &r.StartTime, &r.ExpireTime, &r.ExpireDay, &r.Ver, &r.Ctime, &r.LimitCount,
&r.FullAmount, &r.Amount, &r.State, &r.CouponType); err != nil {
if err == sql.ErrNoRows {
err = nil
r = nil
return
}
err = errors.WithStack(err)
return
}
return
}
// UpdateBatchInfo update batch info.
func (d *Dao) UpdateBatchInfo(c context.Context, tx *sql.Tx, token string, count int) (a int64, err error) {
var res xsql.Result
if res, err = tx.Exec(_updateBatchSQL, count, token); err != nil {
err = errors.WithStack(err)
return
}
if a, err = res.RowsAffected(); err != nil {
err = errors.WithStack(err)
return
}
return
}
// UpdateBatchLimitInfo update batch limit info.
func (d *Dao) UpdateBatchLimitInfo(c context.Context, tx *sql.Tx, token string, count int) (a int64, err error) {
var res xsql.Result
if res, err = tx.Exec(_updateBatchLimitSQL, count, token, count); err != nil {
err = errors.WithStack(err)
return
}
if a, err = res.RowsAffected(); err != nil {
err = errors.WithStack(err)
return
}
return
}
// GrantCouponLog grant coupon log.
func (d *Dao) GrantCouponLog(c context.Context, mid int64, token string, ct int8) (rs []*model.CouponBalanceChangeLog, err error) {
var rows *sql.Rows
if rows, err = d.db.Query(c, fmt.Sprintf(_grantCouponLogSQL, hitUserLog(mid)), mid, token, ct); err != nil {
err = errors.WithStack(err)
return
}
defer rows.Close()
for rows.Next() {
r := &model.CouponBalanceChangeLog{}
if err = rows.Scan(&r.ID, &r.OrderNo, &r.Mid, &r.BatchToken, &r.Balance, &r.ChangeBalance, &r.ChangeType, &r.Ctime, &r.Mtime); err != nil {
err = errors.WithStack(err)
rs = nil
return
}
rs = append(rs, r)
}
err = rows.Err()
return
}
// AllBranchInfo query all branch info .
func (d *Dao) AllBranchInfo(c context.Context) (res []*model.CouponBatchInfo, err error) {
var rows *sql.Rows
if rows, err = d.db.Query(c, _allBatchInfoSQL); err != nil {
err = errors.WithStack(err)
return
}
defer rows.Close()
for rows.Next() {
r := &model.CouponBatchInfo{}
if err = rows.Scan(&r.ID, &r.AppID, &r.Name, &r.BatchToken, &r.MaxCount, &r.CurrentCount, &r.StartTime, &r.ExpireTime, &r.ExpireDay, &r.Ver, &r.Ctime,
&r.LimitCount, &r.FullAmount, &r.Amount, &r.State, &r.CouponType, &r.PlatformLimit, &r.ProdLimMonth, &r.ProdLimRenewal); err != nil {
err = errors.WithStack(err)
res = nil
return
}
res = append(res, r)
}
err = rows.Err()
return
}
// CountByBranchToken get user count by bratch token.
func (d *Dao) CountByBranchToken(c context.Context, mid int64, token string) (count int64, err error) {
row := d.db.QueryRow(c, fmt.Sprintf(_batchCountByMid, hitInfo(mid)), mid, token)
if err = row.Scan(&count); err != nil {
err = errors.WithStack(err)
}
return
}
//ReceiveLog get receive log.
func (d *Dao) ReceiveLog(c context.Context, appkey, orderNo string, ct int8) (r *model.CouponReceiveLog, err error) {
row := d.db.QueryRow(c, _couponReceiveSQL, orderNo, appkey, ct)
r = new(model.CouponReceiveLog)
if err = row.Scan(&r.ID, &r.Appkey, &r.OrderNo, &r.Mid, &r.CouponToken, &r.CouponType); err != nil {
if err == sql.ErrNoRows {
r = nil
err = nil
return
}
err = errors.WithStack(err)
}
return
}
//TxAddReceiveLog add receive log.
func (d *Dao) TxAddReceiveLog(tx *sql.Tx, rlog *model.CouponReceiveLog) (err error) {
if _, err = tx.Exec(_addReceiveSQL, rlog.Appkey, rlog.OrderNo, rlog.Mid, rlog.CouponToken, rlog.CouponType); err != nil {
err = errors.WithStack(err)
}
return
}

View File

@@ -0,0 +1,708 @@
package dao
import (
"bytes"
"context"
"fmt"
"math/rand"
"testing"
"time"
"go-common/app/service/main/coupon/model"
"go-common/library/database/sql"
xtime "go-common/library/time"
"github.com/smartystreets/goconvey/convey"
)
func TestDaohitInfo(t *testing.T) {
var (
mid = int64(0)
)
convey.Convey("hitInfo", t, func(ctx convey.C) {
p1 := hitInfo(mid)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
}
func TestDaohitChangeLog(t *testing.T) {
var (
mid = int64(0)
)
convey.Convey("hitChangeLog", t, func(ctx convey.C) {
p1 := hitChangeLog(mid)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
}
func TestDaohitUser(t *testing.T) {
var (
mid = int64(0)
)
convey.Convey("hitUser", t, func(ctx convey.C) {
p1 := hitUser(mid)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
}
func TestDaohitUserLog(t *testing.T) {
var (
mid = int64(0)
)
convey.Convey("hitUserLog", t, func(ctx convey.C) {
p1 := hitUserLog(mid)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
}
func TestDaoBeginTran(t *testing.T) {
var (
c = context.TODO()
)
convey.Convey("BeginTran", t, func(ctx convey.C) {
p1, err := d.BeginTran(c)
ctx.Convey("Then err should be nil.p1 should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(p1, convey.ShouldNotBeNil)
})
})
}
func TestDaoCouponList(t *testing.T) {
var (
c = context.TODO()
mid = int64(0)
state = int8(0)
ct = int8(0)
no = int64(0)
)
convey.Convey("CouponList", t, func(ctx convey.C) {
_, err := d.CouponList(c, mid, state, ct, no)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestDaoCouponNoStartCheckList(t *testing.T) {
var (
c = context.TODO()
mid = int64(0)
state = int8(0)
ct = int8(0)
no = int64(0)
)
convey.Convey("CouponNoStartCheckList", t, func(ctx convey.C) {
_, err := d.CouponNoStartCheckList(c, mid, state, ct, no)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestDaoBlanceNoStartCheckList(t *testing.T) {
var (
c = context.TODO()
mid = int64(0)
ct = int8(0)
no = int64(0)
)
convey.Convey("BlanceNoStartCheckList", t, func(ctx convey.C) {
_, err := d.BlanceNoStartCheckList(c, mid, ct, no)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestDaoByOrderNO(t *testing.T) {
var (
c = context.TODO()
mid = int64(1)
orderNO = "1235378892"
ct = int8(1)
)
convey.Convey("ByOrderNO", t, func(ctx convey.C) {
r, err := d.ByOrderNO(c, mid, orderNO, ct)
ctx.Convey("Then err should be nil.r should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(r, convey.ShouldNotBeNil)
})
})
}
func TestDaoUpdateCouponInUse(t *testing.T) {
var (
c = context.TODO()
tx = &sql.Tx{}
cp = &model.CouponInfo{}
a int64
err error
)
convey.Convey("UpdateCouponInUse", t, func(ctx convey.C) {
tx, err = d.BeginTran(c)
ctx.So(err, convey.ShouldBeNil)
a, err = d.UpdateCouponInUse(c, tx, cp)
ctx.Convey("Then err should be nil.a should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(a, convey.ShouldNotBeNil)
})
})
}
func TestDaoInsertPointHistory(t *testing.T) {
var (
c = context.TODO()
tx = &sql.Tx{}
l = &model.CouponChangeLog{}
err error
)
convey.Convey("InsertPointHistory", t, func(ctx convey.C) {
tx, err = d.BeginTran(c)
ctx.So(err, convey.ShouldBeNil)
a, err := d.InsertPointHistory(c, tx, l)
ctx.Convey("Then err should be nil.a should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(a, convey.ShouldNotBeNil)
})
})
}
func TestDaoCouponInfo(t *testing.T) {
var (
c = context.TODO()
mid = int64(27515401)
token = "581807988720180417190545"
)
convey.Convey("CouponInfo", t, func(ctx convey.C) {
r, err := d.CouponInfo(c, mid, token)
ctx.Convey("Then err should be nil.r should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(r, convey.ShouldNotBeNil)
})
})
}
func TestDaoCountByState(t *testing.T) {
var (
c = context.TODO()
mid = int64(0)
state = int8(0)
no = int64(0)
stime = time.Now()
)
convey.Convey("CountByState", t, func(ctx convey.C) {
count, err := d.CountByState(c, mid, state, no, stime)
ctx.Convey("Then err should be nil.count should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(count, convey.ShouldNotBeNil)
})
})
}
func TestDaoCouponPage(t *testing.T) {
var (
c = context.TODO()
mid = int64(0)
state = int8(0)
no = int64(0)
start = int(0)
ps = int(0)
stime = time.Now()
)
convey.Convey("CouponPage", t, func(ctx convey.C) {
_, err := d.CouponPage(c, mid, state, no, start, ps, stime)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestDaoAddCoupon(t *testing.T) {
var (
c = context.TODO()
cp = &model.CouponInfo{
Mid: 1,
CouponToken: token(),
State: 0,
StartTime: time.Now().Unix(),
ExpireTime: time.Now().AddDate(0, 0, 1).Unix(),
}
)
convey.Convey("AddCoupon", t, func(ctx convey.C) {
a, err := d.AddCoupon(c, cp)
ctx.Convey("Then err should be nil.a should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(a, convey.ShouldNotBeNil)
})
})
}
func TestDaoBatchAddCoupon(t *testing.T) {
var (
c = context.TODO()
tx = &sql.Tx{}
mid = int64(0)
cps = []*model.CouponInfo{}
err error
a int64
)
convey.Convey("BatchAddCoupon", t, func(ctx convey.C) {
cp := &model.CouponInfo{}
cp.CouponToken = token()
cp.Mid = mid
cp.State = model.NotUsed
cp.StartTime = time.Now().Unix()
cp.ExpireTime = time.Now().AddDate(0, 0, 2).Unix()
cp.Origin = 1
cp.CouponType = 1
cp.CTime = xtime.Time(time.Now().Unix())
cp.BatchToken = "1234"
cps = append(cps, cp)
tx, err = d.BeginTran(c)
ctx.So(err, convey.ShouldBeNil)
a, err = d.BatchAddCoupon(c, tx, mid, cps)
ctx.Convey("Then err should be nil.a should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(a, convey.ShouldNotBeNil)
})
})
}
func TestDaoUpdateCoupon(t *testing.T) {
var (
c = context.TODO()
mid = int64(27515800)
state = int8(0)
useVer = int64(0)
ver = int64(1)
couponToken = "510204683920180420110002"
)
convey.Convey("UpdateCoupon", t, func(ctx convey.C) {
_, err := d.UpdateCoupon(c, mid, state, useVer, ver, couponToken)
ctx.Convey("Then err should be nil.a should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestDaoByThirdTradeNo(t *testing.T) {
var (
c = context.TODO()
thirdTradeNo = "12156121892"
ct = int8(2)
)
convey.Convey("ByThirdTradeNo", t, func(ctx convey.C) {
r, err := d.ByThirdTradeNo(c, thirdTradeNo, ct)
ctx.Convey("Then err should be nil.r should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(r, convey.ShouldNotBeNil)
})
})
}
func TestDaoCouponBlances(t *testing.T) {
var (
c = context.TODO()
mid = int64(520)
ct = int8(2)
no = int64(0)
)
convey.Convey("CouponBlances", t, func(ctx convey.C) {
_, err := d.CouponBlances(c, mid, ct, no)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestDaoUpdateBlance(t *testing.T) {
var (
c = context.TODO()
tx = &sql.Tx{}
id = int64(0)
mid = int64(0)
ver = int64(0)
balance = int64(0)
a int64
err error
)
convey.Convey("UpdateBlance", t, func(ctx convey.C) {
tx, err = d.BeginTran(c)
ctx.So(err, convey.ShouldBeNil)
a, err = d.UpdateBlance(c, tx, id, mid, ver, balance)
ctx.Convey("Then err should be nil.a should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(a, convey.ShouldNotBeNil)
})
})
}
func TestDaoBatchUpdateBlance(t *testing.T) {
var (
c = context.TODO()
tx = &sql.Tx{}
mid = int64(1)
blances = []*model.CouponBalanceInfo{}
err error
)
blances = append(blances, &model.CouponBalanceInfo{
ID: 116197,
Balance: 1,
Ver: 0,
})
convey.Convey("BatchUpdateBlance", t, func(ctx convey.C) {
tx, err = d.BeginTran(c)
ctx.So(err, convey.ShouldBeNil)
_, err = d.BatchUpdateBlance(c, tx, mid, blances)
ctx.Convey("Then err should be nil.a should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
err = tx.Commit()
ctx.So(err, convey.ShouldBeNil)
})
}
func TestDaoBatchInsertBlanceLog(t *testing.T) {
var (
c = context.TODO()
tx = &sql.Tx{}
mid = int64(0)
ls = []*model.CouponBalanceChangeLog{}
err error
)
convey.Convey("BatchInsertBlanceLog", t, func(ctx convey.C) {
blog := new(model.CouponBalanceChangeLog)
blog.OrderNo = "11"
blog.Mid = mid
blog.BatchToken = "123"
blog.ChangeType = model.Consume
blog.Ctime = xtime.Time(time.Now().Unix())
ls = append(ls, blog)
tx, err = d.BeginTran(c)
ctx.So(err, convey.ShouldBeNil)
_, err = d.BatchInsertBlanceLog(c, tx, mid, ls)
ctx.Convey("Then err should be nil.a should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
err = tx.Commit()
ctx.So(err, convey.ShouldBeNil)
})
}
func TestDaoAddOrder(t *testing.T) {
var (
c = context.TODO()
tx = &sql.Tx{}
o = &model.CouponOrder{}
a int64
err error
)
convey.Convey("AddOrder", t, func(ctx convey.C) {
tx, err = d.BeginTran(c)
ctx.So(err, convey.ShouldBeNil)
a, err = d.AddOrder(c, tx, o)
ctx.Convey("Then err should be nil.a should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(a, convey.ShouldNotBeNil)
})
})
}
func TestDaoAddOrderLog(t *testing.T) {
var (
c = context.TODO()
tx = &sql.Tx{}
o = &model.CouponOrderLog{}
a int64
err error
)
convey.Convey("AddOrderLog", t, func(ctx convey.C) {
tx, err = d.BeginTran(c)
ctx.So(err, convey.ShouldBeNil)
a, err = d.AddOrderLog(c, tx, o)
ctx.Convey("Then err should be nil.a should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(a, convey.ShouldNotBeNil)
})
})
}
func TestDaoCouponCarToonCount(t *testing.T) {
var (
c = context.TODO()
mid = int64(0)
no = int64(0)
ct = int8(0)
state = int8(0)
stime = time.Now()
)
convey.Convey("CouponCarToonCount", t, func(ctx convey.C) {
count, err := d.CouponCarToonCount(c, mid, no, ct, state, stime)
ctx.Convey("Then err should be nil.count should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(count, convey.ShouldNotBeNil)
})
})
}
func TestDaoCouponNotUsedPage(t *testing.T) {
var (
c = context.TODO()
mid = int64(0)
ct = int8(0)
no = int64(0)
stime = time.Now()
pn = int(0)
ps = int(0)
)
convey.Convey("CouponNotUsedPage", t, func(ctx convey.C) {
_, err := d.CouponNotUsedPage(c, mid, ct, no, stime, pn, ps)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestDaoCouponExpirePage(t *testing.T) {
var (
c = context.TODO()
mid = int64(27515301)
ct = int8(1)
no = time.Now().Unix()
stime = time.Now().AddDate(-1, 0, 0)
pn = int(1)
ps = int(10)
)
convey.Convey("CouponExpirePage", t, func(ctx convey.C) {
_, err := d.CouponExpirePage(c, mid, ct, no, stime, pn, ps)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestDaoOrderUsedPage(t *testing.T) {
var (
c = context.TODO()
mid = int64(0)
state = int8(0)
ct = int8(0)
stime = time.Now()
pn = int(0)
ps = int(0)
)
convey.Convey("OrderUsedPage", t, func(ctx convey.C) {
_, err := d.OrderUsedPage(c, mid, state, ct, stime, pn, ps)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestDaoAddBalanceCoupon(t *testing.T) {
var (
c = context.TODO()
tx = &sql.Tx{}
b = &model.CouponBalanceInfo{}
a int64
err error
)
convey.Convey("AddBalanceCoupon", t, func(ctx convey.C) {
tx, err = d.BeginTran(c)
ctx.So(err, convey.ShouldBeNil)
a, err = d.AddBalanceCoupon(c, tx, b)
ctx.Convey("Then err should be nil.a should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(a, convey.ShouldNotBeNil)
})
})
}
func TestDaoByMidAndBatchToken(t *testing.T) {
var (
c = context.TODO()
mid = int64(1)
batchToken = "441539420220180806174505"
)
convey.Convey("ByMidAndBatchToken", t, func(ctx convey.C) {
_, err := d.ByMidAndBatchToken(c, mid, batchToken)
ctx.Convey("Then err should be nil.r should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestDaoAddBalanceChangeLog(t *testing.T) {
var (
c = context.TODO()
tx = &sql.Tx{}
bl = &model.CouponBalanceChangeLog{}
a int64
err error
)
convey.Convey("AddBalanceChangeLog", t, func(ctx convey.C) {
tx, err = d.BeginTran(c)
ctx.So(err, convey.ShouldBeNil)
a, err = d.AddBalanceChangeLog(c, tx, bl)
ctx.Convey("Then err should be nil.a should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(a, convey.ShouldNotBeNil)
})
})
}
func TestDaoBatchInfo(t *testing.T) {
var (
c = context.TODO()
token = "900364604420180912170927"
)
convey.Convey("BatchInfo", t, func(ctx convey.C) {
r, err := d.BatchInfo(c, token)
ctx.Convey("Then err should be nil.r should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(r, convey.ShouldNotBeNil)
})
})
}
func TestDaoUpdateBatchInfo(t *testing.T) {
var (
c = context.TODO()
tx = &sql.Tx{}
token = ""
count = int(0)
a int64
err error
)
convey.Convey("UpdateBatchInfo", t, func(ctx convey.C) {
tx, err = d.BeginTran(c)
ctx.So(err, convey.ShouldBeNil)
a, err = d.UpdateBatchInfo(c, tx, token, count)
ctx.Convey("Then err should be nil.a should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(a, convey.ShouldNotBeNil)
})
})
}
func TestDaoUpdateBatchLimitInfo(t *testing.T) {
var (
c = context.TODO()
tx = &sql.Tx{}
token = ""
count = int(0)
a int64
err error
)
convey.Convey("UpdateBatchLimitInfo", t, func(ctx convey.C) {
tx, err = d.BeginTran(c)
ctx.So(err, convey.ShouldBeNil)
a, err = d.UpdateBatchLimitInfo(c, tx, token, count)
ctx.Convey("Then err should be nil.a should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(a, convey.ShouldNotBeNil)
})
})
}
func TestDaoGrantCouponLog(t *testing.T) {
var (
c = context.TODO()
mid = int64(0)
token = ""
ct = int8(0)
)
convey.Convey("GrantCouponLog", t, func(ctx convey.C) {
_, err := d.GrantCouponLog(c, mid, token, ct)
ctx.Convey("Then err should be nil.rs should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestDaoAllBranchInfo(t *testing.T) {
var (
c = context.TODO()
)
convey.Convey("AllBranchInfo", t, func(ctx convey.C) {
res, err := d.AllBranchInfo(c)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(res, convey.ShouldNotBeNil)
})
})
}
func TestDaoCountByBranchToken(t *testing.T) {
var (
c = context.TODO()
mid = int64(0)
token = ""
)
convey.Convey("CountByBranchToken", t, func(ctx convey.C) {
count, err := d.CountByBranchToken(c, mid, token)
ctx.Convey("Then err should be nil.count should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(count, convey.ShouldNotBeNil)
})
})
}
// get coupon token
func token() string {
var b bytes.Buffer
b.WriteString(fmt.Sprintf("%03d", time.Now().UnixNano()/1e6%1000))
b.WriteString(time.Now().Format("20060102150405"))
return b.String()
}
func TestDaoReceiveLog(t *testing.T) {
var (
c = context.Background()
appkey = "7c7ac0db1aa05587"
orderNo = "1536657724"
ct int8 = 3
)
convey.Convey("ReceiveLog ", t, func(ctx convey.C) {
r, err := d.ReceiveLog(c, appkey, orderNo, ct)
ctx.Convey("Then err should be nil.r should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(r, convey.ShouldNotBeNil)
})
r, err = d.ReceiveLog(c, "", "", 21)
ctx.Convey("Then err should be nil.r should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(r, convey.ShouldBeNil)
})
})
}
func TestDaoTxAddReceiveLog(t *testing.T) {
var (
c = context.Background()
tx, _ = d.BeginTran(c)
rlog = &model.CouponReceiveLog{Appkey: fmt.Sprintf("%d", time.Now().Unix()), CouponType: int8(rand.Int63n(127))}
)
convey.Convey("TxAddReceiveLog ", t, func(ctx convey.C) {
err := d.TxAddReceiveLog(tx, rlog)
if err == nil {
if err = tx.Commit(); err != nil {
tx.Rollback()
}
} else {
tx.Rollback()
}
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}

View File

@@ -0,0 +1,84 @@
package dao
import (
"context"
xsql "database/sql"
"go-common/app/service/main/coupon/model"
"go-common/library/database/sql"
"github.com/pkg/errors"
)
const (
_userCardSQL = "SELECT card_type,state,batch_token,coupon_token,act_id FROM coupon_user_card WHERE mid=? AND act_id=? AND card_type=?"
_userCardsSQL = "SELECT card_type,state,batch_token,coupon_token,act_id FROM coupon_user_card WHERE mid=? AND act_id=?"
_addUserCardSQL = "INSERT INTO coupon_user_card(mid,card_type,state,batch_token,coupon_token,act_id) VALUES (?,?,?,?,?,?)"
_updateUserCardSQL = "UPDATE coupon_user_card SET state=? WHERE mid=? AND coupon_token=?"
)
// UserCard .
func (d *Dao) UserCard(c context.Context, mid, actID int64, cardType int8) (r *model.CouponUserCard, err error) {
var row *sql.Row
r = &model.CouponUserCard{}
row = d.db.QueryRow(c, _userCardSQL, mid, actID, cardType)
if err = row.Scan(&r.CardType, &r.State, &r.BatchToken, &r.CouponToken, &r.ActID); err != nil {
if err == sql.ErrNoRows {
err = nil
r = nil
return
}
err = errors.WithStack(err)
return
}
return
}
// UserCards .
func (d *Dao) UserCards(c context.Context, mid, actID int64) (res []*model.CouponUserCard, err error) {
var rows *sql.Rows
if rows, err = d.db.Query(c, _userCardsSQL, mid, actID); err != nil {
err = errors.WithStack(err)
return
}
defer rows.Close()
for rows.Next() {
r := &model.CouponUserCard{}
if err = rows.Scan(&r.CardType, &r.State, &r.BatchToken, &r.CouponToken, &r.ActID); err != nil {
err = errors.WithStack(err)
res = nil
return
}
res = append(res, r)
}
err = rows.Err()
return
}
// AddUserCard .
func (d *Dao) AddUserCard(c context.Context, tx *sql.Tx, uc *model.CouponUserCard) (a int64, err error) {
var res xsql.Result
if res, err = tx.Exec(_addUserCardSQL, uc.MID, uc.CardType, uc.State, uc.BatchToken, uc.CouponToken, uc.ActID); err != nil {
err = errors.WithStack(err)
return
}
if a, err = res.RowsAffected(); err != nil {
err = errors.WithStack(err)
return
}
return
}
// UpdateUserCard .
func (d *Dao) UpdateUserCard(c context.Context, mid int64, state int8, couponToken string) (a int64, err error) {
var res xsql.Result
if res, err = d.db.Exec(c, _updateUserCardSQL, state, mid, couponToken); err != nil {
err = errors.WithStack(err)
return
}
if a, err = res.RowsAffected(); err != nil {
err = errors.WithStack(err)
return
}
return
}

View File

@@ -0,0 +1,100 @@
package dao
import (
"context"
"math/rand"
"testing"
"go-common/app/service/main/coupon/model"
"github.com/smartystreets/goconvey/convey"
)
func TestDaoUserCard(t *testing.T) {
convey.Convey("UserCard", t, func(convCtx convey.C) {
var (
c = context.Background()
mid = int64(88895150)
actID = int64(1)
cardType = int8(1)
noMID = int64(-1)
)
convCtx.Convey("When everything goes positive", func(convCtx convey.C) {
r, err := d.UserCard(c, mid, actID, cardType)
convCtx.Convey("Then err should be nil.r should not be nil.", func(convCtx convey.C) {
convCtx.So(err, convey.ShouldBeNil)
convCtx.So(r, convey.ShouldNotBeNil)
})
r, err = d.UserCard(c, noMID, actID, cardType)
convCtx.Convey("Then err should be nil.r should be nil.", func(convCtx convey.C) {
convCtx.So(err, convey.ShouldBeNil)
convCtx.So(r, convey.ShouldBeNil)
})
})
})
}
func TestDaoUserCards(t *testing.T) {
convey.Convey("UserCards", t, func(convCtx convey.C) {
var (
c = context.Background()
mid = int64(88895150)
actID = int64(1)
)
convCtx.Convey("When everything goes positive", func(convCtx convey.C) {
res, err := d.UserCards(c, mid, actID)
convCtx.Convey("Then err should be nil.res should not be nil.", func(convCtx convey.C) {
convCtx.So(err, convey.ShouldBeNil)
convCtx.So(res, convey.ShouldNotBeNil)
})
})
})
}
func TestDaoAddUserCard(t *testing.T) {
convey.Convey("AddUserCard", t, func(convCtx convey.C) {
var (
c = context.Background()
tx, _ = d.BeginTran(context.Background())
uc = &model.CouponUserCard{MID: rand.Int63n(9999999)}
)
convCtx.Convey("When everything goes positive", func(convCtx convey.C) {
a, err := d.AddUserCard(c, tx, uc)
if err == nil {
if err = tx.Commit(); err != nil {
tx.Rollback()
}
} else {
tx.Rollback()
}
convCtx.Convey("Then err should be nil.a should not be nil.", func(convCtx convey.C) {
convCtx.So(err, convey.ShouldBeNil)
convCtx.So(a, convey.ShouldNotBeNil)
})
})
})
}
func TestDaoUpdateUserCard(t *testing.T) {
convey.Convey("UpdateUserCard", t, func(convCtx convey.C) {
var (
c = context.Background()
mid = int64(0)
state = int8(0)
couponToken = ""
)
convCtx.Convey("When everything goes positive", func(convCtx convey.C) {
a, err := d.UpdateUserCard(c, mid, state, couponToken)
convCtx.Convey("Then err should be nil.a should not be nil.", func(convCtx convey.C) {
convCtx.So(err, convey.ShouldBeNil)
convCtx.So(a, convey.ShouldNotBeNil)
})
})
})
}
func TestDaoClose(t *testing.T) {
convey.Convey("TestDaoClose", t, func(convCtx convey.C) {
d.Close()
})
}

View File

@@ -0,0 +1,40 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = [
"allowance.go",
"coupon.go",
"http.go",
],
importpath = "go-common/app/service/main/coupon/http",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/main/coupon/conf:go_default_library",
"//app/service/main/coupon/model:go_default_library",
"//app/service/main/coupon/service:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/net/http/blademaster/middleware/verify: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,69 @@
package http
import (
"go-common/app/service/main/coupon/model"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
)
func useAllowance(c *bm.Context) {
var err error
arg := new(model.ArgUseAllowance)
if err = c.Bind(arg); err != nil {
return
}
c.JSON(nil, svc.UseAllowanceCoupon(c, arg))
}
func allowanceCount(c *bm.Context) {
var (
err error
res []*model.CouponAllowanceInfo
)
arg := new(model.ArgCount)
if err = c.Bind(arg); err != nil {
return
}
res, err = svc.AllowanceCoupon(c, &model.ArgAllowanceCoupons{
Mid: arg.Mid,
State: model.NotUsed,
})
c.JSON(len(res), err)
}
func receiveAllowance(c *bm.Context) {
var err error
arg := new(model.ArgReceiveAllowance)
if err = c.Bind(arg); err != nil {
log.Error("receive allowance bind %+v", err)
return
}
c.JSON(svc.ReceiveAllowance(c, arg))
}
func useNotify(c *bm.Context) {
var err error
arg := new(model.ArgAllowanceCheck)
if err = c.Bind(arg); err != nil {
return
}
c.JSON(svc.UseNotify(c, arg))
}
func prizeCards(c *bm.Context) {
var err error
arg := new(model.ArgCount)
if err = c.Bind(arg); err != nil {
return
}
c.JSON(svc.PrizeCards(c, arg.Mid))
}
func prizeDraw(c *bm.Context) {
var err error
arg := new(model.ArgPrizeDraw)
if err = c.Bind(arg); err != nil {
return
}
c.JSON(svc.PrizeDraw(c, arg.Mid, arg.CardType))
}

View File

@@ -0,0 +1,122 @@
package http
import (
"go-common/app/service/main/coupon/model"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
)
func userCoupon(c *bm.Context) {
var (
err error
count int
)
arg := new(model.ArgMid)
if err = c.Bind(arg); err != nil {
log.Error("user coupon bind %+v", err)
return
}
switch arg.Type {
case model.CouponVideo:
if count, err = svc.VideoCouponCount(c, arg.Mid, arg.Type); err != nil {
log.Error("user coupon(%d) %+v", arg.Mid, err)
}
case model.CouponCartoon:
if count, err = svc.CarToonCouponCount(c, arg.Mid, arg.Type); err != nil {
log.Error("user coupon(%d) %+v", arg.Mid, err)
}
}
c.JSON(map[string]interface{}{
"count": count,
"mid": arg.Mid,
}, nil)
}
func useCoupon(c *bm.Context) {
var (
err error
state int8
token string
)
arg := new(model.ArgUseCoupon)
if err = c.Bind(arg); err != nil {
log.Error("use coupon bind %+v", err)
return
}
if state, token, err = svc.UseCoupon(c, arg.Mid, arg.Oid, arg.Remark, arg.OrderNO, arg.Type, arg.Ver); err != nil {
log.Error("use coupon(%d) %+v", arg.Mid, err)
}
log.Info("use coupon ret(%d,%s)", state, token)
c.JSON(map[string]interface{}{
"state": state,
"coupon_token": token,
}, nil)
}
func useCartoonCoupon(c *bm.Context) {
var (
err error
state int8
token string
)
arg := new(model.ArgUseCartoonCoupon)
if err = c.Bind(arg); err != nil {
log.Error("use coupon bind %+v", err)
return
}
if state, token, err = svc.CartoonUse(c, arg.Mid, arg.OrderNO, arg.Type, arg.Ver, arg.Remark, arg.Tips, arg.Count); err != nil {
log.Error("use coupon(%d) %+v", arg.Mid, err)
c.JSON(nil, err)
return
}
c.JSON(map[string]interface{}{
"state": state,
"coupon_token": token,
}, nil)
}
func couponInfo(c *bm.Context) {
var err error
arg := new(model.ArgCoupon)
if err = c.Bind(arg); err != nil {
log.Error("coupon info bind %+v", err)
return
}
c.JSON(svc.CouponInfo(c, arg.Mid, arg.CouponToken))
}
func addCoupon(c *bm.Context) {
var err error
arg := new(model.ArgAdd)
if err = c.Bind(arg); err != nil {
log.Error("add coupon bind %+v", err)
return
}
c.JSON(nil, svc.AddCoupon(c, arg.Mid, arg.StartTime, arg.ExpireTime, arg.Type, arg.Origin))
}
func changeCoupon(c *bm.Context) {
var err error
arg := new(model.ChangeCoupon)
if err = c.Bind(arg); err != nil {
log.Error("coupon info bind %+v", err)
return
}
c.JSON(nil, svc.ChangeState(c, arg.Mid, arg.UseVer, arg.Ver, arg.CouponToken))
}
func salaryCoupon(c *bm.Context) {
var err error
arg := new(model.ArgSalaryCoupon)
if err = c.Bind(arg); err != nil {
log.Error("coupon info bind %+v", err)
return
}
arg.Origin = int64(model.VipSalary)
if err = svc.SalaryCoupon(c, arg); err != nil {
log.Error("svc.SalaryCoupon(%d) %+v", arg.Mid, err)
c.JSON(nil, err)
return
}
c.JSON(nil, nil)
}

View File

@@ -0,0 +1,72 @@
package http
import (
"net/http"
"go-common/app/service/main/coupon/conf"
"go-common/app/service/main/coupon/service"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
"go-common/library/net/http/blademaster/middleware/verify"
)
var (
verifySvc *verify.Verify
svc *service.Service
)
// Init init
func Init(c *conf.Config, s *service.Service) {
svc = s
initService(c)
engine := bm.DefaultServer(c.BM)
interRouter(engine)
if err := engine.Start(); err != nil {
log.Error("engine.Start error(%v)", err)
panic(err)
}
}
// initService init services.
func initService(c *conf.Config) {
verifySvc = verify.New(nil)
}
// interRouter init inner router api path.
func interRouter(e *bm.Engine) {
//init api
e.Ping(ping)
e.Register(register)
group := e.Group("/x/internal/coupon", verifySvc.Verify)
{
group.GET("/count", userCoupon)
group.POST("/use", useCoupon)
group.GET("/info", couponInfo)
group.POST("/add", addCoupon)
group.POST("/change", changeCoupon)
group.POST("/cartoon/use", useCartoonCoupon)
group.POST("/grant", salaryCoupon)
ae := group.Group("/allowance")
ae.POST("/use", useAllowance)
ae.POST("/notify", useNotify)
ae.GET("/count", allowanceCount)
ae.POST("/receive", receiveAllowance)
// 元旦活动
group.GET("/prize/cards", prizeCards)
group.POST("/prize/draw", prizeDraw)
}
}
// ping check server ok.
func ping(c *bm.Context) {
if err := svc.Ping(c); err != nil {
log.Error("coupon http service ping error(%v)", err)
c.AbortWithStatus(http.StatusServiceUnavailable)
}
}
// register check server ok.
func register(c *bm.Context) {
c.JSON(map[string]interface{}{}, nil)
}

View File

@@ -0,0 +1,65 @@
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",
)
proto_library(
name = "model_proto",
srcs = ["coupon.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/service/main/coupon/model",
proto = ":model_proto",
tags = ["automanaged"],
deps = [
"//library/time:go_default_library",
"@com_github_gogo_protobuf//gogoproto:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"code.go",
"coupon.go",
"model.go",
"order.go",
"param.go",
"rpc.go",
],
embed = [":model_go_proto"],
importpath = "go-common/app/service/main/coupon/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"],
)

View File

@@ -0,0 +1,45 @@
package model
// CouponCode coupon code.
type CouponCode struct {
ID int64
BatchToken string
State int32
Code string
Mid int64
CouponType int32
CouponToken string
Ver int64
}
//Token get token .
type Token struct {
Token string `json:"token"`
URL string `json:"url"`
}
// ArgUseCouponCode arg use coupon code.
type ArgUseCouponCode struct {
Token string `form:"token" validate:"required"`
Code string `form:"code" validate:"required"`
Verify string `form:"verify" validate:"required"`
IP string
Mid int64
}
// UseCouponCodeResp use coupon code resp.
type UseCouponCodeResp struct {
CouponToken string `json:"coupon_token"`
CouponAmount float64 `json:"coupon_amount"`
FullAmount float64 `json:"full_amount"`
PlatfromLimitExplain string `json:"platfrom_limit_explain"`
ProductLimitMonth int32 `json:"product_limit_month"`
ProductLimitRenewal int32 `json:"product_limit_renewal"`
}
// coupon code state.
const (
CodeStateNotUse = iota + 1
CodeStateUsed
CodeStateBlock
)

View File

@@ -0,0 +1,277 @@
package model
import (
"fmt"
"strings"
"go-common/library/time"
)
// coupon_batch_info表 product_limit_renewal字段.
const (
ProdLimRenewalAll int8 = iota
ProdLimRenewalAuto
ProdLimRenewalNotAuto
)
// coupon_batch_info表 product_limit_renewal字段.
const (
None int8 = 0
ProdLimMonth1 = 1
ProdLimMonth3 = 3
ProdLimMonth12 = 12
)
const (
// CardSalt .
CardSalt = "7RbjA6mpSz9DYQ0n"
)
// CardType table:coupon_user_card field:card_type
const (
CardType1 int8 = iota
CardType3
CardType12
)
// CardState table:coupon_user_card field:state
const (
CardStateNotOpen int8 = iota
CardStateOpened
CardStateUsed
)
// product limit map .
var (
ProdLimMonthMap = map[int8]string{None: "", ProdLimMonth1: "月度", ProdLimMonth3: "季度", ProdLimMonth12: "年度"}
ProdLimRenewalMap = map[int8]string{ProdLimRenewalAll: "", ProdLimRenewalAuto: "自动续期", ProdLimRenewalNotAuto: "非自动续期"}
)
// MapFullAmount .
var MapFullAmount = map[int8]float64{
CardType1: 25,
CardType3: 68,
CardType12: 233,
}
// CouponChangeLog coupon change log.
type CouponChangeLog struct {
ID int64 `json:"-"`
CouponToken string `json:"coupon_token"`
Mid int64 `json:"mid"`
State int8 `json:"state"`
Ctime time.Time `json:"ctime"`
Mtime time.Time `json:"mtime"`
}
// CouponPageResp coupon page.
type CouponPageResp struct {
ID int64 `json:"id"`
Title string `json:"title"`
Time int64 `json:"time"`
RefID int64 `json:"ref_id"`
Tips string `json:"tips"`
Count int64 `json:"count"`
}
// CouponOrder coupon order info.
type CouponOrder struct {
ID int64 `json:"id"`
OrderNo string `json:"order_no"`
Mid int64 `json:"mid"`
Count int64 `json:"count"`
State int8 `json:"state"`
CouponType int8 `json:"coupon_type"`
ThirdTradeNo string `json:"third_trade_no"`
Remark string `json:"remark"`
Tips string `json:"tips"`
UseVer int64 `json:"use_ver"`
Ver int64 `json:"ver"`
Ctime time.Time `json:"ctime"`
Mtime time.Time `json:"mtime"`
}
// CouponOrderLog coupon order log.
type CouponOrderLog struct {
ID int64 `json:"id"`
OrderNo string `json:"order_no"`
Mid int64 `json:"mid"`
State int8 `json:"state"`
Ctime time.Time `json:"ctime"`
Mtime time.Time `json:"mtime"`
}
// CouponBalanceChangeLog coupon balance change log.
type CouponBalanceChangeLog struct {
ID int64 `json:"id"`
OrderNo string `json:"order_no"`
Mid int64 `json:"mid"`
BatchToken string `json:"batch_token"`
Balance int64 `json:"balance"`
ChangeBalance int64 `json:"change_balance"`
ChangeType int8 `json:"change_type"`
Ctime time.Time `json:"ctime"`
Mtime time.Time `json:"mtime"`
}
// CouponCartoonPageResp coupon cartoon page.
type CouponCartoonPageResp struct {
Count int64 `json:"count"`
CouponCount int64 `json:"coupon_count"`
List []*CouponPageResp `json:"list"`
}
// CouponBatchInfo coupon batch info.
type CouponBatchInfo struct {
ID int64 `json:"id"`
AppID int64 `json:"app_id"`
Name string `json:"name"`
BatchToken string `json:"batch_token"`
MaxCount int64 `json:"max_count"`
CurrentCount int64 `json:"current_count"`
LimitCount int64 `json:"limit_count"`
StartTime int64 `json:"start_time"`
ExpireTime int64 `json:"expire_time"`
ExpireDay int64 `json:"expire_day"`
Ver int64 `json:"ver"`
Ctime time.Time `json:"ctime"`
Mtime time.Time `json:"mtime"`
FullAmount float64 `json:"full_amount"`
Amount float64 `json:"amount"`
State int8 `json:"state"`
CouponType int8 `json:"coupon_type"`
PlatformLimit string `json:"platform_limit"`
ProdLimMonth int8 `json:"product_limit_month"`
ProdLimRenewal int8 `json:"product_limit_Renewal"`
}
// CouponAllowancePanelInfo allowance coupon panel info.
type CouponAllowancePanelInfo struct {
CouponToken string `json:"coupon_token"`
Amount float64 `json:"coupon_amount"`
State int32 `json:"state"`
FullLimitExplain string `json:"full_limit_explain"`
ScopeExplain string `json:"scope_explain"`
FullAmount float64 `json:"full_amount"`
CouponDiscountPrice float64 `json:"coupon_discount_price"`
StartTime int64 `json:"start_time"`
ExpireTime int64 `json:"expire_time"`
Selected int8 `json:"selected"`
DisablesExplains string `json:"disables_explains"`
OrderNO string `json:"order_no"`
Name string `json:"name"`
Usable int8 `json:"usable"`
}
// CouponTipInfo coupon tip info.
type CouponTipInfo struct {
CouponTip string `json:"coupon_tip"`
CouponInfo *CouponAllowancePanelInfo `json:"coupon_info"`
}
// CouponAllowanceChangeLog coupon allowance change log.
type CouponAllowanceChangeLog struct {
ID int64 `json:"-"`
CouponToken string `json:"coupon_token"`
OrderNO string `json:"order_no"`
Mid int64 `json:"mid"`
State int8 `json:"state"`
ChangeType int8 `json:"change_type"`
Ctime time.Time `json:"ctime"`
Mtime time.Time `json:"mtime"`
}
//CouponReceiveLog receive log.
type CouponReceiveLog struct {
ID int64 `json:"id"`
Appkey string `json:"appkey"`
OrderNo string `json:"order_no"`
Mid int64 `json:"mid"`
CouponToken string `json:"coupon_token"`
CouponType int8 `json:"coupon_type"`
}
//CouponAllowancePanelResp def.
type CouponAllowancePanelResp struct {
Usables []*CouponAllowancePanelInfo `json:"usables"`
Disables []*CouponAllowancePanelInfo `json:"disables"`
Using []*CouponAllowancePanelInfo `json:"using"`
}
// SalaryCouponForThirdResp resp.
type SalaryCouponForThirdResp struct {
Amount float64 `json:"amount"`
FullAmount float64 `json:"full_amount"`
Description string `json:"description"`
}
// ScopeExplainFmt get scope explain fmt.
func (c *CouponAllowancePanelInfo) ScopeExplainFmt(pstr string, prodLimMonth, prodLimRenewal int8, platMap map[string]string) {
var (
ps []string
plats, scope, scopePlat, limr, limm string
)
if len(pstr) == 0 && prodLimMonth == 0 && prodLimRenewal == 0 {
c.ScopeExplain = ScopeNoLimit
return
}
if len(pstr) > 0 {
ps = strings.Split(pstr, ",")
for _, v := range ps {
plats += platMap[v] + ","
}
}
if len(plats) > 0 {
plats = plats[:len(plats)-1]
scopePlat = fmt.Sprintf(ScopePlatFmt, plats)
}
limr = ProdLimRenewalMap[prodLimRenewal]
limm = ProdLimMonthMap[prodLimMonth]
scope = scopePlat + fmt.Sprintf(ScopeProductFmt, limr, limm)
c.ScopeExplain = scope
}
// PlatfromLimitExplain platform limit explain.
func PlatfromLimitExplain(pstr string, platMap map[string]string) string {
var (
ps []string
plats string
)
if len(pstr) == 0 {
return ""
}
if len(pstr) > 0 {
ps = strings.Split(pstr, ",")
for _, v := range ps {
plats += platMap[v] + ","
}
}
if len(plats) > 0 {
plats = plats[:len(plats)-1]
}
return plats
}
// PrizeCards struct .
type PrizeCards struct {
List []*PrizeCardRep `json:"list"`
}
// PrizeCardRep struct .
type PrizeCardRep struct {
CardType int8 `json:"card_type"`
State int8 `json:"state"`
OriginalPrice int64 `json:"original_price,omitempty"`
CouponAmount int64 `json:"coupon_amount,omitempty"`
DiscountRate string `json:"discount_rate,omitempty"`
}
// CouponUserCard struct .
type CouponUserCard struct {
MID int64 `json:"mid"`
CardType int8 `json:"card_type"`
State int8 `json:"state"`
BatchToken string `json:"batch_token"`
CouponToken string `json:"coupon_token"`
ActID int64 `json:"act_id"`
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,73 @@
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 CouponInfo {
int64 ID = 1 [(gogoproto.jsontag) = "_"];
string CouponToken = 2 [(gogoproto.jsontag) = "coupon_token"];
int64 Mid = 3 [(gogoproto.jsontag) = "mid"];
int64 State = 4 [(gogoproto.jsontag) = "state"];
int64 StartTime = 5 [(gogoproto.jsontag) = "start_time"];
int64 ExpireTime = 6 [(gogoproto.jsontag) = "expire_time"];
int64 Origin = 7 [(gogoproto.jsontag) = "origin"];
int64 CouponType = 8 [(gogoproto.jsontag) = "coupon_type"];
string OrderNO = 9 [(gogoproto.jsontag) = "order_no"];
int64 Ver = 10 [(gogoproto.jsontag) = "ver"];
int64 Oid = 11 [(gogoproto.jsontag) = "oid"];
string Remark = 12 [(gogoproto.jsontag) = "remark"];
int64 UseVer = 13 [(gogoproto.jsontag) = "use_ver"];
int64 CTime = 14 [(gogoproto.jsontag) = "-", (gogoproto.casttype) = "go-common/library/time.Time"];
int64 MTime = 15 [(gogoproto.jsontag) = "-", (gogoproto.casttype) = "go-common/library/time.Time"];
string BatchToken = 16 [(gogoproto.jsontag) = "batch_token"];
}
message PointInfoList {
repeated CouponInfo pointInfoList = 1;
}
message CouponBalanceInfo {
int64 ID = 1 [(gogoproto.jsontag) = "_"];
string BatchToken = 2 [(gogoproto.jsontag) = "batch_token"];
int64 Mid = 3 [(gogoproto.jsontag) = "mid"];
int64 Balance = 4 [(gogoproto.jsontag) = "balance"];
int64 StartTime = 5 [(gogoproto.jsontag) = "start_time"];
int64 ExpireTime = 6 [(gogoproto.jsontag) = "expire_time"];
int64 Origin = 7 [(gogoproto.jsontag) = "origin"];
int64 CouponType = 8 [(gogoproto.jsontag) = "coupon_type"];
int64 Ver = 9 [(gogoproto.jsontag) = "ver"];
int64 CTime = 10 [(gogoproto.jsontag) = "-", (gogoproto.casttype) = "go-common/library/time.Time"];
int64 MTime = 11 [(gogoproto.jsontag) = "-", (gogoproto.casttype) = "go-common/library/time.Time"];
}
message CouponBalanceList {
repeated CouponBalanceInfo couponBalanceList = 1;
}
message CouponAllowanceInfo {
int64 ID = 1 [(gogoproto.jsontag) = "_"];
string CouponToken = 2 [(gogoproto.jsontag) = "coupon_token"];
int64 Mid = 3 [(gogoproto.jsontag) = "mid"];
int32 State = 4 [(gogoproto.jsontag) = "state"];
int64 StartTime = 5 [(gogoproto.jsontag) = "start_time"];
int64 ExpireTime = 6 [(gogoproto.jsontag) = "expire_time"];
int64 Origin = 7 [(gogoproto.jsontag) = "origin"];
string OrderNO = 8 [(gogoproto.jsontag) = "order_no"];
int64 Ver = 9 [(gogoproto.jsontag) = "ver"];
string Remark = 10 [(gogoproto.jsontag) = "remark"];
int64 CTime = 11 [(gogoproto.jsontag) = "-", (gogoproto.casttype) = "go-common/library/time.Time"];
int64 MTime = 12 [(gogoproto.jsontag) = "-", (gogoproto.casttype) = "go-common/library/time.Time"];
string BatchToken = 13 [(gogoproto.jsontag) = "batch_token"];
double Amount = 14 [(gogoproto.jsontag) = "amount"];
double FullAmount = 15 [(gogoproto.jsontag) = "full_amount"];
int64 AppID = 16 [(gogoproto.jsontag) = "app_id"];
}
message CouponAllowanceList {
repeated CouponAllowanceInfo couponAllowanceList = 1;
}

View File

@@ -0,0 +1,163 @@
package model
// coupon use state.
const (
UseFaild int8 = iota
UseSuccess
)
// coupon state.
const (
NotUsed = iota
InUse
Used
Expire
Block
)
// coupon state.
const (
WaitPay = iota
InPay
PaySuccess
PayFaild
)
// max salary count.
const (
MaxSalaryCount = 100
)
// blance change type
const (
VipSalary int8 = iota + 1
SystemAdminSalary
Consume
ConsumeFaildBack
)
// coupon type
const (
CouponVideo = iota + 1
CouponCartoon
CouponAllowance
)
//allowance origin
const (
AllowanceNone = iota
AllowanceSystemAdmin
AllowanceBusinessReceive
AllowanceBusinessNewYear
AllowanceCodeOpen
)
// batch state
const (
BatchStateNormal = iota
BatchStateBlock
)
// coupon disables explains
const (
CouponHadBlock = "代金券已被冻结"
CouponFullAmountDissatisfy = "未达到满额条件"
CouponNotInUsableTime = "当前不在有效期内"
CouponInUse = "已绑定在其他未支付订单,点击解锁"
CouponPlatformExplain = "当前平台不可使用"
CouponProductExplain = "当前商品不可使用"
)
// coupon scope explains
const (
ScopeNoLimit = "不限使用平台"
ScopePlatFmt = "仅限%s端"
ScopeProductFmt = "购买%s%s大会员时使用"
)
// coupon send message
const (
ReceiveMessageTitle = "大会员代金券到账通知"
ReceiveMessage = "大会员代金券已到账快到“我的代金券”看看吧IOS端需要在网页使用。#{传送门}{\"https://account.bilibili.com/account/big/voucher\"}"
)
// device code
const (
DeviceIOS int = iota + 1
DeviceIPAD
DevicePC
DeviceANDROID
DeviceIPADHD
DeviceIOSBLUE
DeviceANDROIDBLUE
DevicePUBLIC
)
// PlatformByCode device name map.
var PlatformByCode = map[int]string{
DeviceIOS: "ios",
DeviceIPAD: "ipad",
DevicePC: "网页",
DeviceANDROID: "Android",
}
// coupon format
const (
CouponFullAmountLimit = "满%s元可用"
CouponAllowanceName = "大会员代金券"
)
// coupon seleted
const (
Seleted = 1
)
// allowance change type
const (
AllowanceSalary int8 = iota + 1
AllowanceConsume
AllowanceCancel
AllowanceConsumeSuccess
AllowanceConsumeFaild
AllowanceReceive
)
// allowance notify pay status
const (
AllowanceUseFaild int8 = iota
AllowanceUseSuccess
)
// allowance able state
const (
AllowanceDisables int8 = iota
AllowanceUsable
)
//PlatformByName .
var PlatformByName = map[string]int{
"ios": DeviceIOS,
"ios_b": DeviceIOS,
"ipad": DeviceIPAD,
"ipadhd": DeviceIPAD,
"pc": DevicePC,
"public": DevicePC,
"android": DeviceANDROID,
"android_b": DeviceANDROID,
}
//PlatfromMapping .
var PlatfromMapping = map[int]int{
DeviceIPADHD: DeviceIPAD,
DeviceIOSBLUE: DeviceIOS,
DeviceANDROIDBLUE: DeviceANDROID,
DevicePUBLIC: DevicePC,
}
// coupon tip.
const (
CouponTipNotUse = "不使用代金券"
CouponTipChooseOther = "选中其他商品有惊喜"
CouponTipUse = "抵扣%.2f元"
CouponTipInUse = "有代金券被锁定"
)

View File

@@ -0,0 +1,30 @@
package model
// 临时逻辑 --- start ----
import "go-common/library/time"
// OrderInfo order info.
type OrderInfo struct {
ID int64
OrderNo string
AppID int64
OrderType int8
Platform int8
Mid int64
ToMid int64
BuyMonths int16
Money float64
RefundAmount float64
Status int8
PayType string
RechargeBP float64
ThirdTradeNo string
PaymentTime time.Time
Ver int64
Ctime time.Time
Mtime time.Time
AppSubID string
}
// 临时逻辑 --- end ----

View File

@@ -0,0 +1,114 @@
package model
// ArgMid .
type ArgMid struct {
Mid int64 `form:"mid" validate:"required,min=1,gte=1"`
Type int8 `form:"type" validate:"required,min=1,gte=1"`
}
// ArgUseCoupon .
type ArgUseCoupon struct {
Mid int64 `form:"mid" validate:"required,min=1,gte=1"`
Type int8 `form:"type" validate:"required,min=1,gte=1"`
Remark string `form:"remark" validate:"required"`
OrderNO string `form:"order_id" validate:"required"`
Oid int64 `form:"oid" validate:"required,min=1,gte=1"`
Ver int64 `form:"ver" validate:"required,min=1,gte=1"`
}
// ArgUseCartoonCoupon def .
type ArgUseCartoonCoupon struct {
Mid int64 `form:"mid" validate:"required,min=1,gte=1"`
Type int8 `form:"type" validate:"required,min=1,gte=1"`
Tips string `form:"tips" validate:"required"`
Remark string `form:"remark" validate:"required"`
OrderNO string `form:"order_id" validate:"required"`
Count int64 `form:"count" validate:"required,min=1,gte=1"`
Ver int64 `form:"ver" validate:"required,min=1,gte=1"`
}
// ArgCoupon .
type ArgCoupon struct {
Mid int64 `form:"mid" validate:"required,min=1,gte=1"`
CouponToken string `form:"coupon_token" validate:"required"`
}
// ChangeCoupon .
type ChangeCoupon struct {
Mid int64 `form:"mid"`
CouponToken string `form:"coupon_token"`
Ver int64 `form:"ver"`
UseVer int64 `form:"use_ver"`
}
// ArgAdd .
type ArgAdd struct {
Mid int64 `form:"mid" validate:"required,min=1,gte=1"`
StartTime int64 `form:"start_time"`
ExpireTime int64 `form:"expire_time" validate:"required,min=1,gte=1"`
Type int64 `form:"type" validate:"required,min=1,gte=1"`
Origin int64 `form:"origin" validate:"required,min=1,gte=1"`
}
// ArgPage .
type ArgPage struct {
State int8 `form:"state"`
Pn int `form:"pn"`
Ps int `form:"ps"`
}
// ArgSalary salary coupon.
type ArgSalary struct {
Mid int64 `form:"mid" validate:"required,min=1,gte=1"`
CouponType int64 `form:"type" validate:"required,min=1,gte=1"`
Count int `form:"count" validate:"required,min=1,gte=1"`
BatchToken string `form:"batch_no" validate:"required"`
AppID int64 `form:"app_id"`
}
// ArgUseAllowance allowance coupon use.
type ArgUseAllowance struct {
Mid int64 `form:"mid" validate:"required,min=1,gte=1"`
CouponToken string `form:"coupon_token" validate:"required"`
Remark string `form:"remark" validate:"required"`
OrderNO string `form:"order_id" validate:"required"`
Price float64 `form:"price" validate:"required"`
Platform string `form:"platform" default:"pc"`
MobiApp string `form:"mobi_app"`
PanelType string `form:"panel_type" default:"normal"`
Device string `form:"device"`
Build int64 `form:"build"`
ProdLimMonth int8 `form:"product_limit_month"`
ProdLimRenewal int8 `form:"product_limit_renewal"`
}
// ArgCount allowance count.
type ArgCount struct {
Mid int64 `form:"mid" validate:"required,min=1,gte=1"`
}
//ArgReceiveAllowance .
type ArgReceiveAllowance struct {
Mid int64 `form:"mid" validate:"required" json:"mid"`
BatchToken string `form:"batch_token" validate:"required" json:"batch_token"`
OrderNo string `form:"order_no" validate:"required" json:"order_no"`
Appkey string `form:"appkey" validate:"required" json:"appkey"`
}
//ArgAllowanceCheck .
type ArgAllowanceCheck struct {
Mid int64 `form:"mid" validate:"required" json:"mid"`
OrderNo string `form:"order_no" validate:"required" json:"order_no"`
}
// ArgPrizeDraw struct .
type ArgPrizeDraw struct {
Mid int64 `form:"mid" validate:"required,gte=1"`
CardType int8 `form:"card_type" validate:"gte=0,lte=2" json:"card_type"`
}
// ArgAllowanceCoupons arg allowance coupon.
type ArgAllowanceCoupons struct {
Mid int64
State int8
}

View File

@@ -0,0 +1,7 @@
#! /bin/sh
# proto.sh
gopath=$GOPATH/src
gogopath=$GOPATH/src/go-common/vendor/github.com/gogo/protobuf
protoc --gofast_out=. --proto_path=$gopath:$gogopath:. *.proto

View File

@@ -0,0 +1,78 @@
package model
// ArgSalaryCoupon salary coupon.
type ArgSalaryCoupon struct {
Mid int64 `form:"mid" validate:"required,min=1,gte=1"`
CouponType int64 `form:"type" validate:"required,min=1,gte=1"`
Origin int64
Count int `form:"count" validate:"required,min=1,gte=1"`
BatchToken string `form:"batch_no" validate:"required"`
AppID int64 `form:"app_id"`
UniqueNo string
}
// ArgRPCPage def .
type ArgRPCPage struct {
Mid int64
State int8
Pn int
Ps int
}
// CouponPageRPCResp def.
type CouponPageRPCResp struct {
Count int64 `json:"count"`
Res []*CouponPageResp `json:"list"`
}
// ArgAllowanceCoupon def .
type ArgAllowanceCoupon struct {
Mid int64
Pirce float64
Platform int
ProdLimMonth int8
ProdLimRenewal int8
}
// ArgUsablePirces def .
type ArgUsablePirces struct {
Mid int64
Pirce []float64
Platform int
ProdLimMonth int8
ProdLimRenewal int8
}
// ArgJuageUsable def .
type ArgJuageUsable struct {
Mid int64
Pirce float64
CouponToken string
Platform int
ProdLimMonth int8
ProdLimRenewal int8
}
// ArgAllowance def .
type ArgAllowance struct {
Mid int64
CouponToken string
}
// ArgNotify .
type ArgNotify struct {
Mid int64
OrderNo string
State int8
}
// ArgAllowanceList .
type ArgAllowanceList struct {
Mid int64
State int8
}
// ArgAllowanceMid .
type ArgAllowanceMid struct {
Mid int64
}

View File

@@ -0,0 +1,32 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = ["coupon.go"],
importpath = "go-common/app/service/main/coupon/rpc/client",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/main/coupon/model:go_default_library",
"//library/net/rpc: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,161 @@
package client
import (
"context"
"go-common/app/service/main/coupon/model"
"go-common/library/net/rpc"
)
var (
_noRes = &struct{}{}
)
const (
_salaryCoupon = "RPC.SalaryCoupon"
_salaryCouponForThird = "RPC.SalaryCouponForThird"
_couponPage = "RPC.CouponPage"
_couponCartoonPage = "RPC.CouponCartoonPage"
_usableAllowanceCoupon = "RPC.UsableAllowanceCoupon"
_allowanceCouponPanel = "RPC.AllowanceCouponPanel"
_multiUsableAllowanceCoupon = "RPC.MultiUsableAllowanceCoupon"
_judgeCouponUsable = "RPC.JudgeCouponUsable"
_allowanceInfo = "RPC.AllowanceInfo"
_cancelUseCoupon = "RPC.CancelUseCoupon"
_couponNotify = "RPC.CouponNotify"
_allowanceList = "RPC.AllowanceList"
_useAllowance = "RPC.UseAllowance"
_allowanceCount = "RPC.AllowanceCount"
_receiveAllowance = "RPC.ReceiveAllowance"
_prizeCards = "RPC.PrizeCards"
_prizeDraw = "RPC.PrizeDraw"
)
const (
_appid = "account.service.coupon"
)
var (
_noArg = &struct{}{}
)
// Service struct info.
type Service struct {
client *rpc.Client2
}
// New create instance of service and return.
func New(c *rpc.ClientConfig) (s *Service) {
s = &Service{}
s.client = rpc.NewDiscoveryCli(_appid, c)
return s
}
// SalaryCoupon salary coupon.
func (s *Service) SalaryCoupon(c context.Context, arg *model.ArgSalaryCoupon) (err error) {
err = s.client.Call(c, _salaryCoupon, arg, _noRes)
return
}
// SalaryCouponForThird salary coupon.
func (s *Service) SalaryCouponForThird(c context.Context, arg *model.ArgSalaryCoupon) (res *model.SalaryCouponForThirdResp, err error) {
res = new(model.SalaryCouponForThirdResp)
err = s.client.Call(c, _salaryCouponForThird, arg, res)
return
}
// CouponPage coupon page.
func (s *Service) CouponPage(c context.Context, arg *model.ArgRPCPage) (res *model.CouponPageRPCResp, err error) {
res = new(model.CouponPageRPCResp)
err = s.client.Call(c, _couponPage, arg, res)
return
}
// CouponCartoonPage coupon cartoon page.
func (s *Service) CouponCartoonPage(c context.Context, arg *model.ArgRPCPage) (res *model.CouponCartoonPageResp, err error) {
res = new(model.CouponCartoonPageResp)
err = s.client.Call(c, _couponCartoonPage, arg, res)
return
}
// UsableAllowanceCoupon get usable allowance coupon.
func (s *Service) UsableAllowanceCoupon(c context.Context, arg *model.ArgAllowanceCoupon) (res *model.CouponAllowancePanelInfo, err error) {
res = new(model.CouponAllowancePanelInfo)
err = s.client.Call(c, _usableAllowanceCoupon, arg, res)
return
}
// AllowanceCouponPanel get allowance coupon.
func (s *Service) AllowanceCouponPanel(c context.Context, arg *model.ArgAllowanceCoupon) (res *model.CouponAllowancePanelResp, err error) {
res = new(model.CouponAllowancePanelResp)
err = s.client.Call(c, _allowanceCouponPanel, arg, res)
return
}
// MultiUsableAllowanceCoupon get usable allowance coupon by muti pirce.
func (s *Service) MultiUsableAllowanceCoupon(c context.Context, arg *model.ArgUsablePirces) (res map[float64]*model.CouponAllowancePanelInfo, err error) {
err = s.client.Call(c, _multiUsableAllowanceCoupon, arg, &res)
return
}
// JudgeCouponUsable judge coupon is usable.
func (s *Service) JudgeCouponUsable(c context.Context, arg *model.ArgJuageUsable) (res *model.CouponAllowanceInfo, err error) {
res = new(model.CouponAllowanceInfo)
err = s.client.Call(c, _judgeCouponUsable, arg, res)
return
}
// AllowanceInfo allowance info.
func (s *Service) AllowanceInfo(c context.Context, arg *model.ArgAllowance) (res *model.CouponAllowanceInfo, err error) {
res = new(model.CouponAllowanceInfo)
err = s.client.Call(c, _allowanceInfo, arg, res)
return
}
// CancelUseCoupon cancel use coupon.
func (s *Service) CancelUseCoupon(c context.Context, arg *model.ArgAllowance) (err error) {
err = s.client.Call(c, _cancelUseCoupon, arg, _noArg)
return
}
// CouponNotify notify coupon.
func (s *Service) CouponNotify(c context.Context, arg *model.ArgNotify) (err error) {
err = s.client.Call(c, _couponNotify, arg, _noArg)
return
}
// AllowanceList allowance list.
func (s *Service) AllowanceList(c context.Context, arg *model.ArgAllowanceList) (res []*model.CouponAllowancePanelInfo, err error) {
err = s.client.Call(c, _allowanceList, arg, &res)
return
}
// UseAllowance use allowance.
func (s *Service) UseAllowance(c context.Context, arg *model.ArgUseAllowance) (err error) {
err = s.client.Call(c, _useAllowance, arg, _noArg)
return
}
// AllowanceCount allowance count.
func (s *Service) AllowanceCount(c context.Context, arg *model.ArgAllowanceMid) (res int, err error) {
err = s.client.Call(c, _allowanceCount, arg, &res)
return
}
//ReceiveAllowance receive allowance
func (s *Service) ReceiveAllowance(c context.Context, arg *model.ArgReceiveAllowance) (res string, err error) {
err = s.client.Call(c, _receiveAllowance, arg, &res)
return
}
// PrizeCards .
func (s *Service) PrizeCards(c context.Context, arg *model.ArgCount) (res []*model.PrizeCardRep, err error) {
err = s.client.Call(c, _prizeCards, arg, &res)
return
}
// PrizeDraw .
func (s *Service) PrizeDraw(c context.Context, arg *model.ArgPrizeDraw) (res *model.PrizeCardRep, err error) {
err = s.client.Call(c, _prizeDraw, arg, &res)
return
}

View File

@@ -0,0 +1,36 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = ["rpc.go"],
importpath = "go-common/app/service/main/coupon/rpc/server",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/main/coupon/conf:go_default_library",
"//app/service/main/coupon/model:go_default_library",
"//app/service/main/coupon/service:go_default_library",
"//library/log:go_default_library",
"//library/net/rpc:go_default_library",
"//library/net/rpc/context: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,217 @@
package server
import (
"go-common/app/service/main/coupon/conf"
"go-common/app/service/main/coupon/model"
"go-common/app/service/main/coupon/service"
"go-common/library/log"
"go-common/library/net/rpc"
"go-common/library/net/rpc/context"
)
// RPC server
type RPC struct {
s *service.Service
}
// New new rpc server.
func New(c *conf.Config, s *service.Service) (svr *rpc.Server) {
r := &RPC{s: s}
svr = rpc.NewServer(c.RPCServer)
if err := svr.Register(r); err != nil {
panic(err)
}
return
}
// Ping check connection success.
func (r *RPC) Ping(c context.Context, arg *struct{}, res *struct{}) (err error) {
return
}
// SalaryCoupon salary coupon.
func (r *RPC) SalaryCoupon(c context.Context, a *model.ArgSalaryCoupon, res *struct{}) (err error) {
return r.s.SalaryCoupon(c, a)
}
// SalaryCouponForThird salary coupon for third.
func (r *RPC) SalaryCouponForThird(c context.Context, a *model.ArgSalaryCoupon, res *model.SalaryCouponForThirdResp) (err error) {
var ct *model.SalaryCouponForThirdResp
if ct, err = r.s.SalaryCouponForThird(c, a); err == nil && ct != nil {
*res = *ct
}
return
}
// CouponPage coupon page.
func (r *RPC) CouponPage(c context.Context, arg *model.ArgRPCPage, res *model.CouponPageRPCResp) (err error) {
var (
cr *model.CouponPageRPCResp
count int64
list []*model.CouponPageResp
)
if count, list, err = r.s.CouponPage(c, arg.Mid, arg.State, arg.Pn, arg.Ps); err != nil {
log.Error("r.s.CouponPage(%d) err(%+v)", arg.Mid, err)
return
}
cr = &model.CouponPageRPCResp{
Count: count,
Res: list,
}
*res = *cr
return
}
// CouponCartoonPage coupon cartoon page.
func (r *RPC) CouponCartoonPage(c context.Context, arg *model.ArgRPCPage, res *model.CouponCartoonPageResp) (err error) {
var p *model.CouponCartoonPageResp
if p, err = r.s.CouponCartoonPage(c, arg.Mid, arg.State, arg.Pn, arg.Ps); err != nil || p == nil {
log.Error("r.s.CouponCartoonPage(%d) err(%+v)", arg.Mid, err)
return
}
*res = *p
return
}
// UsableAllowanceCoupon get usable allowance coupon.
func (r *RPC) UsableAllowanceCoupon(c context.Context, a *model.ArgAllowanceCoupon, res *model.CouponAllowancePanelInfo) (err error) {
var cr *model.CouponAllowancePanelInfo
if cr, err = r.s.UsableAllowanceCoupon(c, a.Mid, a.Pirce, a.Platform, a.ProdLimMonth, a.ProdLimRenewal); err == nil && cr != nil {
*res = *cr
}
if err != nil {
log.Error("rpc.UsableAllowanceCoupon(%+v) err(%+v)", a, err)
}
return
}
// AllowanceCouponPanel get allowance coupon info for pay panel.
func (r *RPC) AllowanceCouponPanel(c context.Context, a *model.ArgAllowanceCoupon, res *model.CouponAllowancePanelResp) (err error) {
var (
cr *model.CouponAllowancePanelResp
us []*model.CouponAllowancePanelInfo
ds []*model.CouponAllowancePanelInfo
ui []*model.CouponAllowancePanelInfo
)
if us, ds, ui, err = r.s.AllowancePanelCoupons(c, a.Mid, a.Pirce, a.Platform, a.ProdLimMonth, a.ProdLimRenewal); err != nil {
log.Error("rpc.AllowancePanelCoupons(%+v) err(%+v)", a, err)
return
}
cr = &model.CouponAllowancePanelResp{
Usables: us,
Disables: ds,
Using: ui,
}
*res = *cr
return
}
// MultiUsableAllowanceCoupon get usable allowance coupon by muti pirce.
func (r *RPC) MultiUsableAllowanceCoupon(c context.Context, a *model.ArgUsablePirces, res *map[float64]*model.CouponAllowancePanelInfo) (err error) {
if *res, err = r.s.MultiUsableAllowanceCoupon(c, a.Mid, a.Pirce, a.Platform, a.ProdLimMonth, a.ProdLimRenewal); err != nil {
log.Error("rpc.MultiUsableAllowanceCoupon(%+v) err(%+v)", a, err)
return
}
return
}
// JudgeCouponUsable judge coupon is usable.
func (r *RPC) JudgeCouponUsable(c context.Context, a *model.ArgJuageUsable, res *model.CouponAllowanceInfo) (err error) {
var cp *model.CouponAllowanceInfo
if cp, err = r.s.JudgeCouponUsable(c, a.Mid, a.Pirce, a.CouponToken, a.Platform, a.ProdLimMonth, a.ProdLimRenewal); err == nil && cp != nil {
*res = *cp
return
}
if err != nil {
log.Error("rpc.JudgeCouponUsable(%+v) err(%+v)", a, err)
}
return
}
// AllowanceInfo allowance info.
func (r *RPC) AllowanceInfo(c context.Context, a *model.ArgAllowance, res *model.CouponAllowanceInfo) (err error) {
var cp *model.CouponAllowanceInfo
if cp, err = r.s.AllowanceInfo(c, a.Mid, a.CouponToken); err == nil && cp != nil {
*res = *cp
return
}
if err != nil {
log.Error("rpc.AllowanceInfo(%+v) err(%+v)", a, err)
}
return
}
// CancelUseCoupon cancel use coupon .
func (r *RPC) CancelUseCoupon(c context.Context, a *model.ArgAllowance, res *struct{}) (err error) {
if err = r.s.CancelUseCoupon(c, a.Mid, a.CouponToken); err != nil {
log.Error("rpc.CancelUseCoupon(%+v) err(%+v)", a, err)
}
return
}
// CouponNotify notify coupon .
func (r *RPC) CouponNotify(c context.Context, a *model.ArgNotify, res *struct{}) (err error) {
if err = r.s.CouponNotify(c, a.Mid, a.OrderNo, a.State); err != nil {
log.Error("rpc.CouponNotify(%+v) err(%+v)", a, err)
}
return
}
// AllowanceList allowance list .
func (r *RPC) AllowanceList(c context.Context, a *model.ArgAllowanceList, res *[]*model.CouponAllowancePanelInfo) (err error) {
if *res, err = r.s.AllowanceList(c, a.Mid, a.State); err != nil {
log.Error("rpc.AllowanceList(%+v) err(%+v)", a, err)
}
return
}
// UseAllowance use allowance .
func (r *RPC) UseAllowance(c context.Context, a *model.ArgUseAllowance, res *struct{}) (err error) {
if err = r.s.UseAllowanceCoupon(c, a); err != nil {
log.Error("rpc.UseAllowanceCoupon(%+v) err(%+v)", a, err)
}
return
}
// AllowanceCount allowance count
func (r *RPC) AllowanceCount(c context.Context, a *model.ArgAllowanceMid, res *int) (err error) {
var rs []*model.CouponAllowanceInfo
if rs, err = r.s.AllowanceCoupon(c, &model.ArgAllowanceCoupons{
Mid: a.Mid,
State: model.NotUsed,
}); err == nil {
*res = len(rs)
}
return
}
//ReceiveAllowance receive allowance.
func (r *RPC) ReceiveAllowance(c context.Context, arg *model.ArgReceiveAllowance, res *string) (err error) {
var couponToken string
if couponToken, err = r.s.ReceiveAllowance(c, arg); err != nil {
log.Error("receive allowance(%+v) err(%+v)", arg, err)
return
}
*res = couponToken
return
}
//PrizeCards .
func (r *RPC) PrizeCards(c context.Context, arg *model.ArgCount, res *[]*model.PrizeCardRep) (err error) {
if *res, err = r.s.PrizeCards(c, arg.Mid); err != nil {
log.Error("r.s.PrizeCards(%+v) err(%+v)", arg, err)
return
}
return
}
//PrizeDraw .
func (r *RPC) PrizeDraw(c context.Context, arg *model.ArgPrizeDraw, res *model.PrizeCardRep) (err error) {
var pc = &model.PrizeCardRep{}
if pc, err = r.s.PrizeDraw(c, arg.Mid, arg.CardType); err != nil {
log.Error("r.s.PrizeDraw(%+v) err(%+v)", arg, err)
return
}
*res = *pc
return
}

View File

@@ -0,0 +1,34 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = ["server.go"],
importpath = "go-common/app/service/main/coupon/server/grpc",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/main/coupon/api:go_default_library",
"//app/service/main/coupon/model:go_default_library",
"//app/service/main/coupon/service:go_default_library",
"//library/net/rpc/warden: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,92 @@
// Package server generate by warden_gen
package server
import (
"context"
v1 "go-common/app/service/main/coupon/api"
"go-common/app/service/main/coupon/model"
"go-common/app/service/main/coupon/service"
"go-common/library/net/rpc/warden"
)
// New VipInfo warden rpc server
func New(c *warden.ServerConfig, svr *service.Service) *warden.Server {
ws := warden.NewServer(c)
v1.RegisterCouponServer(ws.Server(), &server{svr})
ws, err := ws.Start()
if err != nil {
panic(err)
}
return ws
}
type server struct {
svr *service.Service
}
var _ v1.CouponServer = &server{}
func (s *server) CaptchaToken(c context.Context, req *v1.CaptchaTokenReq) (res *v1.CaptchaTokenReply, err error) {
var token *model.Token
if token, err = s.svr.CaptchaToken(c, req.Ip); err != nil || token == nil {
return
}
return &v1.CaptchaTokenReply{
Token: token.Token,
Url: token.URL,
}, err
}
func (s *server) UseCouponCode(c context.Context, req *v1.UseCouponCodeReq) (res *v1.UseCouponCodeResp, err error) {
var data *model.UseCouponCodeResp
if data, err = s.svr.UseCouponCode(c, &model.ArgUseCouponCode{
Token: req.Token,
Code: req.Code,
Verify: req.Verify,
IP: req.Ip,
Mid: req.Mid,
}); err != nil || data == nil {
return
}
return &v1.UseCouponCodeResp{
CouponToken: data.CouponToken,
CouponAmount: data.CouponAmount,
FullAmount: data.FullAmount,
PlatfromLimitExplain: data.PlatfromLimitExplain,
ProductLimitMonth: data.ProductLimitMonth,
ProductLimitRenewal: data.ProductLimitRenewal,
}, err
}
func (s *server) UsableAllowanceCouponV2(c context.Context, req *v1.UsableAllowanceCouponV2Req) (res *v1.UsableAllowanceCouponV2Reply, err error) {
var (
data *model.CouponTipInfo
ci *v1.ModelCouponAllowancePanelInfo
)
if data, err = s.svr.UsableAllowanceCouponV2(c, req); err != nil {
return
}
if data.CouponInfo != nil {
ci = &v1.ModelCouponAllowancePanelInfo{
CouponToken: data.CouponInfo.CouponToken,
CouponAmount: data.CouponInfo.Amount,
State: data.CouponInfo.State,
FullAmount: data.CouponInfo.FullAmount,
FullLimitExplain: data.CouponInfo.FullLimitExplain,
ScopeExplain: data.CouponInfo.ScopeExplain,
CouponDiscountPrice: data.CouponInfo.CouponDiscountPrice,
StartTime: data.CouponInfo.StartTime,
ExpireTime: data.CouponInfo.ExpireTime,
Selected: int32(data.CouponInfo.Selected),
DisablesExplains: data.CouponInfo.DisablesExplains,
OrderNo: data.CouponInfo.OrderNO,
Name: data.CouponInfo.Name,
Usable: int32(data.CouponInfo.Usable),
}
}
return &v1.UsableAllowanceCouponV2Reply{
CouponTip: data.CouponTip,
CouponInfo: ci,
}, err
}

View File

@@ -0,0 +1,69 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = [
"allowance_test.go",
"code_test.go",
"coupon_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/service/main/coupon/api:go_default_library",
"//app/service/main/coupon/conf:go_default_library",
"//app/service/main/coupon/model:go_default_library",
"//library/database/sql:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"allowance.go",
"branch.go",
"code.go",
"coupon.go",
"coupon_cartoon.go",
"service.go",
],
importpath = "go-common/app/service/main/coupon/service",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/main/coupon/api:go_default_library",
"//app/service/main/coupon/conf:go_default_library",
"//app/service/main/coupon/dao:go_default_library",
"//app/service/main/coupon/model:go_default_library",
"//app/service/main/vipinfo/api:go_default_library",
"//app/service/main/vipinfo/model:go_default_library",
"//library/database/sql:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/sync/pipeline/fanout:go_default_library",
"//library/time: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"],
)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,290 @@
package service
import (
"fmt"
"testing"
coupinv1 "go-common/app/service/main/coupon/api"
"go-common/app/service/main/coupon/model"
"github.com/smartystreets/goconvey/convey"
. "github.com/smartystreets/goconvey/convey"
)
// go test -test.v -test.run TestAddAllowanceCoupon
func TestAddAllowanceCoupon(t *testing.T) {
convey.Convey("TestAddAllowanceCoupon ", t, func() {
var (
err error
batchToken = "allowance_test1"
bi *model.CouponBatchInfo
_mid int64 = 233
count = 4
)
bi, err = s.dao.BatchInfo(c, batchToken)
convey.So(err, convey.ShouldBeNil)
convey.So(bi, convey.ShouldNotBeNil)
err = s.AddAllowanceCoupon(c, bi, _mid, count, int64(1), 0)
convey.So(err, convey.ShouldBeNil)
})
}
// go test -test.v -test.run TestAllowanceCoupon
func TestAllowanceCoupon(t *testing.T) {
convey.Convey("TestAllowanceCoupon ", t, func() {
var (
err error
_mid int64 = 1
res []*model.CouponAllowanceInfo
)
res, err = s.AllowanceCoupon(c, &model.ArgAllowanceCoupons{
Mid: _mid,
State: model.NotUsed,
})
t.Logf("count(%d)", len(res))
for _, v := range res {
t.Logf("v(%v)", v)
}
convey.So(err, convey.ShouldBeNil)
})
}
// go test -test.v -test.run TestUseAllowanceCoupon
func TestUseAllowanceCoupon(t *testing.T) {
convey.Convey("TestUseAllowanceCoupon ", t, func() {
var (
err error
arg = &model.ArgUseAllowance{
Mid: int64(2233),
CouponToken: "275685366320181010160429",
Remark: "test1",
Price: float64(120),
OrderNO: "100101",
Platform: "pc",
}
)
err = s.UseAllowanceCoupon(c, arg)
convey.So(err, convey.ShouldBeNil)
})
}
func TestUsableAllowanceCoupons(t *testing.T) {
convey.Convey("TestUsableAllowanceCoupons ", t, func() {
var (
err error
_mid = int64(1)
_price = float64(120)
us []*model.CouponAllowancePanelInfo
ds []*model.CouponAllowancePanelInfo
ui []*model.CouponAllowancePanelInfo
)
us, ds, ui, err = s.UsableAllowanceCoupons(c, _mid, _price, []*model.CouponAllowanceInfo{}, 2, 1, 1)
t.Logf("count(%d)", len(us))
for _, v := range us {
t.Logf("v(%v)", v)
}
t.Logf("count(%d)", len(ds))
for _, v := range ds {
t.Logf("v(%v)", v)
}
for _, v := range ui {
t.Logf("v(%+v)", v)
}
convey.So(err, convey.ShouldBeNil)
})
}
// go test -test.v -test.run TestAllowancePanelCoupons
func TestAllowancePanelCoupons(t *testing.T) {
convey.Convey("TestAllowancePanelCoupons ", t, func() {
var (
err error
_mid = int64(233)
_price = float64(100)
us []*model.CouponAllowancePanelInfo
ds []*model.CouponAllowancePanelInfo
ui []*model.CouponAllowancePanelInfo
)
us, ds, ui, err = s.AllowancePanelCoupons(c, _mid, _price, 3, 1, 1)
t.Logf("count(%d)", len(us))
for _, v := range us {
t.Logf("v(%+v)", v)
}
t.Logf("count(%d)", len(ds))
for _, v := range ds {
t.Logf("v(%+v)", v)
}
for _, v := range ui {
t.Logf("v(%+v)", v)
}
convey.So(err, convey.ShouldBeNil)
})
}
// go test -test.v -test.run TestMultiUsableAllowanceCoupon
func TestMultiUsableAllowanceCoupon(t *testing.T) {
convey.Convey("TestMultiUsableAllowanceCoupon ", t, func() {
var (
err error
_mid = int64(233)
_price = append([]float64{}, float64(120))
res map[float64]*model.CouponAllowancePanelInfo
)
res, err = s.MultiUsableAllowanceCoupon(c, _mid, _price, 3, 1, 1)
t.Logf("count(%d)", len(res))
for _, v := range res {
t.Logf("v(%+v)", v)
}
convey.So(err, convey.ShouldBeNil)
})
}
// go test -test.v -test.run TestCancelUseCoupon
func TestCancelUseCoupon(t *testing.T) {
convey.Convey("TestCancelUseCoupon ", t, func() {
var (
err error
_mid = int64(1)
_token = "443385168420180705155534"
)
err = s.CancelUseCoupon(c, _mid, _token)
convey.So(err, convey.ShouldBeNil)
})
}
// go test -test.v -test.run TestAllowanceList
func TestAllowanceList(t *testing.T) {
convey.Convey("TestAllowanceList ", t, func() {
var (
err error
_mid = int64(1)
res []*model.CouponAllowancePanelInfo
)
res, err = s.AllowanceList(c, _mid, model.NotUsed)
t.Logf("count(%d)", len(res))
for _, v := range res {
t.Logf("v(%+v)", v)
}
convey.So(err, convey.ShouldBeNil)
})
}
// go test -test.v -test.run TestScopeExplainFmt
func TestScopeExplainFmt(t *testing.T) {
convey.Convey("TestScopeExplainFmt ", t, func() {
c := &model.CouponAllowancePanelInfo{}
c.ScopeExplainFmt("3", 1, 1, map[string]string{"1": "iPhone"})
t.Logf("v(%+v)", c.ScopeExplain)
convey.So(c.ScopeExplain != "", convey.ShouldBeTrue)
})
}
// go test -test.v -test.run TestUsableAllowanceCoupon
func TestUsableAllowanceCoupon(t *testing.T) {
convey.Convey("TestUsableAllowanceCoupon ", t, func() {
var (
err error
_mid = int64(233)
_price = float64(120)
res *model.CouponAllowancePanelInfo
)
res, err = s.UsableAllowanceCoupon(c, _mid, _price, 2, 1, 1)
convey.So(err, convey.ShouldBeNil)
convey.So(res, convey.ShouldNotBeNil)
})
}
// go test -test.v -test.run TestCouponNotify
func TestCouponNotify(t *testing.T) {
convey.Convey("TestCouponNotify ", t, func() {
err := s.CouponNotify(c, _mid, "1807202041103", 1)
convey.So(err, convey.ShouldBeNil)
})
}
//go test -v -run TestReceiveAllowance
func TestReceiveAllowance(t *testing.T) {
convey.Convey("test receive allowance", t, func() {
arg := new(model.ArgReceiveAllowance)
arg.Mid = 210
arg.OrderNo = "1806141156245717948"
arg.Appkey = "6a29f8ed87407c11"
arg.BatchToken = "595017790420180808150514"
couponToken, err := s.ReceiveAllowance(c, arg)
t.Logf("%+v", couponToken)
convey.So(err, convey.ShouldBeNil)
})
}
// go test -test.v -test.run TestUseNotify
func TestUseNotify(t *testing.T) {
convey.Convey("TestUseNotify ", t, func() {
_, err := s.UseNotify(c, &model.ArgAllowanceCheck{Mid: 1, OrderNo: "1"})
convey.So(err, convey.ShouldBeNil)
})
}
// go test -test.v -test.run TestconvertCoupon
func TestConvertCoupon(t *testing.T) {
convey.Convey("TestconvertCoupon ", t, func(convCtx convey.C) {
r := s.convertCoupon(&model.CouponAllowanceInfo{}, []string{"test"}, float64(0), model.AllowanceDisables)
convey.So(r, convey.ShouldNotBeNil)
})
}
// go test -test.v -test.run TestUsableAllowanceCouponV2
func TestUsableAllowanceCouponV2(t *testing.T) {
Convey("TestUsableAllowanceCouponV2 ", t, func() {
res, err := s.UsableAllowanceCouponV2(c, &coupinv1.UsableAllowanceCouponV2Req{
Mid: 1,
PriceInfo: []*coupinv1.ModelPriceInfo{
{
Price: 25,
Plat: 1,
ProdLimMonth: 1,
ProdLimRenewal: 1,
},
},
})
fmt.Println("res", res, res.CouponInfo)
So(err, ShouldBeNil)
res, err = s.UsableAllowanceCouponV2(c, &coupinv1.UsableAllowanceCouponV2Req{
Mid: 1,
PriceInfo: []*coupinv1.ModelPriceInfo{
{
Price: 25,
Plat: 1,
ProdLimMonth: 1,
ProdLimRenewal: 1,
},
{
Price: 148,
Plat: 1,
ProdLimMonth: 12,
ProdLimRenewal: 2,
},
},
})
fmt.Println("res", res, res.CouponInfo)
So(err, ShouldBeNil)
res, err = s.UsableAllowanceCouponV2(c, &coupinv1.UsableAllowanceCouponV2Req{
Mid: 1,
PriceInfo: []*coupinv1.ModelPriceInfo{
{
Price: 148,
Plat: 1,
ProdLimMonth: 12,
ProdLimRenewal: 2,
},
{
Price: 68,
Plat: 1,
ProdLimMonth: 3,
ProdLimRenewal: 2,
},
},
})
fmt.Println("res", res, res.CouponInfo)
So(err, ShouldBeNil)
})
}

View File

@@ -0,0 +1,65 @@
package service
import (
"context"
"go-common/app/service/main/coupon/model"
"go-common/library/database/sql"
"go-common/library/ecode"
"go-common/library/log"
"github.com/pkg/errors"
)
// UpdateBranch update branch info.
func (s *Service) UpdateBranch(c context.Context, tx *sql.Tx, count int, bi *model.CouponBatchInfo) (err error) {
var aff int64
if bi.MaxCount == _maxCount {
if aff, err = s.dao.UpdateBatchInfo(c, tx, bi.BatchToken, count); err != nil {
err = errors.WithStack(err)
return
}
} else {
if aff, err = s.dao.UpdateBatchLimitInfo(c, tx, bi.BatchToken, count); err != nil {
err = errors.WithStack(err)
return
}
}
if aff != 1 {
err = ecode.CouPonGrantMaxCountErr
return
}
if bi.MaxCount != _maxCount {
s.dao.IncreaseBranchCurrentCountCache(c, bi.BatchToken, uint64(count))
}
return
}
// CurrentCount branch current count.
func (s *Service) CurrentCount(c context.Context, token string) (count int, err error) {
var (
mc = true
b *model.CouponBatchInfo
)
if count, err = s.dao.BranchCurrentCountCache(c, token); err != nil {
log.Error("token(%s) err(%+v)", token, err)
err = nil
mc = false
}
if count >= 0 {
return
}
if b, err = s.dao.BatchInfo(c, token); err != nil {
err = errors.WithStack(err)
return
}
if b == nil {
err = ecode.CouPonBatchNotExistErr
return
}
count = int(b.CurrentCount)
if mc {
s.dao.SetBranchCurrentCountCache(c, token, count)
}
return
}

View File

@@ -0,0 +1,144 @@
package service
import (
"context"
"time"
"go-common/app/service/main/coupon/model"
"go-common/library/database/sql"
"go-common/library/ecode"
"github.com/pkg/errors"
)
// CaptchaToken get captcha token.
func (s *Service) CaptchaToken(c context.Context, ip string) (res *model.Token, err error) {
return s.dao.CaptchaToken(c, s.c.Property.CaptchaBID, ip)
}
// UseCouponCode use coupon code.
func (s *Service) UseCouponCode(c context.Context, a *model.ArgUseCouponCode) (res *model.UseCouponCodeResp, err error) {
var (
code *model.CouponCode
bi *model.CouponBatchInfo
count int64
couponToken string
)
if err = s.dao.CaptchaVerify(c, a.Verify, a.Token, a.IP); err != nil {
err = ecode.CouponCodeVerifyFaildErr
return
}
if code, err = s.dao.CouponCode(c, a.Code); err != nil {
return
}
if code == nil {
err = ecode.CouponCodeNotFoundErr
return
}
if code.State == model.CodeStateUsed {
err = ecode.CouponCodeUsedErr
return
}
if code.State == model.CodeStateBlock {
err = ecode.CouponCodeBlockErr
return
}
if bi = s.allBranchInfo[code.BatchToken]; bi == nil {
err = ecode.CouPonBatchNotExistErr
return
}
if bi.State == model.BatchStateBlock {
err = ecode.CouponCodeBlockErr
return
}
if bi.ExpireDay == -1 && bi.ExpireTime < time.Now().Unix() {
err = ecode.CouponBatchExpireTimeErr
return
}
if bi.LimitCount != -1 {
if count, err = s.dao.CountCodeByMid(c, a.Mid, bi.BatchToken); err != nil {
return
}
if bi.LimitCount <= count {
err = ecode.CouponCodeLimitByMidErr
return
}
}
if bi.MaxCount != -1 && bi.MaxCount <= bi.CurrentCount {
err = ecode.CouponCodeMaxLimitByMidErr
return
}
if couponToken, err = s.updateCode(c, code, bi, a.Mid); err != nil {
return
}
res = &model.UseCouponCodeResp{
CouponToken: couponToken,
CouponAmount: bi.Amount,
FullAmount: bi.FullAmount,
ProductLimitMonth: int32(bi.ProdLimMonth),
ProductLimitRenewal: int32(bi.ProdLimRenewal),
PlatfromLimitExplain: model.PlatfromLimitExplain(bi.PlatformLimit, s.c.Platform),
}
return
}
// UpdateCode update code.
func (s *Service) updateCode(c context.Context, code *model.CouponCode, bi *model.CouponBatchInfo, mid int64) (couponToken string, err error) {
var (
tx *sql.Tx
aff int64
)
if tx, err = s.dao.BeginTran(c); err != nil {
err = errors.Wrapf(err, "s.dao.BeginTran(%d)", mid)
return
}
defer func() {
if err != nil {
if err1 := tx.Rollback(); err1 != nil {
err = errors.Wrapf(err, "tx.Rollback(%d)", mid)
}
return
}
if err = tx.Commit(); err != nil {
err = errors.Wrapf(err, "tx.Commit(%d)", mid)
}
s.dao.DelCouponAllowancesKey(c, mid, model.NotUsed)
}()
if err = s.UpdateBranch(c, tx, 1, bi); err != nil {
return
}
info := new(model.CouponAllowanceInfo)
info.BatchToken = bi.BatchToken
info.Mid = mid
info.CouponToken = s.token()
info.State = model.NotUsed
info.FullAmount = bi.FullAmount
info.AppID = bi.AppID
info.Amount = bi.Amount
info.Origin = model.AllowanceCodeOpen
if bi.ExpireDay >= 0 {
now, _ := time.ParseInLocation("2006-01-02", time.Now().Format("2006-01-02"), time.Local)
info.StartTime = time.Now().Unix()
info.ExpireTime = now.AddDate(0, 0, int(bi.ExpireDay+1)).Add(-1 * time.Second).Unix()
} else {
info.StartTime = bi.StartTime
info.ExpireTime = bi.ExpireTime
}
if err = s.dao.TxAddAllowanceCoupon(tx, info); err != nil {
return
}
if aff, err = s.dao.TxUpdateCodeState(tx, &model.CouponCode{
State: model.CodeStateUsed,
Mid: mid,
CouponToken: info.CouponToken,
Code: code.Code,
Ver: code.Ver,
}); err != nil {
return
}
if aff != 1 {
return "", ecode.CouponCodeCanNotUseErr
}
couponToken = info.CouponToken
return
}

View File

@@ -0,0 +1,35 @@
package service
import (
"fmt"
"go-common/app/service/main/coupon/model"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
// go test -test.v -test.run TestAddCartoonCoupon
func TestCaptchaToken(t *testing.T) {
Convey("TestCaptchaToken ", t, func() {
res, err := s.CaptchaToken(c, "")
fmt.Println("token:", res)
So(err, ShouldBeNil)
So(res, ShouldNotBeNil)
})
}
// go test -test.v -test.run TestUseCouponCode
func TestUseCouponCode(t *testing.T) {
Convey("TestUseCouponCode ", t, func() {
coupon, err := s.UseCouponCode(c, &model.ArgUseCouponCode{
Token: "a15e6f81374b4c5bb591ec3a1eba7461",
Code: "sasazxcvfdsa",
Verify: "69vrz",
IP: "",
Mid: 1,
})
fmt.Println("coupon:", coupon)
So(err, ShouldBeNil)
So(coupon, ShouldNotBeNil)
})
}

View File

@@ -0,0 +1,416 @@
package service
import (
"bytes"
"context"
"fmt"
"time"
"go-common/app/service/main/coupon/model"
"go-common/library/database/sql"
"go-common/library/ecode"
"go-common/library/log"
xtime "go-common/library/time"
"github.com/pkg/errors"
)
// UserCoupon user coupon.
func (s *Service) UserCoupon(c context.Context, mid int64, ct int8) (cs []*model.CouponInfo, err error) {
var (
mc = true
now = time.Now().Unix()
)
if mid <= 0 {
return
}
if cs, err = s.dao.CouponsCache(c, mid, ct); err != nil {
log.Error("mid(%d) err(%+v)", mid, err)
err = nil
mc = false
}
// empty cache.
if cs != nil && len(cs) == 0 {
return
}
tmp := []*model.CouponInfo{}
for _, c := range cs {
if c.ExpireTime > now && c.StartTime < now {
tmp = append(tmp, c)
}
}
if len(tmp) > 0 {
cs = tmp
return
}
if cs, err = s.dao.CouponNoStartCheckList(c, mid, model.NotUsed, ct, now); err != nil {
err = errors.WithStack(err)
return
} else if len(cs) == 0 {
cs = _emptyCoupons
}
if mc {
s.dao.SetCouponsCache(c, mid, ct, cs)
}
tmp = []*model.CouponInfo{}
for _, c := range cs {
if c.StartTime < now {
tmp = append(tmp, c)
}
}
cs = tmp
return
}
// UseCoupon use coupon.
func (s *Service) UseCoupon(c context.Context, mid int64, oid int64, remark string, orderNO string, ct int8, useVer int64) (ret int8, token string, err error) {
var (
cp *model.CouponInfo
now = time.Now().Unix()
cs []*model.CouponInfo
lock bool
)
defer func() {
if lock {
s.dao.DelUniqueKey(c, orderNO, ct)
}
}()
if lock = s.dao.AddUseUniqueLock(c, orderNO, ct); !lock {
err = ecode.CouPonUseTooFrequently
return
}
ret = model.UseFaild
if cp, err = s.dao.ByOrderNO(c, mid, orderNO, ct); err != nil {
err = errors.WithStack(err)
return
}
if cp != nil {
if cp.State == model.InUse || cp.State == model.Used {
ret = model.UseSuccess
}
token = cp.CouponToken
return
}
if cs, err = s.dao.CouponList(c, mid, model.NotUsed, ct, now); err != nil {
err = errors.WithStack(err)
return
}
if len(cs) == 0 {
return
}
cp = cs[0]
if err = s.UpdateCoupon(c, cp, oid, remark, orderNO, ct, useVer); err != nil {
err = errors.Wrapf(err, "use coupon error(%d)", mid)
return
}
token = cp.CouponToken
ret = model.UseSuccess
return
}
// UpdateCoupon update coupon info.
func (s *Service) UpdateCoupon(c context.Context, cp *model.CouponInfo, oid int64, remark string, orderNO string, ct int8, useVer int64) (err error) {
var (
tx *sql.Tx
aff int64
)
if tx, err = s.dao.BeginTran(c); err != nil {
log.Error("%+v", err)
return
}
defer func() {
if err != nil {
if err1 := tx.Rollback(); err1 != nil {
log.Error("tx.Rollback %+v", err)
}
return
}
if err = tx.Commit(); err != nil {
log.Error("tx.Commit %+v", err)
}
s.dao.DelCouponsCache(c, cp.Mid, ct)
}()
cp.State = model.InUse
cp.OrderNO = orderNO
cp.Oid = oid
cp.Remark = remark
cp.UseVer = useVer
if aff, err = s.dao.UpdateCouponInUse(c, tx, cp); err != nil {
err = errors.WithStack(err)
return
}
if aff != 1 {
err = fmt.Errorf("use coupon faild")
return
}
l := &model.CouponChangeLog{}
l.CouponToken = cp.CouponToken
l.Mid = cp.Mid
l.State = int8(cp.State)
l.Ctime = xtime.Time(time.Now().Unix())
if aff, err = s.dao.InsertPointHistory(c, tx, l); err != nil {
log.Error("%+v", err)
return
}
if aff != 1 {
err = fmt.Errorf("add change log faild")
return
}
return
}
// CouponInfo coupon info.
func (s *Service) CouponInfo(c context.Context, mid int64, token string) (cp *model.CouponInfo, err error) {
if cp, err = s.dao.CouponInfo(c, mid, token); err != nil {
err = errors.WithStack(err)
return
}
if cp == nil {
err = ecode.NothingFound
return
}
if cp.State == model.NotUsed && cp.ExpireTime < time.Now().Unix() {
cp.State = model.Expire
}
return
}
// CouponPage coupon page.
func (s *Service) CouponPage(c context.Context, mid int64, state int8, pn, ps int) (count int64, res []*model.CouponPageResp, err error) {
var (
t = time.Now().Unix()
cp []*model.CouponInfo
)
stime := time.Now().AddDate(0, -3, 0)
if count, err = s.dao.CountByState(c, mid, state, t, stime); err != nil {
err = errors.WithStack(err)
return
}
if count == 0 {
return
}
if pn == 0 {
pn = _defpn
}
if ps == 0 {
ps = _defps
}
if cp, err = s.dao.CouponPage(c, mid, state, t, (pn-1)*ps, ps, stime); err != nil {
err = errors.WithStack(err)
return
}
if len(cp) == 0 {
return
}
for _, v := range cp {
r := &model.CouponPageResp{}
r.ID = v.ID
switch state {
case model.NotUsed:
r.Title = _deftitle
r.Time = v.ExpireTime
case model.Used:
r.Title = v.Remark
r.Time = v.MTime.Time().Unix()
case model.Expire:
r.Title = _deftitle
r.Time = v.ExpireTime
}
r.RefID = v.Oid
res = append(res, r)
}
return
}
// AddCoupon add coupon.
func (s *Service) AddCoupon(c context.Context, mid int64, startTime int64, expireTime int64, ct int64, origin int64) (err error) {
cp := &model.CouponInfo{}
cp.CouponToken = s.token()
cp.Mid = mid
cp.State = model.NotUsed
cp.StartTime = startTime
cp.ExpireTime = expireTime
cp.Origin = origin
cp.CouponType = ct
cp.CTime = xtime.Time(time.Now().Unix())
if _, err = s.dao.AddCoupon(c, cp); err != nil {
log.Error("%+v", err)
return
}
s.dao.DelCouponsCache(c, mid, int8(ct))
return
}
// get coupon token
func (s *Service) token() string {
var b bytes.Buffer
b.WriteString(fmt.Sprintf("%07d", s.r.Int63n(9999999)))
b.WriteString(fmt.Sprintf("%03d", time.Now().UnixNano()/1e6%1000))
b.WriteString(time.Now().Format("20060102150405"))
return b.String()
}
//ChangeState change state.
func (s *Service) ChangeState(c context.Context, mid int64, userVer int64, ver int64, couponToken string) (err error) {
if _, err = s.dao.UpdateCoupon(c, mid, model.Used, userVer, ver, couponToken); err != nil {
err = errors.WithStack(err)
return
}
return
}
// SalaryCoupon salary coupon.
func (s *Service) SalaryCoupon(c context.Context, a *model.ArgSalaryCoupon) (err error) {
var (
bi *model.CouponBatchInfo
lock bool
htc int
)
defer func() {
if lock {
s.dao.DelGrantKey(c, a.BatchToken, a.Mid)
}
}()
if a.Count <= 0 || a.Count > model.MaxSalaryCount {
err = ecode.RequestErr
return
}
if bi = s.allBranchInfo[a.BatchToken]; bi == nil {
err = ecode.CouPonBatchNotExistErr
return
}
if bi.State == model.BatchStateBlock {
err = ecode.CouponBatchBlockErr
return
}
// max count
if bi.MaxCount != _maxCount {
if htc, err = s.CurrentCount(c, a.BatchToken); err != nil {
err = errors.WithStack(err)
return
}
if int64(htc+a.Count) > bi.MaxCount {
err = ecode.CouPonBatchNotEnoughErr
return
}
}
// limit count
if bi.LimitCount != _maxCount {
if lock = s.dao.AddGrantUniqueLock(c, a.BatchToken, a.Mid); !lock {
err = ecode.CouPonGrantTooFrequently
return
}
}
switch a.CouponType {
case model.CouponVideo:
if err = s.AddVideoCoupon(c, bi, a.Mid, a.CouponType, a.Origin, a.Count); err != nil {
err = errors.WithStack(err)
return
}
case model.CouponCartoon:
if err = s.AddCartoonCoupon(c, bi, a.Mid, a.CouponType, a.Origin, a.Count); err != nil {
err = errors.WithStack(err)
return
}
case model.CouponAllowance:
if err = s.AddAllowanceCoupon(c, bi, a.Mid, a.Count, a.Origin, a.AppID); err != nil {
err = errors.WithStack(err)
return
}
default:
err = ecode.CouPonTypeNotExistErr
}
return
}
// SalaryCouponForThird salary coupon for third.
func (s *Service) SalaryCouponForThird(c context.Context, a *model.ArgSalaryCoupon) (res *model.SalaryCouponForThirdResp, err error) {
var lock bool
if lock = s.dao.AddUniqueNoLock(c, a.UniqueNo); !lock {
err = ecode.VipCouponUniqueNoErr
return
}
if err = s.SalaryCoupon(c, a); err != nil {
return
}
var bi *model.CouponBatchInfo
if bi = s.allBranchInfo[a.BatchToken]; bi == nil {
err = ecode.CouPonBatchNotExistErr
return
}
res = new(model.SalaryCouponForThirdResp)
res.Amount = bi.Amount
res.FullAmount = bi.FullAmount
res.Description = bi.Name
return
}
// AddVideoCoupon add video coupon.
func (s *Service) AddVideoCoupon(c context.Context, bi *model.CouponBatchInfo, mid int64, ct int64, origin int64, count int) (err error) {
var (
tx *sql.Tx
hc int64
)
// limit count
if bi.LimitCount != _maxCount {
// check grant state
if hc, err = s.dao.CountByBranchToken(c, mid, bi.BatchToken); err != nil {
err = errors.WithStack(err)
return
}
if int64(count)+hc > bi.LimitCount {
err = ecode.CouPonBatchLimitErr
return
}
}
if tx, err = s.dao.BeginTran(c); err != nil {
err = errors.Wrapf(err, "s.dao.BeginTran(%d)", mid)
return
}
defer func() {
if err != nil {
if err1 := tx.Rollback(); err1 != nil {
err = errors.Wrapf(err, "tx.Rollback(%d)", mid)
}
return
}
if err = tx.Commit(); err != nil {
err = errors.Wrapf(err, "tx.Commit(%d)", mid)
}
s.dao.DelCouponsCache(c, mid, int8(ct))
}()
if err = s.UpdateBranch(c, tx, count, bi); err != nil {
err = errors.WithStack(err)
return
}
cps := make([]*model.CouponInfo, count)
for i := 0; i < count; i++ {
cp := &model.CouponInfo{}
cp.CouponToken = s.token()
cp.Mid = mid
cp.State = model.NotUsed
cp.StartTime = bi.StartTime
cp.ExpireTime = bi.ExpireTime
cp.Origin = origin
cp.CouponType = ct
cp.CTime = xtime.Time(time.Now().Unix())
cp.BatchToken = bi.BatchToken
cps[i] = cp
}
if _, err = s.dao.BatchAddCoupon(c, tx, mid, cps); err != nil {
err = errors.WithStack(err)
return
}
return
}
// VideoCouponCount video coupon count.
func (s *Service) VideoCouponCount(c context.Context, mid int64, ct int8) (count int, err error) {
var cs []*model.CouponInfo
if cs, err = s.UserCoupon(c, mid, ct); err != nil {
err = errors.WithStack(err)
return
}
count = len(cs)
return
}

View File

@@ -0,0 +1,430 @@
package service
import (
"bytes"
"context"
"fmt"
"time"
"go-common/app/service/main/coupon/model"
"go-common/library/database/sql"
"go-common/library/ecode"
"go-common/library/log"
xtime "go-common/library/time"
"github.com/pkg/errors"
)
// CartoonCoupon user cartoon coupon.
func (s *Service) CartoonCoupon(c context.Context, mid int64, ct int8) (res []*model.CouponBalanceInfo, err error) {
var (
mc = true
now = time.Now().Unix()
)
if mid <= 0 {
return
}
if res, err = s.dao.CouponBlanceCache(c, mid, ct); err != nil {
log.Error("mid(%d) err(%+v)", mid, err)
err = nil
mc = false
}
// empty cache.
if res != nil && len(res) == 0 {
return
}
tmp := []*model.CouponBalanceInfo{}
for _, c := range res {
if c.ExpireTime > now && c.StartTime < now {
tmp = append(tmp, c)
}
}
if len(tmp) > 0 {
res = tmp
return
}
if res, err = s.dao.BlanceNoStartCheckList(c, mid, ct, now); err != nil {
err = errors.WithStack(err)
return
} else if len(res) == 0 {
res = _emptyBlance
}
if mc {
s.dao.SetCouponBlanceCache(c, mid, ct, res)
}
tmp = []*model.CouponBalanceInfo{}
for _, c := range res {
if c.StartTime < now {
tmp = append(tmp, c)
}
}
res = tmp
return
}
// CartoonUse cartoon coupon use.
func (s *Service) CartoonUse(c context.Context, mid int64, thirdTradeNo string, ct int8, useVer int64, remark string, tips string,
count int64) (ret int8, token string, err error) {
var (
o *model.CouponOrder
now = time.Now().Unix()
blance int64
cs []*model.CouponBalanceInfo
lock bool
)
defer func() {
if lock {
s.dao.DelUniqueKey(c, thirdTradeNo, ct)
}
}()
if lock = s.dao.AddUseUniqueLock(c, thirdTradeNo, ct); !lock {
err = ecode.CouPonUseTooFrequently
return
}
ret = model.UseFaild
if o, err = s.dao.ByThirdTradeNo(c, thirdTradeNo, ct); err != nil {
err = errors.WithStack(err)
return
}
if o != nil {
if o.State == model.InPay || o.State == model.PaySuccess {
ret = model.UseSuccess
}
token = o.OrderNo
return
}
if cs, err = s.dao.CouponBlances(c, mid, ct, now); err != nil {
err = errors.WithStack(err)
return
}
if len(cs) == 0 {
return
}
// check blance
for _, v := range cs {
blance += v.Balance
}
if blance < count {
err = ecode.CouPonNotEnoughErr
return
}
var orderNo string
if orderNo, err = s.ConsumeCoupon(c, mid, ct, cs, count, thirdTradeNo, remark, tips, useVer); err != nil {
err = errors.WithStack(err)
return
}
token = orderNo
ret = model.UseSuccess
return
}
// ConsumeCoupon consume coupon.
func (s *Service) ConsumeCoupon(c context.Context, mid int64, ct int8, cs []*model.CouponBalanceInfo, count int64, thirdTradeNo string,
remark string, tips string, useVer int64) (orderNo string, err error) {
var (
tx *sql.Tx
aff int64
o *model.CouponOrder
ol *model.CouponOrderLog
now = time.Now()
)
orderNo = s.orderID()
if tx, err = s.dao.BeginTran(c); err != nil {
err = errors.Wrapf(err, "s.dao.BeginTran(%d)", mid)
return
}
defer func() {
if err != nil {
if err1 := tx.Rollback(); err1 != nil {
err = errors.Wrapf(err, "tx.Rollback(%d)", mid)
}
return
}
if err = tx.Commit(); err != nil {
err = errors.Wrapf(err, "tx.Commit(%d)", mid)
}
s.dao.DelCouponBalancesCache(c, mid, ct)
}()
if err = s.UpdateBalance(c, tx, mid, count, cs, orderNo, ct); err != nil {
err = errors.WithStack(err)
return
}
// add order
o = new(model.CouponOrder)
o.OrderNo = orderNo
o.Mid = mid
o.Count = count
o.State = model.InPay
o.CouponType = ct
o.ThirdTradeNo = thirdTradeNo
o.Remark = remark
o.Tips = tips
o.UseVer = useVer
o.Ver = 1
o.Ctime = xtime.Time(now.Unix())
if aff, err = s.dao.AddOrder(c, tx, o); err != nil {
err = errors.WithStack(err)
return
}
if aff != 1 {
err = ecode.CouPonConsumeFaildErr
return
}
// add order log.
ol = new(model.CouponOrderLog)
ol.OrderNo = orderNo
ol.Mid = mid
ol.State = model.InPay
ol.Ctime = xtime.Time(now.Unix())
if _, err = s.dao.AddOrderLog(c, tx, ol); err != nil {
err = errors.WithStack(err)
return
}
return
}
// UpdateBalance update user balance.
func (s *Service) UpdateBalance(c context.Context, tx *sql.Tx, mid int64, count int64, cs []*model.CouponBalanceInfo, orderNo string, ct int8) (err error) {
var (
now = time.Now()
usebs []*model.CouponBalanceInfo
blogs []*model.CouponBalanceChangeLog
aff int64
)
for _, v := range cs {
if v.Balance <= 0 {
continue
}
b := new(model.CouponBalanceInfo)
b.ID = v.ID
b.Ver = v.Ver
blog := new(model.CouponBalanceChangeLog)
blog.OrderNo = orderNo
blog.Mid = mid
blog.BatchToken = v.BatchToken
blog.ChangeType = model.Consume
blog.Ctime = xtime.Time(now.Unix())
if v.Balance >= count {
b.Balance = v.Balance - count
usebs = append(usebs, b)
blog.Balance = b.Balance
blog.ChangeBalance = -count
blogs = append(blogs, blog)
break
}
count = count - v.Balance
b.Balance = 0
usebs = append(usebs, b)
blog.Balance = b.Balance
blog.ChangeBalance = -v.Balance
blogs = append(blogs, blog)
}
if len(usebs) == 1 {
b := usebs[0]
if aff, err = s.dao.UpdateBlance(c, tx, b.ID, mid, b.Ver, b.Balance); err != nil {
err = errors.WithStack(err)
return
}
} else {
if aff, err = s.dao.BatchUpdateBlance(c, tx, mid, usebs); err != nil {
err = errors.WithStack(err)
return
}
}
if int(aff) != len(usebs) {
err = ecode.CouPonConsumeFaildErr
return
}
if _, err = s.dao.BatchInsertBlanceLog(c, tx, mid, blogs); err != nil {
err = errors.WithStack(err)
return
}
return
}
// CouponCartoonPage coupon cartoon page.
func (s *Service) CouponCartoonPage(c context.Context, mid int64, state int8, pn, ps int) (data *model.CouponCartoonPageResp, err error) {
var (
t = time.Now().Unix()
bs []*model.CouponBalanceInfo
os []*model.CouponOrder
res []*model.CouponPageResp
stime = time.Now().AddDate(0, -3, 0)
couponCount int64
count int64
)
data = new(model.CouponCartoonPageResp)
if count, err = s.dao.CouponCarToonCount(c, mid, t, model.CouponCartoon, state, stime); err != nil {
err = errors.WithStack(err)
return
}
if count <= 0 {
return
}
if ps == 0 {
ps = _defps
}
if pn == 0 {
pn = _defpn
}
switch state {
case model.NotUsed:
bs, err = s.dao.CouponNotUsedPage(c, mid, model.CouponCartoon, t, stime, pn, ps)
res, couponCount = s.convertByBalance(bs, state)
case model.Used:
os, err = s.dao.OrderUsedPage(c, mid, model.PaySuccess, model.CouponCartoon, stime, pn, ps)
res, couponCount = s.convertByOrder(os)
case model.Expire:
bs, err = s.dao.CouponExpirePage(c, mid, model.CouponCartoon, t, stime, pn, ps)
res, couponCount = s.convertByBalance(bs, state)
default:
return
}
if err != nil {
err = errors.WithStack(err)
return
}
data.Count = count
data.CouponCount = couponCount
data.List = res
return
}
func (s *Service) convertByBalance(bs []*model.CouponBalanceInfo, state int8) (res []*model.CouponPageResp, couponCount int64) {
for _, v := range bs {
r := new(model.CouponPageResp)
r.ID = v.ID
switch state {
case model.NotUsed:
r.Title = _defCartoonTitle
r.Time = v.ExpireTime
r.Count = v.Balance
case model.Expire:
r.Title = _defCartoonTitle
r.Time = v.ExpireTime
r.Count = v.Balance
}
couponCount += v.Balance
res = append(res, r)
}
return
}
func (s *Service) convertByOrder(os []*model.CouponOrder) (res []*model.CouponPageResp, couponCount int64) {
for _, v := range os {
r := new(model.CouponPageResp)
r.ID = v.ID
r.Title = v.Remark
r.Tips = v.Tips
r.Time = v.Mtime.Time().Unix()
r.Count = v.Count
couponCount += v.Count
res = append(res, r)
}
return
}
// AddCartoonCoupon add cartoon coupon.
func (s *Service) AddCartoonCoupon(c context.Context, bi *model.CouponBatchInfo, mid int64, ct int64, origin int64, count int) (err error) {
var (
tx *sql.Tx
oldb *model.CouponBalanceInfo
logs []*model.CouponBalanceChangeLog
hc int64
)
// limit count
if bi.LimitCount != _maxCount {
// check grant state
if logs, err = s.dao.GrantCouponLog(c, mid, bi.BatchToken, model.VipSalary); err != nil {
err = errors.WithStack(err)
return
}
for _, v := range logs {
hc += v.ChangeBalance
}
if int64(count)+hc > bi.LimitCount {
err = ecode.CouPonBatchLimitErr
return
}
}
if oldb, err = s.dao.ByMidAndBatchToken(c, mid, bi.BatchToken); err != nil {
err = errors.WithStack(err)
return
}
if tx, err = s.dao.BeginTran(c); err != nil {
err = errors.Wrapf(err, "s.dao.BeginTran(%d)", mid)
return
}
defer func() {
if err != nil {
if err1 := tx.Rollback(); err1 != nil {
err = errors.Wrapf(err, "tx.Rollback(%d)", mid)
}
return
}
if err = tx.Commit(); err != nil {
err = errors.Wrapf(err, "tx.Commit(%d)", mid)
}
s.dao.DelCouponBalancesCache(c, mid, int8(ct))
}()
if err = s.UpdateBranch(c, tx, count, bi); err != nil {
err = errors.WithStack(err)
return
}
bc := new(model.CouponBalanceInfo)
bc.BatchToken = bi.BatchToken
bc.Mid = mid
bc.Balance = int64(count)
bc.StartTime = bi.StartTime
bc.ExpireTime = bi.ExpireTime
bc.Origin = origin
bc.CouponType = ct
bc.Ver = 1
bc.CTime = xtime.Time(time.Now().Unix())
if _, err = s.dao.AddBalanceCoupon(c, tx, bc); err != nil {
err = errors.WithStack(err)
return
}
blog := new(model.CouponBalanceChangeLog)
blog.Mid = mid
blog.BatchToken = bi.BatchToken
if oldb == nil {
blog.Balance = int64(count)
} else {
blog.Balance = oldb.Balance + int64(count)
}
blog.ChangeBalance = int64(count)
blog.ChangeType = model.VipSalary
blog.Ctime = xtime.Time(time.Now().Unix())
if _, err = s.dao.AddBalanceChangeLog(c, tx, blog); err != nil {
err = errors.WithStack(err)
return
}
return
}
// orderID get order id.
func (s *Service) orderID() string {
var b bytes.Buffer
b.WriteString(fmt.Sprintf("%010d", s.r.Int63n(9999999999)))
b.WriteString(time.Now().Format("150405"))
b.WriteString(fmt.Sprintf("%03d", time.Now().UnixNano()/1e6%1000))
return b.String()
}
// CarToonCouponCount cartoon coupon count.
func (s *Service) CarToonCouponCount(c context.Context, mid int64, ct int8) (count int, err error) {
var res []*model.CouponBalanceInfo
if res, err = s.CartoonCoupon(c, mid, ct); err != nil {
err = errors.WithStack(err)
return
}
for _, v := range res {
count += int(v.Balance)
}
return
}

View File

@@ -0,0 +1,239 @@
package service
import (
"context"
"flag"
"fmt"
"testing"
"time"
"go-common/app/service/main/coupon/conf"
"go-common/app/service/main/coupon/model"
"go-common/library/database/sql"
. "github.com/smartystreets/goconvey/convey"
)
var (
_mid int64 = 1
c = context.TODO()
s *Service
)
func init() {
var (
err error
)
flag.Set("conf", "../cmd/coupon-service.toml")
if err = conf.Init(); err != nil {
panic(err)
}
c = context.Background()
if s == nil {
s = New(conf.Conf)
}
time.Sleep(time.Second)
}
// go test -test.v -test.run TestUserCoupon
func TestUserCoupon(t *testing.T) {
Convey("TestUserCoupon ", t, func() {
var (
startTime = time.Now().Unix()
expireTime = time.Now().Unix() + int64(1000000)
err error
)
err = s.AddCoupon(c, _mid, startTime, expireTime, int64(1), int64(1))
So(err, ShouldBeNil)
err = s.dao.DelCouponsCache(c, _mid, int8(1))
So(err, ShouldBeNil)
cs, err := s.UserCoupon(c, _mid, int8(1))
t.Logf("cs(%v)", len(cs))
So(err, ShouldBeNil)
ret, couponToken, err := s.UseCoupon(c, _mid, int64(1), "test use", fmt.Sprintf("%d", time.Now().Unix()), int8(1), int64(1))
t.Logf("use couponToken(%s)(%v)", couponToken, err)
So(ret == model.UseSuccess, ShouldBeTrue)
So(err, ShouldBeNil)
})
}
// go test -test.v -test.run TestCouponPage
func TestCouponPage(t *testing.T) {
Convey("TestCouponPage ", t, func() {
var (
err error
)
count, cs, err := s.CouponPage(c, _mid, model.NotUsed, 1, 10)
t.Logf("count(%d)", count)
for _, v := range cs {
t.Logf("v(%v)", v)
}
So(err, ShouldBeNil)
})
}
// go test -test.v -test.run TestAddCartoonCoupon
func TestAddCartoonCoupon(t *testing.T) {
Convey("TestAddCartoonCoupon ", t, func() {
var (
err error
bi *model.CouponBatchInfo
batchToken = "test1"
mid int64 = 1
ct int64 = 2 // cartoon
origin int64 = 1
count = 6
)
bi, err = s.dao.BatchInfo(c, batchToken)
So(err, ShouldBeNil)
So(bi, ShouldNotBeNil)
err = s.AddCartoonCoupon(c, bi, mid, ct, origin, count)
So(err, ShouldBeNil)
})
}
// go test -test.v -test.run TestSalaryCoupon
func TestSalaryCoupon(t *testing.T) {
Convey("TestSalaryCoupon ", t, func() {
var (
err error
batchToken = "test02"
mid int64 = 1
ct int64 = 2 // cartoon
origin int64 = 1
count = 6
)
err = s.SalaryCoupon(c, &model.ArgSalaryCoupon{
Mid: mid,
CouponType: ct,
Origin: origin,
Count: count,
BatchToken: batchToken,
AppID: 0,
})
So(err, ShouldBeNil)
})
}
// go test -test.v -test.run TestCarToonCouponCount
func TestCarToonCouponCount(t *testing.T) {
Convey("TestCarToonCouponCount ", t, func() {
var (
err error
mid int64 = 1
ct int8 = 2
count int
_novalmid int64 = 9999999
)
count, err = s.CarToonCouponCount(c, mid, ct)
t.Logf("count(%d)", count)
So(err, ShouldBeNil)
count, err = s.CarToonCouponCount(c, _novalmid, ct)
t.Logf("count(%d)", count)
So(err, ShouldBeNil)
})
}
// go test -test.v -test.run TestUpdateBalance
func TestUpdateBalance(t *testing.T) {
Convey("TestUpdateBalance ", t, func() {
var (
err error
mid int64 = 1
ct int8 = 2
count int64 = 2
tx *sql.Tx
cs []*model.CouponBalanceInfo
orderNo = "test001"
)
tx, err = s.dao.BeginTran(c)
So(err, ShouldBeNil)
cs, err = s.dao.CouponBlances(c, mid, ct, time.Now().Unix())
So(err, ShouldBeNil)
t.Logf("cs(%d)", len(cs))
err = s.UpdateBalance(c, tx, mid, count, cs, orderNo, ct)
So(err, ShouldBeNil)
err = tx.Commit()
So(err, ShouldBeNil)
})
}
// go test -test.v -test.run TestConsumeCoupon
func TestConsumeCoupon(t *testing.T) {
Convey("TestConsumeCoupon ", t, func() {
var (
err error
mid int64 = 1
ct int8 = 2
count int64 = 2
cs []*model.CouponBalanceInfo
orderNo = "test002"
remake = "我是传奇2"
tips = "共2话"
ver int64 = 1
token string
)
cs, err = s.dao.CouponBlances(c, mid, ct, time.Now().Unix())
So(err, ShouldBeNil)
t.Logf("cs(%d)", len(cs))
token, err = s.ConsumeCoupon(c, mid, ct, cs, count, orderNo, remake, tips, ver)
So(err, ShouldBeNil)
t.Logf("token(%s)", token)
})
}
// go test -test.v -test.run TestCartoonUse
func TestCartoonUse(t *testing.T) {
Convey("TestCartoonUse ", t, func() {
var (
err error
mid int64 = 1
ct int8 = 2
count int64 = 3
orderNo = "test0059"
remake = "我是传奇5"
tips = "共2话"
ver int64 = 1
token string
ret int8
)
ret, token, err = s.CartoonUse(c, mid, orderNo, ct, ver, remake, tips, count)
t.Logf("token(%s)", token)
t.Logf("ret(%d)", ret)
So(err, ShouldBeNil)
})
}
// go test -test.v -test.run TestCouponCartoonPage
func TestCouponCartoonPage(t *testing.T) {
Convey("TestCouponCartoonPage ", t, func() {
var (
err error
data *model.CouponCartoonPageResp
)
data, err = s.CouponCartoonPage(c, _mid, model.NotUsed, 1, 10)
if data != nil {
for _, v := range data.List {
t.Logf("v(%v)", v)
}
}
t.Logf("data(%v)", data)
So(err, ShouldBeNil)
data, err = s.CouponCartoonPage(c, _mid, model.Used, 1, 10)
if data != nil {
for _, v := range data.List {
t.Logf("v(%v)", v)
}
}
t.Logf("data(%v)", data)
So(err, ShouldBeNil)
data, err = s.CouponCartoonPage(c, _mid, model.Expire, 1, 10)
if data != nil {
for _, v := range data.List {
t.Logf("v(%v)", v)
}
}
t.Logf("data(%v)", data)
So(err, ShouldBeNil)
})
}

View File

@@ -0,0 +1,143 @@
package service
import (
"context"
"math/rand"
"time"
"github.com/pkg/errors"
"go-common/app/service/main/coupon/conf"
"go-common/app/service/main/coupon/dao"
"go-common/app/service/main/coupon/model"
v1 "go-common/app/service/main/vipinfo/api"
"go-common/library/log"
"go-common/library/sync/pipeline/fanout"
)
var (
_emptyCoupons = make([]*model.CouponInfo, 0)
_emptyBlance = make([]*model.CouponBalanceInfo, 0)
_emptyAllowance = make([]*model.CouponAllowanceInfo, 0)
_defps = 20
_defpn = 1
_deftitle = "观影劵"
_defCartoonTitle = "漫画体验券"
_maxCount int64 = -1
)
// Service struct
type Service struct {
c *conf.Config
dao *dao.Dao
r *rand.Rand
messageChan chan func()
cache *fanout.Fanout
allBranchInfo map[string]*model.CouponBatchInfo
vipinfoClient v1.VipInfoClient //vipinfo grpc client
MapNoVipBatchToken map[int8]string
MapMonthBatchToken map[int8]string
MapMore180BatchToken map[int8]string
MapLess180BatchToken map[int8]string
}
// New init
func New(c *conf.Config) (s *Service) {
s = &Service{
c: c,
dao: dao.New(c),
r: rand.New(rand.NewSource(time.Now().Unix())),
allBranchInfo: make(map[string]*model.CouponBatchInfo),
messageChan: make(chan func(), 10240),
// cache chan
cache: fanout.New("cache", fanout.Buffer(10240)),
MapNoVipBatchToken: map[int8]string{
model.CardType1: c.NewYearConf.NoVipBatchToken1,
model.CardType3: c.NewYearConf.NoVipBatchToken3,
model.CardType12: c.NewYearConf.NoVipBatchToken12,
},
MapMonthBatchToken: map[int8]string{
model.CardType1: c.NewYearConf.MonthBatchToken1,
model.CardType3: c.NewYearConf.MonthBatchToken3,
model.CardType12: c.NewYearConf.MonthBatchToken12,
},
MapMore180BatchToken: map[int8]string{
model.CardType1: c.NewYearConf.More180BatchToken1,
model.CardType3: c.NewYearConf.More180BatchToken3,
model.CardType12: c.NewYearConf.More180BatchToken12,
},
MapLess180BatchToken: map[int8]string{
model.CardType1: c.NewYearConf.Less180BatchToken1,
model.CardType3: c.NewYearConf.Less180BatchToken3,
model.CardType12: c.NewYearConf.Less180BatchToken12,
},
}
var err error
if s.vipinfoClient, err = v1.NewClient(c.VipinfoRPC); err != nil {
panic(errors.Wrap(err, "v1.NewClient failed"))
}
if err := s.loadbatchinfo(); err != nil {
panic(err)
}
go s.loadbatchinfoproc()
go s.handlermessageproc()
return s
}
// Ping Service
func (s *Service) Ping(c context.Context) (err error) {
return s.dao.Ping(c)
}
// Close Service
func (s *Service) Close() {
s.dao.Close()
s.cache.Close()
}
func (s *Service) loadbatchinfo() (err error) {
var (
c = context.Background()
bs []*model.CouponBatchInfo
)
if bs, err = s.dao.AllBranchInfo(c); err != nil {
log.Error("loadbatchinfo allevent error(%v)", err)
return
}
tmp := make(map[string]*model.CouponBatchInfo, len(bs))
for _, v := range bs {
tmp[v.BatchToken] = v
}
s.allBranchInfo = tmp
log.Info("loadbatchinfo (%v) load success", tmp)
return
}
func (s *Service) loadbatchinfoproc() {
defer func() {
if x := recover(); x != nil {
log.Error("service.loadbatchinfoproc panic(%v)", x)
go s.loadbatchinfoproc()
log.Info("service.loadbatchinfoproc recover")
}
}()
for {
time.Sleep(time.Minute * 1)
s.loadbatchinfo()
}
}
func (s *Service) sendMessage(f func()) {
select {
case s.messageChan <- f:
default:
log.Warn("message chan full")
}
}
func (s *Service) handlermessageproc() {
for {
f := <-s.messageChan
f()
}
}