Initial commit

This commit is contained in:
Donny
2019-04-22 20:46:32 +08:00
commit 49ab8aadd1
25441 changed files with 4055000 additions and 0 deletions

View File

@@ -0,0 +1,98 @@
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = [
"account_test.go",
"dao_test.go",
"distrib_test.go",
"item_test.go",
"order_detail_test.go",
"order_log_test.go",
"order_test.go",
"promotion_group_test.go",
"promotion_order_test.go",
"promotion_test.go",
"stock_test.go",
"ticket_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/service/openplatform/ticket-sales/api/grpc/type:go_default_library",
"//app/service/openplatform/ticket-sales/api/grpc/v1:go_default_library",
"//app/service/openplatform/ticket-sales/conf:go_default_library",
"//app/service/openplatform/ticket-sales/model:go_default_library",
"//app/service/openplatform/ticket-sales/model/consts:go_default_library",
"//library/conf/paladin:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"account.go",
"dao.cache.go",
"dao.go",
"distrib.go",
"item.go",
"order.go",
"order_detail.go",
"order_log.go",
"promotion.go",
"promotion_group.go",
"promotion_order.go",
"redis.go",
"stock.go",
"ticket.go",
],
importpath = "go-common/app/service/openplatform/ticket-sales/dao",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/common/openplatform/encoding:go_default_library",
"//app/service/main/account/api:go_default_library",
"//app/service/openplatform/ticket-item/api/grpc/v1:go_default_library",
"//app/service/openplatform/ticket-sales/api/grpc/type:go_default_library",
"//app/service/openplatform/ticket-sales/api/grpc/v1:go_default_library",
"//app/service/openplatform/ticket-sales/conf:go_default_library",
"//app/service/openplatform/ticket-sales/model:go_default_library",
"//app/service/openplatform/ticket-sales/model/consts:go_default_library",
"//library/cache:go_default_library",
"//library/cache/redis:go_default_library",
"//library/database/sql:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/naming/discovery:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/net/metadata:go_default_library",
"//library/net/rpc/warden:go_default_library",
"//library/net/rpc/warden/resolver:go_default_library",
"//library/queue/databus:go_default_library",
"//library/stat/prom:go_default_library",
"//library/time:go_default_library",
"//library/xstr:go_default_library",
"//vendor/github.com/pkg/errors:go_default_library",
"@com_github_gogo_protobuf//types: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,17 @@
package dao
import (
"context"
acc "go-common/app/service/main/account/api"
"go-common/library/net/metadata"
)
//GetUserCards 获取用户卡片信息
func (d *Dao) GetUserCards(ctx context.Context, mids []int64) (*acc.CardsReply, error) {
req := &acc.MidsReq{
Mids: mids,
RealIp: metadata.String(ctx, metadata.RemoteIP),
}
return d.accClient.Cards3(ctx, req)
}

View File

@@ -0,0 +1,16 @@
package dao
import (
"context"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestGetUserCards(t *testing.T) {
convey.Convey("GetUserCards", t, func() {
cards, _ := d.GetUserCards(context.TODO(), []int64{27515405, 27515305})
convey.So(len(cards.Cards), convey.ShouldEqual, 2)
convey.So(cards.Cards[27515305].Name, convey.ShouldEqual, "Test000044")
})
}

View File

@@ -0,0 +1,738 @@
// Code generated by $GOPATH/src/go-common/app/tool/cache/gen. DO NOT EDIT.
/*
Package dao is a generated cache proxy package.
It is generated from:
type _cache interface {
// cache: -nullcache=&model.Promotion{PromoID:-1} -check_null_code=$!=nil&&$.PromoID==-1
Promo(c context.Context, promoID int64) (*model.Promotion, error)
// cache: -nullcache=&model.PromotionGroup{GroupID:-1} -check_null_code=$!=nil&&$.GroupID==-1
PromoGroup(c context.Context, groupID int64) (*model.PromotionGroup, error)
// cache: -nullcache=&model.PromotionOrder{OrderID:-1} -check_null_code=$!=nil&&$.OrderID==-1
PromoOrder(c context.Context, orderID int64) (*model.PromotionOrder, error)
// cache: -nullcache=[]*model.PromotionOrder{{GroupID:-1}} -check_null_code=len($)==1&&$[0].GroupID==-1
PromoOrders(c context.Context, groupID int64) ([]*model.PromotionOrder, error)
// cache: -nullcache=[]*model.OrderMain{{OrderID:-1}} -check_null_code=len($)==1&&$[0].OrderID==-1
Orders(context.Context, *model.OrderMainQuerier) ([]*model.OrderMain, error)
// cache: -nullcache=-1 -check_null_code=$==-1
OrderCount(context.Context, *model.OrderMainQuerier) (int64, error)
// cache: -nullcache=&model.OrderDetail{OrderID:0} -check_null_code=$!=nil&&$.OrderID==0
OrderDetails(context.Context, []int64) (map[int64]*model.OrderDetail, error)
// cache: -nullcache=[]*model.OrderSKU{{OrderID:-1}} -check_null_code=len($)==1&&$[0].OrderID==-1
OrderSKUs(context.Context, []int64) (map[int64][]*model.OrderSKU, error)
// cache: -nullcache=&model.OrderPayCharge{ChargeID:""} -check_null_code=$!=nil&&$.ChargeID==""
OrderPayCharges(context.Context, []int64) (map[int64]*model.OrderPayCharge, error)
// cache:
SkuByItemID(c context.Context, itemID int64) (map[string]*model.SKUStock, error)
// cache:
GetSKUs(c context.Context, skuIds []int64, withNewStock bool) (map[int64]*model.SKUStock, error)
// cache:
Stocks(c context.Context, keys []int64, isLocked bool) (res map[int64]int64, err error)
// cache: -nullcache=[]*model.Ticket{{ID:-1}} -check_null_code=len($)==1&&$[0].ID==-1
TicketsByOrderID(c context.Context, orderID int64) (res []*model.Ticket, err error)
// cache: -nullcache=[]*model.Ticket{{ID:-1}} -check_null_code=len($)==1&&$[0].ID==-1
TicketsByScreen(c context.Context, screenID int64, UID int64) (res []*model.Ticket, err error)
// cache: -nullcache=&model.Ticket{ID:-1} -check_null_code=$!=nil&&$.ID==-1
TicketsByID(c context.Context, id []int64) (res map[int64]*model.Ticket, err error)
// cache: -nullcache=&model.TicketSend{ID:-1} -check_null_code=$!=nil&&$.ID==-1
TicketSend(c context.Context, SendTID []int64, TIDType string) (res map[int64]*model.TicketSend, err error)
}
*/
package dao
import (
"context"
"go-common/app/service/openplatform/ticket-sales/model"
"go-common/library/net/metadata"
"go-common/library/stat/prom"
)
var _ _cache
// Promo get data from cache if miss will call source method, then add to cache.
func (d *Dao) Promo(c context.Context, id int64) (res *model.Promotion, err error) {
addCache := true
res, err = d.CachePromo(c, id)
if err != nil {
addCache = false
err = nil
}
defer func() {
if res != nil && res.PromoID == -1 {
res = nil
}
}()
if res != nil {
prom.CacheHit.Incr("Promo")
return
}
prom.CacheMiss.Incr("Promo")
res, err = d.RawPromo(c, id)
if err != nil {
return
}
miss := res
if miss == nil {
miss = &model.Promotion{PromoID: -1}
}
if !addCache {
return
}
d.cache.Save(func() {
d.AddCachePromo(metadata.WithContext(c), id, miss)
})
return
}
// PromoGroup get data from cache if miss will call source method, then add to cache.
func (d *Dao) PromoGroup(c context.Context, id int64) (res *model.PromotionGroup, err error) {
addCache := true
res, err = d.CachePromoGroup(c, id)
if err != nil {
addCache = false
err = nil
}
defer func() {
if res != nil && res.GroupID == -1 {
res = nil
}
}()
if res != nil {
prom.CacheHit.Incr("PromoGroup")
return
}
prom.CacheMiss.Incr("PromoGroup")
res, err = d.RawPromoGroup(c, id)
if err != nil {
return
}
miss := res
if miss == nil {
miss = &model.PromotionGroup{GroupID: -1}
}
if !addCache {
return
}
d.cache.Save(func() {
d.AddCachePromoGroup(metadata.WithContext(c), id, miss)
})
return
}
// PromoOrder get data from cache if miss will call source method, then add to cache.
func (d *Dao) PromoOrder(c context.Context, id int64) (res *model.PromotionOrder, err error) {
addCache := true
res, err = d.CachePromoOrder(c, id)
if err != nil {
addCache = false
err = nil
}
defer func() {
if res != nil && res.OrderID == -1 {
res = nil
}
}()
if res != nil {
prom.CacheHit.Incr("PromoOrder")
return
}
prom.CacheMiss.Incr("PromoOrder")
res, err = d.RawPromoOrder(c, id)
if err != nil {
return
}
miss := res
if miss == nil {
miss = &model.PromotionOrder{OrderID: -1}
}
if !addCache {
return
}
d.cache.Save(func() {
d.AddCachePromoOrder(metadata.WithContext(c), id, miss)
})
return
}
// PromoOrders get data from cache if miss will call source method, then add to cache.
func (d *Dao) PromoOrders(c context.Context, id int64) (res []*model.PromotionOrder, err error) {
addCache := true
res, err = d.CachePromoOrders(c, id)
if err != nil {
addCache = false
err = nil
}
defer func() {
if len(res) == 1 && res[0].GroupID == -1 {
res = nil
}
}()
if len(res) != 0 {
prom.CacheHit.Incr("PromoOrders")
return
}
prom.CacheMiss.Incr("PromoOrders")
res, err = d.RawPromoOrders(c, id)
if err != nil {
return
}
miss := res
if len(miss) == 0 {
miss = []*model.PromotionOrder{{GroupID: -1}}
}
if !addCache {
return
}
d.cache.Save(func() {
d.AddCachePromoOrders(metadata.WithContext(c), id, miss)
})
return
}
// Orders get data from cache if miss will call source method, then add to cache.
func (d *Dao) Orders(c context.Context, id *model.OrderMainQuerier) (res []*model.OrderMain, err error) {
addCache := true
res, err = d.CacheOrders(c, id)
if err != nil {
addCache = false
err = nil
}
defer func() {
if len(res) == 1 && res[0].OrderID == -1 {
res = nil
}
}()
if len(res) != 0 {
prom.CacheHit.Incr("Orders")
return
}
prom.CacheMiss.Incr("Orders")
res, err = d.RawOrders(c, id)
if err != nil {
return
}
miss := res
if len(miss) == 0 {
miss = []*model.OrderMain{{OrderID: -1}}
}
if !addCache {
return
}
d.cache.Save(func() {
d.AddCacheOrders(metadata.WithContext(c), id, miss)
})
return
}
// OrderCount get data from cache if miss will call source method, then add to cache.
func (d *Dao) OrderCount(c context.Context, id *model.OrderMainQuerier) (res int64, err error) {
addCache := true
res, err = d.CacheOrderCount(c, id)
if err != nil {
addCache = false
err = nil
}
defer func() {
if res == -1 {
res = 0
}
}()
if res != 0 {
prom.CacheHit.Incr("OrderCount")
return
}
prom.CacheMiss.Incr("OrderCount")
res, err = d.RawOrderCount(c, id)
if err != nil {
return
}
miss := res
if miss == 0 {
miss = -1
}
if !addCache {
return
}
d.cache.Save(func() {
d.AddCacheOrderCount(metadata.WithContext(c), id, miss)
})
return
}
// OrderDetails get data from cache if miss will call source method, then add to cache.
func (d *Dao) OrderDetails(c context.Context, keys []int64) (res map[int64]*model.OrderDetail, err error) {
if len(keys) == 0 {
return
}
addCache := true
res, err = d.CacheOrderDetails(c, keys)
if err != nil {
addCache = false
res = nil
err = nil
}
var miss []int64
for _, key := range keys {
if (res == nil) || (res[key] == nil) {
miss = append(miss, key)
}
}
prom.CacheHit.Add("OrderDetails", int64(len(keys)-len(miss)))
defer func() {
for k, v := range res {
if v != nil && v.OrderID == 0 {
delete(res, k)
}
}
}()
if len(miss) == 0 {
return
}
var missData map[int64]*model.OrderDetail
prom.CacheMiss.Add("OrderDetails", int64(len(miss)))
missData, err = d.RawOrderDetails(c, miss)
if res == nil {
res = make(map[int64]*model.OrderDetail)
}
for k, v := range missData {
res[k] = v
}
if err != nil {
return
}
for _, key := range keys {
if res[key] == nil {
if missData == nil {
missData = make(map[int64]*model.OrderDetail, len(keys))
}
missData[key] = &model.OrderDetail{OrderID: 0}
}
}
if !addCache {
return
}
d.cache.Save(func() {
d.AddCacheOrderDetails(metadata.WithContext(c), missData)
})
return
}
// OrderSKUs get data from cache if miss will call source method, then add to cache.
func (d *Dao) OrderSKUs(c context.Context, keys []int64) (res map[int64][]*model.OrderSKU, err error) {
if len(keys) == 0 {
return
}
addCache := true
res, err = d.CacheOrderSKUs(c, keys)
if err != nil {
addCache = false
res = nil
err = nil
}
var miss []int64
for _, key := range keys {
if (res == nil) || (len(res[key]) == 0) {
miss = append(miss, key)
}
}
prom.CacheHit.Add("OrderSKUs", int64(len(keys)-len(miss)))
defer func() {
for k, v := range res {
if len(v) == 1 && v[0].OrderID == -1 {
delete(res, k)
}
}
}()
if len(miss) == 0 {
return
}
var missData map[int64][]*model.OrderSKU
prom.CacheMiss.Add("OrderSKUs", int64(len(miss)))
missData, err = d.RawOrderSKUs(c, miss)
if res == nil {
res = make(map[int64][]*model.OrderSKU)
}
for k, v := range missData {
res[k] = v
}
if err != nil {
return
}
for _, key := range keys {
if len(res[key]) == 0 {
if missData == nil {
missData = make(map[int64][]*model.OrderSKU, len(keys))
}
missData[key] = []*model.OrderSKU{{OrderID: -1}}
}
}
if !addCache {
return
}
d.cache.Save(func() {
d.AddCacheOrderSKUs(metadata.WithContext(c), missData)
})
return
}
// OrderPayCharges get data from cache if miss will call source method, then add to cache.
func (d *Dao) OrderPayCharges(c context.Context, keys []int64) (res map[int64]*model.OrderPayCharge, err error) {
if len(keys) == 0 {
return
}
addCache := true
res, err = d.CacheOrderPayCharges(c, keys)
if err != nil {
addCache = false
res = nil
err = nil
}
var miss []int64
for _, key := range keys {
if (res == nil) || (res[key] == nil) {
miss = append(miss, key)
}
}
prom.CacheHit.Add("OrderPayCharges", int64(len(keys)-len(miss)))
defer func() {
for k, v := range res {
if v != nil && v.ChargeID == "" {
delete(res, k)
}
}
}()
if len(miss) == 0 {
return
}
var missData map[int64]*model.OrderPayCharge
prom.CacheMiss.Add("OrderPayCharges", int64(len(miss)))
missData, err = d.RawOrderPayCharges(c, miss)
if res == nil {
res = make(map[int64]*model.OrderPayCharge)
}
for k, v := range missData {
res[k] = v
}
if err != nil {
return
}
for _, key := range keys {
if res[key] == nil {
if missData == nil {
missData = make(map[int64]*model.OrderPayCharge, len(keys))
}
missData[key] = &model.OrderPayCharge{ChargeID: ""}
}
}
if !addCache {
return
}
d.cache.Save(func() {
d.AddCacheOrderPayCharges(metadata.WithContext(c), missData)
})
return
}
// SkuByItemID get data from cache if miss will call source method, then add to cache.
func (d *Dao) SkuByItemID(c context.Context, id int64) (res map[string]*model.SKUStock, err error) {
addCache := true
res, err = d.CacheSkuByItemID(c, id)
if err != nil {
addCache = false
err = nil
}
if len(res) != 0 {
prom.CacheHit.Incr("SkuByItemID")
return
}
prom.CacheMiss.Incr("SkuByItemID")
res, err = d.RawSkuByItemID(c, id)
if err != nil {
return
}
miss := res
if !addCache {
return
}
d.cache.Save(func() {
d.AddCacheSkuByItemID(metadata.WithContext(c), id, miss)
})
return
}
// GetSKUs get data from cache if miss will call source method, then add to cache.
func (d *Dao) GetSKUs(c context.Context, keys []int64, withNewStock bool) (res map[int64]*model.SKUStock, err error) {
if len(keys) == 0 {
return
}
addCache := true
res, err = d.CacheGetSKUs(c, keys, withNewStock)
if err != nil {
addCache = false
res = nil
err = nil
}
var miss []int64
for _, key := range keys {
if (res == nil) || (res[key] == nil) {
miss = append(miss, key)
}
}
prom.CacheHit.Add("GetSKUs", int64(len(keys)-len(miss)))
if len(miss) == 0 {
return
}
var missData map[int64]*model.SKUStock
prom.CacheMiss.Add("GetSKUs", int64(len(miss)))
missData, err = d.RawGetSKUs(c, miss, withNewStock)
if res == nil {
res = make(map[int64]*model.SKUStock)
}
for k, v := range missData {
res[k] = v
}
if err != nil {
return
}
if !addCache {
return
}
d.cache.Save(func() {
d.AddCacheGetSKUs(metadata.WithContext(c), missData, withNewStock)
})
return
}
// Stocks get data from cache if miss will call source method, then add to cache.
func (d *Dao) Stocks(c context.Context, keys []int64, isLocked bool) (res map[int64]int64, err error) {
if len(keys) == 0 {
return
}
addCache := true
res, err = d.CacheStocks(c, keys, isLocked)
if err != nil {
addCache = false
res = nil
err = nil
}
var miss []int64
for _, key := range keys {
if _, ok := res[key]; !ok {
miss = append(miss, key)
}
}
prom.CacheHit.Add("Stocks", int64(len(keys)-len(miss)))
if len(miss) == 0 {
return
}
var missData map[int64]int64
prom.CacheMiss.Add("Stocks", int64(len(miss)))
missData, err = d.RawStocks(c, miss, isLocked)
if res == nil {
res = make(map[int64]int64)
}
for k, v := range missData {
res[k] = v
}
if err != nil {
return
}
if !addCache {
return
}
d.cache.Save(func() {
d.AddCacheStocks(metadata.WithContext(c), missData, isLocked)
})
return
}
// TicketsByOrderID get data from cache if miss will call source method, then add to cache.
func (d *Dao) TicketsByOrderID(c context.Context, id int64) (res []*model.Ticket, err error) {
addCache := true
res, err = d.CacheTicketsByOrderID(c, id)
if err != nil {
addCache = false
err = nil
}
defer func() {
if len(res) == 1 && res[0].ID == -1 {
res = nil
}
}()
if len(res) != 0 {
prom.CacheHit.Incr("TicketsByOrderID")
return
}
prom.CacheMiss.Incr("TicketsByOrderID")
res, err = d.RawTicketsByOrderID(c, id)
if err != nil {
return
}
miss := res
if len(miss) == 0 {
miss = []*model.Ticket{{ID: -1}}
}
if !addCache {
return
}
d.cache.Save(func() {
d.AddCacheTicketsByOrderID(metadata.WithContext(c), id, miss)
})
return
}
// TicketsByScreen get data from cache if miss will call source method, then add to cache.
func (d *Dao) TicketsByScreen(c context.Context, id int64, UID int64) (res []*model.Ticket, err error) {
addCache := true
res, err = d.CacheTicketsByScreen(c, id, UID)
if err != nil {
addCache = false
err = nil
}
defer func() {
if len(res) == 1 && res[0].ID == -1 {
res = nil
}
}()
if len(res) != 0 {
prom.CacheHit.Incr("TicketsByScreen")
return
}
prom.CacheMiss.Incr("TicketsByScreen")
res, err = d.RawTicketsByScreen(c, id, UID)
if err != nil {
return
}
miss := res
if len(miss) == 0 {
miss = []*model.Ticket{{ID: -1}}
}
if !addCache {
return
}
d.cache.Save(func() {
d.AddCacheTicketsByScreen(metadata.WithContext(c), id, miss, UID)
})
return
}
// TicketsByID get data from cache if miss will call source method, then add to cache.
func (d *Dao) TicketsByID(c context.Context, keys []int64) (res map[int64]*model.Ticket, err error) {
if len(keys) == 0 {
return
}
addCache := true
res, err = d.CacheTicketsByID(c, keys)
if err != nil {
addCache = false
res = nil
err = nil
}
var miss []int64
for _, key := range keys {
if (res == nil) || (res[key] == nil) {
miss = append(miss, key)
}
}
prom.CacheHit.Add("TicketsByID", int64(len(keys)-len(miss)))
defer func() {
for k, v := range res {
if v != nil && v.ID == -1 {
delete(res, k)
}
}
}()
if len(miss) == 0 {
return
}
var missData map[int64]*model.Ticket
prom.CacheMiss.Add("TicketsByID", int64(len(miss)))
missData, err = d.RawTicketsByID(c, miss)
if res == nil {
res = make(map[int64]*model.Ticket)
}
for k, v := range missData {
res[k] = v
}
if err != nil {
return
}
for _, key := range keys {
if res[key] == nil {
if missData == nil {
missData = make(map[int64]*model.Ticket, len(keys))
}
missData[key] = &model.Ticket{ID: -1}
}
}
if !addCache {
return
}
d.cache.Save(func() {
d.AddCacheTicketsByID(metadata.WithContext(c), missData)
})
return
}
// TicketSend get data from cache if miss will call source method, then add to cache.
func (d *Dao) TicketSend(c context.Context, keys []int64, TIDType string) (res map[int64]*model.TicketSend, err error) {
if len(keys) == 0 {
return
}
addCache := true
res, err = d.CacheTicketSend(c, keys, TIDType)
if err != nil {
addCache = false
res = nil
err = nil
}
var miss []int64
for _, key := range keys {
if (res == nil) || (res[key] == nil) {
miss = append(miss, key)
}
}
prom.CacheHit.Add("TicketSend", int64(len(keys)-len(miss)))
defer func() {
for k, v := range res {
if v != nil && v.ID == -1 {
delete(res, k)
}
}
}()
if len(miss) == 0 {
return
}
var missData map[int64]*model.TicketSend
prom.CacheMiss.Add("TicketSend", int64(len(miss)))
missData, err = d.RawTicketSend(c, miss, TIDType)
if res == nil {
res = make(map[int64]*model.TicketSend)
}
for k, v := range missData {
res[k] = v
}
if err != nil {
return
}
for _, key := range keys {
if res[key] == nil {
if missData == nil {
missData = make(map[int64]*model.TicketSend, len(keys))
}
missData[key] = &model.TicketSend{ID: -1}
}
}
if !addCache {
return
}
d.cache.Save(func() {
d.AddCacheTicketSend(metadata.WithContext(c), missData, TIDType)
})
return
}

View File

@@ -0,0 +1,174 @@
package dao
import (
"context"
"time"
"go-common/app/common/openplatform/encoding"
acc "go-common/app/service/main/account/api"
itemv1 "go-common/app/service/openplatform/ticket-item/api/grpc/v1"
"go-common/app/service/openplatform/ticket-sales/conf"
"go-common/app/service/openplatform/ticket-sales/model"
"go-common/library/cache"
"go-common/library/cache/redis"
"go-common/library/database/sql"
"go-common/library/log"
"go-common/library/naming/discovery"
bm "go-common/library/net/http/blademaster"
"go-common/library/net/rpc/warden"
"go-common/library/net/rpc/warden/resolver"
"go-common/library/queue/databus"
)
//Dao 数据操作层结构体
type Dao struct {
c *conf.Config
db *sql.DB
redis *redis.Pool
expire int32
cache *cache.Cache
httpClientR *bm.Client
itemClient itemv1.ItemClient
accClient acc.AccountClient
databus *databus.Databus
}
//go:generate $GOPATH/src/go-common/app/tool/cache/gen
type _cache interface {
// cache: -nullcache=&model.Promotion{PromoID:-1} -check_null_code=$!=nil&&$.PromoID==-1
Promo(c context.Context, promoID int64) (*model.Promotion, error)
// cache: -nullcache=&model.PromotionGroup{GroupID:-1} -check_null_code=$!=nil&&$.GroupID==-1
PromoGroup(c context.Context, groupID int64) (*model.PromotionGroup, error)
// cache: -nullcache=&model.PromotionOrder{OrderID:-1} -check_null_code=$!=nil&&$.OrderID==-1
PromoOrder(c context.Context, orderID int64) (*model.PromotionOrder, error)
// cache: -nullcache=[]*model.PromotionOrder{{GroupID:-1}} -check_null_code=len($)==1&&$[0].GroupID==-1
PromoOrders(c context.Context, groupID int64) ([]*model.PromotionOrder, error)
// cache: -nullcache=[]*model.OrderMain{{OrderID:-1}} -check_null_code=len($)==1&&$[0].OrderID==-1
Orders(context.Context, *model.OrderMainQuerier) ([]*model.OrderMain, error)
// cache: -nullcache=-1 -check_null_code=$==-1
OrderCount(context.Context, *model.OrderMainQuerier) (int64, error)
// cache: -nullcache=&model.OrderDetail{OrderID:0} -check_null_code=$!=nil&&$.OrderID==0
OrderDetails(context.Context, []int64) (map[int64]*model.OrderDetail, error)
// cache: -nullcache=[]*model.OrderSKU{{OrderID:-1}} -check_null_code=len($)==1&&$[0].OrderID==-1
OrderSKUs(context.Context, []int64) (map[int64][]*model.OrderSKU, error)
// cache: -nullcache=&model.OrderPayCharge{ChargeID:""} -check_null_code=$!=nil&&$.ChargeID==""
OrderPayCharges(context.Context, []int64) (map[int64]*model.OrderPayCharge, error)
// cache:
SkuByItemID(c context.Context, itemID int64) (map[string]*model.SKUStock, error)
// cache:
GetSKUs(c context.Context, skuIds []int64, withNewStock bool) (map[int64]*model.SKUStock, error)
// cache:
Stocks(c context.Context, keys []int64, isLocked bool) (res map[int64]int64, err error)
// cache: -nullcache=[]*model.Ticket{{ID:-1}} -check_null_code=len($)==1&&$[0].ID==-1
TicketsByOrderID(c context.Context, orderID int64) (res []*model.Ticket, err error)
// cache: -nullcache=[]*model.Ticket{{ID:-1}} -check_null_code=len($)==1&&$[0].ID==-1
TicketsByScreen(c context.Context, screenID int64, UID int64) (res []*model.Ticket, err error)
// cache: -nullcache=&model.Ticket{ID:-1} -check_null_code=$!=nil&&$.ID==-1
TicketsByID(c context.Context, id []int64) (res map[int64]*model.Ticket, err error)
// cache: -nullcache=&model.TicketSend{ID:-1} -check_null_code=$!=nil&&$.ID==-1
TicketSend(c context.Context, SendTID []int64, TIDType string) (res map[int64]*model.TicketSend, err error)
}
// FIXME this just a example
func newItemClient(cfg *warden.ClientConfig) itemv1.ItemClient {
cc, err := warden.NewClient(cfg).Dial(context.Background(), "discovery://default/ticket.service.item")
if err != nil {
panic(err)
}
return itemv1.NewItemClient(cc)
}
func newAccClient(cfg *warden.ClientConfig) acc.AccountClient {
cc, err := warden.NewClient(cfg).Dial(context.Background(), "discovery://default/account.service")
if err != nil {
panic(err)
}
return acc.NewAccountClient(cc)
}
//New 根据配置文件 生成一个 Dao struct
func New(c *conf.Config) (d *Dao) {
resolver.Register(discovery.New(nil))
d = &Dao{
c: c,
db: sql.NewMySQL(c.DB.Master),
redis: redis.NewPool(c.Redis.Master),
cache: cache.New(1, 1024),
expire: int32(time.Duration(c.Redis.Expire) / time.Second),
httpClientR: bm.NewClient(c.HTTPClient.Read),
itemClient: newItemClient(c.GRPCClient["item"]),
accClient: newAccClient(c.GRPCClient["account"]),
databus: databus.New(c.Databus["update"]),
}
return
}
// Ping ping 方法
func (d *Dao) Ping(c context.Context) (err error) {
conn := d.redis.Get(c)
defer conn.Close()
_, err = conn.Do("PING")
if err != nil {
return
}
err = d.db.Ping(c)
return
}
//Close 关闭redis 和 db 连接
func (d *Dao) Close() (err error) {
d.redis.Close()
d.db.Close()
return
}
//BeginTx 开启事务
func (d *Dao) BeginTx(c context.Context) (conn *sql.Tx, err error) {
return d.db.Begin(c)
}
//LogX 记录日志args:请求参数 res:正常返回 err:错误返回 ld:更多日志项
func LogX(ctx context.Context, args interface{}, res interface{}, err error, ld ...log.D) {
l := len(ld)
u := 0
ld1 := make([]log.D, l)
for i := 0; i < l; i++ {
if ld[i].Key != "" {
ld1[u] = ld[i]
u++
}
}
ld1 = ld1[:u]
if args != nil {
ld1 = append(ld1, log.KV("args", encoding.JSON(args)))
}
if err != nil {
ld1 = append(ld1, log.KV("log", err.Error()))
log.Errorv(ctx, ld1...)
} else if log.V(3) {
if res == nil {
log.Infov(ctx, ld1...)
return
}
ld1 = append(ld1, log.KV("log", encoding.JSON(res)))
log.Infov(ctx, ld1...)
}
}
//DatabusPub 向databus发布消息
func (d *Dao) DatabusPub(ctx context.Context, action string, data interface{}) error {
type input struct {
Action string `json:"action"`
Data interface{} `json:"data"`
}
err := d.databus.Send(ctx, action, &input{action, data})
if err != nil {
log.Error("pub databus failed action:%s, data:%+v", action, data)
}
return err
}

View File

@@ -0,0 +1,40 @@
package dao
import (
"context"
"flag"
"path/filepath"
"testing"
"go-common/app/service/openplatform/ticket-sales/conf"
"go-common/library/conf/paladin"
"github.com/smartystreets/goconvey/convey"
)
var (
d *Dao
ctx context.Context
)
func init() {
dir, _ := filepath.Abs("../cmd/ticket-sales.toml")
flag.Set("conf", dir)
flag.Set("appid", "open.ticket.sales")
if err := paladin.Init(); err != nil {
panic(err)
}
if err := paladin.Watch("ticket-sales.toml", conf.Conf); err != nil {
panic(err)
}
d = New(conf.Conf)
ctx = context.TODO()
}
func TestDatabusPub(t *testing.T) {
convey.Convey("DatabusPub", t, func() {
err := d.DatabusPub(context.TODO(), "aaa", []string{"masaji"})
convey.So(err, convey.ShouldEqual, nil)
})
}

View File

@@ -0,0 +1,65 @@
package dao
import (
"context"
"database/sql"
"fmt"
"github.com/pkg/errors"
"go-common/app/service/openplatform/ticket-sales/model"
"go-common/library/log"
)
const (
_hasDisOrder = "SELECT order_id,status FROM dist_order where order_id=? and status=?"
_getOrder = "SELECT order_id,cm_amount,cm_method,cm_price,dist_user,status,pid,count,sid,type,payment_amount,serial_num,ctime,mtime FROM dist_order where order_id = ?"
_addDisOrder = "INSERT INTO dist_order(order_id,cm_amount,cm_method,cm_price,dist_user,status,pid,count,sid,type,payment_amount,serial_num) VALUES(?,?,?,?,?,?,?,?,?,?,?,?)"
)
// InsertOrder 同步订单到分销表方法
func (d *Dao) InsertOrder(c context.Context, oi *model.DistOrderArg) (lastID int64, err error) {
res, err := d.db.Exec(c, _addDisOrder, &oi.Oid, &oi.CmAmount, &oi.CmMethod, &oi.CmPrice, &oi.Duid, &oi.Stat, &oi.Pid, &oi.Count, &oi.Sid, &oi.Type, &oi.PayAmount, &oi.Serial)
if err != nil {
errors.Wrap(err, fmt.Sprintf("db.Exec(%s) err ", _addDisOrder))
return
}
lastID, err = res.LastInsertId()
return
}
// HasOrder 检查订单是否存在
func (d *Dao) HasOrder(c context.Context, oi *model.DistOrderArg) (has bool, err error) {
has = false
row := d.db.QueryRow(c, _hasDisOrder, &oi.Oid, &oi.Stat)
err = row.Scan(&oi.Oid, &oi.Stat)
if err == nil {
has = true
return
}
if err != nil && err != sql.ErrNoRows {
errors.Wrap(err, "dao Hasorder err")
return
}
return
}
// GetOrder 检查订单是否存在
func (d *Dao) GetOrder(c context.Context, oid uint64) (res []*model.OrderInfo, err error) {
rows, err := d.db.Query(c, _getOrder, oid)
if err != nil {
log.Error("[dao.distrib|GetOrder] d.db.Query err: %v", err)
return
}
defer rows.Close()
for rows.Next() {
oi := &model.OrderInfo{}
if err = rows.Scan(&oi.Oid, &oi.CmAmount, &oi.CmMethod, &oi.CmPrice, &oi.Duid, &oi.Stat, &oi.Pid, &oi.Count, &oi.Sid, &oi.Type, &oi.PayAmount, &oi.Serial, &oi.Ctime, &oi.Mtime); err != nil {
log.Error("[dao.distrib|GetOrder] rows.Scan err: %v", err)
return
}
res = append(res, oi)
}
return
}

View File

@@ -0,0 +1,14 @@
package dao
import (
"context"
. "github.com/smartystreets/goconvey/convey"
"testing"
)
func TestGetOrder(t *testing.T) {
Convey("Get Order", t, func() {
_, err := d.GetOrder(context.TODO(), 10001)
So(err, ShouldBeNil)
})
}

View File

@@ -0,0 +1,16 @@
package dao
import (
"context"
itemv1 "go-common/app/service/openplatform/ticket-item/api/grpc/v1"
)
//ItemBillInfo 获取商品信息
func (d *Dao) ItemBillInfo(ctx context.Context, itemIDs []int64, scIDs []int64, tkIDs []int64) (*itemv1.BillReply, error) {
req := &itemv1.BillRequest{
IDs: itemIDs,
ScIDs: scIDs,
TkIDs: tkIDs,
}
return d.itemClient.BillInfo(ctx, req)
}

View File

@@ -0,0 +1,20 @@
package dao
import (
"context"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestItemBillInfo(t *testing.T) {
convey.Convey("ItemBillInfo", t, func() {
itemID := int64(676)
scID := int64(870)
tkID := int64(2843)
infos, _ := d.ItemBillInfo(context.TODO(), []int64{itemID}, []int64{scID}, []int64{tkID})
convey.So(infos.BaseInfo, convey.ShouldContainKey, itemID)
convey.So(infos.BaseInfo[itemID].Screen, convey.ShouldContainKey, scID)
convey.So(infos.BaseInfo[itemID].Screen[scID].Ticket, convey.ShouldContainKey, tkID)
})
}

View File

@@ -0,0 +1,860 @@
package dao
import (
"context"
"crypto/md5"
"database/sql"
"encoding/json"
"errors"
"fmt"
"net/url"
"strings"
"time"
"go-common/app/service/openplatform/ticket-sales/model"
"go-common/app/service/openplatform/ticket-sales/model/consts"
"go-common/library/cache/redis"
xsql "go-common/library/database/sql"
"go-common/library/ecode"
"github.com/gogo/protobuf/types"
)
//订单相关常量
const (
cacheTimeout = 10
DefaultOrderPSize = 20 //默认每页数量
DefaultOrderOrderBy = "id desc" //默认排序
//sqlGetUserOrders 查询用户订单列表
sqlGetUserOrders = "SELECT %s FROM order_main WHERE uid=? AND is_deleted = 0 ORDER BY %s LIMIT %d,%d"
//sqlGetUserItemOrders 查询用户已购买的某个项目订单
sqlGetUserItemOrders = "SELECT %s FROM order_main WHERE uid=? AND item_id=? AND status IN (%s)"
//sqlCountUserOrders 查询用户订单数量
sqlCountUserOrders = "SELECT COUNT(*) FROM order_main WHERE uid=? AND is_deleted=0"
//sqlGetOrders 查询订单列表
sqlGetOrders = "SELECT %s FROM order_main WHERE order_id IN (%s)"
//sqlInsertOrderMains 批量写入order_main
sqlInsertOrderMains = "INSERT INTO order_main(%s) VALUES %s"
//sqlGetOrderDetails 查询订单详情
sqlGetOrderDetails = "SELECT %s FROM order_detail WHERE order_id IN (%s)"
//sqlInsertOrderDetails 批量写入order_detail
sqlInsertOrderDetails = "INSERT INTO order_detail(%s) VALUES %s"
//sqlGetOrderSkus 查询order_sku
sqlGetOrderSkus = "SELECT %s FROM order_sku WHERE order_id IN (%s)"
//sqlInsertOrderSkus 批量写入order_sku
sqlInsertOrderSkus = "INSERT INTO order_sku(%s) VALUES %s"
//sqlGetBoughtSkus 获取已购买的sku
sqlGetBoughtSkus = "SELECT `count` FROM order_sku WHERE order_id IN (%s) AND sku_id IN (%s)"
//sqlGetOrderPayChs 获取支付流水
sqlGetOrderPayChs = "SELECT %s FROM order_pay_charge WHERE order_id IN (%s) AND paid=1"
//获取结算对账订单(0元单)
sqlGetSettleCompareOrders = "SELECT id,order_id FROM order_main WHERE ctime>=? and ctime<? AND id>? AND status IN (%s) AND pay_money=0 ORDER BY ctime,id LIMIT ?"
//获取结算对帐退款单
sqlGetSettleCompareRefunds = "SELECT id,order_id,refund_apply_time FROM order_refund WHERE ctime>=? AND ctime<? AND id>? AND status IN (%s) AND refund_money=0 ORDER BY ctime,id LIMIT ?"
)
//RawOrders 从db查询用户订单信息包括以下情况
//* 按照订单号查询
//* 按照uid查分页
//* 按照uid+商品id+状态查询列表
func (d *Dao) RawOrders(ctx context.Context, req *model.OrderMainQuerier) (orders []*model.OrderMain, err error) {
defer LogX(ctx, req, orders, err)
o := new(model.OrderMain)
sqls, args := pickOrderSQL(req, o.GetFields(nil))
q := sqls[0]
if q == "" {
return
}
r, err := d.db.Query(ctx, q, args...)
if err != nil {
if err == sql.ErrNoRows {
err = nil
}
return
}
defer r.Close()
for r.Next() {
vptrs := make(map[int]interface{})
ptrs := o.GetPtrs(nil, vptrs)
if err = r.Scan(ptrs...); err != nil {
return
}
for k, v := range vptrs {
json.Unmarshal([]byte(*ptrs[k].(*string)), v)
}
orders = append(orders, o)
o = new(model.OrderMain)
}
return
}
//RawOrderCount 从db获取用户订单数目当查询条件仅有uid时生效否则返回0
func (d *Dao) RawOrderCount(ctx context.Context, req *model.OrderMainQuerier) (cnt int64, err error) {
defer LogX(ctx, req, cnt, err)
sqls, args := pickOrderSQL(req, nil)
q := sqls[1]
if q == "" {
return
}
r := d.db.QueryRow(ctx, q, args...)
err = r.Scan(&cnt)
//缓存回源逻辑0会被当成没命中缓存
if cnt == 0 {
cnt = -1
}
return
}
//RawOrderDetails 从db获取订单详细
func (d *Dao) RawOrderDetails(ctx context.Context, oids []int64) (orders map[int64]*model.OrderDetail, err error) {
defer LogX(ctx, oids, orders, err)
lo := len(oids)
if lo == 0 {
return
}
a := make([]interface{}, lo)
for k, v := range oids {
a[k] = v
}
o := new(model.OrderDetail)
f := o.GetFields(nil)
q := fmt.Sprintf(sqlGetOrderDetails, "`"+strings.Join(f, "`,`")+"`", strings.Repeat(",?", lo)[1:])
r, err := d.db.Query(ctx, q, a...)
if err != nil {
if err == sql.ErrNoRows {
err = nil
}
return
}
defer r.Close()
orders = make(map[int64]*model.OrderDetail, lo)
for r.Next() {
vptrs := make(map[int]interface{})
ptrs := o.GetPtrs(nil, vptrs)
if err = r.Scan(ptrs...); err != nil {
return
}
for k, v := range vptrs {
json.Unmarshal([]byte(*ptrs[k].(*string)), v)
}
o.Decrypt(d.c.Encrypt)
orders[o.OrderID] = o
o = new(model.OrderDetail)
}
return
}
//RawOrderSKUs 从db获取订单的sku
func (d *Dao) RawOrderSKUs(ctx context.Context, oids []int64) (skus map[int64][]*model.OrderSKU, err error) {
defer LogX(ctx, oids, skus, err)
lo := len(oids)
if lo == 0 {
return
}
a := make([]interface{}, lo)
for k, v := range oids {
a[k] = v
}
o := new(model.OrderSKU)
f := o.GetFields(nil)
q := fmt.Sprintf(sqlGetOrderSkus, "`"+strings.Join(f, "`,`")+"`", strings.Repeat(",?", lo)[1:])
r, err := d.db.Query(ctx, q, a...)
if err != nil {
if err == sql.ErrNoRows {
err = nil
}
return
}
defer r.Close()
skus = make(map[int64][]*model.OrderSKU, lo)
for r.Next() {
vptrs := make(map[int]interface{})
ptrs := o.GetPtrs(nil, vptrs)
if err = r.Scan(ptrs...); err != nil {
return
}
for k, v := range vptrs {
json.Unmarshal([]byte(*ptrs[k].(*string)), v)
}
skus[o.OrderID] = append(skus[o.OrderID], o)
o = new(model.OrderSKU)
}
return
}
//RawBoughtCount 按照票种获取用户已购的订单票数
func (d *Dao) RawBoughtCount(ctx context.Context, uid string, itemID int64, skuIDs []int64) (cnt int64, err error) {
query := &model.OrderMainQuerier{
UID: uid,
ItemID: itemID,
Status: []int16{consts.OrderStatusUnpaid, consts.OrderStatusPaid},
}
orders, err := d.RawOrders(ctx, query)
if err != nil {
return
}
//存在部分退款,要减去已退款票数
pt := false
lo := len(orders)
oids := make([]int64, lo)
for k, v := range orders {
if v.RefundStatus == consts.RefundStatusPtRefunded {
pt = true
}
cnt += v.Count
oids[k] = v.OrderID
}
ls := len(skuIDs)
//查具体sku的要再次从order_sku表统计
if ls > 0 && lo > 0 {
cnt, err = d.rawBoughtSkusCnt(ctx, oids, skuIDs)
if err != nil {
return
}
}
//部分退款的减去已退款张数
if pt {
var rCnt int64
rCnt, err = d.rawRefundTicketCnt(ctx, oids)
if err != nil {
return
}
cnt -= rCnt
}
return
}
//rawBoughtSkusCnt 按照skuID统计用户购买数
func (d *Dao) rawBoughtSkusCnt(ctx context.Context, oids []int64, skuIDs []int64) (cnt int64, err error) {
lo := len(oids)
ls := len(skuIDs)
if lo == 0 || ls == 0 {
err = ecode.RequestErr
return
}
q := fmt.Sprintf(sqlGetBoughtSkus, strings.Repeat(",?", lo)[1:], strings.Repeat(",?", ls)[1:])
a := make([]interface{}, lo+ls)
for k, v := range oids {
a[k] = v
}
for k, v := range skuIDs {
a[k+lo] = v
}
r, err := d.db.Query(ctx, q, a...)
if err != nil {
return
}
defer r.Close()
var c int64
for r.Next() {
if err = r.Scan(&c); err != nil {
return
}
cnt += c
}
return
}
//RawOrderPayCharges 从db获取订单流水
func (d *Dao) RawOrderPayCharges(ctx context.Context, oids []int64) (chs map[int64]*model.OrderPayCharge, err error) {
defer LogX(ctx, oids, chs, err)
lo := len(oids)
if lo == 0 {
return
}
a := make([]interface{}, lo)
for k, v := range oids {
a[k] = v
}
o := new(model.OrderPayCharge)
f := o.GetFields(nil)
q := fmt.Sprintf(sqlGetOrderPayChs, "`"+strings.Join(f, "`,`")+"`", strings.Repeat(",?", lo)[1:])
r, err := d.db.Query(ctx, q, a...)
if err != nil {
if err == sql.ErrNoRows {
err = nil
}
return
}
defer r.Close()
chs = make(map[int64]*model.OrderPayCharge, lo)
for r.Next() {
ptrs := o.GetPtrs(&types.FieldMask{Paths: f}, nil)
if err = r.Scan(ptrs...); err != nil {
return
}
chs[o.OrderID] = o
o = new(model.OrderPayCharge)
}
return
}
//CacheOrders 从缓存获取订单基础信息
func (d *Dao) CacheOrders(ctx context.Context, req *model.OrderMainQuerier) (orders []*model.OrderMain, err error) {
pool := d.redis.Get(ctx)
defer func() {
pool.Close()
LogX(ctx, req, orders, err)
}()
var keys []interface{}
if l := len(req.OrderID); l > 0 {
keys = make([]interface{}, l)
for k, v := range req.OrderID {
keys[k] = fmt.Sprintf("%s:%d", model.CacheKeyOrderMn, v)
}
} else if key := oidCacheKey(req); key != "" {
//如果查的是列表先查出列表缓存的orderId再根据orderId查订单信息
var b []byte
key = model.CacheKeyOrderList + ":" + key
if b, err = redis.Bytes(pool.Do("GET", key)); err != nil {
if err == redis.ErrNil {
err = nil
}
return
}
s := string(b)
LogX(ctx, []string{"GET", key}, s, err)
oids := strings.Split(s, ",")
keys = make([]interface{}, len(oids))
for k, v := range oids {
keys[k] = model.CacheKeyOrderMn + ":" + v
}
}
if len(keys) == 0 {
return
}
var data [][]byte
if data, err = redis.ByteSlices(pool.Do("MGET", keys...)); err != nil {
return
}
LogX(ctx, append([]interface{}{"MGET"}, keys...), data, err)
for _, v := range data {
if v != nil {
o := &model.OrderMain{}
orders = append(orders, o)
json.Unmarshal(v, o)
}
}
return
}
//CacheOrderCount 从缓存获取订单数目
func (d *Dao) CacheOrderCount(ctx context.Context, req *model.OrderMainQuerier) (cnt int64, err error) {
pool := d.redis.Get(ctx)
defer func() {
pool.Close()
LogX(ctx, req, cnt, err)
}()
if key := oidCacheKey(req); key != "" {
if cnt, err = redis.Int64(pool.Do("GET", model.CacheKeyOrderCnt+":"+key)); err == redis.ErrNil {
err = nil
}
}
return
}
//CacheOrderDetails 从缓存获取订单详细
func (d *Dao) CacheOrderDetails(ctx context.Context, oids []int64) (orders map[int64]*model.OrderDetail, err error) {
pool := d.redis.Get(ctx)
defer func() {
pool.Close()
LogX(ctx, oids, orders, err)
}()
lo := len(oids)
keys := make([]interface{}, lo)
for k, v := range oids {
keys[k] = fmt.Sprintf("%s:%d", model.CacheKeyOrderDt, v)
}
var data [][]byte
if data, err = redis.ByteSlices(pool.Do("MGET", keys...)); err != nil {
return
}
LogX(ctx, append([]interface{}{"MGET"}, keys...), data, nil)
orders = make(map[int64]*model.OrderDetail, lo)
for k, v := range oids {
if data[k] == nil {
continue
}
o := &model.OrderDetail{}
if err = json.Unmarshal(data[k], o); err != nil {
err = nil
} else {
orders[v] = o
}
}
return
}
//CacheOrderSKUs 获取订单sku缓存
func (d *Dao) CacheOrderSKUs(ctx context.Context, oids []int64) (skus map[int64][]*model.OrderSKU, err error) {
pool := d.redis.Get(ctx)
defer func() {
pool.Close()
LogX(ctx, oids, skus, err)
}()
lo := len(oids)
keys := make([]interface{}, lo)
for k, v := range oids {
keys[k] = fmt.Sprintf("%s:%d", model.CacheKeyOrderSKU, v)
}
var data [][]byte
if data, err = redis.ByteSlices(pool.Do("MGET", keys...)); err != nil {
return
}
LogX(ctx, append([]interface{}{"MGET"}, keys...), data, nil)
skus = make(map[int64][]*model.OrderSKU, lo)
for k, v := range oids {
if data[k] == nil {
continue
}
o := []*model.OrderSKU{}
if err = json.Unmarshal(data[k], &o); err != nil {
err = nil
} else {
skus[v] = o
}
}
return
}
//CacheOrderPayCharges 从缓存获取订单流水
func (d *Dao) CacheOrderPayCharges(ctx context.Context, oids []int64) (chs map[int64]*model.OrderPayCharge, err error) {
pool := d.redis.Get(ctx)
defer func() {
pool.Close()
LogX(ctx, oids, chs, err)
}()
lo := len(oids)
if lo == 0 {
return
}
keys := make([]interface{}, lo)
for k, v := range oids {
keys[k] = fmt.Sprintf("%s:%d", model.CacheKeyOrderPayCh, v)
}
var data [][]byte
if data, err = redis.ByteSlices(pool.Do("MGET", keys...)); err != nil {
return
}
LogX(ctx, append([]interface{}{"MGET"}, keys...), data, nil)
chs = make(map[int64]*model.OrderPayCharge, lo)
for k, v := range oids {
if data[k] == nil {
continue
}
ch := &model.OrderPayCharge{}
if err = json.Unmarshal(data[k], ch); err != nil {
err = nil
} else {
chs[v] = ch
}
}
return
}
//AddCacheOrders 设置订单基础信息缓存
func (d *Dao) AddCacheOrders(ctx context.Context, req *model.OrderMainQuerier, res []*model.OrderMain) (err error) {
pool := d.redis.Get(ctx)
defer func() {
pool.Flush()
pool.Close()
LogX(ctx, []interface{}{req, res}, nil, err)
}()
data := make([]interface{}, len(res)*2)
var sOids string
for k, v := range res {
if sOids == "" {
sOids = fmt.Sprintf("%d", v.OrderID)
} else {
sOids += fmt.Sprintf(",%d", v.OrderID)
}
b, _ := json.Marshal(v)
data[k*2] = fmt.Sprintf("%s:%d", model.CacheKeyOrderMn, v.OrderID)
data[k*2+1] = b
}
//设置列表orderID缓存
if key := oidCacheKey(req); key != "" {
arg := []interface{}{model.CacheKeyOrderList + ":" + key, cacheTimeout, sOids}
LogX(ctx, append([]interface{}{"SETEX"}, arg...), nil, nil)
if err = pool.Send("SETEX", arg...); err != nil {
return
}
}
LogX(ctx, append([]interface{}{"MSET"}, data...), nil, nil)
if err = pool.Send("MSET", data...); err != nil {
return
}
for i := 0; i < len(data); i += 2 {
pool.Send("EXPIRE", data[i], cacheTimeout)
}
return
}
//AddCacheOrderCount 设置订单数目缓存
func (d *Dao) AddCacheOrderCount(ctx context.Context, req *model.OrderMainQuerier, res int64) (err error) {
pool := d.redis.Get(ctx)
defer func() {
pool.Close()
LogX(ctx, []interface{}{req, res}, nil, err)
}()
if key := oidCacheKey(req); key != "" {
_, err = pool.Do("SETEX", model.CacheKeyOrderCnt+":"+key, cacheTimeout, res)
}
return
}
//AddCacheOrderDetails 增加订单详细缓存
func (d *Dao) AddCacheOrderDetails(ctx context.Context, orders map[int64]*model.OrderDetail) (err error) {
pool := d.redis.Get(ctx)
defer func() {
pool.Flush()
pool.Close()
LogX(ctx, orders, nil, err)
}()
data := make([]interface{}, len(orders)*2)
i := 0
for k, v := range orders {
key := fmt.Sprintf("%s:%d", model.CacheKeyOrderDt, k)
var b []byte
b, _ = json.Marshal(v)
data[i] = key
data[i+1] = b
i += 2
}
LogX(ctx, append([]interface{}{"MSET"}, data...), nil, nil)
if err = pool.Send("MSET", data...); err != nil {
return
}
for i := 0; i < len(data); i += 2 {
pool.Send("EXPIRE", data[i], cacheTimeout)
}
return
}
//AddCacheOrderSKUs 增加订单sku缓存
func (d *Dao) AddCacheOrderSKUs(ctx context.Context, skus map[int64][]*model.OrderSKU) (err error) {
pool := d.redis.Get(ctx)
defer func() {
pool.Flush()
pool.Close()
LogX(ctx, skus, nil, err)
}()
data := make([]interface{}, len(skus)*2)
i := 0
for k, v := range skus {
key := fmt.Sprintf("%s:%d", model.CacheKeyOrderSKU, k)
var b []byte
b, err = json.Marshal(v)
data[i] = key
data[i+1] = b
i += 2
}
LogX(ctx, append([]interface{}{"MSET"}, data...), nil, nil)
if err = pool.Send("MSET", data...); err != nil {
return
}
for i := 0; i < len(data); i += 2 {
pool.Send("EXPIRE", data[i], cacheTimeout)
}
return
}
//AddCacheOrderPayCharges 增加订单流水缓存
func (d *Dao) AddCacheOrderPayCharges(ctx context.Context, chs map[int64]*model.OrderPayCharge) (err error) {
pool := d.redis.Get(ctx)
defer func() {
pool.Flush()
pool.Close()
LogX(ctx, chs, nil, err)
}()
data := make([]interface{}, len(chs)*2)
i := 0
for k, v := range chs {
key := fmt.Sprintf("%s:%d", model.CacheKeyOrderPayCh, k)
var b []byte
b, _ = json.Marshal(v)
data[i] = key
data[i+1] = b
i += 2
}
LogX(ctx, append([]interface{}{"MSET"}, data...), nil, nil)
if err = pool.Send("MSET", data...); err != nil {
return
}
for i := 0; i < len(data); i += 2 {
pool.Send("EXPIRE", data[i], cacheTimeout)
}
return
}
//DelCacheOrders 删除订单相关缓存如果是新增或删除订单要删除这个uid的订单列表缓存
func (d *Dao) DelCacheOrders(ctx context.Context, req *model.OrderMainQuerier) {
pool := d.redis.Get(ctx)
var ret interface{}
defer func() {
pool.Close()
LogX(ctx, req, ret, nil)
}()
for _, v := range req.OrderID {
ret, _ = pool.Do("DEL",
fmt.Sprintf("%s:%d", model.CacheKeyOrderMn, v),
fmt.Sprintf("%s:%d", model.CacheKeyOrderDt, v),
fmt.Sprintf("%s:%d", model.CacheKeyOrderSKU, v),
)
}
if key := oidCacheKey(req); key != "" {
ret, _ = pool.Do("DEL", model.CacheKeyOrderList+":"+key, model.CacheKeyOrderCnt+":"+key)
}
}
//TxInsertOrders 插入订单表,返回成功行数
func (d *Dao) TxInsertOrders(tx *xsql.Tx, orders []*model.OrderMain) (cnt int64, err error) {
lo := len(orders)
if lo == 0 {
return
}
f := orders[0].GetFields(&types.FieldMask{Paths: []string{"ctime", "mtime"}})
lf := len(f)
hlds := model.InsPlHlds(lf, lo)
a := make([]interface{}, lf*lo)
i := 0
for _, o := range orders {
vals := o.GetVals(&types.FieldMask{Paths: f}, true)
copy(a[i:], vals)
i += lf
}
r, err := tx.Exec(fmt.Sprintf(sqlInsertOrderMains, "`"+strings.Join(f, "`,`")+"`", hlds), a...)
if err != nil {
return
}
cnt, err = r.RowsAffected()
return
}
//TxInsertOrderDetails 写入orderDetail表
func (d *Dao) TxInsertOrderDetails(tx *xsql.Tx, orders []*model.OrderDetail) (cnt int64, err error) {
for _, v := range orders {
v.Encrypt(d.c.Encrypt)
}
lo := len(orders)
if lo == 0 {
return
}
f := orders[0].GetFields(&types.FieldMask{Paths: []string{"ctime", "mtime"}})
lf := len(f)
hlds := model.InsPlHlds(lf, lo)
a := make([]interface{}, lf*lo)
i := 0
for _, o := range orders {
vals := o.GetVals(&types.FieldMask{Paths: f}, true)
copy(a[i:], vals)
i += lf
}
r, err := tx.Exec(fmt.Sprintf(sqlInsertOrderDetails, "`"+strings.Join(f, "`,`")+"`", hlds), a...)
if err != nil {
cnt = 0
return
}
cnt, err = r.RowsAffected()
return
}
//TxInsertOrderSKUs 增加订单Sku
func (d *Dao) TxInsertOrderSKUs(tx *xsql.Tx, orders []*model.OrderSKU) (cnt int64, err error) {
lo := len(orders)
if lo == 0 {
return
}
f := orders[0].GetFields(&types.FieldMask{Paths: []string{"ctime", "mtime"}})
lf := len(f)
hlds := model.InsPlHlds(lf, lo)
a := make([]interface{}, lf*lo)
i := 0
for _, o := range orders {
vals := o.GetVals(&types.FieldMask{Paths: f}, true)
copy(a[i:], vals)
i += lf
}
r, err := tx.Exec(fmt.Sprintf(sqlInsertOrderSkus, "`"+strings.Join(f, "`,`")+"`", hlds), a...)
if err != nil {
cnt = 0
return
}
cnt, err = r.RowsAffected()
return
}
//OrderID 获取订单号的方法
func (d *Dao) OrderID(ctx context.Context, n int) ([]int64, error) {
if n <= 0 {
return nil, nil
}
if _, ok := d.c.URLs["basecenter"]; !ok {
return nil, errors.New("miss basecenter's url conf")
}
u := d.c.URLs["basecenter"]
var res struct {
Errno int32 `json:"errno"`
Data []int64 `json:"data"`
}
uv := url.Values{}
uv.Set("app_id", d.c.BaseCenter.AppID)
uv.Set("app_token", d.c.BaseCenter.Token)
uv.Set("count", fmt.Sprintf("%d", n))
if err := d.httpClientR.Get(ctx, u+"/orderid/get", "", uv, &res); err != nil {
return nil, err
}
if len(res.Data) == 0 {
return nil, ecode.TicketGetOidFail
}
return res.Data, nil
}
//pickOrderSQL 查订单的sql返回sqls:{0:查列表的sql, 1:查数量的sql}, args:需要代入的变量
func pickOrderSQL(q *model.OrderMainQuerier, fields []string) (sqls []string, args []interface{}) {
sqls = make([]string, 2)
var f string
if len(fields) > 0 {
f = "`" + strings.Join(fields, "`,`") + "`"
}
if l := len(q.OrderID); l > 0 {
if f != "" {
sqls[0] = fmt.Sprintf(sqlGetOrders, f, strings.Repeat(",?", l)[1:])
}
args = make([]interface{}, len(q.OrderID))
for k, v := range q.OrderID {
args[k] = v
}
return
}
if l := len(q.Status); l > 0 && q.ItemID > 0 {
if f != "" {
sqls[0] = fmt.Sprintf(sqlGetUserItemOrders, f, strings.Repeat(",?", l)[1:])
}
args = make([]interface{}, 2+l)
args[0] = q.UID
args[1] = q.ItemID
for k, v := range q.Status {
args[k+2] = v
}
return
}
if q.OrderBy == "" {
q.OrderBy = DefaultOrderOrderBy
}
if q.Limit == 0 {
q.Limit = DefaultOrderPSize
}
if f != "" {
sqls[0] = fmt.Sprintf(sqlGetUserOrders, f, q.OrderBy, q.Offset, q.Limit)
}
sqls[1] = sqlCountUserOrders
args = []interface{}{q.UID}
return
}
//oidCacheKey orderId列表的缓存key, 返回空不缓存列表
func oidCacheKey(q *model.OrderMainQuerier) string {
s := ""
if len(q.OrderID) > 0 {
return s
}
if q.OrderBy == "" {
q.OrderBy = DefaultOrderOrderBy
}
if q.Limit == 0 {
q.Limit = DefaultOrderPSize
}
//仅缓存第一页
if q.Offset > 0 || q.Limit != DefaultOrderPSize || strings.ToLower(q.OrderBy) != DefaultOrderOrderBy {
return ""
}
if q.UID != "" {
s = "&uid=" + q.UID
}
if q.ItemID > 0 {
s += fmt.Sprintf("&item_id=%d", q.ItemID)
}
fs := map[string][]int16{
"status": q.Status,
"sub_status": q.SubStatus,
"refund_status": q.RefundStatus,
}
for k, v := range fs {
if len(v) > 0 {
s += fmt.Sprintf("&%s=%s", k, strings.Trim(strings.Join(strings.Fields(fmt.Sprint(v)), ","), "[]"))
}
}
ls := len(s)
if ls > 32 {
return fmt.Sprintf("%x", md5.Sum([]byte(s[1:])))
}
if ls > 2 {
return s[1:]
}
//空缓存key
return "nil"
}
//RawGetSettleOrders 获取待结算订单
func (d *Dao) RawGetSettleOrders(ctx context.Context, bt time.Time, et time.Time, id int64, size int) (res *model.SettleOrders, offset int64, err error) {
q := fmt.Sprintf(sqlGetSettleCompareOrders, "?,?")
if size > 200 || size <= 0 {
size = 200
}
r, err := d.db.Query(ctx, q, bt.Format("2006-01-02"), et.Format("2006-01-02"), id, consts.OrderStatusPaid, consts.OrderStatusRefunded, size+1)
if err != nil {
if err == sql.ErrNoRows {
err = nil
}
return
}
defer r.Close()
res = &model.SettleOrders{}
res.Data = make([]*model.SettleOrder, 0, size+1)
for r.Next() {
o := &model.SettleOrder{}
if err = r.Scan(&o.ID, &o.OrderID); err != nil {
return
}
res.Data = append(res.Data, o)
}
l := len(res.Data)
if l > size {
res.Data = res.Data[:l-1]
offset = res.Data[l-2].ID
}
return
}
//RawGetSettleRefunds 获取待结算退款订单
func (d *Dao) RawGetSettleRefunds(ctx context.Context, bt time.Time, et time.Time, id int64, size int) (res *model.SettleOrders, offset int64, err error) {
q := fmt.Sprintf(sqlGetSettleCompareRefunds, "?")
if size > 200 || size <= 0 {
size = 200
}
r, err := d.db.Query(ctx, q, bt.Format("2006-01-02"), et.Format("2006-01-02"), id, consts.RefundTxStatusSucc, size+1)
if err != nil {
if err == sql.ErrNoRows {
err = nil
}
return
}
defer r.Close()
res = &model.SettleOrders{}
res.Data = make([]*model.SettleOrder, 0)
for r.Next() {
o := &model.SettleOrder{}
if err = r.Scan(&o.RefID, &o.OrderID, &o.RefundApplyTime); err != nil {
return
}
res.Data = append(res.Data, o)
}
l := len(res.Data)
if l > size {
res.Data = res.Data[:l-1]
offset = res.Data[l-2].RefID
}
return
}

View File

@@ -0,0 +1,49 @@
package dao
import (
"context"
"database/sql"
"encoding/json"
"go-common/app/common/openplatform/encoding"
"go-common/app/service/openplatform/ticket-sales/api/grpc/type"
rpc "go-common/app/service/openplatform/ticket-sales/api/grpc/v1"
"go-common/library/log"
)
const (
// 更新购买人信息
_updateDetailBuyer = "update order_detail set buyer = ?,tel = ?,personal_id = ? where order_id = ?"
// 更新配送信息
_updateDetailDelivery = "update order_detail set deliver_detail = ? where order_id = ?"
)
//UpdateDetailBuyer 更新购买人信息
func (d *Dao) UpdateDetailBuyer(c context.Context, req *rpc.UpBuyerRequest) (num int64, err error) {
var res sql.Result
PersonIDEnc, _ := encoding.Encrypt(req.Buyers.PersonalID, d.c.Encrypt)
TelEnc, _ := encoding.Encrypt(req.Buyers.Tel, d.c.Encrypt)
if res, err = d.db.Exec(c, _updateDetailBuyer, req.Buyers.Name, TelEnc, string(PersonIDEnc), req.OrderID); err != nil {
log.Warn("更新订单详情%d失败", req.OrderID)
return
}
return res.RowsAffected()
}
//UpdateDetailDelivery 更新配送信息
func (d *Dao) UpdateDetailDelivery(c context.Context, arg *_type.OrderDeliver, orderID int64) (num int64, err error) {
var res sql.Result
arg.Tel, _ = encoding.Encrypt(arg.Tel, d.c.Encrypt)
DeliverDetail, err := json.Marshal(arg)
if err != nil {
log.Warn("更新订单详情%d失败", orderID)
}
if res, err = d.db.Exec(c, _updateDetailDelivery, string(DeliverDetail), orderID); err != nil {
log.Warn("更新订单详情%d失败", orderID)
return
}
return res.RowsAffected()
}

View File

@@ -0,0 +1,45 @@
package dao
import (
"fmt"
"testing"
"time"
"go-common/app/service/openplatform/ticket-sales/api/grpc/type"
"go-common/app/service/openplatform/ticket-sales/model"
"net"
. "github.com/smartystreets/goconvey/convey"
)
func TestUpdate(t *testing.T) {
Convey("Get Order", t, func() {
data := &model.OrderDetail{
OrderID: 10000012001970,
Buyer: "TEST",
Tel: "13800138000",
PersonalID: "342921",
ExpressCO: "shunfeng",
ExpressNO: "000",
Remark: "TEST",
DeviceType: 1,
IP: net.ParseIP("::1"),
DeliverDetail: &_type.OrderDeliver{
AddrID: 1,
Name: "张三",
Tel: "13810559189",
Addr: "北京市",
},
Detail: &_type.OrderExtra{
AutoRecvTime: time.Now().Unix(),
DelayRecvTimes: 1,
},
}
// effID, err := d.UpdateDetail(context.TODO(), data)
fmt.Println(data)
// So(err, ShouldBeNil)
})
}

View File

@@ -0,0 +1,70 @@
package dao
import (
"context"
"database/sql"
"fmt"
"net"
time2 "time"
"go-common/app/service/openplatform/ticket-sales/api/grpc/v1"
"go-common/library/log"
"go-common/library/net/metadata"
"go-common/library/time"
)
const (
_addOrderLog = "insert into order_log (uid,ip,order_id,op_data,remark,op_object,op_name,ctime) values(?,?,?,?,?,?,?,?)"
_getOrderLogList = "select id,uid, order_id, ip,op_data,remark,op_object,op_name,ctime,mtime from order_log where order_id = %v order by %v desc limit %v,%v"
_getOrderCnt = "select count(1) from order_log where order_id = ? "
)
//GetOrderLogList 获取订单日志列表
func (d *Dao) GetOrderLogList(c context.Context, OID int64, index int64, size int64, orderBy string) (res []*v1.OrderLog, err error) {
res = make([]*v1.OrderLog, 0)
rows, err := d.db.Query(c, fmt.Sprintf(_getOrderLogList, OID, orderBy, index, size))
if err != nil {
log.Warn("d.GetOrderLogList(%v) d.db.Query() error(%v)", OID, err)
return
}
defer rows.Close()
var ip net.IP
for rows.Next() {
r := &v1.OrderLog{}
if err = rows.Scan(&r.ID, &r.UID, &r.OID, &ip, &r.OpData, &r.Remark, &r.OpObject, &r.OpName, &r.CTime, &r.MTime); err != nil {
return
}
r.IP = ip.String()
res = append(res, r)
}
return
}
//GetOrderLogCnt 获取订单日志条数
func (d *Dao) GetOrderLogCnt(c context.Context, OID int64) (cnt int64, err error) {
err = d.db.QueryRow(c, _getOrderCnt, OID).Scan(&cnt)
if err != nil {
log.Warn("d.GetOrderLogCnt error(%v)", err)
return
}
return
}
//AddOrderLog 添加订单日志
func (d *Dao) AddOrderLog(c context.Context, oi *v1.OrderLog) (cnt int64, err error) {
var res sql.Result
if oi.CTime == 0 {
oi.CTime = time.Time(time2.Now().Unix())
}
var ip []byte
if ip = net.ParseIP(metadata.String(c, metadata.RemoteIP)); ip == nil {
ip = []byte{}
}
if res, err = d.db.Exec(c, _addOrderLog, oi.UID, ip, oi.OID, oi.OpData, oi.Remark, oi.OpObject, oi.OpName, oi.CTime); err != nil {
log.Warn("创建订单日志%d失败", oi.OID)
return
}
return res.LastInsertId()
}

View File

@@ -0,0 +1,47 @@
package dao
import (
"context"
"fmt"
"testing"
"go-common/app/service/openplatform/ticket-sales/api/grpc/v1"
. "github.com/smartystreets/goconvey/convey"
)
func TestListOrderLogs(t *testing.T) {
Convey("ListOrderLogs", t, func() {
data, err := d.GetOrderLogList(context.TODO(), 12222, 0, 10, "ctime")
if err != nil {
fmt.Println(err)
}
So(err, ShouldBeNil)
So(data, ShouldNotBeNil)
})
}
func TestAddOrderLogs(t *testing.T) {
Convey("AddOrderLogs", t, func() {
oi := &v1.OrderLog{}
oi.UID = "wlt"
oi.OpData = "test"
oi.OID = 12222
oi.OpName = "name"
oi.OpObject = "object"
oi.IP = "127.0.0.1"
oi.Remark = "remark"
data, err := d.AddOrderLog(context.TODO(), oi)
if err != nil {
fmt.Println(err)
}
So(err, ShouldBeNil)
So(data, ShouldNotBeNil)
})
}

View File

@@ -0,0 +1,254 @@
package dao
import (
"context"
"fmt"
"net"
"strings"
"testing"
"time"
"go-common/app/service/openplatform/ticket-sales/api/grpc/type"
"go-common/app/service/openplatform/ticket-sales/model"
"go-common/app/service/openplatform/ticket-sales/model/consts"
"github.com/smartystreets/goconvey/convey"
)
var (
oids []int64
)
func TestTxInsertOrders(t *testing.T) {
convey.Convey("OrderID", t, func() {
oids, _ = d.OrderID(context.TODO(), 3)
convey.So(len(oids), convey.ShouldEqual, 3)
})
convey.Convey("TxInsertOrders", t, func() {
o1 := &model.OrderMain{
OrderID: oids[0],
UID: "TEST",
OrderType: 1,
ItemID: 1,
ItemInfo: &_type.OrderItemInfo{
Name: "TEST",
Img: "//img.bilibili.com",
ScreenID: 1,
ScreenName: "TEST",
ScreenType: 1,
DeliverType: 1,
ExpressFee: 1,
VIPExpressFree: 1,
VerID: 1,
},
Count: 1,
TotalMoney: 2,
ExpressFee: 1,
PayMoney: 2,
PayChannel: 1,
PayTime: time.Now().Unix(),
Source: "TEST",
Status: 1,
SubStatus: 1,
RefundStatus: 1,
}
tx, _ := d.BeginTx(context.TODO())
c, _ := d.TxInsertOrders(tx, []*model.OrderMain{o1})
convey.So(c, convey.ShouldEqual, 1)
o2, o3 := &model.OrderMain{}, &model.OrderMain{}
*o2 = *o1
o2.OrderID = oids[1]
o2.ItemID = 2
*o3 = *o1
o3.OrderID = oids[2]
o3.ItemID = 2
o3.RefundStatus = consts.RefundStatusPtRefunded
c, _ = d.TxInsertOrders(tx, []*model.OrderMain{o2, o3})
convey.So(c, convey.ShouldEqual, 2)
tx.Commit()
})
}
func TestOrders(t *testing.T) {
convey.Convey("UserOrders", t, func() {
orders, _ := d.CacheOrders(context.TODO(), &model.OrderMainQuerier{UID: "TEST", OrderID: oids[:1]})
convey.So(len(orders), convey.ShouldEqual, 0)
orders, _ = d.Orders(context.TODO(), &model.OrderMainQuerier{UID: "TEST"})
convey.So(len(orders), convey.ShouldEqual, 3)
for i := 0; i < 10; i++ {
orders, _ = d.CacheOrders(context.TODO(), &model.OrderMainQuerier{UID: "TEST"})
if len(orders) > 0 {
break
}
time.Sleep(100 * time.Millisecond)
}
convey.So(len(orders), convey.ShouldEqual, 3)
for i := 0; i < 10; i++ {
orders, _ = d.CacheOrders(context.TODO(), &model.OrderMainQuerier{UID: "TEST", OrderID: oids[1:2]})
if len(orders) > 0 {
break
}
time.Sleep(100 * time.Millisecond)
}
convey.So(len(orders), convey.ShouldEqual, 1)
orders, _ = d.Orders(context.TODO(), &model.OrderMainQuerier{UID: "TEST", ItemID: 2, Status: []int16{1}})
convey.So(len(orders), convey.ShouldEqual, 2)
})
}
func TestOrderCount(t *testing.T) {
convey.Convey("OrderCount", t, func() {
cnt, _ := d.CacheOrderCount(context.TODO(), &model.OrderMainQuerier{UID: "TEST"})
convey.So(cnt, convey.ShouldEqual, 0)
cnt, _ = d.OrderCount(context.TODO(), &model.OrderMainQuerier{UID: "TEST"})
convey.So(cnt, convey.ShouldEqual, 3)
for i := 0; i < 10; i++ {
cnt, _ = d.CacheOrderCount(context.TODO(), &model.OrderMainQuerier{UID: "TEST"})
if cnt > 0 {
break
}
time.Sleep(100 * time.Millisecond)
}
convey.So(cnt, convey.ShouldEqual, 3)
})
}
func TestTxInsertOrderDetails(t *testing.T) {
convey.Convey("TxInsertOrderDetails", t, func() {
dt1 := &model.OrderDetail{
OrderID: oids[0],
Buyer: "TEST",
Tel: "13800138000",
PersonalID: "342921",
ExpressCO: "shunfeng",
ExpressNO: "000",
Remark: "TEST",
DeviceType: 1,
IP: net.ParseIP("127.0.0.1"),
DeliverDetail: &_type.OrderDeliver{
AddrID: 1,
Name: "张三",
Tel: "13810559189",
Addr: "北京市",
},
Detail: &_type.OrderExtra{
AutoRecvTime: time.Now().Unix(),
DelayRecvTimes: 1,
},
}
dt2 := &model.OrderDetail{}
*dt2 = *dt1
dt2.OrderID = oids[1]
tx, _ := d.BeginTx(context.TODO())
c, _ := d.TxInsertOrderDetails(tx, []*model.OrderDetail{dt1, dt2})
tx.Commit()
convey.So(c, convey.ShouldEqual, 2)
})
}
func TestOrderDetails(t *testing.T) {
convey.Convey("OrderDetails", t, func() {
dts, _ := d.CacheOrderDetails(context.TODO(), oids)
convey.So(len(dts), convey.ShouldEqual, 0)
dts, _ = d.OrderDetails(context.TODO(), oids)
convey.So(len(dts), convey.ShouldEqual, 2)
for i := 0; i < 10; i++ {
dts, _ = d.CacheOrderDetails(context.TODO(), oids)
if len(dts) > 0 {
break
}
time.Sleep(100 * time.Millisecond)
}
convey.So(len(dts), convey.ShouldEqual, 3)
dts, _ = d.OrderDetails(context.TODO(), oids)
convey.So(len(dts), convey.ShouldEqual, 2)
})
}
func TestTxInsertOrderSKUs(t *testing.T) {
convey.Convey("TxInsertOrderSKUs", t, func() {
sku1 := &model.OrderSKU{
OrderID: oids[0],
SKUID: 1,
Count: 1,
OriginPrice: 1,
Price: 1,
TicketType: 1,
Discounts: &_type.OrderSKUDiscounts{
Platform: map[int32]int64{1: 1},
},
}
sku2 := &model.OrderSKU{
OrderID: oids[0],
SKUID: 2,
Count: 1,
OriginPrice: 2,
Price: 2,
TicketType: 1,
}
tx, _ := d.BeginTx(context.TODO())
cnt, _ := d.TxInsertOrderSKUs(tx, []*model.OrderSKU{sku1, sku2})
tx.Commit()
convey.So(cnt, convey.ShouldEqual, 2)
})
}
func TestOrderSKUs(t *testing.T) {
convey.Convey("OrderSKUs", t, func() {
skus, _ := d.CacheOrderSKUs(context.TODO(), oids)
convey.So(len(skus), convey.ShouldEqual, 0)
skus, _ = d.OrderSKUs(context.TODO(), oids)
convey.So(len(skus), convey.ShouldEqual, 1)
for i := 0; i < 10; i++ {
skus, _ = d.CacheOrderSKUs(context.TODO(), oids)
if len(skus) > 0 {
break
}
time.Sleep(100 * time.Millisecond)
}
convey.So(len(skus), convey.ShouldEqual, 3)
skus, _ = d.OrderSKUs(context.TODO(), oids)
convey.So(len(skus), convey.ShouldEqual, 1)
})
}
func TestOrderPayCharges(t *testing.T) {
convey.Convey("OrderPayCharges", t, func() {
var oid int64 = 1519626683221383
chs, _ := d.OrderPayCharges(context.TODO(), []int64{oid})
convey.So(chs, convey.ShouldContainKey, oid)
})
}
func TestGetBoughtCount(t *testing.T) {
convey.Convey("GetBoughtCount", t, func() {
c, _ := d.RawBoughtCount(context.TODO(), "TEST", 2, nil)
convey.So(c, convey.ShouldEqual, 2)
c, _ = d.RawBoughtCount(context.TODO(), "TEST", 1, []int64{1})
convey.So(c, convey.ShouldEqual, 1)
})
}
//删除测试数据
func TestDelOrders(t *testing.T) {
tx, _ := d.BeginTx(ctx)
tables := []string{"order_main", "order_detail", "order_sku", "order_pay_charge", "ticket"}
w := strings.Repeat(",?", len(oids))[1:]
a := make([]interface{}, len(oids))
for k, v := range oids {
a[k] = v
}
for _, t := range tables {
f := "order_id"
if t == "ticket" {
f = "oid"
}
_, err := tx.Exec(fmt.Sprintf("DELETE FROM `%s` WHERE %s IN (%s)", t, f, w), a...)
if err != nil {
tx.Rollback()
return
}
}
tx.Commit()
d.DelCacheOrders(context.TODO(), &model.OrderMainQuerier{UID: "TEST"})
}

View File

@@ -0,0 +1,156 @@
package dao
import (
"context"
"database/sql"
"encoding/json"
"fmt"
"go-common/app/service/openplatform/ticket-sales/model"
"go-common/library/cache/redis"
xsql "go-common/library/database/sql"
"go-common/library/log"
)
const (
//insert
_createPromo = "insert into promotion (promo_id,type,item_id,sku_id,extra,expire_sec,sku_count,amount,buyer_count,begin_time,end_time,status,priv_sku_id,usable_coupons) values(?,?,?,?,?,?,?,?,?,?,?,1,?,?)"
//update
_operatePromo = "update promotion set status = ? where promo_id = ? and status= ?"
_updatePromoBuyerCount = "update promotion set buyer_count = buyer_count + ? where promo_id ="
_updatePromo = "update promotion set amount = %v,expire_sec = %v,sku_count = %v,begin_time = %v,end_time = %v,priv_sku_id = %v,usable_coupons = '%v' where promo_id = %v"
//select
_promo = "select promo_id,type,item_id,sku_id,extra,expire_sec,sku_count,amount,buyer_count,begin_time,end_time,status,ctime,mtime,priv_sku_id,usable_coupons from promotion where promo_id = ?"
_selctPromoBySKU = "select count(*) as num from promotion where end_time >= ? and begin_time <= ? and sku_id = ? and status = 1"
_getPromoList = "select promo_id,type,item_id,sku_id,extra,expire_sec,sku_count,amount,buyer_count,begin_time,end_time,status,ctime,mtime,priv_sku_id,usable_coupons from promotion ? order by mtime desc limit ?,?"
)
//keyPromo 获取活动缓存key
func keyPromo(promoID int64) string {
return fmt.Sprintf(model.CacheKeyPromo, promoID)
}
//RawPromo get promo info from db
func (d *Dao) RawPromo(c context.Context, promoID int64) (res *model.Promotion, err error) {
res = new(model.Promotion)
row := d.db.QueryRow(c, _promo, promoID)
if err = row.Scan(&res.PromoID, &res.Type, &res.ItemID, &res.SKUID, &res.Extra, &res.ExpireSec, &res.SKUCount, &res.Amount, &res.BuyerCount, &res.BeginTime, &res.EndTime, &res.Status, &res.Ctime, &res.Mtime, &res.PrivSKUID, &res.UsableCoupons); err != nil {
if err == sql.ErrNoRows {
err = nil
res = nil
}
return
}
return
}
//CachePromo get promo info from cache
func (d *Dao) CachePromo(c context.Context, promoID int64) (res *model.Promotion, err error) {
var (
data []byte
key = keyPromo(promoID)
)
conn := d.redis.Get(c)
defer conn.Close()
if data, err = redis.Bytes(conn.Do("GET", key)); err != nil {
if err == redis.ErrNil {
err = nil
}
return
}
json.Unmarshal(data, &res)
return
}
//AddCachePromo add promo info into cache
func (d *Dao) AddCachePromo(c context.Context, promoID int64, promo *model.Promotion) (err error) {
var (
data []byte
key = keyPromo(promoID)
)
conn := d.redis.Get(c)
defer conn.Close()
if data, err = json.Marshal(promo); err != nil {
return
}
conn.Do("SET", key, data, "EX", model.RedisExpirePromo)
return
}
//DelCachePromo delete promo cache
func (d *Dao) DelCachePromo(c context.Context, promoID int64) {
var key = keyPromo(promoID)
conn := d.redis.Get(c)
defer conn.Close()
conn.Do("DEL", key)
}
//CreatePromo create user promo order
func (d *Dao) CreatePromo(c context.Context, promo *model.Promotion) (id int64, err error) {
if _, err = d.db.Exec(c, _createPromo, promo.PromoID, promo.Type, promo.ItemID, promo.SKUID, promo.Extra, promo.ExpireSec, promo.SKUCount, promo.Amount, promo.BuyerCount, promo.BeginTime, promo.EndTime, promo.PrivSKUID, promo.UsableCoupons); err != nil {
log.Warn("创建拼团活动失败:%d", promo.PromoID)
return
}
id = promo.PromoID
return
}
//OperatePromo 修改拼团活动状态
func (d *Dao) OperatePromo(c context.Context, promoID int64, fromStatus int16, toStatus int16) (num int64, err error) {
var res sql.Result
if res, err = d.db.Exec(c, _operatePromo, toStatus, promoID, fromStatus); err != nil {
log.Warn("更新拼团状态失败:%d", promoID)
return
}
num, err = res.RowsAffected()
return
}
//HasPromoOfSKU 判断skuID是否有正在上架的拼团活动
func (d *Dao) HasPromoOfSKU(c context.Context, skuID int64, beginTime int64, endTime int64) (num int64, err error) {
var res *xsql.Row
if res = d.db.QueryRow(c, _selctPromoBySKU, skuID, beginTime, endTime); err != nil {
return
}
err = res.Scan(&num)
return
}
//GetPromoList 获取拼团列表
func (d *Dao) GetPromoList(c context.Context, where string, index int64, size int64) (res []*model.Promotion, err error) {
var rows *xsql.Rows
if rows, err = d.db.Query(c, _getPromoList, where, index, size); err != nil {
return
}
defer rows.Close()
for rows.Next() {
r := new(model.Promotion)
if err = rows.Scan(&r.PromoID, &r.Type, &r.ItemID, &r.SKUID, &r.Extra, &r.ExpireSec, &r.SKUCount, &r.Amount, &r.BuyerCount, &r.BeginTime, &r.EndTime, &r.Status, &r.Ctime, &r.Mtime, &r.PrivSKUID, &r.UsableCoupons); err != nil {
return
}
res = append(res, r)
}
return
}
//TxUpdatePromoBuyerCount 更新活动的购买人数
func (d *Dao) TxUpdatePromoBuyerCount(c context.Context, tx *xsql.Tx, promoID int64, count int64) (number int64, err error) {
var res sql.Result
if res, err = tx.Exec(_updatePromoBuyerCount, count, promoID); err != nil {
return
}
return res.RowsAffected()
}
//UpdatePromo 更新拼团
func (d *Dao) UpdatePromo(c context.Context, arg *model.Promotion) (num int64, err error) {
var res sql.Result
if res, err = d.db.Exec(c, fmt.Sprintf(_updatePromo, arg.Amount, arg.ExpireSec, arg.SKUCount, arg.BeginTime, arg.EndTime, arg.PrivSKUID, arg.UsableCoupons, arg.PromoID)); err != nil {
log.Warn("更新拼团活动%d失败", arg.PromoID)
return
}
return res.RowsAffected()
}

View File

@@ -0,0 +1,148 @@
package dao
import (
"context"
"database/sql"
"encoding/json"
"fmt"
"go-common/app/service/openplatform/ticket-sales/model"
"go-common/app/service/openplatform/ticket-sales/model/consts"
"go-common/library/cache/redis"
xsql "go-common/library/database/sql"
xtime "time"
)
const (
_getGroupByID = "select promo_id,group_id,uid,order_count,status,expire_at,ctime,mtime from promotion_group where group_id = ?"
_getUserNotExpiredGroup = "select promo_id,group_id,uid,order_count,status,expire_at,ctime,mtime from promotion_group where promo_id = ? and uid = ? and expire_at >= ? and status = ?"
_updateGroupOrderCount = "update promotion_group set order_count = order_count + ? where group_id = ? and status = ? and order_count < ? and expire_at > ?"
_updateGroupStatus = "update promotion_group set status = ? where group_id = ? and status = ?"
_updateGroupStatusAndOrderCount = "update promotion_group set status = ?,order_count = order_count + ? where group_id = ? and status = ?"
_insertGroupOrder = "insert into promotion_group (promo_id,group_id,uid,order_count,status,expire_at) values (?,?,?,?,?,?)"
)
//keyPromoGroup 获取拼团缓存key
func keyPromoGroup(groupID int64) string {
return fmt.Sprintf(model.CacheKeyPromoGroup, groupID)
}
//RawPromoGroup 根据id获取拼团信息
func (d *Dao) RawPromoGroup(c context.Context, groupID int64) (res *model.PromotionGroup, err error) {
res = new(model.PromotionGroup)
row := d.db.QueryRow(c, _getGroupByID, groupID)
if err = row.Scan(&res.PromoID, &res.GroupID, &res.UID, &res.OrderCount, &res.Status, &res.ExpireAt, &res.Ctime, &res.Mtime); err != nil {
if err == sql.ErrNoRows {
err = nil
res = nil
}
return
}
return
}
//AddPromoGroup add promo group into db
func (d *Dao) AddPromoGroup(c context.Context, promoID int64, groupID int64, uid int64, orderCount int64, status int16, expireAt int64) (id int64, err error) {
var res sql.Result
if res, err = d.db.Exec(c, _insertGroupOrder, promoID, groupID, uid, orderCount, status, expireAt); err != nil {
return
}
return res.LastInsertId()
}
//TxAddPromoGroup add promo group into db
func (d *Dao) TxAddPromoGroup(c context.Context, tx *xsql.Tx, promoID int64, groupID int64, uid int64, orderCount int64, status int16, expireAt int64) (id int64, err error) {
var res sql.Result
if res, err = tx.Exec(_insertGroupOrder, promoID, groupID, uid, orderCount, status, expireAt); err != nil {
return
}
return res.LastInsertId()
}
//CachePromoGroup get promo group info from cache
func (d *Dao) CachePromoGroup(c context.Context, groupID int64) (res *model.PromotionGroup, err error) {
var (
data []byte
key = keyPromoGroup(groupID)
)
conn := d.redis.Get(c)
defer conn.Close()
if data, err = redis.Bytes(conn.Do("GET", key)); err != nil {
if err == redis.ErrNil {
err = nil
}
return
}
json.Unmarshal(data, &res)
return
}
//AddCachePromoGroup add promo group info into cache
func (d *Dao) AddCachePromoGroup(c context.Context, groupID int64, group *model.PromotionGroup) (err error) {
var (
data []byte
key = keyPromoGroup(groupID)
)
conn := d.redis.Get(c)
defer conn.Close()
if data, err = json.Marshal(group); err != nil {
return
}
conn.Do("SET", key, data, "EX", model.RedisExpirePromoGroup)
return
}
//DelCachePromoGroup delete promo group cache
func (d *Dao) DelCachePromoGroup(c context.Context, groupID int64) {
var key = keyPromo(groupID)
conn := d.redis.Get(c)
defer conn.Close()
conn.Do("DEL", key)
}
//GetUserGroupDoing 获取用户正在进行中的拼团信息
func (d *Dao) GetUserGroupDoing(c context.Context, promoID int64, uid int64, status int16) (res *model.PromotionGroup, err error) {
var (
currentTime = xtime.Now().Unix()
)
res = new(model.PromotionGroup)
row := d.db.QueryRow(c, _getUserNotExpiredGroup, promoID, uid, currentTime, status)
if err = row.Scan(&res.PromoID, &res.GroupID, &res.UID, &res.OrderCount, &res.Status, &res.ExpireAt, &res.Ctime, &res.Mtime); err != nil {
return
}
return
}
//TxUpdateGroupOrderCount 更新拼团的人数
func (d *Dao) TxUpdateGroupOrderCount(c context.Context, tx *xsql.Tx, step int64, groupID int64, skuCount int64) (number int64, err error) {
var (
currentTime = xtime.Now().Unix()
res sql.Result
)
if res, err = tx.Exec(_updateGroupOrderCount, step, groupID, consts.GroupDoing, skuCount, currentTime); err != nil {
return
}
return res.RowsAffected()
}
//TxUpdateGroupStatus 更新拼团状态
func (d *Dao) TxUpdateGroupStatus(c context.Context, tx *xsql.Tx, groupID int64, oldStatus int16, newStatus int16) (number int64, err error) {
var res sql.Result
if res, err = tx.Exec(_updateGroupStatus, newStatus, groupID, oldStatus); err != nil {
return
}
return res.RowsAffected()
}
//UpdateGroupStatusAndOrderCount 更新拼团状态和人数
func (d *Dao) UpdateGroupStatusAndOrderCount(c context.Context, groupID int64, step int64, oldStatus int16, newStatus int16) (number int64, err error) {
var res sql.Result
if res, err = d.db.Exec(c, _updateGroupStatusAndOrderCount, newStatus, step, groupID, oldStatus); err != nil {
return
}
return res.RowsAffected()
}

View File

@@ -0,0 +1,62 @@
package dao
import (
"context"
"go-common/app/service/openplatform/ticket-sales/model"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func TestDao_AddPromoGroup(t *testing.T) {
Convey("AddPromoGroup", t, func() {
res, err := d.AddPromoGroup(context.TODO(), 1, 1, 1, 1, 1, 1)
So(err, ShouldBeNil)
t.Logf("res:%v", res)
})
}
func TestDao_RawPromoGroup(t *testing.T) {
Convey("RawPromoGroup", t, func() {
res, err := d.PromoGroup(context.TODO(), 1)
So(err, ShouldBeNil)
t.Logf("res:%v", res)
})
}
func TestDao_CachePromoGroup(t *testing.T) {
Convey("CachePromoGroup", t, func() {
res, err := d.CachePromoGroup(context.TODO(), 1)
So(err, ShouldBeNil)
t.Logf("res:%v", res)
})
}
func TestDao_AddCachePromoGroup(t *testing.T) {
Convey("AddCachePromoGroup", t, func() {
err := d.AddCachePromoGroup(context.TODO(), 1, &model.PromotionGroup{PromoID: 1})
So(err, ShouldBeNil)
})
}
func TestDao_DelCacheGroup(t *testing.T) {
Convey("DelCacheGroup", t, func() {
d.DelCachePromoGroup(context.TODO(), 1)
})
}
func TestDao_GetUserGroupDoing(t *testing.T) {
Convey("GetUserGroupDoing", t, func() {
res, err := d.GetUserGroupDoing(context.TODO(), 1, 1, 1)
So(err, ShouldBeNil)
t.Logf("res:%v", res)
})
}
func TestDao_UpdateGroupStatusAndOrderCount(t *testing.T) {
Convey("UpdateGroupStatusAndOrderCount", t, func() {
res, err := d.UpdateGroupStatusAndOrderCount(context.TODO(), 1, 1, 1, 1)
So(err, ShouldBeNil)
t.Logf("res:%v", res)
})
}

View File

@@ -0,0 +1,251 @@
package dao
import (
"context"
"database/sql"
"encoding/json"
"fmt"
"go-common/app/service/openplatform/ticket-sales/model"
"go-common/app/service/openplatform/ticket-sales/model/consts"
"go-common/library/cache/redis"
xsql "go-common/library/database/sql"
"go-common/library/log"
xtime "time"
)
const (
_addPromoOrder = "insert into promotion_order (promo_id,group_id,order_id,is_master,uid,status,ctime,sku_id) values(?,?,?,?,?,?,?,?)"
_updatePromoOrderStatus = "update promotion_order set status = ? where order_id = ?"
_updatePromoOrderGroupIDAndStatus = "update promotion_order set group_id = ?,status = ? where order_id = ?"
_promoOrderByStatus = "select promo_id,group_id,order_id,is_master,uid,status,ctime,mtime,sku_id from promotion_order where promo_id = ? and group_id = ? and uid = ? and status = ?"
_promoOrderDoing = "select promo_id,group_id,order_id,is_master,uid,status,ctime,mtime,sku_id from promotion_order where promo_id = ? and group_id = ? and uid = ? and status in (?,?)"
_groupOrdersByStatus = "select promo_id,group_id,order_id,is_master,uid,status,ctime,mtime,sku_id from promotion_order where group_id = ? and status = ?"
_promoOrdersByGroupID = "select promo_id,group_id,order_id,is_master,uid,status,ctime,mtime,sku_id from promotion_order where group_id = ? and status in (?,?,?)"
_promoOrder = "select promo_id,group_id,order_id,is_master,uid,status,ctime,mtime,sku_id from promotion_order where order_id = ?"
)
//keyPromoOrder 获取拼团订单缓存key
func keyPromoOrder(orderID int64) string {
return fmt.Sprintf(model.CacheKeyPromoOrder, orderID)
}
//RawPromoOrder get promo order info from db
func (d *Dao) RawPromoOrder(c context.Context, orderID int64) (res *model.PromotionOrder, err error) {
res = new(model.PromotionOrder)
row := d.db.QueryRow(c, _promoOrder, orderID)
if err = row.Scan(&res.PromoID, &res.GroupID, &res.OrderID, &res.IsMaster, &res.UID, &res.Status, &res.Ctime, &res.Mtime, &res.SKUID); err != nil {
if err == sql.ErrNoRows {
err = nil
res = nil
}
return
}
return
}
//CachePromoOrder get promo order info from cache
func (d *Dao) CachePromoOrder(c context.Context, orderID int64) (res *model.PromotionOrder, err error) {
var (
data []byte
key = keyPromoOrder(orderID)
)
conn := d.redis.Get(c)
defer conn.Close()
if data, err = redis.Bytes(conn.Do("GET", key)); err != nil {
if err == redis.ErrNil {
err = nil
}
return
}
json.Unmarshal(data, &res)
return
}
//AddCachePromoOrder add promo order info into cache
func (d *Dao) AddCachePromoOrder(c context.Context, orderID int64, promoOrder *model.PromotionOrder) (err error) {
var (
data []byte
key = keyPromoOrder(orderID)
)
conn := d.redis.Get(c)
defer conn.Close()
if data, err = json.Marshal(promoOrder); err != nil {
return
}
conn.Do("SET", key, data, "EX", model.RedisExpirePromoOrder)
return
}
//DelCachePromoOrder delete promo order cache
func (d *Dao) DelCachePromoOrder(c context.Context, orderID int64) {
var key = keyPromoOrder(orderID)
conn := d.redis.Get(c)
defer conn.Close()
conn.Do("DEL", key)
}
//keyPromoOrders 获取拼团团订单缓存key
func keyPromoOrders(groupID int64) string {
return fmt.Sprintf(model.CacheKeyPromoOrders, groupID)
}
//RawPromoOrders get promo orders info from db
func (d *Dao) RawPromoOrders(c context.Context, groupID int64) (res []*model.PromotionOrder, err error) {
var rows *xsql.Rows
if rows, err = d.db.Query(c, _promoOrdersByGroupID, groupID, consts.PromoOrderUnpaid, consts.PromoOrderPaid, consts.PromoOrderRefund); err != nil {
return
}
defer rows.Close()
for rows.Next() {
r := new(model.PromotionOrder)
if err = rows.Scan(&r.PromoID, &r.GroupID, &r.OrderID, &r.IsMaster, &r.UID, &r.Status, &r.Ctime, &r.Mtime, &r.SKUID); err != nil {
return
}
res = append(res, r)
}
return
}
//CachePromoOrders get promo orders info from cache
func (d *Dao) CachePromoOrders(c context.Context, groupID int64) (res []*model.PromotionOrder, err error) {
var (
data []byte
key = keyPromoOrders(groupID)
)
conn := d.redis.Get(c)
defer conn.Close()
if data, err = redis.Bytes(conn.Do("GET", key)); err != nil {
if err == redis.ErrNil {
err = nil
}
return
}
json.Unmarshal(data, &res)
return
}
//AddCachePromoOrders add promo orders info into cache
func (d *Dao) AddCachePromoOrders(c context.Context, groupID int64, promoOrders []*model.PromotionOrder) (err error) {
var (
data []byte
key = keyPromoOrders(groupID)
)
conn := d.redis.Get(c)
defer conn.Close()
if data, err = json.Marshal(promoOrders); err != nil {
return
}
conn.Do("SET", key, data, "EX", model.RedisExpirePromoOrders)
return
}
//DelCachePromoOrders delete promo orders cache
func (d *Dao) DelCachePromoOrders(c context.Context, groupID int64) {
var key = keyPromoOrders(groupID)
conn := d.redis.Get(c)
defer conn.Close()
conn.Do("DEL", key)
}
//PromoOrderByStatus get user promo order by status
func (d *Dao) PromoOrderByStatus(c context.Context, promoID int64, groupID int64, uid int64, status int16) (res *model.PromotionOrder, err error) {
res = new(model.PromotionOrder)
row := d.db.QueryRow(c, _promoOrderByStatus, promoID, groupID, uid, status)
if err = row.Scan(&res.PromoID, &res.GroupID, &res.OrderID, &res.IsMaster, &res.UID, &res.Status, &res.Ctime, &res.Mtime, &res.SKUID); err != nil {
return
}
return
}
//PromoOrderDoing get user promo order where status in unpaid and paid
func (d *Dao) PromoOrderDoing(c context.Context, promoID int64, groupID int64, uid int64) (res *model.PromotionOrder, err error) {
res = new(model.PromotionOrder)
row := d.db.QueryRow(c, _promoOrderDoing, promoID, groupID, uid, consts.PromoOrderUnpaid, consts.PromoOrderPaid)
if err = row.Scan(&res.PromoID, &res.GroupID, &res.OrderID, &res.IsMaster, &res.UID, &res.Status, &res.Ctime, &res.Mtime, &res.SKUID); err != nil {
return
}
return
}
//AddPromoOrder create user promo order
func (d *Dao) AddPromoOrder(c context.Context, promoID int64, groupID int64, orderID int64, isMaster int16, uid int64, status int16, skuID int64, ctime int64) (id int64, err error) {
var (
res sql.Result
ctimeDate = xtime.Unix(ctime, 0)
)
if res, err = d.db.Exec(c, _addPromoOrder, promoID, groupID, orderID, isMaster, uid, status, ctimeDate, skuID); err != nil {
log.Warn("创建活动订单%d失败", orderID)
return
}
return res.LastInsertId()
}
//TxAddPromoOrder create user promo order
func (d *Dao) TxAddPromoOrder(c context.Context, tx *xsql.Tx, promoID int64, groupID int64, orderID int64, isMaster int16, uid int64, status int16, skuID int64, ctime int64) (id int64, err error) {
var (
res sql.Result
ctimeDate = xtime.Unix(ctime, 0)
)
if res, err = tx.Exec(_addPromoOrder, promoID, groupID, orderID, isMaster, uid, status, ctimeDate, skuID); err != nil {
log.Warn("创建活动订单%d失败", orderID)
return
}
return res.LastInsertId()
}
//UpdatePromoOrderStatus update promo order status
func (d *Dao) UpdatePromoOrderStatus(c context.Context, orderID int64, status int16) (number int64, err error) {
var (
res sql.Result
)
if res, err = d.db.Exec(c, _updatePromoOrderStatus, status, orderID); err != nil {
log.Warn("更新活动订单%d失败", orderID)
return
}
return res.RowsAffected()
}
//TxUpdatePromoOrderStatus update promo order status
func (d *Dao) TxUpdatePromoOrderStatus(c context.Context, tx *xsql.Tx, orderID int64, status int16) (number int64, err error) {
var res sql.Result
if res, err = tx.Exec(_updatePromoOrderStatus, status, orderID); err != nil {
log.Warn("更新活动订单%d失败", orderID)
return
}
return res.RowsAffected()
}
//TxUpdatePromoOrderGroupIDAndStatus update promo order groupid and status
func (d *Dao) TxUpdatePromoOrderGroupIDAndStatus(c context.Context, tx *xsql.Tx, orderID int64, groupID int64, status int16) (number int64, err error) {
var res sql.Result
if res, err = tx.Exec(_updatePromoOrderGroupIDAndStatus, groupID, status, orderID); err != nil {
log.Warn("更新活动订单%d失败", orderID)
return
}
return res.RowsAffected()
}
//GroupOrdersByStatus 根据groupid和status获取活动订单
func (d *Dao) GroupOrdersByStatus(c context.Context, groupID int64, status int16) (res []*model.PromotionOrder, err error) {
var rows *xsql.Rows
if rows, err = d.db.Query(c, _groupOrdersByStatus, groupID, status); err != nil {
return
}
defer rows.Close()
for rows.Next() {
temp := new(model.PromotionOrder)
if err = rows.Scan(&temp.PromoID, &temp.GroupID, &temp.OrderID, &temp.IsMaster, &temp.UID, &temp.Status, &temp.Ctime, &temp.Mtime, &temp.SKUID); err != nil {
return
}
res = append(res, temp)
}
return
}

View File

@@ -0,0 +1,72 @@
package dao
import (
"context"
"go-common/app/service/openplatform/ticket-sales/model"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func TestDao_PromoOrder(t *testing.T) {
Convey("PromoOrder", t, func() {
res, err := d.PromoOrder(context.TODO(), 1)
So(err, ShouldBeNil)
t.Logf("res:%v", res)
})
}
func TestDao_CachePromoOrder(t *testing.T) {
Convey("CachePromoOrder", t, func() {
res, err := d.CachePromoOrder(context.TODO(), 1)
So(err, ShouldBeNil)
t.Logf("res:%v", res)
})
}
func TestDao_AddCachePromoOrder(t *testing.T) {
Convey("AddCachePromoOrder", t, func() {
err := d.AddCachePromoOrder(context.TODO(), 1, &model.PromotionOrder{PromoID: 1})
So(err, ShouldBeNil)
})
}
func TestDao_PromoOrderByStatus(t *testing.T) {
Convey("PromoOrderByStatus", t, func() {
res, err := d.PromoOrderByStatus(context.TODO(), 1, 1, 1, 1)
So(err, ShouldBeNil)
t.Logf("res:%v", res)
})
}
func TestDao_PromoOrderDoing(t *testing.T) {
Convey("PromoOrderDoing", t, func() {
res, err := d.PromoOrderDoing(context.TODO(), 1, 1, 1)
So(err, ShouldBeNil)
t.Logf("res:%v", res)
})
}
func TestDao_AddPromoOrder(t *testing.T) {
Convey("AddPromoOrder", t, func() {
res, err := d.AddPromoOrder(context.TODO(), 1, 1, 1, 1, 1, 1, 1, 1)
So(err, ShouldBeNil)
t.Logf("res:%v", res)
})
}
func TestDao_UpdatePromoOrderStatus(t *testing.T) {
Convey("UpdatePromoOrderStatus", t, func() {
res, err := d.UpdatePromoOrderStatus(context.TODO(), 1, 1)
So(err, ShouldBeNil)
t.Logf("res:%v", res)
})
}
func TestDao_GroupOrdersByStatus(t *testing.T) {
Convey("GroupOrdersByStatus", t, func() {
res, err := d.GroupOrdersByStatus(context.TODO(), 1, 1)
So(err, ShouldBeNil)
t.Logf("res:%v", res)
})
}

View File

@@ -0,0 +1,46 @@
package dao
import (
"context"
"go-common/app/service/openplatform/ticket-sales/model"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func TestDao_RawPromo(t *testing.T) {
Convey("RawPromo", t, func() {
res, err := d.RawPromo(context.TODO(), 1)
So(err, ShouldBeNil)
t.Logf("res:%v", res)
})
}
func TestDao_CachePromo(t *testing.T) {
Convey("CachePromo", t, func() {
res, err := d.CachePromo(context.TODO(), 1)
So(err, ShouldBeNil)
t.Logf("res:%v", res)
})
}
func TestDao_AddCachePromo(t *testing.T) {
Convey("AddCachePromo", t, func() {
err := d.AddCachePromo(context.TODO(), 1, &model.Promotion{PromoID: 1})
So(err, ShouldBeNil)
})
}
func TestDao_DelCachePromo(t *testing.T) {
Convey("DelCachePromo", t, func() {
d.DelCachePromo(context.TODO(), 1)
})
}
func TestDao_CreatePromo(t *testing.T) {
Convey("CreatePromo", t, func() {
res, err := d.CreatePromo(context.TODO(), &model.Promotion{PromoID: 1})
So(err, ShouldBeNil)
t.Logf("res:%v", res)
})
}

View File

@@ -0,0 +1,74 @@
package dao
import (
"context"
"fmt"
"go-common/library/log"
)
// RedisDecr 指定 key 减去 num
func (d *Dao) RedisDecr(c context.Context, key string, num int) (err error) {
conn := d.redis.Get(c)
defer conn.Close()
if num == 1 {
_, err = conn.Do("DECR", key)
} else {
_, err = conn.Do("DERCBY", key, num)
}
if err != nil {
log.Error("d.RedisDecr(%s, %d) error(%v)", key, num, err)
}
return
}
// RedisDecrExist 当 key 存在时 给 key 减去指定数值 key 不存在时不做操作
func (d *Dao) RedisDecrExist(c context.Context, key string, num int64) (err error) {
conn := d.redis.Get(c)
defer conn.Close()
lua := `if redis.call("EXISTS",KEYS[1])==1 then return redis.call("%s",KEYS[1]%s);else return nil;end`
if num == 1 {
log.Info(fmt.Sprintf(fmt.Sprintf(lua, "DECR", "")+"%d %s", 1, key))
_, err = conn.Do("EVAL", fmt.Sprintf(lua, "DECR", ""), 1, key)
} else {
log.Info(fmt.Sprintf(fmt.Sprintf(lua, "DECRBY", ",ARGV[1]")+"%d %s %d"), 1, key, num)
_, err = conn.Do("EVAL", fmt.Sprintf(lua, "DECRBY", ",ARGV[1]"), 1, key, num)
}
if err != nil {
log.Error("d.RedisDecrExist(%s, %d) error(%v)", key, num, err)
}
return
}
// RedisDel del keys
func (d *Dao) RedisDel(c context.Context, key ...interface{}) (err error) {
if len(key) == 0 {
return
}
conn := d.redis.Get(c)
defer conn.Close()
if _, err = conn.Do("DEL", key...); err != nil {
log.Error("d.RedisDel(%v) error(%v)", key, err)
}
return
}
// RedisSetnx setnx
func (d *Dao) RedisSetnx(c context.Context, key string, val interface{}, ttl int64) (err error) {
conn := d.redis.Get(c)
defer conn.Close()
if ttl > 0 {
lua := `if redis.call("SETNX",KEYS[1],ARGV[1])==1 then return redis.call("EXPIRE",KEYS[1],ARGV[2]);else return 0;end'`
_, err = conn.Do("EVAL", lua, 1, key, val, ttl)
} else {
_, err = conn.Do("SETNX", key, val)
}
if err != nil {
log.Error("d.RedisSetnx(%s, %v, %d) error(%v)", key, val, ttl, err)
}
return
}

View File

@@ -0,0 +1,535 @@
package dao
import (
"context"
"database/sql"
"encoding/json"
"fmt"
"strings"
"time"
"go-common/app/service/openplatform/ticket-sales/model"
"go-common/library/cache/redis"
xsql "go-common/library/database/sql"
"go-common/library/log"
"go-common/library/xstr"
)
const (
_lockStockSQL = "UPDATE sku_stock SET stock=stock-?, locked_stock=locked_stock+? WHERE sku_id=? AND stock>=?"
_unlockStockSQL = "UPDATE sku_stock SET stock=stock+?, locked_stock=locked_stock-? WHERE sku_id=? AND stock<=total_stock-? AND locked_stock>=?"
_decrStockSQL = "UPDATE sku_stock SET stock=stock-? WHERE sku_id=? AND stock>=?"
_incrStockSQL = "UPDATE sku_stock SET stock=stock+? WHERE sku_id=? AND stock<=total_stock-?"
_decrStockLockedSQL = "UPDATE sku_stock SET locked_stock=locked_stock-? WHERE sku_id=? AND total_stock>=?"
_getStockBySkuIDSQL = "SELECT sku_id, parent_sku_id, item_id, specs, total_stock, stock, locked_stock, sk_alert, ctime, mtime FROM sku_stock WHERE sku_id=? LIMIT 1"
_getStocksBySkuIDSQL = "SELECT sku_id, parent_sku_id, item_id, specs, total_stock, stock, locked_stock, sk_alert, ctime, mtime FROM sku_stock WHERE sku_id IN (%s)"
_getStockByItemIDSQL = "SELECT sku_id, parent_sku_id, item_id, specs, total_stock, stock, locked_stock, sk_alert, ctime, mtime FROM sku_stock WHERE item_id=?"
_getStockBySpecsSQL = "SELECT sku_id, parent_sku_id, item_id, specs, total_stock, stock, locked_stock, sk_alert, ctime, mtime FROM sku_stock WHERE item_id=? AND specs=? LIMIT 1"
_insertStockSQL = "INSERT INTO sku_stock (sku_id, parent_sku_id, item_id, specs, total_stock, stock, locked_stock, sk_alert) VALUES %s"
_resetStockSQL = "UPDATE sku_stock SET stock=stock+(?-total_stock),total_stock=?, sk_alert=? WHERE sku_id=? AND stock>=(total_stock-?)"
_getStockBySkuID = "SELECT sku_id, stock, locked_stock FROM sku_stock WHERE sku_id IN (%s)"
_insertSKUStockLog = "INSERT INTO sku_stock_log (sku_id, op_type, src_id, stock) VALUES %s"
_selectSKUStockLog = "SELECT id, sku_id, op_type, src_id, stock FROM sku_stock_log WHERE src_id=? AND op_type=? AND sku_id IN(%s)"
_rollbackSKUStockLog = "UPDATE sku_stock_log set canceled_at=? where id=? AND canceled_at=0"
)
// StockLock lock stock
func (d *Dao) StockLock(c context.Context, skuID int64, cnt int64) (err error) {
_, err = d.db.Exec(c, _lockStockSQL, cnt, cnt, skuID, cnt)
if err != nil {
log.Error("d.StockLock(%d, %d) error(%v)", skuID, cnt, err)
}
return
}
// TxStockLock lock stock with tx
func (d *Dao) TxStockLock(tx *xsql.Tx, skuID int64, cnt int64) (affected int64, err error) {
res, err := tx.Exec(_lockStockSQL, cnt, cnt, skuID, cnt)
if err != nil {
log.Error("d.TxStockLock(%d, %d) error(%v)", skuID, cnt, err)
return
}
affected, err = res.RowsAffected()
if err != nil {
log.Error("d.TxStockLock(%d, %d) res.RowsAffected() error(%v)", skuID, cnt, err)
return
}
return
}
// StockDecr 减库存 DB
func (d *Dao) StockDecr(c context.Context, skuID int64, num int64) (affected int64, err error) {
res, err := d.db.Exec(c, _decrStockSQL, num, skuID, num)
if err != nil {
log.Error("d.StockDecr(%d, %d) error(%v)", skuID, num, err)
return
}
affected, err = res.RowsAffected()
if err != nil {
log.Error("d.StockDecr(%d, %d) res.RowsAffected() error(%v)", skuID, num, err)
return
}
return
}
// TxStockDecr 减库存 DB
func (d *Dao) TxStockDecr(tx *xsql.Tx, skuID int64, num int64) (affected int64, err error) {
res, err := tx.Exec(_decrStockSQL, num, skuID, num)
if err != nil {
log.Error("d.TxStockDecr(%d, %d) error(%v)", skuID, num, err)
return
}
affected, err = res.RowsAffected()
if err != nil {
log.Error("d.TxStockDecr(%d, %d) res.RowsAffected() error(%v)", skuID, num, err)
return
}
return
}
// StockCacheDecr 减库存缓存
func (d *Dao) StockCacheDecr(c context.Context, skuID int64, total int64) (err error) {
if err = d.RedisDecrExist(c, fmt.Sprintf(model.CacheKeyStock, skuID), total); err != nil {
log.Error("d.StockCacheDecr(%d) error(%v)", skuID, err)
}
return
}
// StockLockedCacheDecr 减锁定库存缓存
func (d *Dao) StockLockedCacheDecr(c context.Context, skuID int64, total int64) (err error) {
if err = d.RedisDecrExist(c, fmt.Sprintf(model.CacheKeyStockL, skuID), total); err != nil {
log.Error("d.StockLockedCacheDecr(%d) error(%v)", skuID, err)
}
return
}
// StockCacheDel 删除库存缓存
func (d *Dao) StockCacheDel(c context.Context, skuID int64) (err error) {
if err = d.RedisDel(c, fmt.Sprintf(model.CacheKeyStock, skuID)); err != nil {
log.Error("d.StockCacheDel(%d) error(%v)", skuID, err)
}
return
}
// DelCacheSku 删除 skuId => sku 缓存
func (d *Dao) DelCacheSku(c context.Context, skuID int64) (err error) {
if err = d.RedisDel(c, fmt.Sprintf(model.CacheKeySku, skuID)); err != nil {
log.Error("d.StockCacheDel(%d) error(%v)", skuID, err)
}
return
}
// AddStockLog TxAddStockLog
func (d *Dao) AddStockLog() {
}
// TxAddStockLog 添加库存操作日志
func (d *Dao) TxAddStockLog(tx *xsql.Tx, stockLogs ...*model.SKUStockLog) (err error) {
if len(stockLogs) == 0 {
return
}
placeholder := strings.Trim(strings.Repeat("(?, ?, ?, ?),", len(stockLogs)), ",")
var values []interface{}
for _, stockLog := range stockLogs {
values = append(values, stockLog.SKUID, stockLog.OpType, stockLog.SrcID, stockLog.Stock)
}
if _, err = tx.Exec(fmt.Sprintf(_insertSKUStockLog, placeholder), values...); err != nil {
log.Error("d.TxAddStockLog() error(%v)", err)
return
}
return
}
// TxStockUnlock 解锁库存(减去锁定库存增加库存)
func (d *Dao) TxStockUnlock(tx *xsql.Tx, skuID int64, count int64) (affected int64, err error) {
res, err := tx.Exec(_unlockStockSQL, count, count, skuID, count, count)
if err != nil {
log.Error("d.TxStockUnlock(%d, %d) error(%v)", skuID, count, err)
return
}
if affected, err = res.RowsAffected(); err != nil {
log.Error("d.TxStockUnlock(%d, %d) res.RowsAffected() error(%v)", skuID, count, err)
}
return
}
// TxStockIncr 增加库存
func (d *Dao) TxStockIncr(tx *xsql.Tx, skuID int64, count int64) (affected int64, err error) {
res, err := tx.Exec(_incrStockSQL, count, skuID, count)
if err != nil {
log.Error("d.TxStockIncr(%d, %d) error(%v)", skuID, count, err)
return
}
if affected, err = res.RowsAffected(); err != nil {
log.Error("d.TxStockIncr(%d, %d) res.RowsAffected() error(%v)", skuID, count, err)
}
return
}
// TxStockLockedDecr 减去锁定库存
func (d *Dao) TxStockLockedDecr(tx *xsql.Tx, skuID int64, count int64) (affected int64, err error) {
res, err := tx.Exec(_decrStockLockedSQL, count, skuID, count)
if err != nil {
log.Error("d.TxStockLockedDecr(%d, %d) error(%v)", skuID, count, err)
return
}
if affected, err = res.RowsAffected(); err != nil {
log.Error("d.TxStockLockedDecr(%d, %d) res.RowsAffected() error(%v)", skuID, count, err)
}
return
}
// Stock 查询库存信息
func (d *Dao) Stock(c context.Context, skuID int64) (stock *model.SKUStock, err error) {
stock = new(model.SKUStock)
if err = d.db.QueryRow(c, _getStockBySkuIDSQL, skuID).Scan(&stock.SKUID, &stock.ParentSKUID, &stock.ItemID, &stock.Specs, &stock.TotalStock, &stock.Stock, &stock.LockedStock, &stock.SkAlert, &stock.Ctime, &stock.Mtime); err != nil {
log.Error("d.Stock(%d), error(%v)", skuID, err)
}
return
}
// StockLogs 查询库存操作记录
func (d *Dao) StockLogs(c context.Context, opType int16, srcID int64, skuIDs ...int64) (stockLogs []*model.SKUStockLog, err error) {
if len(skuIDs) == 0 {
return
}
rows, err := d.db.Query(c, fmt.Sprintf(_selectSKUStockLog, xstr.JoinInts(skuIDs)), srcID, opType)
if err != nil {
log.Error("d.StockLogs() error(%v)", err)
return
}
defer rows.Close()
stockLogs = make([]*model.SKUStockLog, 0)
for rows.Next() {
stockLog := &model.SKUStockLog{}
if err = rows.Scan(&stockLog.ID, &stockLog.SKUID, &stockLog.OpType, &stockLog.SrcID, &stockLog.Stock); err != nil {
log.Error("d.StockLogs() rows.Scan() error(%v)", err)
return
}
stockLogs = append(stockLogs)
}
return
}
// TxAddStockInsert 插入 stock 数据
func (d *Dao) TxAddStockInsert(tx *xsql.Tx, stocks ...*model.SKUStock) (affected int64, err error) {
placeholder := strings.Trim(strings.Repeat("(?, ?, ?, ?, ?, ?, ?, ?),", len(stocks)), ",")
var values []interface{}
for _, stock := range stocks {
values = append(values, stock.SKUID, stock.ParentSKUID, stock.ItemID, stock.Specs, stock.TotalStock, stock.Stock, stock.LockedStock, stock.SkAlert)
}
res, err := tx.Exec(fmt.Sprintf(_insertStockSQL, placeholder), values...)
if err != nil {
log.Error("d.TxStockInsert() error(%v)", err)
return
}
if affected, err = res.RowsAffected(); err != nil {
log.Error("d.TxStockInsert() res.RowsAffected() error(%v)", err)
return
}
return
}
// TxStockReset 重置库存
func (d *Dao) TxStockReset(tx *xsql.Tx, stock *model.SKUStock) (affected int64, err error) {
res, err := tx.Exec(_resetStockSQL, stock.TotalStock, stock.TotalStock, stock.SkAlert, stock.SKUID, stock.TotalStock)
fmt.Println(_resetStockSQL, stock.TotalStock, stock.TotalStock, stock.SkAlert, stock.SKUID, stock.TotalStock)
if err != nil {
log.Error("d.TxStockReset() error(%v)", err)
return
}
if affected, err = res.RowsAffected(); err != nil {
log.Error("d.TxStockReset() res.RowsAffected() error(%v)", err)
return
}
return
}
// TxStockLogRollBack 回滚操作日志
func (d *Dao) TxStockLogRollBack(tx *xsql.Tx, stockLogID int64) (affected int64, err error) {
res, err := tx.Exec(_rollbackSKUStockLog, time.Now().Unix(), stockLogID)
if err != nil {
log.Error("d.TxStockLogRollBack(%d) error(%v)", stockLogID, err)
return
}
if affected, err = res.RowsAffected(); err != nil {
log.Error("d.TxStockLogRollBack(%d) res.RowsAffected() error(%v)", stockLogID, err)
}
return
}
// SkuItemCacheDel 删除 itemId => sku 缓存
func (d *Dao) SkuItemCacheDel(c context.Context, itemID int64) (err error) {
if err = d.RedisDel(c, fmt.Sprintf(model.CacheKeyItemSku, itemID)); err != nil {
log.Error("d.SkuItemCacheDel(%d) error(%v)", itemID, err)
}
return
}
// SkuByItemSpecs 通过 itemID specs 获取单个 sku
func (d *Dao) SkuByItemSpecs(c context.Context, itemID int64, specs string) (stock *model.SKUStock, err error) {
res, err := d.SkuByItemID(c, itemID)
if err != nil {
log.Error("d.SkuByItemSpecs(%d, %s) d.SkuByItemID() error(%v)", itemID, specs, err)
return
}
if item, ok := res[specs]; ok {
stock = item
}
return
}
// RawSkuByItemSpecs 根据 itemID 和规格获取单个 sku
func (d *Dao) RawSkuByItemSpecs(c context.Context, itemID int64, specs string) (stock *model.SKUStock, err error) {
stock = new(model.SKUStock)
if err = d.db.QueryRow(c, _getStockBySpecsSQL, itemID, specs).Scan(&stock.SKUID, &stock.ParentSKUID, &stock.ItemID, &stock.Specs, &stock.TotalStock, &stock.Stock, &stock.LockedStock, &stock.SkAlert, &stock.Ctime, &stock.Mtime); err != nil {
if err != sql.ErrNoRows {
log.Error("d.SkuByItemSpecs(%d, %s) error(%v)", itemID, specs, err)
}
}
return
}
// RawSkuByItemID 根据规格获取 sku
func (d *Dao) RawSkuByItemID(c context.Context, itemID int64) (stocks map[string]*model.SKUStock, err error) {
rows, err := d.db.Query(c, _getStockByItemIDSQL, itemID)
if err != nil {
log.Error("d.RawSkuByItemID(%d) error(%v)", itemID, err)
return
}
defer rows.Close()
stocks = make(map[string]*model.SKUStock)
for rows.Next() {
stock := new(model.SKUStock)
if err = rows.Scan(&stock.SKUID, &stock.ParentSKUID, &stock.ItemID, &stock.Specs, &stock.TotalStock, &stock.Stock, &stock.LockedStock, &stock.SkAlert, &stock.Ctime, &stock.Mtime); err != nil {
log.Error("d.RawSkuByItemID(%d) rows.Scan() error(%v)", itemID, err)
return
}
stocks[stock.Specs] = stock
}
return
}
// CacheSkuByItemID 根据 itemID 获取 sku 缓存
func (d *Dao) CacheSkuByItemID(c context.Context, itemID int64) (stocks map[string]*model.SKUStock, err error) {
conn := d.redis.Get(c)
defer conn.Close()
reply, err := redis.Bytes(conn.Do("GET", fmt.Sprintf(model.CacheKeyItemSku, itemID)))
if err != nil {
if err == redis.ErrNil {
err = nil
return
}
log.Error("d.CacheSkuByItemID(%d) redis.Bytes() error(%v)", itemID, err)
return
}
stocks = make(map[string]*model.SKUStock)
if err = json.Unmarshal(reply, &stocks); err != nil {
log.Error("d.CacheSkuByItemID(%d) json.Unmarshal() error(%v)", itemID, err)
return
}
return
}
// AddCacheSkuByItemID 添加 itemId => sku 缓存
func (d *Dao) AddCacheSkuByItemID(c context.Context, itemID int64, stocks map[string]*model.SKUStock) (err error) {
if stocks == nil {
return
}
conn := d.redis.Get(c)
defer conn.Close()
s, err := json.Marshal(stocks)
if err != nil {
log.Error("d.AddCacheSkuByItemID(%d, %+v) json.Marshal() error(%v)", itemID, stocks, err)
return
}
if _, err = conn.Do("SETEX", fmt.Sprintf(model.CacheKeyItemSku, itemID), model.RedisExpireSku, s); err != nil {
log.Error("d.AddCacheSkuByItemID(%d, %+v) conn.Do() error(%v)", itemID, stocks, err)
return
}
return
}
// CacheStocks 获取 skuID => stock 库存缓存
func (d *Dao) CacheStocks(c context.Context, keys []int64, isLocked bool) (res map[int64]int64, err error) {
if len(keys) == 0 {
return
}
conn := d.redis.Get(c)
defer conn.Close()
cacheKey := model.CacheKeyStock
if isLocked {
cacheKey = model.CacheKeyStockL
}
args := make([]interface{}, 0)
for _, key := range keys {
args = append(args, fmt.Sprintf(cacheKey, key))
}
int64s, err := redis.Int64s(conn.Do("MGET", args...))
if err != nil {
if err == redis.ErrNil {
err = nil
return
}
log.Error("d.CacheStocks(%v, %t) error(%v)", keys, isLocked, err)
return
}
res = make(map[int64]int64)
for index, val := range int64s {
if val < 0 {
val = 0
}
res[keys[index]] = val
}
return
}
// RawStocks skuID => stock 缓存回源
func (d *Dao) RawStocks(c context.Context, keys []int64, isLocked bool) (res map[int64]int64, err error) {
if len(keys) == 0 {
return
}
rows, err := d.db.Query(c, fmt.Sprintf(_getStockBySkuID, xstr.JoinInts(keys)))
if err != nil {
log.Error("d.RawStocks() error(%v)", err)
return
}
defer rows.Close()
res = make(map[int64]int64)
for rows.Next() {
var skuID, stock, lockedStock int64
if err = rows.Scan(&skuID, &stock, &lockedStock); err != nil {
log.Error("d.RawStocks() rows.Scan() error(%v)", err)
return
}
if isLocked {
res[skuID] = lockedStock
} else {
res[skuID] = stock
}
}
return
}
// AddCacheStocks skuID => stock 加入缓存
func (d *Dao) AddCacheStocks(c context.Context, stocks map[int64]int64, isLocked bool) (err error) {
cacheKey := model.CacheKeyStock
if isLocked {
cacheKey = model.CacheKeyStockL
}
for skuID, stock := range stocks {
if err1 := d.RedisSetnx(c, fmt.Sprintf(cacheKey, skuID), stock, model.RedisExpireStock); err1 != nil {
log.Warn("d.AddCacheStocks() d.RedisSetnx(%s, %d, %d) error(%v)", fmt.Sprintf(cacheKey, skuID), stock, model.RedisExpireStock, err)
}
}
return
}
// CacheGetSKUs 根据 skuID 获取 sku
// withNewStock 是否获取最新库存信息
func (d *Dao) CacheGetSKUs(c context.Context, skuIds []int64, withNewStock bool) (skuMap map[int64]*model.SKUStock, err error) {
if len(skuIds) == 0 {
return
}
conn := d.redis.Get(c)
defer conn.Close()
args := make([]interface{}, 0)
for _, skuID := range skuIds {
args = append(args, fmt.Sprintf(model.CacheKeySku, skuID))
}
res, err := redis.ByteSlices(conn.Do("MGET", args...))
if err != nil {
if err == redis.ErrNil {
err = nil
return
}
log.Error("d.CacheGetSKUs(%v, %t) error(%v)", skuIds, withNewStock, err)
return
}
skuMap = make(map[int64]*model.SKUStock, len(res))
for _, v := range res {
if len(v) == 0 {
continue
}
sku := &model.SKUStock{}
if err = json.Unmarshal(v, sku); err != nil {
log.Error("d.CacheGetSKUs() json.Unmarshal(%s) error(%v)", v, err)
return
}
skuMap[sku.SKUID] = sku
}
if withNewStock {
var stockMap map[int64]int64
if stockMap, err = d.Stocks(c, skuIds, false); err != nil {
log.Error("d.CacheGetSKUs() d.Stocks(%v) error(%v)", skuIds, err)
return
}
for _, sku := range skuMap {
sku.Stock = stockMap[sku.SKUID]
}
}
return
}
// RawGetSKUs .
func (d *Dao) RawGetSKUs(c context.Context, skuIds []int64, withNewStock bool) (skuMap map[int64]*model.SKUStock, err error) {
if len(skuIds) == 0 {
return
}
rows, err := d.db.Query(c, fmt.Sprintf(_getStocksBySkuIDSQL, xstr.JoinInts(skuIds)))
if err != nil {
log.Error("d.RawGetSKUs() error(%v)", err)
}
defer rows.Close()
skuMap = make(map[int64]*model.SKUStock)
for rows.Next() {
sku := &model.SKUStock{}
if err = rows.Scan(&sku.SKUID, &sku.ParentSKUID, &sku.ItemID, &sku.Specs, &sku.TotalStock, &sku.Stock, &sku.LockedStock, &sku.SkAlert, &sku.Ctime, &sku.Mtime); err != nil {
log.Error("d.RawGetSKUs() rows.Scan error(%v)", err)
return
}
skuMap[sku.SKUID] = sku
}
return
}
// AddCacheGetSKUs .
func (d *Dao) AddCacheGetSKUs(c context.Context, skuMap map[int64]*model.SKUStock, withNewStock bool) (err error) {
conn := d.redis.Get(c)
defer func() {
conn.Flush()
conn.Close()
}()
for skuID, sku := range skuMap {
var v []byte
if v, err = json.Marshal(sku); err != nil {
log.Warn("d.AddCacheGetSKUs() json.Marshal(%v) error(%v)", sku, err)
err = nil
continue
}
conn.Send("SETEX", fmt.Sprintf(model.CacheKeySku, skuID), model.RedisExpireSkuTmp, v)
}
return
}

View File

@@ -0,0 +1,52 @@
package dao
import (
"strings"
"testing"
"go-common/app/service/openplatform/ticket-sales/model"
. "github.com/smartystreets/goconvey/convey"
)
func TestTxAddStockLog(t *testing.T) {
Convey("TestTxAddStockLog", t, func() {
tx, _ := d.BeginTx(ctx)
err := d.TxAddStockLog(tx, &model.SKUStockLog{
SKUID: 1,
OpType: 1,
SrcID: 1,
Stock: 1,
})
tx.Rollback()
if strings.Contains(err.Error(), "Error 1062: Duplicate entry") {
So(err, ShouldNotBeNil)
} else {
So(err, ShouldBeNil)
}
})
}
func TestSkuByItemID(t *testing.T) {
Convey("TestSkuByItemID", t, func() {
res, err := d.SkuByItemID(ctx, 1)
So(err, ShouldBeNil)
So(res, ShouldNotBeNil)
})
}
func TestStocks(t *testing.T) {
Convey("TestStocks", t, func() {
res, err := d.Stocks(ctx, []int64{1}, false)
So(err, ShouldBeNil)
So(res, ShouldNotBeNil)
})
}
func TestGetSKUs(t *testing.T) {
Convey("TestGetSKUs", t, func() {
res, err := d.GetSKUs(ctx, []int64{1}, false)
So(err, ShouldBeNil)
So(res, ShouldNotBeNil)
})
}

View File

@@ -0,0 +1,416 @@
package dao
import (
"context"
"encoding/json"
"fmt"
"strings"
"go-common/app/service/openplatform/ticket-sales/model"
"go-common/app/service/openplatform/ticket-sales/model/consts"
"go-common/library/cache/redis"
"go-common/library/log"
"go-common/library/xstr"
)
//票号相关常量
const (
sqlCountRefundTicket = "SELECT COUNT(*) FROM ticket WHERE oid IN (%s) AND refund_status=?"
_selectTicketByOrderIDSQL = "SELECT id, uid, oid, sid, price, src, type, status, qr, ref_id, sku_id, seat_id, seat, etime, refund_apply_time, ctime, mtime FROM ticket WHERE oid=?"
_selectTicketByScreenIDSQL = "SELECT id, uid, oid, sid, price, src, type, status, qr, ref_id, sku_id, seat_id, seat, etime, refund_apply_time, ctime, mtime FROM ticket WHERE sid=? AND uid=? AND type != ?"
_selectTicketByIDSQL = "SELECT id, uid, oid, sid, price, src, type, status, qr, ref_id, sku_id, seat_id, seat, etime, refund_apply_time, ctime, mtime FROM ticket WHERE id IN (%s)"
_updateTicketStatusSQL = "UPDATE ticket set status=? WHERE id IN (%s)"
_selectTicketSendBySendTID = "SELECT id, sid, send_tid, recv_tid, send_uid, recv_uid, recv_tel, status, ctime, mtime, oid FROM ticket_send WHERE send_tid IN (%s)"
_selectTicketSendByRecvTID = "SELECT id, sid, send_tid, recv_tid, send_uid, recv_uid, recv_tel, status, ctime, mtime, oid FROM ticket_send WHERE recv_tid IN (%s)"
)
//rawRefundTicketCnt 统计用户已退票数
func (d *Dao) rawRefundTicketCnt(ctx context.Context, oids []int64) (cnt int64, err error) {
lo := len(oids)
if lo == 0 {
return
}
q := fmt.Sprintf(sqlCountRefundTicket, strings.Repeat(",?", lo)[1:])
a := make([]interface{}, lo+1)
a[lo] = consts.TkStatusRefunded
for k, v := range oids {
a[k] = v
}
err = d.db.QueryRow(ctx, q, a...).Scan(&cnt)
return
}
// CacheTicketsByOrderID 通过 order_id 获取 tickets 取缓存
func (d *Dao) CacheTicketsByOrderID(c context.Context, orderID int64) (res []*model.Ticket, err error) {
conn := d.redis.Get(c)
defer conn.Close()
reply, err := redis.Bytes(conn.Do("GET", fmt.Sprintf(model.CacheKeyOrderTickets, orderID)))
if err != nil {
if err == redis.ErrNil {
err = nil
return
}
log.Error("d.CacheTicketsByOrderID(%d) error(%v)", orderID, err)
return
}
if err = json.Unmarshal(reply, &res); err != nil {
log.Error("d.CacheTicketsByOrderID(%d) json.Unmarshal() error(%v)", orderID, err)
return
}
return
}
// RawTicketsByOrderID 通过 order_id 获取 tickets
func (d *Dao) RawTicketsByOrderID(c context.Context, orderID int64) (res []*model.Ticket, err error) {
rows, err := d.db.Query(c, _selectTicketByOrderIDSQL, orderID)
if err != nil {
log.Error("d.TicketsByOrderID(%v) d.db.Query() error(%v)", orderID, err)
return
}
defer rows.Close()
for rows.Next() {
ticket := &model.Ticket{}
if err = rows.Scan(&ticket.ID, &ticket.UID, &ticket.OID, &ticket.SID, &ticket.Price, &ticket.Src, &ticket.Type,
&ticket.Status, &ticket.Qr, &ticket.RefID, &ticket.SkuID, &ticket.SeatID,
&ticket.Seat, &ticket.ETime, &ticket.RefundApplyTime, &ticket.CTime, &ticket.MTime); err != nil {
log.Error("d.TicketsByOrderID(%v) rows.Scan() error(%v)", orderID, err)
return
}
res = append(res, ticket)
}
return
}
// AddCacheTicketsByOrderID 通过 order_id 获取 tickets 写缓存
func (d *Dao) AddCacheTicketsByOrderID(c context.Context, orderID int64, tickets []*model.Ticket) (err error) {
conn := d.redis.Get(c)
defer conn.Close()
val, err := json.Marshal(tickets)
if err != nil {
log.Error("d.AddCacheTicketsByScreen() error(%v)", err)
return
}
if _, err = conn.Do("SETEX", fmt.Sprintf(model.CacheKeyOrderTickets, orderID), model.RedisExpireOneDayTmp, val); err != nil {
log.Error("d.AddCacheTicketsByOrderID(%d, %+v) error(%v)", orderID, tickets, err)
return
}
return
}
// CacheTicketsByScreen 通过 screen_id user_id 获取 tickets
func (d *Dao) CacheTicketsByScreen(c context.Context, screenID int64, UID int64) (res []*model.Ticket, err error) {
conn := d.redis.Get(c)
defer conn.Close()
reply, err := redis.Bytes(conn.Do("GET", fmt.Sprintf(model.CacheKeyScreenTickets, screenID, UID)))
if err != nil {
if err == redis.ErrNil {
err = nil
return
}
log.Error("d.CacheTicketsByScreen(%d, %d) error(%v)", screenID, UID, err)
return
}
if err = json.Unmarshal(reply, &res); err != nil {
log.Error("d.CacheTicketsByScreen(%d, %d) json.Unmarshal() error(%v)", screenID, UID, err)
return
}
return
}
// RawTicketsByScreen 通过 screen_id user_id 获取 tickets
func (d *Dao) RawTicketsByScreen(c context.Context, screenID int64, UID int64) (res []*model.Ticket, err error) {
rows, err := d.db.Query(c, _selectTicketByScreenIDSQL, screenID, UID, consts.TkTypeDistrib)
if err != nil {
log.Error("d.RawTicketsByScreen(%d, %d) error(%v)", screenID, UID, err)
return
}
defer rows.Close()
for rows.Next() {
ticket := &model.Ticket{}
if err = rows.Scan(&ticket.ID, &ticket.UID, &ticket.OID, &ticket.SID, &ticket.Price, &ticket.Src, &ticket.Type,
&ticket.Status, &ticket.Qr, &ticket.RefID, &ticket.SkuID, &ticket.SeatID,
&ticket.Seat, &ticket.ETime, &ticket.RefundApplyTime, &ticket.CTime, &ticket.MTime); err != nil {
log.Error("d.RawTicketsByScreen(%d, %d) rows.Scan() error(%v)", screenID, UID, err)
return
}
res = append(res, ticket)
}
return
}
// AddCacheTicketsByScreen 通过 screen_id user_id 获取 tickets
func (d *Dao) AddCacheTicketsByScreen(c context.Context, screenID int64, tickets []*model.Ticket, UID int64) (err error) {
conn := d.redis.Get(c)
defer conn.Close()
val, err := json.Marshal(tickets)
if err != nil {
log.Error("d.AddCacheTicketsByScreen() error(%v)", err)
return
}
if _, err = conn.Do("SETEX", fmt.Sprintf(model.CacheKeyScreenTickets, screenID, UID), model.RedisExpireOneDayTmp, val); err != nil {
log.Error("d.AddCacheTicketsByScreen(%d, %d, %+v) error(%v)", screenID, UID, tickets, err)
return
}
return
}
// CacheTicketsByID .
func (d *Dao) CacheTicketsByID(c context.Context, ticketID []int64) (res map[int64]*model.Ticket, err error) {
if len(ticketID) == 0 {
return
}
conn := d.redis.Get(c)
defer conn.Close()
keys := make([]interface{}, 0)
for _, ID := range ticketID {
keys = append(keys, fmt.Sprintf(model.CacheKeyTicket, ID))
}
reply, err := redis.ByteSlices(conn.Do("MGET", keys...))
if err != nil {
if err == redis.ErrNil {
err = nil
return
}
log.Error("d.CacheTicketsByID(%v) conn.Do() error(%v)", ticketID, err)
return
}
res = make(map[int64]*model.Ticket)
for _, item := range reply {
if len(item) == 0 {
continue
}
ticket := &model.Ticket{}
if err = json.Unmarshal(item, ticket); err != nil {
log.Error("d.CacheTicketsByID(%v) json.Unmarshal(%s) error(%v)", ticketID, item, err)
continue
}
res[ticket.ID] = ticket
}
return
}
// RawTicketsByID .
func (d *Dao) RawTicketsByID(c context.Context, ticketID []int64) (res map[int64]*model.Ticket, err error) {
if len(ticketID) == 0 {
return
}
rows, err := d.db.Query(c, fmt.Sprintf(_selectTicketByIDSQL, xstr.JoinInts(ticketID)))
if err != nil {
log.Error("d.RawTicketsByID(%v) d.db.Query() error(%v)", ticketID, err)
return
}
defer rows.Close()
res = make(map[int64]*model.Ticket)
for rows.Next() {
ticket := &model.Ticket{}
if err = rows.Scan(&ticket.ID, &ticket.UID, &ticket.OID, &ticket.SID, &ticket.Price, &ticket.Src, &ticket.Type,
&ticket.Status, &ticket.Qr, &ticket.RefID, &ticket.SkuID, &ticket.SeatID,
&ticket.Seat, &ticket.ETime, &ticket.RefundApplyTime, &ticket.CTime, &ticket.MTime); err != nil {
log.Error("d.RawTicketsByID(%v) rows.Scan() error(%v)", ticketID, err)
return
}
res[ticket.ID] = ticket
}
return
}
// AddCacheTicketsByID .
func (d *Dao) AddCacheTicketsByID(c context.Context, tickets map[int64]*model.Ticket) (err error) {
if len(tickets) == 0 {
return
}
conn := d.redis.Get(c)
defer func() {
conn.Flush()
conn.Close()
}()
args := make([]interface{}, 0)
for ID, ticket := range tickets {
var b []byte
if b, err = json.Marshal(ticket); err != nil {
log.Error("d.AddCacheTicketsByID(%+v) json.Marshal(%+v) error(%v)", tickets, ticket, err)
continue
}
args = append(args, fmt.Sprintf(model.CacheKeyTicket, ID), b)
}
if err = conn.Send("MSET", args...); err != nil {
log.Error("d.AddCacheTicketsByID(%+v) conn.Send() error(%v)", tickets, err)
return
}
for ID := range tickets {
conn.Send("EXPIRE", fmt.Sprintf(model.CacheKeyTicket, ID), model.RedisExpireTenMinTmp)
}
return
}
// UpdateTicketStatus 更新票状态
func (d *Dao) UpdateTicketStatus(c context.Context, status int16, ticketID ...int64) (err error) {
if len(ticketID) == 0 {
return
}
if _, err = d.db.Exec(c, fmt.Sprintf(_updateTicketStatusSQL, xstr.JoinInts(ticketID)), status); err != nil {
log.Error("d.UpdateTicketStatus(%d, %v) error(%v)", status, ticketID, err)
}
return
}
// DelTicketCache 删除单张电子票全部 cache
func (d *Dao) DelTicketCache(c context.Context, tickets ...*model.Ticket) (err error) {
if len(tickets) == 0 {
return
}
var keys []interface{}
for _, ticket := range tickets {
keys = append(
keys,
fmt.Sprintf(model.CacheKeyOrderTickets, ticket.OID),
fmt.Sprintf(model.CacheKeyScreenTickets, ticket.SID, ticket.UID),
fmt.Sprintf(model.CacheKeyTicket, ticket.ID),
fmt.Sprintf(model.CacheKeyTicketQr, ticket.Qr),
)
}
if err = d.RedisDel(c, keys...); err != nil {
log.Error("d.DelTicketCache() d.RedisDel(%v) error(%v)", keys, err)
}
return
}
// CacheTicketSend .
func (d *Dao) CacheTicketSend(c context.Context, IDs []int64, TIDType string) (res map[int64]*model.TicketSend, err error) {
var cacheKey string
switch TIDType {
case consts.TIDTypeSend:
cacheKey = model.CacheKeyTicketSend
case consts.TIDTypeRecv:
cacheKey = model.CacheKeyTicketRecv
default:
return
}
conn := d.redis.Get(c)
defer conn.Close()
keys := make([]interface{}, 0)
for _, ID := range IDs {
keys = append(keys, fmt.Sprintf(cacheKey, ID))
}
reply, err := redis.ByteSlices(conn.Do("MGET", keys...))
if err != nil {
if err == redis.ErrNil {
err = nil
return
}
log.Error("d.CacheTicketSend(%v, %s) conn.Do() error(%v)", IDs, TIDType, err)
return
}
res = make(map[int64]*model.TicketSend)
for _, item := range reply {
if len(item) == 0 {
continue
}
tmp := &model.TicketSend{}
if err = json.Unmarshal(item, tmp); err != nil {
log.Error("d.CacheTicketSend() json.Unmarshal(%s) error(%v)", item, err)
continue
}
switch TIDType {
case consts.TIDTypeSend:
res[tmp.SendTID] = tmp
case consts.TIDTypeRecv:
res[tmp.RecvTID] = tmp
default:
return
}
}
return
}
// RawTicketSend .
func (d *Dao) RawTicketSend(c context.Context, IDs []int64, TIDType string) (res map[int64]*model.TicketSend, err error) {
if len(IDs) == 0 {
return
}
var sql string
switch TIDType {
case consts.TIDTypeSend:
sql = _selectTicketSendBySendTID
case consts.TIDTypeRecv:
sql = _selectTicketSendByRecvTID
default:
return
}
rows, err := d.db.Query(c, fmt.Sprintf(sql, xstr.JoinInts(IDs)))
if err != nil {
log.Error("d.RawTicketSend(%v, %s) d.db.Query() error(%v)", IDs, TIDType, err)
return
}
defer rows.Close()
res = make(map[int64]*model.TicketSend)
for rows.Next() {
tmp := &model.TicketSend{}
if err = rows.Scan(&tmp.ID, &tmp.SID, &tmp.SendTID, &tmp.RecvTID, &tmp.SendUID, &tmp.RecvUID, &tmp.RecvTel, &tmp.Status, &tmp.CTime, &tmp.MTime, &tmp.OID); err != nil {
log.Error("d.RawTicketSend(%v, %s) rows.Scan() error(%v)", IDs, TIDType, err)
return
}
switch TIDType {
case consts.TIDTypeSend:
res[tmp.SendTID] = tmp
case consts.TIDTypeRecv:
res[tmp.RecvTID] = tmp
default:
return
}
}
return
}
// AddCacheTicketSend .
func (d *Dao) AddCacheTicketSend(c context.Context, tsMap map[int64]*model.TicketSend, TIDType string) (err error) {
var cacheKey string
switch TIDType {
case consts.TIDTypeSend:
cacheKey = model.CacheKeyTicketSend
case consts.TIDTypeRecv:
cacheKey = model.CacheKeyTicketRecv
default:
return
}
conn := d.redis.Get(c)
defer func() {
conn.Flush()
conn.Close()
}()
var args []interface{}
for ID, item := range tsMap {
var b []byte
if b, err = json.Marshal(item); err != nil {
log.Error("d.AddCacheTicketSend(%v, %s), json.Marshal(%s) error(%v)", tsMap, TIDType, b, err)
continue
}
args = append(args, fmt.Sprintf(cacheKey, ID), b)
}
if err = conn.Send("MSET", args...); err != nil {
log.Error("d.AddCacheTicketsByID(%+v) conn.Send() error(%v)", tsMap, err)
return
}
for ID := range tsMap {
conn.Send("EXPIRE", fmt.Sprintf(cacheKey, ID), model.RedisExpireOneDayTmp)
}
return
}

View File

@@ -0,0 +1,23 @@
package dao
import (
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func TestTicketsByID(t *testing.T) {
Convey("TestTicketsByID", t, func() {
tickets, err := d.TicketsByID(ctx, []int64{101, 102})
So(err, ShouldBeNil)
So(tickets, ShouldNotBeNil)
})
}
func TestTicketSend(t *testing.T) {
Convey("TestTicketSend", t, func() {
sends, err := d.TicketSend(ctx, []int64{402, 412}, "send")
So(err, ShouldBeNil)
So(sends, ShouldNotBeNil)
})
}